diff options
author | Wim Taymans <wim.taymans@collabora.co.uk> | 2009-09-03 18:43:26 +0200 |
---|---|---|
committer | Wim Taymans <wim.taymans@collabora.co.uk> | 2009-09-03 18:45:31 +0200 |
commit | 823f06f039a11920a9c0337821b7528eaab4b33b (patch) | |
tree | 67d624cf96b5dda37bb16d60a07d896f230f028e /gst/siren | |
parent | 9a1597e58b9b4420dcf0237afe92bbd266944ffe (diff) |
sirenenc: fix timestamping
Handle DISCONT and reset adapter.
code cleanups.
Put timestamps and discont flags on output buffers.
Fix error handling.
Remove bogus object locks, it's all protected by the STREAM_LOCK.
Diffstat (limited to 'gst/siren')
-rw-r--r-- | gst/siren/gstsirenenc.c | 141 | ||||
-rw-r--r-- | gst/siren/gstsirenenc.h | 3 |
2 files changed, 99 insertions, 45 deletions
diff --git a/gst/siren/gstsirenenc.c b/gst/siren/gstsirenenc.c index fbf2b6e07..e21da4fc4 100644 --- a/gst/siren/gstsirenenc.c +++ b/gst/siren/gstsirenenc.c @@ -40,6 +40,8 @@ GST_DEBUG_CATEGORY (sirenenc_debug); #define GST_CAT_DEFAULT (sirenenc_debug) +#define FRAME_DURATION (20 * GST_MSECOND) + /* elementfactory information */ static const GstElementDetails gst_siren_enc_details = GST_ELEMENT_DETAILS ("Siren Encoder element", @@ -176,14 +178,22 @@ gst_siren_enc_chain (GstPad * pad, GstBuffer * buf) { GstSirenEnc *enc = GST_SIREN_ENC (gst_pad_get_parent_element (pad)); GstFlowReturn ret = GST_FLOW_OK; - GstBuffer *encoded = NULL; - guint8 *data = NULL; - gint out_offset = 0; - gint encode_ret = 0; - gint size = 0; - guint in_offset = 0; - - GST_OBJECT_LOCK (enc); + GstBuffer *out_buf; + guint8 *in_data, *out_data; + guint8 *to_free = NULL; + guint i, size, num_frames; + gint out_size, in_size; + gint encode_ret; + gboolean discont; + GstClockTime timestamp; + guint64 distance; + + discont = GST_BUFFER_IS_DISCONT (buf); + if (discont) { + GST_DEBUG_OBJECT (enc, "received DISCONT, flush adapter"); + gst_adapter_clear (enc->adapter); + enc->discont = TRUE; + } gst_adapter_push (enc->adapter, buf); @@ -191,50 +201,90 @@ gst_siren_enc_chain (GstPad * pad, GstBuffer * buf) GST_BUFFER_SIZE (buf), gst_adapter_available (enc->adapter)); size = gst_adapter_available (enc->adapter); - size /= 16; - size -= size % 40; - if (size == 0) { - GST_OBJECT_UNLOCK (enc); - goto out; - } + /* we need to process 640 input bytes to produce 40 output bytes */ + /* calculate the amount of frames we will handle */ + num_frames = size / 640; - data = gst_adapter_take (enc->adapter, size * 16); + /* no frames, wait some more */ + if (num_frames == 0) + goto done; - GST_OBJECT_UNLOCK (enc); + /* this is the output size */ + in_size = num_frames * 640; + out_size = num_frames * 40; - ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad, - GST_BUFFER_OFFSET (buf) / 16, size, enc->srccaps, &encoded); + GST_LOG_OBJECT (enc, "we have %u frames, %u in, %u out", num_frames, in_size, + out_size); + /* get a buffer */ + ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad, -1, + out_size, enc->srccaps, &out_buf); if (ret != GST_FLOW_OK) - goto out; - - while (out_offset < size && ret == GST_FLOW_OK) { - GST_LOG_OBJECT (enc, "Encoding frame"); - - encode_ret = Siren7_EncodeFrame (enc->encoder, - data + in_offset, GST_BUFFER_DATA (encoded) + out_offset); - if (encode_ret != 0) { - GST_ERROR_OBJECT (enc, "Siren7_EncodeFrame returned %d", encode_ret); - ret = GST_FLOW_ERROR; - gst_buffer_unref (encoded); - goto out; - } - - out_offset += 40; - in_offset += 640; + goto alloc_failed; + + /* get the timestamp for the output buffer */ + timestamp = gst_adapter_prev_timestamp (enc->adapter, &distance); + + /* add the amount of time taken by the distance */ + timestamp += gst_util_uint64_scale_int (distance / 2, GST_SECOND, 16000); + + GST_LOG_OBJECT (enc, + "timestamp %" GST_TIME_FORMAT ", distance %" G_GUINT64_FORMAT, + GST_TIME_ARGS (timestamp), distance); + + /* get the input data for all the frames */ + to_free = in_data = gst_adapter_take (enc->adapter, in_size); + out_data = GST_BUFFER_DATA (out_buf); + + for (i = 0; i < num_frames; i++) { + GST_LOG_OBJECT (enc, "Encoding frame %u/%u", i, num_frames); + + /* encode 640 input bytes to 40 output bytes */ + encode_ret = Siren7_EncodeFrame (enc->encoder, in_data, out_data); + if (encode_ret != 0) + goto encode_error; + + /* move to next frame */ + out_data += 40; + in_data += 640; } - GST_LOG_OBJECT (enc, "Finished encoding : %d", out_offset); + GST_LOG_OBJECT (enc, "Finished encoding"); + + /* mark discont */ + if (enc->discont) { + GST_BUFFER_FLAG_SET (out_buf, GST_BUFFER_FLAG_DISCONT); + enc->discont = FALSE; + } + GST_BUFFER_TIMESTAMP (out_buf) = timestamp; + GST_BUFFER_DURATION (out_buf) = num_frames * FRAME_DURATION; - ret = gst_pad_push (enc->srcpad, encoded); + ret = gst_pad_push (enc->srcpad, out_buf); -out: - if (data) - g_free (data); +done: + if (to_free) + g_free (to_free); gst_object_unref (enc); + return ret; + + /* ERRORS */ +alloc_failed: + { + GST_DEBUG_OBJECT (enc, "failed to pad_alloc buffer: %d (%d)", ret, + gst_flow_get_name (ret)); + goto done; + } +encode_error: + { + GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL), + ("Error encoding frame: %d", encode_ret)); + ret = GST_FLOW_ERROR; + gst_buffer_unref (out_buf); + goto done; + } } static GstStateChangeReturn @@ -243,16 +293,19 @@ gst_siren_change_state (GstElement * element, GstStateChange transition) GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstSirenEnc *enc = GST_SIREN_ENC (element); - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + enc->discont = FALSE; + break; + default: + break; + } - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_OBJECT_LOCK (element); gst_adapter_clear (enc->adapter); - GST_OBJECT_UNLOCK (element); break; default: break; diff --git a/gst/siren/gstsirenenc.h b/gst/siren/gstsirenenc.h index 47e05bc78..66709be89 100644 --- a/gst/siren/gstsirenenc.h +++ b/gst/siren/gstsirenenc.h @@ -52,9 +52,10 @@ struct _GstSirenEnc /* protected by the stream lock */ SirenEncoder encoder; - /* protected by the object lock */ GstAdapter *adapter; + gboolean discont; + GstPad *srcpad; GstPad *sinkpad; |