diff --git a/ext/theora/gsttheoradec.c b/ext/theora/gsttheoradec.c index d1a7b24d89..d2f14b0981 100644 --- a/ext/theora/gsttheoradec.c +++ b/ext/theora/gsttheoradec.c @@ -418,7 +418,7 @@ theora_handle_type_packet (GstTheoraDec * dec) } /* theora has: * - * width/height : dimension of the encoded frame + * width/height : dimension of the encoded frame * pic_width/pic_height : dimension of the visible part * pic_x/pic_y : offset in encoded frame where visible part starts */ @@ -559,6 +559,62 @@ header_read_error: } } +#define MIN_NUM_HEADERS 3 +static GstFlowReturn +theoradec_handle_header_caps (GstTheoraDec * dec) +{ + GstFlowReturn result = GST_CUSTOM_FLOW_DROP; + GstCaps *caps; + GstStructure *s = NULL; + const GValue *array = NULL; + + GST_DEBUG_OBJECT (dec, "Looking for Theora headers in caps"); + caps = gst_pad_get_current_caps (GST_VIDEO_DECODER_SINK_PAD (dec)); + if (caps) + s = gst_caps_get_structure (caps, 0); + if (s) + array = gst_structure_get_value (s, "streamheader"); + + if (caps) + gst_caps_unref (caps); + + if (array && (gst_value_array_get_size (array) >= MIN_NUM_HEADERS)) { + const GValue *value = NULL; + GstBuffer *buf = NULL; + gint i = 0; + + while (result == GST_CUSTOM_FLOW_DROP + && i < gst_value_array_get_size (array)) { + value = gst_value_array_get_value (array, i); + buf = gst_value_get_buffer (value); + if (!buf) + goto null_buffer; + GST_LOG_OBJECT (dec, "Submitting header packet"); + result = theora_dec_decode_buffer (dec, buf, NULL); + i++; + } + } else + goto array_error; + +done: + return (result != + GST_CUSTOM_FLOW_DROP ? GST_FLOW_NOT_NEGOTIATED : GST_FLOW_OK); + + /* ERRORS */ +array_error: + { + GST_WARNING_OBJECT (dec, "streamheader array not found"); + result = GST_FLOW_ERROR; + goto done; + } +null_buffer: + { + GST_WARNING_OBJECT (dec, "streamheader with null buffer received"); + result = GST_FLOW_ERROR; + goto done; + } +} + /* Allocate buffer and copy image data into Y444 format */ static GstFlowReturn theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf, @@ -683,10 +739,13 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet, GstFlowReturn result; ogg_int64_t gp; - if (G_UNLIKELY (!dec->have_header)) - goto not_initialized; + if (G_UNLIKELY (!dec->have_header)) { + result = theoradec_handle_header_caps (dec); + if (result != GST_FLOW_OK) + goto not_initialized; + } - /* the second most significant bit of the first data byte is cleared + /* the second most significant bit of the first data byte is cleared * for keyframes. We can only check it if it's not a zero-length packet. */ keyframe = packet->bytes && ((packet->packet[0] & 0x40) == 0); if (G_UNLIKELY (keyframe)) {