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.
This commit is contained in:
Wim Taymans 2007-11-15 16:31:32 +00:00
parent 66ca1b2280
commit a4540bca1e
4 changed files with 158 additions and 0 deletions

View file

@ -1,3 +1,13 @@
2007-11-15 Wim Taymans <wim.taymans@gmail.com>
* 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 <edgard.lima@indt.org.br>
* sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init),

View file

@ -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);
@ -2113,6 +2145,66 @@ qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, guint8 * buf,
return TRUE;
}
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:
{

View file

@ -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__ */

View file

@ -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 =