}
/* 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
*/
}
}
+#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,
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)) {