From a4540bca1e0ee64dc60c68cec03e5f3e9639e92c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2007 16:31:32 +0000 Subject: [PATCH] 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. --- ChangeLog | 10 ++++ gst/qtdemux/qtdemux.c | 139 +++++++++++++++++++++++++++++++++++++++++++ gst/qtdemux/qtdemux_fourcc.h | 7 +++ gst/qtdemux/qtdemux_types.c | 2 + 4 files changed, 158 insertions(+) diff --git a/ChangeLog b/ChangeLog index 8ccd0af..3437426 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2007-11-15 Wim Taymans + + * 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. + 2007-11-15 Edgard Lima * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init), diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c index 1a93324..99f52e6 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 16ad851..cd8197c 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 76813b0..7e78077 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 = -- 2.7.4