summaryrefslogtreecommitdiffstats
path: root/gst
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@gmail.com>2007-11-15 16:31:32 +0000
committerWim Taymans <wim.taymans@gmail.com>2007-11-15 16:31:32 +0000
commita4540bca1e0ee64dc60c68cec03e5f3e9639e92c (patch)
treedfb83ce2b55ec8e4ea7d6fca9bb28b7b64b171b9 /gst
parent66ca1b2280a918d3bd7c7ce09ec22d485be34666 (diff)
gst/qtdemux/: Add suppport for theora in quicktime according to XiphQT.
Original commit message from CVS: * gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state), (gst_qtdemux_prepare_current_sample), (gst_qtdemux_loop_state_movie), (qtdemux_parse_theora_extension), (qtdemux_parse_node), (qtdemux_parse_trak), (qtdemux_video_caps): * gst/qtdemux/qtdemux_fourcc.h: * gst/qtdemux/qtdemux_types.c: Add suppport for theora in quicktime according to XiphQT.
Diffstat (limited to 'gst')
-rw-r--r--gst/qtdemux/qtdemux.c139
-rw-r--r--gst/qtdemux/qtdemux_fourcc.h7
-rw-r--r--gst/qtdemux/qtdemux_types.c2
3 files changed, 148 insertions, 0 deletions
diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c
index 1a933246..99f52e68 100644
--- a/gst/qtdemux/qtdemux.c
+++ b/gst/qtdemux/qtdemux.c
@@ -130,6 +130,7 @@ struct _QtDemuxStream
/* if we use chunks or samples */
gboolean sampled;
+ guint padding;
/* video info */
gint width;
@@ -153,6 +154,9 @@ struct _QtDemuxStream
/* when a discontinuity is pending */
gboolean discont;
+ /* list of buffers to push first */
+ GSList *buffers;
+
/* if we need to clip this buffer. This is only needed for uncompressed
* data */
gboolean need_clip;
@@ -912,6 +916,11 @@ gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
for (n = 0; n < qtdemux->n_streams; n++) {
QtDemuxStream *stream = qtdemux->streams[n];
+ while (stream->buffers) {
+ gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
+ stream->buffers =
+ g_slist_delete_link (stream->buffers, stream->buffers);
+ }
if (stream->pad)
gst_element_remove_pad (element, stream->pad);
if (stream->samples)
@@ -1170,6 +1179,21 @@ gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
stream->sample_index, stream->n_samples);
+ /* send out pending buffers */
+ while (stream->buffers) {
+ GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
+
+ if (stream->discont) {
+ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
+ stream->discont = FALSE;
+ }
+ gst_buffer_set_caps (buffer, stream->caps);
+
+ gst_pad_push (stream->pad, buffer);
+
+ stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
+ }
+
if (stream->sample_index >= stream->n_samples)
goto eos;
@@ -1182,6 +1206,12 @@ gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
*duration = sample->duration;
*keyframe = stream->all_keyframe || sample->keyframe;
+ /* add padding */
+ if (stream->padding) {
+ *offset += stream->padding;
+ *size -= stream->padding;
+ }
+
return TRUE;
/* special cases */
@@ -1489,6 +1519,8 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
GST_BUFFER_TIMESTAMP (buf) = timestamp;
GST_BUFFER_DURATION (buf) = duration;
+ GST_BUFFER_OFFSET (buf) = -1;
+ GST_BUFFER_OFFSET_END (buf) = -1;
if (stream->need_clip)
buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
@@ -2114,6 +2146,66 @@ qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, guint8 * buf,
}
static gboolean
+qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
+ GNode * xdxt)
+{
+ int len = QT_UINT32 (xdxt->data);
+ guint8 *buf = xdxt->data;
+ guint8 *end = buf + len;
+ GstBuffer *buffer;
+
+ /* skip size and type */
+ buf += 8;
+ end -= 8;
+
+ while (buf < end) {
+ gint size;
+ guint32 type;
+
+ size = QT_UINT32 (buf);
+ type = QT_FOURCC (buf + 4);
+
+ GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
+
+ if (buf + size > end || size <= 0)
+ break;
+
+ buf += 8;
+ size -= 8;
+
+ GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (type));
+
+ switch (type) {
+ case FOURCC_tCtH:
+ buffer = gst_buffer_new_and_alloc (size);
+ memcpy (GST_BUFFER_DATA (buffer), buf, size);
+ stream->buffers = g_slist_append (stream->buffers, buffer);
+ GST_LOG_OBJECT (qtdemux, "parsing theora header");
+ break;
+ case FOURCC_tCt_:
+ buffer = gst_buffer_new_and_alloc (size);
+ memcpy (GST_BUFFER_DATA (buffer), buf, size);
+ stream->buffers = g_slist_append (stream->buffers, buffer);
+ GST_LOG_OBJECT (qtdemux, "parsing theora comment");
+ break;
+ case FOURCC_tCtC:
+ buffer = gst_buffer_new_and_alloc (size);
+ memcpy (GST_BUFFER_DATA (buffer), buf, size);
+ stream->buffers = g_slist_append (stream->buffers, buffer);
+ GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
+ break;
+ default:
+ GST_WARNING_OBJECT (qtdemux,
+ "unknown theora cookie %" GST_FOURCC_FORMAT, type);
+ break;
+ }
+ buf += size;
+ }
+ return TRUE;
+}
+
+static gboolean
qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, guint8 * buffer,
int length)
{
@@ -2225,6 +2317,27 @@ qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, guint8 * buffer,
qtdemux_parse_container (qtdemux, node, buffer + 12, end);
break;
}
+ case FOURCC_XiTh:
+ {
+ guint32 version;
+ guint32 offset;
+
+ version = QT_UINT32 (buffer + 12);
+ GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
+
+ switch (version) {
+ case 0x00000001:
+ offset = 0x62;
+ break;
+ default:
+ GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
+ offset = 0;
+ break;
+ }
+ if (offset)
+ qtdemux_parse_container (qtdemux, node, buffer + offset, end);
+ break;
+ }
default:
break;
}
@@ -2983,6 +3096,25 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
"depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
break;
}
+ case FOURCC_XiTh:
+ {
+ GNode *xith, *xdxt;
+
+ GST_DEBUG_OBJECT (qtdemux, "found XiTh");
+ xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
+ if (!xith)
+ break;
+
+ xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
+ if (!xdxt)
+ break;
+
+ GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
+ /* collect the headers and store them in a stream list so that we can
+ * send them out first */
+ qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
+ break;
+ }
default:
break;
}
@@ -4072,6 +4204,13 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
_codec ("VP3");
caps = gst_caps_from_string ("video/x-vp3");
break;
+ case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
+ _codec ("Theora");
+ caps = gst_caps_from_string ("video/x-theora");
+ /* theora uses one byte of padding in the data stream because it does not
+ * allow 0 sized packets while theora does */
+ stream->padding = 1;
+ break;
case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
default:
{
diff --git a/gst/qtdemux/qtdemux_fourcc.h b/gst/qtdemux/qtdemux_fourcc.h
index 16ad8511..cd8197c3 100644
--- a/gst/qtdemux/qtdemux_fourcc.h
+++ b/gst/qtdemux/qtdemux_fourcc.h
@@ -128,6 +128,13 @@ G_BEGIN_DECLS
#define FOURCC_frma GST_MAKE_FOURCC('f','r','m','a')
#define FOURCC_ctts GST_MAKE_FOURCC('c','t','t','s')
+/* Xiph fourcc */
+#define FOURCC_XiTh GST_MAKE_FOURCC('X','i','T','h')
+#define FOURCC_XdxT GST_MAKE_FOURCC('X','d','x','T')
+#define FOURCC_tCtH GST_MAKE_FOURCC('t','C','t','H')
+#define FOURCC_tCt_ GST_MAKE_FOURCC('t','C','t','#')
+#define FOURCC_tCtC GST_MAKE_FOURCC('t','C','t','C')
+
G_END_DECLS
#endif /* __GST_QTDEMUX_FOURCC_H__ */
diff --git a/gst/qtdemux/qtdemux_types.c b/gst/qtdemux/qtdemux_types.c
index 76813b06..7e780778 100644
--- a/gst/qtdemux/qtdemux_types.c
+++ b/gst/qtdemux/qtdemux_types.c
@@ -108,6 +108,8 @@ static const QtNodeType qt_node_types[] = {
{FOURCC_rdrf, "rdrf", 0,},
{FOURCC__gen, "Custom Genre", QT_FLAG_CONTAINER,},
{FOURCC_ctts, "Composition time to sample", 0, qtdemux_dump_ctts},
+ {FOURCC_XiTh, "XiTh", 0},
+ {FOURCC_XdxT, "XdxT", 0},
{0, "unknown", 0,},
};
static const int n_qt_node_types =