Commit 55e767b6 authored by Vincent Penquerc'h's avatar Vincent Penquerc'h Committed by Tim-Philipp Müller

oggmux: prefer headers from caps to determine stream type

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.
parent 1d05e814
......@@ -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,
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));
......@@ -2051,3 +2051,58 @@ gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet * packet)
return FALSE;
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);
......@@ -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,
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment