From a7b09098b94e48ed207056f2418d3fe8396733f1 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Sat, 27 May 2023 13:06:22 +0100 Subject: [PATCH] oggdemux: vp8: Detect keyframe packets decodebin3 drops data on video streams until a keyframe or header is detected, so for Ogg/VP8 we now need to correctly flag and signal keyframes downstream. The first buffer pushed from each src pad also has the HEADER flag set. Fixes playback of https://github.com/web-platform-tests/wpt/raw/master/media/test.ogv in playbin3. Fixes #1418 Part-of: --- subprojects/gst-integration-testsuites/medias | 2 +- .../testsuites/validate.testslist | 1 + .../validate/playbin3/ogv_vp8.validatetest | 6 ++++++ .../gst-plugins-base/ext/ogg/gstoggdemux.c | 9 +++++++-- .../gst-plugins-base/ext/ogg/gstoggdemux.h | 2 ++ .../gst-plugins-base/ext/ogg/gstoggstream.c | 18 +++++++++++++++++- 6 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 subprojects/gst-integration-testsuites/testsuites/validate/playbin3/ogv_vp8.validatetest diff --git a/subprojects/gst-integration-testsuites/medias b/subprojects/gst-integration-testsuites/medias index 7d39b42f64..ea0342a6bf 160000 --- a/subprojects/gst-integration-testsuites/medias +++ b/subprojects/gst-integration-testsuites/medias @@ -1 +1 @@ -Subproject commit 7d39b42f64f0e1f4e131266a2b4a72087ef6427b +Subproject commit ea0342a6bf6e27320b4aaec75019ab31ca9c3c6a diff --git a/subprojects/gst-integration-testsuites/testsuites/validate.testslist b/subprojects/gst-integration-testsuites/testsuites/validate.testslist index 9678975aee..69f6613ee1 100644 --- a/subprojects/gst-integration-testsuites/testsuites/validate.testslist +++ b/subprojects/gst-integration-testsuites/testsuites/validate.testslist @@ -948,6 +948,7 @@ validate.test.mse.segment_future_past_nomse validate.test.nle.urisource.play validate.test.playbin.check_active_stream validate.test.playbin3.ignore_raw_audio_from_demuxer +validate.test.playbin3.ogv_vp8 validate.test.playbin3.sourcebin_check_mixed_static_and_dyanmic_pads validate.test.rtp.h264.payloader_fail_nego_force_profile validate.test.rtp.h264.payloader_nego_profile diff --git a/subprojects/gst-integration-testsuites/testsuites/validate/playbin3/ogv_vp8.validatetest b/subprojects/gst-integration-testsuites/testsuites/validate/playbin3/ogv_vp8.validatetest new file mode 100644 index 0000000000..623e739f7f --- /dev/null +++ b/subprojects/gst-integration-testsuites/testsuites/validate/playbin3/ogv_vp8.validatetest @@ -0,0 +1,6 @@ +set-globals, media_dir="$(test_dir)/../../../medias/" +meta, + args = { + "playbin3 uri=file://$(media_dir)/defaults/ogg/wpt-test-ogg-vp8.ogv name=playbin video-sink=\"$(videosink) name=videosink\" audio-sink=\"$(audiosink)\"", + }, + scenario=play_5s diff --git a/subprojects/gst-plugins-base/ext/ogg/gstoggdemux.c b/subprojects/gst-plugins-base/ext/ogg/gstoggdemux.c index 693dc70c1e..4e6b370aa6 100644 --- a/subprojects/gst-plugins-base/ext/ogg/gstoggdemux.c +++ b/subprojects/gst-plugins-base/ext/ogg/gstoggdemux.c @@ -580,6 +580,9 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet, if ((packet->bytes >= 7 && memcmp (packet->packet, "OVP80\2 ", 7) == 0) || packet->b_o_s || (packet->bytes >= 5 && memcmp (packet->packet, "OVP80", 5) == 0)) { + /* Request the first packet being pushed downstream to have the header + flag set, unblocking the keyframe_waiter_probe in decodebin3. */ + pad->need_header_flag = TRUE; /* We don't push header packets for VP8 */ goto done; } @@ -818,9 +821,11 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet, if (delta_unit) GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); - /* set header flag for buffers that are also in the streamheaders */ - if (is_header) + /* set header flag for buffers that are also in the streamheaders or when explicitely requested (VP8). */ + if (is_header || pad->need_header_flag) { + pad->need_header_flag = FALSE; GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER); + } if (packet->packet != NULL) { /* copy packet in buffer */ diff --git a/subprojects/gst-plugins-base/ext/ogg/gstoggdemux.h b/subprojects/gst-plugins-base/ext/ogg/gstoggdemux.h index 4275070be2..967a552ab9 100644 --- a/subprojects/gst-plugins-base/ext/ogg/gstoggdemux.h +++ b/subprojects/gst-plugins-base/ext/ogg/gstoggdemux.h @@ -102,6 +102,8 @@ struct _GstOggPad GList *continued; + gboolean need_header_flag; + gboolean discont; GstFlowReturn last_ret; /* last return of _pad_push() */ gboolean is_eos; diff --git a/subprojects/gst-plugins-base/ext/ogg/gstoggstream.c b/subprojects/gst-plugins-base/ext/ogg/gstoggstream.c index a974215a92..a8883304a5 100644 --- a/subprojects/gst-plugins-base/ext/ogg/gstoggstream.c +++ b/subprojects/gst-plugins-base/ext/ogg/gstoggstream.c @@ -761,6 +761,22 @@ is_keyframe_vp8 (GstOggStream * pad, gint64 granulepos) return ((gpos & 0x07ffffff) == 0); } +static gboolean +is_packet_keyframe_vp8 (GstOggStream * pad, ogg_packet * packet) +{ + guint32 hdr; + gboolean is_kf = FALSE; + + if (packet->bytes < 3) { + return FALSE; + } + + hdr = GST_READ_UINT24_LE (packet->packet); + + is_kf = (hdr & 0x1); + return is_kf; +} + static gint64 granulepos_to_granule_vp8 (GstOggStream * pad, gint64 gpos) { @@ -2576,7 +2592,7 @@ const GstOggMap mappers[] = { granulepos_to_granule_vp8, granule_to_granulepos_vp8, is_keyframe_vp8, - NULL, + is_packet_keyframe_vp8, is_header_vp8, packet_duration_vp8, granulepos_to_key_granule_vp8,