From d8312994aa68a2bade307cf71ed10ae5a2e61748 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Sat, 8 Oct 2011 20:09:09 +0200 Subject: [PATCH 1/7] audiodecoder: handle empty input by discarding --- gst-libs/gst/audio/gstaudiodecoder.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/audio/gstaudiodecoder.c b/gst-libs/gst/audio/gstaudiodecoder.c index 3843f22050..32cbc61aaa 100644 --- a/gst-libs/gst/audio/gstaudiodecoder.c +++ b/gst-libs/gst/audio/gstaudiodecoder.c @@ -1065,7 +1065,14 @@ gst_audio_decoder_flush (GstAudioDecoder * dec, gboolean hard) static GstFlowReturn gst_audio_decoder_chain_forward (GstAudioDecoder * dec, GstBuffer * buffer) { - GstFlowReturn ret; + GstFlowReturn ret = GST_FLOW_OK; + + /* discard silly case, though maybe ts may be of value ?? */ + if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) == 0)) { + GST_DEBUG_OBJECT (dec, "discarding empty buffer"); + gst_buffer_unref (buffer); + goto exit; + } /* grab buffer */ gst_adapter_push (dec->priv->adapter, buffer); @@ -1076,6 +1083,7 @@ gst_audio_decoder_chain_forward (GstAudioDecoder * dec, GstBuffer * buffer) /* hand to subclass */ ret = gst_audio_decoder_push_buffers (dec, FALSE); +exit: GST_LOG_OBJECT (dec, "chain-done"); return ret; } From a7ce550d04071b31b600339262deca41cda8ad71 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Sat, 8 Oct 2011 20:11:22 +0200 Subject: [PATCH 2/7] audiodecoder: fix timestamp tolerance handling --- gst-libs/gst/audio/gstaudiodecoder.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gst-libs/gst/audio/gstaudiodecoder.c b/gst-libs/gst/audio/gstaudiodecoder.c index 32cbc61aaa..ca9dfd2885 100644 --- a/gst-libs/gst/audio/gstaudiodecoder.c +++ b/gst-libs/gst/audio/gstaudiodecoder.c @@ -792,17 +792,17 @@ gst_audio_decoder_finish_frame (GstAudioDecoder * dec, GstBuffer * buf, g_assert (GST_CLOCK_TIME_IS_VALID (priv->base_ts)); next_ts = priv->base_ts + - gst_util_uint64_scale (samples, GST_SECOND, ctx->info.rate); + gst_util_uint64_scale (priv->samples, GST_SECOND, ctx->info.rate); GST_LOG_OBJECT (dec, "buffer is %d samples past base_ts %" GST_TIME_FORMAT - ", expected ts %" GST_TIME_FORMAT, samples, + ", expected ts %" GST_TIME_FORMAT, priv->samples, GST_TIME_ARGS (priv->base_ts), GST_TIME_ARGS (next_ts)); diff = GST_CLOCK_DIFF (next_ts, ts); GST_LOG_OBJECT (dec, "ts diff %d ms", (gint) (diff / GST_MSECOND)); /* if within tolerance, * discard buffer ts and carry on producing perfect stream, * otherwise resync to ts */ - if (G_UNLIKELY (diff < -dec->priv->tolerance || - diff > dec->priv->tolerance)) { + if (G_UNLIKELY (diff < (gint64) - dec->priv->tolerance || + diff > (gint64) dec->priv->tolerance)) { GST_DEBUG_OBJECT (dec, "base_ts resync"); priv->base_ts = ts; priv->samples = 0; From 871b1584c9c09b029ede55e6621eb33ef41a5fdd Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Sat, 8 Oct 2011 20:13:11 +0200 Subject: [PATCH 3/7] audioencoder: only resync to upstream upon discont in perfect ts mode ... as documented, where discont is marked here if tolerance has been exceeded. --- gst-libs/gst/audio/gstaudioencoder.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gst-libs/gst/audio/gstaudioencoder.c b/gst-libs/gst/audio/gstaudioencoder.c index 5051efa3cc..39d5c53619 100644 --- a/gst-libs/gst/audio/gstaudioencoder.c +++ b/gst-libs/gst/audio/gstaudioencoder.c @@ -950,10 +950,12 @@ gst_audio_encoder_chain (GstPad * pad, GstBuffer * buffer) gst_audio_encoder_drain (enc); } } - /* now re-sync ts */ - priv->base_ts += diff; - gst_audio_encoder_set_base_gp (enc); - priv->discont |= discont; + if (discont) { + /* now re-sync ts */ + priv->base_ts += diff; + gst_audio_encoder_set_base_gp (enc); + priv->discont |= discont; + } } gst_adapter_push (enc->priv->adapter, buffer); From 12b54cccd153d64025aa3b7ae3eb1a092f7eceda Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Sat, 8 Oct 2011 20:14:27 +0200 Subject: [PATCH 4/7] tests: vorbisdec: remove empty header buffer check ... as empty buffers are discarded, and header buffers are now also optionally retrieved from caps anyway. --- tests/check/elements/vorbisdec.c | 37 -------------------------------- 1 file changed, 37 deletions(-) diff --git a/tests/check/elements/vorbisdec.c b/tests/check/elements/vorbisdec.c index 29e3cd5cd8..8a9281af4a 100644 --- a/tests/check/elements/vorbisdec.c +++ b/tests/check/elements/vorbisdec.c @@ -94,42 +94,6 @@ cleanup_vorbisdec (GstElement * vorbisdec) gst_check_teardown_element (vorbisdec); } -GST_START_TEST (test_empty_identification_header) -{ - GstElement *vorbisdec; - GstBuffer *inbuffer; - GstBus *bus; - GstMessage *message; - - vorbisdec = setup_vorbisdec (); - bus = gst_bus_new (); - - fail_unless (gst_element_set_state (vorbisdec, - GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, - "could not set to playing"); - - inbuffer = gst_buffer_new_and_alloc (0); - ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); - - /* set a bus here so we avoid getting state change messages */ - gst_element_set_bus (vorbisdec, bus); - - fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_ERROR); - /* ... but it ends up being collected on the global buffer list */ - fail_unless_equals_int (g_list_length (buffers), 0); - - fail_if ((message = gst_bus_pop (bus)) == NULL); - fail_unless_message_error (message, STREAM, DECODE); - gst_message_unref (message); - gst_element_set_bus (vorbisdec, NULL); - - /* cleanup */ - gst_object_unref (GST_OBJECT (bus)); - cleanup_vorbisdec (vorbisdec); -} - -GST_END_TEST; - /* FIXME: also tests comment header */ GST_START_TEST (test_identification_header) { @@ -329,7 +293,6 @@ vorbisdec_suite (void) TCase *tc_chain = tcase_create ("general"); suite_add_tcase (s, tc_chain); - tcase_add_test (tc_chain, test_empty_identification_header); tcase_add_test (tc_chain, test_identification_header); tcase_add_test (tc_chain, test_empty_vorbis_packet); From 9e72c4790cd863d75b61d72989dfdd8c93d712a7 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Sat, 8 Oct 2011 20:16:04 +0200 Subject: [PATCH 5/7] tests: vorbisdec: properly configure audiodecoder when requiring perfect ts --- tests/check/pipelines/vorbisdec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/check/pipelines/vorbisdec.c b/tests/check/pipelines/vorbisdec.c index 751e79a82d..8434d6004a 100644 --- a/tests/check/pipelines/vorbisdec.c +++ b/tests/check/pipelines/vorbisdec.c @@ -54,8 +54,11 @@ GST_START_TEST (test_timestamps) GstBus *bus; GError *error = NULL; + /* allowing some tolerance permits audiodecoder to come up with + * perfect timestamps rather than sticking to upstream ts */ pipe_str = g_strdup_printf ("audiotestsrc num-buffers=100" - " ! audio/x-raw-int,rate=44100 ! audioconvert ! vorbisenc ! vorbisdec" + " ! audio/x-raw-int,rate=44100 ! audioconvert ! vorbisenc " + " ! vorbisdec tolerance=10000000 " " ! identity check-imperfect-timestamp=TRUE ! fakesink"); pipeline = gst_parse_launch (pipe_str, &error); From 7b56261acf31213b59e9638d0fb5b55a674fbfdf Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Sat, 8 Oct 2011 20:17:43 +0200 Subject: [PATCH 6/7] tests: vorbisenc: adjust discontinuity checking to audioencoder behaviour ... which still detects gaps and marks DISCONT, depending on configuration, but may come up with somewhat different timestamps when crossing the gap. --- tests/check/pipelines/vorbisenc.c | 43 ++++++++++++------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/tests/check/pipelines/vorbisenc.c b/tests/check/pipelines/vorbisenc.c index b207dffee2..4b15a1038b 100644 --- a/tests/check/pipelines/vorbisenc.c +++ b/tests/check/pipelines/vorbisenc.c @@ -264,7 +264,7 @@ GST_END_TEST; static gboolean drop_second_data_buffer (GstPad * droppad, GstBuffer * buffer, gpointer unused) { - return !(GST_BUFFER_OFFSET (buffer) == 1024); + return !(GST_BUFFER_OFFSET (buffer) == 4096); } GST_START_TEST (test_discontinuity) @@ -276,8 +276,10 @@ GST_START_TEST (test_discontinuity) GError *error = NULL; guint drop_id; + /* make audioencoder act sufficiently pedantic */ pipe_str = g_strdup_printf ("audiotestsrc samplesperbuffer=1024" - " ! audio/x-raw-int,rate=44100" " ! audioconvert ! vorbisenc ! fakesink"); + " ! audio/x-raw-int,rate=44100" " ! audioconvert " + " ! vorbisenc tolerance=10000000 ! fakesink"); bin = gst_parse_launch (pipe_str, &error); fail_unless (bin != NULL, "Error parsing pipeline: %s", @@ -330,38 +332,27 @@ GST_START_TEST (test_discontinuity) check_buffer_granulepos (buffer, 0); gst_buffer_unref (buffer); - /* two phases: continuous granulepos values up to 1024, then a first - discontinuous granulepos whose granulepos corresponds to a gap ending at - 2048. */ { GstClockTime next_timestamp = 0; - gint64 last_granulepos = 0; + gint64 last_granulepos = 0, granulepos; + gint i; - while (last_granulepos < 1024) { + for (i = 0; i < 10; i++) { buffer = gst_buffer_straw_get_buffer (bin, pad); - last_granulepos = GST_BUFFER_OFFSET_END (buffer); + granulepos = GST_BUFFER_OFFSET_END (buffer); + /* discont is either at start, or following gap */ + if (GST_BUFFER_IS_DISCONT (buffer)) { + if (next_timestamp) { + fail_unless (granulepos - last_granulepos > 1024, + "expected discont of at least 1024 samples"); + next_timestamp = GST_BUFFER_TIMESTAMP (buffer); + } + } check_buffer_timestamp (buffer, next_timestamp); - fail_if (GST_BUFFER_IS_DISCONT (buffer), "expected continuous buffer"); next_timestamp += GST_BUFFER_DURATION (buffer); + last_granulepos = granulepos; gst_buffer_unref (buffer); } - - fail_unless (last_granulepos == 1024, - "unexpected granulepos: %" G_GUINT64_FORMAT, last_granulepos); - } - - { - buffer = gst_buffer_straw_get_buffer (bin, pad); - /* The first buffer after the discontinuity will produce zero output - * samples (because of the overlap/add), so it won't increment the - * granulepos, which should be 2048 after the discontinuity. - */ - fail_unless (GST_BUFFER_OFFSET_END (buffer) == 2048, - "expected granulepos after gap: %" G_GUINT64_FORMAT, - GST_BUFFER_OFFSET_END (buffer)); - fail_unless (GST_BUFFER_IS_DISCONT (buffer), - "expected discontinuous buffer"); - gst_buffer_unref (buffer); } gst_buffer_straw_stop_pipeline (bin, pad); From bc6f00becb630204f83593ef0320d19aacec5df7 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Sun, 9 Oct 2011 16:48:18 +0200 Subject: [PATCH 7/7] audioencoder: fix compile warning --- gst-libs/gst/audio/gstaudiodecoder.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gst-libs/gst/audio/gstaudiodecoder.c b/gst-libs/gst/audio/gstaudiodecoder.c index ca9dfd2885..5ed2af107a 100644 --- a/gst-libs/gst/audio/gstaudiodecoder.c +++ b/gst-libs/gst/audio/gstaudiodecoder.c @@ -555,7 +555,7 @@ gst_audio_decoder_setup (GstAudioDecoder * dec) gst_query_unref (query); /* normalize to bool */ - dec->priv->agg = ! !res; + dec->priv->agg = !!res; } /* mini aggregator combining output buffers into fewer larger ones, @@ -793,8 +793,9 @@ gst_audio_decoder_finish_frame (GstAudioDecoder * dec, GstBuffer * buf, g_assert (GST_CLOCK_TIME_IS_VALID (priv->base_ts)); next_ts = priv->base_ts + gst_util_uint64_scale (priv->samples, GST_SECOND, ctx->info.rate); - GST_LOG_OBJECT (dec, "buffer is %d samples past base_ts %" GST_TIME_FORMAT - ", expected ts %" GST_TIME_FORMAT, priv->samples, + GST_LOG_OBJECT (dec, + "buffer is %" G_GUINT64_FORMAT " samples past base_ts %" + GST_TIME_FORMAT ", expected ts %" GST_TIME_FORMAT, priv->samples, GST_TIME_ARGS (priv->base_ts), GST_TIME_ARGS (next_ts)); diff = GST_CLOCK_DIFF (next_ts, ts); GST_LOG_OBJECT (dec, "ts diff %d ms", (gint) (diff / GST_MSECOND));