diff options
author | Wim Taymans <wim.taymans@collabora.co.uk> | 2012-10-29 17:19:50 +0000 |
---|---|---|
committer | Wim Taymans <wim.taymans@collabora.co.uk> | 2012-10-29 17:19:50 +0000 |
commit | 1936d84771c0b4baf50fca8efc250eeb953425d5 (patch) | |
tree | 2279739c11238634446972ff23bb796b6d6d970a | |
parent | aceb0a95962ddaa21f1e428f553b11ed39e35c4d (diff) |
sbcdec: handle DISCONT and timestamps
Reset state on discont.
Interpollate timestamps.
-rw-r--r-- | audio/gstsbcdec.c | 58 | ||||
-rw-r--r-- | audio/gstsbcdec.h | 1 |
2 files changed, 50 insertions, 9 deletions
diff --git a/audio/gstsbcdec.c b/audio/gstsbcdec.c index ebcc0e43..420d7e45 100644 --- a/audio/gstsbcdec.c +++ b/audio/gstsbcdec.c @@ -62,9 +62,18 @@ static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer) GstFlowReturn res = GST_FLOW_OK; guint size, codesize, offset = 0; guint8 *data; + GstClockTime timestamp; codesize = sbc_get_codesize(&dec->sbc); + if (GST_BUFFER_IS_DISCONT (buffer)) { + /* reset previous buffer */ + gst_buffer_unref(dec->buffer); + dec->buffer = NULL; + /* we need a new timestamp to lock onto */ + dec->next_sample = -1; + } + if (dec->buffer) { GstBuffer *temp = buffer; buffer = gst_buffer_span(dec->buffer, 0, buffer, @@ -77,11 +86,16 @@ static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer) data = GST_BUFFER_DATA(buffer); size = GST_BUFFER_SIZE(buffer); + timestamp = GST_BUFFER_TIMESTAMP (buffer); + + while (offset < size) { GstBuffer *output; GstPadTemplate *template; GstCaps *caps; int consumed; + GstClockTime duration; + gint rate, channels; res = gst_pad_alloc_buffer_and_set_caps(dec->srcpad, GST_BUFFER_OFFSET_NONE, @@ -93,18 +107,46 @@ static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer) consumed = sbc_decode(&dec->sbc, data + offset, size - offset, GST_BUFFER_DATA(output), codesize, NULL); + GST_INFO_OBJECT (dec, "consumed %d bytes", consumed); + if (consumed <= 0) break; + rate = gst_sbc_parse_rate_from_sbc (dec->sbc.frequency); + channels = gst_sbc_get_channel_number (dec->sbc.mode); + + if (GST_CLOCK_TIME_IS_VALID (timestamp)) { + /* lock onto timestamp when we have one */ + dec->next_sample = gst_util_uint64_scale_int (timestamp, + rate, GST_SECOND); + } if (dec->next_sample != (guint64) -1) { + /* reconstruct timestamp from our sample counter otherwise */ + timestamp = gst_util_uint64_scale_int (dec->next_sample, + GST_SECOND, rate); + } + GST_BUFFER_TIMESTAMP (output) = timestamp; + + /* calculate the next sample */ + if (dec->next_sample != (guint64) -1) { + /* we ave a valid sample, counter, increment it. */ + dec->next_sample += codesize / (2 * channels); + duration = gst_util_uint64_scale_int (dec->next_sample, + GST_SECOND, rate) - timestamp; + } else { + /* otherwise calculate duration based on output size */ + duration = gst_util_uint64_scale_int (codesize / (2 * channels), + GST_SECOND, rate) - timestamp; + } + GST_BUFFER_DURATION (output) = duration; + + /* reset timestamp for next round */ + timestamp = GST_CLOCK_TIME_NONE; + /* we will reuse the same caps object */ if (dec->outcaps == NULL) { caps = gst_caps_new_simple("audio/x-raw-int", - "rate", G_TYPE_INT, - gst_sbc_parse_rate_from_sbc( - dec->sbc.frequency), - "channels", G_TYPE_INT, - gst_sbc_get_channel_number( - dec->sbc.mode), + "rate", G_TYPE_INT, rate, + "channels", G_TYPE_INT, channels, NULL); template = gst_static_pad_template_get(&sbc_dec_src_factory); @@ -118,9 +160,6 @@ static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer) gst_buffer_set_caps(output, dec->outcaps); - gst_buffer_copy_metadata(output, buffer, - GST_BUFFER_COPY_TIMESTAMPS); - res = gst_pad_push(dec->srcpad, output); if (res != GST_FLOW_OK) goto done; @@ -154,6 +193,7 @@ static GstStateChangeReturn sbc_dec_change_state(GstElement *element, } sbc_init(&dec->sbc, 0); dec->outcaps = NULL; + dec->next_sample = -1; break; default: break; diff --git a/audio/gstsbcdec.h b/audio/gstsbcdec.h index c77feaed..a62e61b2 100644 --- a/audio/gstsbcdec.h +++ b/audio/gstsbcdec.h @@ -53,6 +53,7 @@ struct _GstSbcDec { GstCaps *outcaps; sbc_t sbc; + guint64 next_sample; }; struct _GstSbcDecClass { |