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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4725>
This commit is contained in:
Philippe Normand 2023-05-27 13:06:22 +01:00 committed by GStreamer Marge Bot
parent cd4b84b60b
commit a7b09098b9
6 changed files with 34 additions and 4 deletions

@ -1 +1 @@
Subproject commit 7d39b42f64f0e1f4e131266a2b4a72087ef6427b Subproject commit ea0342a6bf6e27320b4aaec75019ab31ca9c3c6a

View file

@ -948,6 +948,7 @@ validate.test.mse.segment_future_past_nomse
validate.test.nle.urisource.play validate.test.nle.urisource.play
validate.test.playbin.check_active_stream validate.test.playbin.check_active_stream
validate.test.playbin3.ignore_raw_audio_from_demuxer 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.playbin3.sourcebin_check_mixed_static_and_dyanmic_pads
validate.test.rtp.h264.payloader_fail_nego_force_profile validate.test.rtp.h264.payloader_fail_nego_force_profile
validate.test.rtp.h264.payloader_nego_profile validate.test.rtp.h264.payloader_nego_profile

View file

@ -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

View file

@ -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) || if ((packet->bytes >= 7 && memcmp (packet->packet, "OVP80\2 ", 7) == 0) ||
packet->b_o_s || packet->b_o_s ||
(packet->bytes >= 5 && memcmp (packet->packet, "OVP80", 5) == 0)) { (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 */ /* We don't push header packets for VP8 */
goto done; goto done;
} }
@ -818,9 +821,11 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet,
if (delta_unit) if (delta_unit)
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
/* set header flag for buffers that are also in the streamheaders */ /* set header flag for buffers that are also in the streamheaders or when explicitely requested (VP8). */
if (is_header) if (is_header || pad->need_header_flag) {
pad->need_header_flag = FALSE;
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER); GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
}
if (packet->packet != NULL) { if (packet->packet != NULL) {
/* copy packet in buffer */ /* copy packet in buffer */

View file

@ -102,6 +102,8 @@ struct _GstOggPad
GList *continued; GList *continued;
gboolean need_header_flag;
gboolean discont; gboolean discont;
GstFlowReturn last_ret; /* last return of _pad_push() */ GstFlowReturn last_ret; /* last return of _pad_push() */
gboolean is_eos; gboolean is_eos;

View file

@ -761,6 +761,22 @@ is_keyframe_vp8 (GstOggStream * pad, gint64 granulepos)
return ((gpos & 0x07ffffff) == 0); 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 static gint64
granulepos_to_granule_vp8 (GstOggStream * pad, gint64 gpos) granulepos_to_granule_vp8 (GstOggStream * pad, gint64 gpos)
{ {
@ -2576,7 +2592,7 @@ const GstOggMap mappers[] = {
granulepos_to_granule_vp8, granulepos_to_granule_vp8,
granule_to_granulepos_vp8, granule_to_granulepos_vp8,
is_keyframe_vp8, is_keyframe_vp8,
NULL, is_packet_keyframe_vp8,
is_header_vp8, is_header_vp8,
packet_duration_vp8, packet_duration_vp8,
granulepos_to_key_granule_vp8, granulepos_to_key_granule_vp8,