summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Schmidt <jan@centricular.com>2015-02-03 01:19:05 +1100
committerJan Schmidt <jan@centricular.com>2015-02-06 04:05:27 +1100
commitf852f3bc7526afd470acb4e65a77b22d4821cc8e (patch)
tree8fe46c3a5b2b2cd49e98dcc1e1f100d128c8d80a
parent615118dea8fb393b8746694bf1d38b47bb75a7d7 (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.c67
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)) {