diff options
author | Jan Schmidt <jan@centricular.com> | 2015-02-03 01:19:05 +1100 |
---|---|---|
committer | Jan Schmidt <jan@centricular.com> | 2015-02-06 04:05:27 +1100 |
commit | f852f3bc7526afd470acb4e65a77b22d4821cc8e (patch) | |
tree | 8fe46c3a5b2b2cd49e98dcc1e1f100d128c8d80a | |
parent | 615118dea8fb393b8746694bf1d38b47bb75a7d7 (diff) |
theora: If no header packets in stream, look for them in the caps
Makes theora work in cases where the header packets are only in the caps
(because theoradec was connected to oggdemux late and missed the
beginning of the stream)
-rw-r--r-- | ext/theora/gsttheoradec.c | 67 |
1 files changed, 63 insertions, 4 deletions
diff --git a/ext/theora/gsttheoradec.c b/ext/theora/gsttheoradec.c index d1a7b24d8..d2f14b098 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)) { |