mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-05 06:58:49 +00:00
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:
parent
66ca1b2280
commit
a4540bca1e
4 changed files with 158 additions and 0 deletions
10
ChangeLog
10
ChangeLog
|
@ -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>
|
2007-11-15 Edgard Lima <edgard.lima@indt.org.br>
|
||||||
|
|
||||||
* sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init),
|
* sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init),
|
||||||
|
|
|
@ -130,6 +130,7 @@ struct _QtDemuxStream
|
||||||
|
|
||||||
/* if we use chunks or samples */
|
/* if we use chunks or samples */
|
||||||
gboolean sampled;
|
gboolean sampled;
|
||||||
|
guint padding;
|
||||||
|
|
||||||
/* video info */
|
/* video info */
|
||||||
gint width;
|
gint width;
|
||||||
|
@ -153,6 +154,9 @@ struct _QtDemuxStream
|
||||||
/* when a discontinuity is pending */
|
/* when a discontinuity is pending */
|
||||||
gboolean discont;
|
gboolean discont;
|
||||||
|
|
||||||
|
/* list of buffers to push first */
|
||||||
|
GSList *buffers;
|
||||||
|
|
||||||
/* if we need to clip this buffer. This is only needed for uncompressed
|
/* if we need to clip this buffer. This is only needed for uncompressed
|
||||||
* data */
|
* data */
|
||||||
gboolean need_clip;
|
gboolean need_clip;
|
||||||
|
@ -912,6 +916,11 @@ gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
|
||||||
for (n = 0; n < qtdemux->n_streams; n++) {
|
for (n = 0; n < qtdemux->n_streams; n++) {
|
||||||
QtDemuxStream *stream = qtdemux->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)
|
if (stream->pad)
|
||||||
gst_element_remove_pad (element, stream->pad);
|
gst_element_remove_pad (element, stream->pad);
|
||||||
if (stream->samples)
|
if (stream->samples)
|
||||||
|
@ -1170,6 +1179,21 @@ gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
|
||||||
GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
|
GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
|
||||||
stream->sample_index, stream->n_samples);
|
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)
|
if (stream->sample_index >= stream->n_samples)
|
||||||
goto eos;
|
goto eos;
|
||||||
|
|
||||||
|
@ -1182,6 +1206,12 @@ gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
|
||||||
*duration = sample->duration;
|
*duration = sample->duration;
|
||||||
*keyframe = stream->all_keyframe || sample->keyframe;
|
*keyframe = stream->all_keyframe || sample->keyframe;
|
||||||
|
|
||||||
|
/* add padding */
|
||||||
|
if (stream->padding) {
|
||||||
|
*offset += stream->padding;
|
||||||
|
*size -= stream->padding;
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* special cases */
|
/* special cases */
|
||||||
|
@ -1489,6 +1519,8 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (buf) = timestamp;
|
GST_BUFFER_TIMESTAMP (buf) = timestamp;
|
||||||
GST_BUFFER_DURATION (buf) = duration;
|
GST_BUFFER_DURATION (buf) = duration;
|
||||||
|
GST_BUFFER_OFFSET (buf) = -1;
|
||||||
|
GST_BUFFER_OFFSET_END (buf) = -1;
|
||||||
|
|
||||||
if (stream->need_clip)
|
if (stream->need_clip)
|
||||||
buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
|
buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
|
||||||
|
@ -2113,6 +2145,66 @@ qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, guint8 * buf,
|
||||||
return TRUE;
|
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
|
static gboolean
|
||||||
qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, guint8 * buffer,
|
qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, guint8 * buffer,
|
||||||
int length)
|
int length)
|
||||||
|
@ -2225,6 +2317,27 @@ qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, guint8 * buffer,
|
||||||
qtdemux_parse_container (qtdemux, node, buffer + 12, end);
|
qtdemux_parse_container (qtdemux, node, buffer + 12, end);
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2983,6 +3096,25 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
|
||||||
"depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
|
"depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4072,6 +4204,13 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
_codec ("VP3");
|
_codec ("VP3");
|
||||||
caps = gst_caps_from_string ("video/x-vp3");
|
caps = gst_caps_from_string ("video/x-vp3");
|
||||||
break;
|
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'):
|
case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
|
|
@ -128,6 +128,13 @@ G_BEGIN_DECLS
|
||||||
#define FOURCC_frma GST_MAKE_FOURCC('f','r','m','a')
|
#define FOURCC_frma GST_MAKE_FOURCC('f','r','m','a')
|
||||||
#define FOURCC_ctts GST_MAKE_FOURCC('c','t','t','s')
|
#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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GST_QTDEMUX_FOURCC_H__ */
|
#endif /* __GST_QTDEMUX_FOURCC_H__ */
|
||||||
|
|
|
@ -108,6 +108,8 @@ static const QtNodeType qt_node_types[] = {
|
||||||
{FOURCC_rdrf, "rdrf", 0,},
|
{FOURCC_rdrf, "rdrf", 0,},
|
||||||
{FOURCC__gen, "Custom Genre", QT_FLAG_CONTAINER,},
|
{FOURCC__gen, "Custom Genre", QT_FLAG_CONTAINER,},
|
||||||
{FOURCC_ctts, "Composition time to sample", 0, qtdemux_dump_ctts},
|
{FOURCC_ctts, "Composition time to sample", 0, qtdemux_dump_ctts},
|
||||||
|
{FOURCC_XiTh, "XiTh", 0},
|
||||||
|
{FOURCC_XdxT, "XdxT", 0},
|
||||||
{0, "unknown", 0,},
|
{0, "unknown", 0,},
|
||||||
};
|
};
|
||||||
static const int n_qt_node_types =
|
static const int n_qt_node_types =
|
||||||
|
|
Loading…
Reference in a new issue