oggdemux: vp8: Detect keyframe packets
authorPhilippe Normand <philn@igalia.com>
Sat, 27 May 2023 12:06:22 +0000 (13:06 +0100)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Thu, 1 Jun 2023 17:00:44 +0000 (17:00 +0000)
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/4745>

subprojects/gst-integration-testsuites/testsuites/validate.testslist
subprojects/gst-integration-testsuites/testsuites/validate/playbin3/ogv_vp8.validatetest [new file with mode: 0644]
subprojects/gst-plugins-base/ext/ogg/gstoggdemux.c
subprojects/gst-plugins-base/ext/ogg/gstoggdemux.h
subprojects/gst-plugins-base/ext/ogg/gstoggstream.c

index 3a87d99..ad17ae3 100644 (file)
@@ -948,6 +948,7 @@ validate.test.mse.segment_future_past_nomse.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 (file)
index 0000000..623e739
--- /dev/null
@@ -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
index e72fda8..5b181b4 100644 (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) ||
         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 */
index 4275070..967a552 100644 (file)
@@ -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;
index a974215..a888330 100644 (file)
@@ -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,