oggmux: prefer headers from caps to determine stream type
authorVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Fri, 15 Apr 2011 12:36:39 +0000 (13:36 +0100)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Sat, 16 Apr 2011 10:55:27 +0000 (11:55 +0100)
Ogg mandates the first header packet must determine a stream's type.
However, some streams (such as VP8) do not include such a header
when muxed in other containers, and thus do not include this header
as a buffer, but only in caps. We thus use headers from caps when
available to determine a new stream's type.

https://bugzilla.gnome.org/show_bug.cgi?id=647856

ext/ogg/gstoggmux.c
ext/ogg/gstoggstream.c
ext/ogg/gstoggstream.h

index 9f3047f6592c0581e339ae75f9538ea0733403e0..4dda50b4ec2fffe2bac96fd4d27265ae5d45a43c 100644 (file)
@@ -848,7 +848,18 @@ gst_ogg_mux_queue_pads (GstOggMux * ogg_mux)
 
           /* if we're not yet in data mode, ensure we're setup on the first packet */
           if (!pad->have_type) {
-            pad->have_type = gst_ogg_stream_setup_map (&pad->map, &packet);
+            /* Use headers in caps, if any; this will allow us to be resilient
+             * to starting streams on the fly, and some streams (like VP8
+             * at least) do not send headers packets, as other muxers don't
+             * expect/need them. */
+            pad->have_type =
+                gst_ogg_stream_setup_map_from_caps_headers (&pad->map,
+                GST_BUFFER_CAPS (buf));
+
+            if (!pad->have_type) {
+              /* fallback on the packet */
+              pad->have_type = gst_ogg_stream_setup_map (&pad->map, &packet);
+            }
             if (!pad->have_type) {
               GST_ERROR_OBJECT (pad, "mapper didn't recognise input stream "
                   "(pad caps: %" GST_PTR_FORMAT ")", GST_PAD_CAPS (pad));
index 3ef2fd00f59bcfa46ad2348cf4cb0d59a41a0277..e843f48721660789b66212a8d343c68d6f68a56f 100644 (file)
@@ -2051,3 +2051,58 @@ gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet * packet)
 
   return FALSE;
 }
+
+gboolean
+gst_ogg_stream_setup_map_from_caps_headers (GstOggStream * pad,
+    const GstCaps * caps)
+{
+  const GstStructure *structure;
+  const GstBuffer *buf;
+  const GValue *streamheader;
+  const GValue *first_element;
+  ogg_packet packet;
+
+  GST_INFO ("Checking streamheader on caps %" GST_PTR_FORMAT, caps);
+
+  if (caps == NULL)
+    return FALSE;
+
+  structure = gst_caps_get_structure (caps, 0);
+  streamheader = gst_structure_get_value (structure, "streamheader");
+
+  if (streamheader == NULL) {
+    GST_LOG ("no streamheader field in caps %" GST_PTR_FORMAT, caps);
+    return FALSE;
+  }
+
+  if (!GST_VALUE_HOLDS_ARRAY (streamheader)) {
+    GST_ERROR ("streamheader field not an array, caps: %" GST_PTR_FORMAT, caps);
+    return FALSE;
+  }
+
+  if (gst_value_array_get_size (streamheader) == 0) {
+    GST_ERROR ("empty streamheader field in caps %" GST_PTR_FORMAT, caps);
+    return FALSE;
+  }
+
+  first_element = gst_value_array_get_value (streamheader, 0);
+
+  if (!GST_VALUE_HOLDS_BUFFER (first_element)) {
+    GST_ERROR ("first streamheader not a buffer, caps: %" GST_PTR_FORMAT, caps);
+    return FALSE;
+  }
+
+  buf = gst_value_get_buffer (first_element);
+  if (buf == NULL || GST_BUFFER_SIZE (buf) == 0) {
+    GST_ERROR ("invalid first streamheader buffer");
+    return FALSE;
+  }
+
+  GST_MEMDUMP ("streamheader", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+
+  packet.packet = GST_BUFFER_DATA (buf);
+  packet.bytes = GST_BUFFER_SIZE (buf);
+
+  GST_INFO ("Found headers on caps, using those to determine type");
+  return gst_ogg_stream_setup_map (pad, &packet);
+}
index 94c8f05504ae0105156f5364252c6c454ce6b615..f843692eaf85b028350960984c5018fc47d0f268 100644 (file)
@@ -106,6 +106,8 @@ struct _GstOggStream
 
 
 gboolean gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet *packet);
+gboolean gst_ogg_stream_setup_map_from_caps_headers (GstOggStream * pad,
+    const GstCaps * caps);
 GstClockTime gst_ogg_stream_get_end_time_for_granulepos (GstOggStream *pad,
     gint64 granulepos);
 GstClockTime gst_ogg_stream_get_start_time_for_granulepos (GstOggStream *pad,