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)
This commit is contained in:
Jan Schmidt 2015-02-03 01:19:05 +11:00
parent 615118dea8
commit f852f3bc75

View file

@ -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)) {