summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2014-06-20 09:00:14 (GMT)
committerSebastian Dröge <sebastian@centricular.com>2014-06-20 09:02:55 (GMT)
commit909dd7831b3f8e5b6a8c5d6e6b0efc346012408d (patch)
tree430af60be417cf649eb75885bd2f2dad0c6105a3
parent5ebfe5b26b6e404e663945fbd61ad7ca3f1a058b (diff)
downloadgst-plugins-base-909dd7831b3f8e5b6a8c5d6e6b0efc346012408d.tar.gz
gst-plugins-base-909dd7831b3f8e5b6a8c5d6e6b0efc346012408d.tar.xz
audiodecoder: Don't be too picky about the output frame counter
With most decoder libraries, and especially when accessing codecs via OpenMAX or similar APIs, we don't have the ability to properly related the output buffers to a number of input samples. And could e.g. get a fractional number of input buffers decoded at a time. Previously this would in the end lead to an error message and stopped playback. Change it to a warning message instead and try to handle it gracefully. In theory the subclass can now get timestamp tracking wrong if it completely misuses the API, but if on average it behaves correct (and gst-omx and others do) it will continue to work properly. Also add a test for the new behaviour. We don't change it in the encoder yet as that requires more internal logic changes AFAIU and I'm not aware of a case where this was a problem so far.
-rw-r--r--gst-libs/gst/audio/gstaudiodecoder.c29
-rw-r--r--tests/check/libs/audiodecoder.c65
2 files changed, 76 insertions, 18 deletions
diff --git a/gst-libs/gst/audio/gstaudiodecoder.c b/gst-libs/gst/audio/gstaudiodecoder.c
index 0ded9a2..314ce93 100644
--- a/gst-libs/gst/audio/gstaudiodecoder.c
+++ b/gst-libs/gst/audio/gstaudiodecoder.c
@@ -1173,16 +1173,21 @@ gst_audio_decoder_finish_frame (GstAudioDecoder * dec, GstBuffer * buf,
/* frame and ts book-keeping */
if (G_UNLIKELY (frames < 0)) {
- if (G_UNLIKELY (-frames - 1 > priv->frames.length))
- goto overflow;
- frames = priv->frames.length + frames + 1;
+ if (G_UNLIKELY (-frames - 1 > priv->frames.length)) {
+ GST_ELEMENT_WARNING (dec, STREAM, ENCODE,
+ ("received more decoded frames %d than provided %d", frames,
+ priv->frames.length), (NULL));
+ frames = 0;
+ } else {
+ frames = priv->frames.length + frames + 1;
+ }
} else if (G_UNLIKELY (frames > priv->frames.length)) {
if (G_LIKELY (!priv->force)) {
- /* no way we can let this pass */
- g_assert_not_reached ();
- /* really no way */
- goto overflow;
+ GST_ELEMENT_WARNING (dec, STREAM, ENCODE,
+ ("received more decoded frames %d than provided %d", frames,
+ priv->frames.length), (NULL));
}
+ frames = priv->frames.length;
}
if (G_LIKELY (priv->frames.length))
@@ -1291,16 +1296,6 @@ wrong_buffer:
ret = GST_FLOW_ERROR;
goto exit;
}
-overflow:
- {
- GST_ELEMENT_ERROR (dec, STREAM, ENCODE,
- ("received more decoded frames %d than provided %d", frames,
- priv->frames.length), (NULL));
- if (buf)
- gst_buffer_unref (buf);
- ret = GST_FLOW_ERROR;
- goto exit;
- }
}
static GstFlowReturn
diff --git a/tests/check/libs/audiodecoder.c b/tests/check/libs/audiodecoder.c
index b3f460a..8f77a18 100644
--- a/tests/check/libs/audiodecoder.c
+++ b/tests/check/libs/audiodecoder.c
@@ -44,6 +44,7 @@ struct _GstAudioDecoderTester
GstAudioDecoder parent;
gboolean setoutputformat_on_decoding;
+ gboolean output_too_many_frames;
};
struct _GstAudioDecoderTesterClass
@@ -129,7 +130,11 @@ gst_audio_decoder_tester_handle_frame (GstAudioDecoder * dec,
gst_buffer_unmap (buffer, &map);
- return gst_audio_decoder_finish_frame (dec, output_buffer, 1);
+ if (tester->output_too_many_frames) {
+ return gst_audio_decoder_finish_frame (dec, output_buffer, 2);
+ } else {
+ return gst_audio_decoder_finish_frame (dec, output_buffer, 1);
+ }
}
static void
@@ -582,6 +587,63 @@ GST_START_TEST (audiodecoder_buffer_after_segment)
}
GST_END_TEST;
+
+GST_START_TEST (audiodecoder_output_too_many_frames)
+{
+ GstSegment segment;
+ GstBuffer *buffer;
+ guint64 i;
+
+ setup_audiodecodertester ();
+
+ ((GstAudioDecoderTester *) dec)->output_too_many_frames = TRUE;
+
+ gst_pad_set_active (mysrcpad, TRUE);
+ gst_element_set_state (dec, GST_STATE_PLAYING);
+ gst_pad_set_active (mysinkpad, TRUE);
+
+ send_startup_events ();
+
+ /* push a new segment */
+ gst_segment_init (&segment, GST_FORMAT_TIME);
+ fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+ /* push buffers, the data is actually a number so we can track them */
+ for (i = 0; i < 3; i++) {
+ GstMapInfo map;
+ guint64 num;
+
+ buffer = create_test_buffer (i);
+
+ fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+
+ /* check that buffer was received by our source pad */
+ buffer = buffers->data;
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+ num = *(guint64 *) map.data;
+ fail_unless_equals_uint64 (i, num);
+ fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer),
+ gst_util_uint64_scale_round (i, GST_SECOND, TEST_MSECS_PER_SAMPLE));
+ fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer),
+ gst_util_uint64_scale_round (1, GST_SECOND, TEST_MSECS_PER_SAMPLE));
+
+ gst_buffer_unmap (buffer, &map);
+
+ gst_buffer_unref (buffer);
+ buffers = g_list_delete_link (buffers, buffers);
+ }
+
+ fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+
+ fail_unless (buffers == NULL);
+
+ cleanup_audiodecodertest ();
+}
+
+GST_END_TEST;
+
static Suite *
gst_audiodecoder_suite (void)
{
@@ -595,6 +657,7 @@ gst_audiodecoder_suite (void)
tcase_add_test (tc, audiodecoder_negotiation_with_gap_event);
tcase_add_test (tc, audiodecoder_delayed_negotiation_with_gap_event);
tcase_add_test (tc, audiodecoder_buffer_after_segment);
+ tcase_add_test (tc, audiodecoder_output_too_many_frames);
return s;
}