2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
31 GST_DEBUG_CATEGORY_EXTERN (qtdemux_debug);
32 #define GST_CAT_DEFAULT qtdemux_debug
35 #define gst_util_dump_mem(a,b) /* */
37 #define QTDEMUX_GUINT32_GET(a) (GST_READ_UINT32_BE(a))
38 #define QTDEMUX_GUINT24_GET(a) (GST_READ_UINT32_BE(a) >> 8)
39 #define QTDEMUX_GUINT16_GET(a) (GST_READ_UINT16_BE(a))
40 #define QTDEMUX_GUINT8_GET(a) (*(guint8 *)(a))
41 #define QTDEMUX_FP32_GET(a) ((GST_READ_UINT32_BE(a))/65536.0)
42 #define QTDEMUX_FP16_GET(a) ((GST_READ_UINT16_BE(a))/256.0)
43 #define QTDEMUX_FOURCC_GET(a) (GST_READ_UINT32_LE(a))
45 #define QTDEMUX_GUINT64_GET(a) ((((guint64)QTDEMUX_GUINT32_GET(a))<<32)|QTDEMUX_GUINT32_GET(((void *)a)+4))
47 typedef struct _QtNode QtNode;
48 typedef struct _QtNodeType QtNodeType;
49 typedef struct _QtDemuxSample QtDemuxSample;
51 //typedef struct _QtDemuxStream QtDemuxStream;
65 void (*dump) (GstQTDemux * qtdemux, void *buffer, int depth);
74 guint64 timestamp; /* In GstClockTime */
75 guint32 duration; /* in stream->timescale units */
76 gboolean keyframe; /* TRUE when this packet is a keyframe */
86 QtDemuxSample *samples;
88 gboolean all_keyframe; /* TRUE when all packets are keyframes (no stss) */
94 /* Numerator/denominator framerate */
100 guint bytes_per_frame;
102 guint samples_per_packet;
103 guint16 bits_per_sample;
104 guint16 color_table_id;
106 /* when a discontinuity is pending */
112 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
113 QTDEMUX_STATE_HEADER, /* Parsing the header */
114 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
115 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
118 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
119 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
121 static GstElementDetails gst_qtdemux_details = {
124 "Demultiplex a QuickTime file into audio and video streams",
125 "David Schleef <ds@schleef.org>"
128 static GstStaticPadTemplate gst_qtdemux_sink_template =
129 GST_STATIC_PAD_TEMPLATE ("sink",
132 GST_STATIC_CAPS ("video/quicktime; audio/x-m4a; application/x-3gp")
135 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
136 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
139 GST_STATIC_CAPS_ANY);
141 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
142 GST_STATIC_PAD_TEMPLATE ("video_%02d",
145 GST_STATIC_CAPS_ANY);
147 static GstElementClass *parent_class = NULL;
149 /* we could generate these programmatically, but the generation code
150 * is only a few lines shorter than the tables, and much uglier */
151 static const guint32 ff_qt_default_palette_256[256] = {
152 0xFFFFFF, 0xFFFFCC, 0xFFFF99, 0xFFFF66, 0xFFFF33, 0xFFFF00,
153 0xFFCCFF, 0xFFCCCC, 0xFFCC99, 0xFFCC66, 0xFFCC33, 0xFFCC00,
154 0xFF99FF, 0xFF99CC, 0xFF9999, 0xFF9966, 0xFF9933, 0xFF9900,
155 0xFF66FF, 0xFF66CC, 0xFF6699, 0xFF6666, 0xFF6633, 0xFF6600,
156 0xFF33FF, 0xFF33CC, 0xFF3399, 0xFF3366, 0xFF3333, 0xFF3300,
157 0xFF00FF, 0xFF00CC, 0xFF0099, 0xFF0066, 0xFF0033, 0xFF0000,
158 0xCCFFFF, 0xCCFFCC, 0xCCFF99, 0xCCFF66, 0xCCFF33, 0xCCFF00,
159 0xCCCCFF, 0xCCCCCC, 0xCCCC99, 0xCCCC66, 0xCCCC33, 0xCCCC00,
160 0xCC99FF, 0xCC99CC, 0xCC9999, 0xCC9966, 0xCC9933, 0xCC9900,
161 0xCC66FF, 0xCC66CC, 0xCC6699, 0xCC6666, 0xCC6633, 0xCC6600,
162 0xCC33FF, 0xCC33CC, 0xCC3399, 0xCC3366, 0xCC3333, 0xCC3300,
163 0xCC00FF, 0xCC00CC, 0xCC0099, 0xCC0066, 0xCC0033, 0xCC0000,
164 0x99FFFF, 0x99FFCC, 0x99FF99, 0x99FF66, 0x99FF33, 0x99FF00,
165 0x99CCFF, 0x99CCCC, 0x99CC99, 0x99CC66, 0x99CC33, 0x99CC00,
166 0x9999FF, 0x9999CC, 0x999999, 0x999966, 0x999933, 0x999900,
167 0x9966FF, 0x9966CC, 0x996699, 0x996666, 0x996633, 0x996600,
168 0x9933FF, 0x9933CC, 0x993399, 0x993366, 0x993333, 0x993300,
169 0x9900FF, 0x9900CC, 0x990099, 0x990066, 0x990033, 0x990000,
170 0x66FFFF, 0x66FFCC, 0x66FF99, 0x66FF66, 0x66FF33, 0x66FF00,
171 0x66CCFF, 0x66CCCC, 0x66CC99, 0x66CC66, 0x66CC33, 0x66CC00,
172 0x6699FF, 0x6699CC, 0x669999, 0x669966, 0x669933, 0x669900,
173 0x6666FF, 0x6666CC, 0x666699, 0x666666, 0x666633, 0x666600,
174 0x6633FF, 0x6633CC, 0x663399, 0x663366, 0x663333, 0x663300,
175 0x6600FF, 0x6600CC, 0x660099, 0x660066, 0x660033, 0x660000,
176 0x33FFFF, 0x33FFCC, 0x33FF99, 0x33FF66, 0x33FF33, 0x33FF00,
177 0x33CCFF, 0x33CCCC, 0x33CC99, 0x33CC66, 0x33CC33, 0x33CC00,
178 0x3399FF, 0x3399CC, 0x339999, 0x339966, 0x339933, 0x339900,
179 0x3366FF, 0x3366CC, 0x336699, 0x336666, 0x336633, 0x336600,
180 0x3333FF, 0x3333CC, 0x333399, 0x333366, 0x333333, 0x333300,
181 0x3300FF, 0x3300CC, 0x330099, 0x330066, 0x330033, 0x330000,
182 0x00FFFF, 0x00FFCC, 0x00FF99, 0x00FF66, 0x00FF33, 0x00FF00,
183 0x00CCFF, 0x00CCCC, 0x00CC99, 0x00CC66, 0x00CC33, 0x00CC00,
184 0x0099FF, 0x0099CC, 0x009999, 0x009966, 0x009933, 0x009900,
185 0x0066FF, 0x0066CC, 0x006699, 0x006666, 0x006633, 0x006600,
186 0x0033FF, 0x0033CC, 0x003399, 0x003366, 0x003333, 0x003300,
187 0x0000FF, 0x0000CC, 0x000099, 0x000066, 0x000033, 0xEE0000,
188 0xDD0000, 0xBB0000, 0xAA0000, 0x880000, 0x770000, 0x550000,
189 0x440000, 0x220000, 0x110000, 0x00EE00, 0x00DD00, 0x00BB00,
190 0x00AA00, 0x008800, 0x007700, 0x005500, 0x004400, 0x002200,
191 0x001100, 0x0000EE, 0x0000DD, 0x0000BB, 0x0000AA, 0x000088,
192 0x000077, 0x000055, 0x000044, 0x000022, 0x000011, 0xEEEEEE,
193 0xDDDDDD, 0xBBBBBB, 0xAAAAAA, 0x888888, 0x777777, 0x555555,
194 0x444444, 0x222222, 0x111111, 0x000000
197 static const guint32 ff_qt_grayscale_palette_256[256] = {
198 0xffffff, 0xfefefe, 0xfdfdfd, 0xfcfcfc, 0xfbfbfb, 0xfafafa, 0xf9f9f9,
199 0xf8f8f8, 0xf7f7f7, 0xf6f6f6, 0xf5f5f5, 0xf4f4f4, 0xf3f3f3, 0xf2f2f2,
200 0xf1f1f1, 0xf0f0f0, 0xefefef, 0xeeeeee, 0xededed, 0xececec, 0xebebeb,
201 0xeaeaea, 0xe9e9e9, 0xe8e8e8, 0xe7e7e7, 0xe6e6e6, 0xe5e5e5, 0xe4e4e4,
202 0xe3e3e3, 0xe2e2e2, 0xe1e1e1, 0xe0e0e0, 0xdfdfdf, 0xdedede, 0xdddddd,
203 0xdcdcdc, 0xdbdbdb, 0xdadada, 0xd9d9d9, 0xd8d8d8, 0xd7d7d7, 0xd6d6d6,
204 0xd5d5d5, 0xd4d4d4, 0xd3d3d3, 0xd2d2d2, 0xd1d1d1, 0xd0d0d0, 0xcfcfcf,
205 0xcecece, 0xcdcdcd, 0xcccccc, 0xcbcbcb, 0xcacaca, 0xc9c9c9, 0xc8c8c8,
206 0xc7c7c7, 0xc6c6c6, 0xc5c5c5, 0xc4c4c4, 0xc3c3c3, 0xc2c2c2, 0xc1c1c1,
207 0xc0c0c0, 0xbfbfbf, 0xbebebe, 0xbdbdbd, 0xbcbcbc, 0xbbbbbb, 0xbababa,
208 0xb9b9b9, 0xb8b8b8, 0xb7b7b7, 0xb6b6b6, 0xb5b5b5, 0xb4b4b4, 0xb3b3b3,
209 0xb2b2b2, 0xb1b1b1, 0xb0b0b0, 0xafafaf, 0xaeaeae, 0xadadad, 0xacacac,
210 0xababab, 0xaaaaaa, 0xa9a9a9, 0xa8a8a8, 0xa7a7a7, 0xa6a6a6, 0xa5a5a5,
211 0xa4a4a4, 0xa3a3a3, 0xa2a2a2, 0xa1a1a1, 0xa0a0a0, 0x9f9f9f, 0x9e9e9e,
212 0x9d9d9d, 0x9c9c9c, 0x9b9b9b, 0x9a9a9a, 0x999999, 0x989898, 0x979797,
213 0x969696, 0x959595, 0x949494, 0x939393, 0x929292, 0x919191, 0x909090,
214 0x8f8f8f, 0x8e8e8e, 0x8d8d8d, 0x8c8c8c, 0x8b8b8b, 0x8a8a8a, 0x898989,
215 0x888888, 0x878787, 0x868686, 0x858585, 0x848484, 0x838383, 0x828282,
216 0x818181, 0x808080, 0x7f7f7f, 0x7e7e7e, 0x7d7d7d, 0x7c7c7c, 0x7b7b7b,
217 0x7a7a7a, 0x797979, 0x787878, 0x777777, 0x767676, 0x757575, 0x747474,
218 0x737373, 0x727272, 0x717171, 0x707070, 0x6f6f6f, 0x6e6e6e, 0x6d6d6d,
219 0x6c6c6c, 0x6b6b6b, 0x6a6a6a, 0x696969, 0x686868, 0x676767, 0x666666,
220 0x656565, 0x646464, 0x636363, 0x626262, 0x616161, 0x606060, 0x5f5f5f,
221 0x5e5e5e, 0x5d5d5d, 0x5c5c5c, 0x5b5b5b, 0x5a5a5a, 0x595959, 0x585858,
222 0x575757, 0x565656, 0x555555, 0x545454, 0x535353, 0x525252, 0x515151,
223 0x505050, 0x4f4f4f, 0x4e4e4e, 0x4d4d4d, 0x4c4c4c, 0x4b4b4b, 0x4a4a4a,
224 0x494949, 0x484848, 0x474747, 0x464646, 0x454545, 0x444444, 0x434343,
225 0x424242, 0x414141, 0x404040, 0x3f3f3f, 0x3e3e3e, 0x3d3d3d, 0x3c3c3c,
226 0x3b3b3b, 0x3a3a3a, 0x393939, 0x383838, 0x373737, 0x363636, 0x353535,
227 0x343434, 0x333333, 0x323232, 0x313131, 0x303030, 0x2f2f2f, 0x2e2e2e,
228 0x2d2d2d, 0x2c2c2c, 0x2b2b2b, 0x2a2a2a, 0x292929, 0x282828, 0x272727,
229 0x262626, 0x252525, 0x242424, 0x232323, 0x222222, 0x212121, 0x202020,
230 0x1f1f1f, 0x1e1e1e, 0x1d1d1d, 0x1c1c1c, 0x1b1b1b, 0x1a1a1a, 0x191919,
231 0x181818, 0x171717, 0x161616, 0x151515, 0x141414, 0x131313, 0x121212,
232 0x111111, 0x101010, 0x0f0f0f, 0x0e0e0e, 0x0d0d0d, 0x0c0c0c, 0x0b0b0b,
233 0x0a0a0a, 0x090909, 0x080808, 0x070707, 0x060606, 0x050505, 0x040404,
234 0x030303, 0x020202, 0x010101, 0x000000
237 static void gst_qtdemux_class_init (GstQTDemuxClass * klass);
238 static void gst_qtdemux_base_init (GstQTDemuxClass * klass);
239 static void gst_qtdemux_init (GstQTDemux * quicktime_demux);
240 static void gst_qtdemux_dispose (GObject * object);
241 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
242 GstStateChange transition);
243 static void gst_qtdemux_loop (GstPad * pad);
244 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf);
245 static gboolean qtdemux_sink_activate (GstPad * sinkpad);
246 static gboolean qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active);
247 static gboolean qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active);
248 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstEvent * event);
250 static void qtdemux_parse_moov (GstQTDemux * qtdemux, void *buffer, int length);
251 static void qtdemux_parse (GstQTDemux * qtdemux, GNode * node, void *buffer,
253 static QtNodeType *qtdemux_type_get (guint32 fourcc);
254 static void qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node);
255 static void qtdemux_parse_tree (GstQTDemux * qtdemux);
256 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta);
257 static void qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
259 static void qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
260 const char *tag2, GNode * node);
261 static void qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag,
264 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
265 QtDemuxStream * stream, GNode * esds);
266 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux, guint32 fourcc,
267 const guint8 * stsd_data, const gchar ** codec_name);
268 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
269 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
270 const gchar ** codec_name);
273 gst_qtdemux_get_type (void)
275 static GType qtdemux_type = 0;
278 static const GTypeInfo qtdemux_info = {
279 sizeof (GstQTDemuxClass),
280 (GBaseInitFunc) gst_qtdemux_base_init, NULL,
281 (GClassInitFunc) gst_qtdemux_class_init,
282 NULL, NULL, sizeof (GstQTDemux), 0,
283 (GInstanceInitFunc) gst_qtdemux_init,
287 g_type_register_static (GST_TYPE_ELEMENT, "GstQTDemux", &qtdemux_info,
294 gst_qtdemux_base_init (GstQTDemuxClass * klass)
296 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
298 gst_element_class_add_pad_template (element_class,
299 gst_static_pad_template_get (&gst_qtdemux_sink_template));
300 gst_element_class_add_pad_template (element_class,
301 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
302 gst_element_class_add_pad_template (element_class,
303 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
304 gst_element_class_set_details (element_class, &gst_qtdemux_details);
309 gst_qtdemux_class_init (GstQTDemuxClass * klass)
311 GObjectClass *gobject_class;
312 GstElementClass *gstelement_class;
314 gobject_class = (GObjectClass *) klass;
315 gstelement_class = (GstElementClass *) klass;
317 parent_class = g_type_class_peek_parent (klass);
319 gobject_class->dispose = gst_qtdemux_dispose;
321 gstelement_class->change_state = gst_qtdemux_change_state;
325 gst_qtdemux_init (GstQTDemux * qtdemux)
328 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
329 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
330 gst_pad_set_activatepull_function (qtdemux->sinkpad,
331 qtdemux_sink_activate_pull);
332 gst_pad_set_activatepush_function (qtdemux->sinkpad,
333 qtdemux_sink_activate_push);
334 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
335 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
336 gst_element_add_pad (GST_ELEMENT (qtdemux), qtdemux->sinkpad);
338 qtdemux->state = QTDEMUX_STATE_INITIAL;
339 qtdemux->last_ts = GST_CLOCK_TIME_NONE;
340 qtdemux->pullbased = FALSE;
341 qtdemux->neededbytes = 16;
343 qtdemux->adapter = gst_adapter_new ();
345 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
346 qtdemux->mdatbuffer = NULL;
347 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
351 gst_qtdemux_dispose (GObject * object)
353 GstQTDemux *qtdemux = GST_QTDEMUX (object);
355 if (qtdemux->adapter) {
356 g_object_unref (G_OBJECT (qtdemux->adapter));
357 qtdemux->adapter = NULL;
360 G_OBJECT_CLASS (parent_class)->dispose (object);
365 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
366 GstFormat * dest_format, gint64 * dest_value)
369 QtDemuxStream *stream = gst_pad_get_element_private (pad);
371 if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e') &&
372 (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
375 switch (src_format) {
376 case GST_FORMAT_TIME:
377 switch (*dest_format) {
378 case GST_FORMAT_BYTES:
379 *dest_value = src_value * 1; /* FIXME */
381 case GST_FORMAT_DEFAULT:
382 *dest_value = src_value * 1; /* FIXME */
389 case GST_FORMAT_BYTES:
390 switch (*dest_format) {
391 case GST_FORMAT_TIME:
392 *dest_value = src_value * 1; /* FIXME */
399 case GST_FORMAT_DEFAULT:
400 switch (*dest_format) {
401 case GST_FORMAT_TIME:
402 *dest_value = src_value * 1; /* FIXME */
417 static const GstQueryType *
418 gst_qtdemux_get_src_query_types (GstPad * pad)
420 static const GstQueryType src_types[] = {
430 gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
432 gboolean res = FALSE;
433 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
435 switch (GST_QUERY_TYPE (query)) {
436 case GST_QUERY_POSITION:
437 if (GST_CLOCK_TIME_IS_VALID (qtdemux->last_ts)) {
438 gst_query_set_position (query, GST_FORMAT_TIME, qtdemux->last_ts);
442 case GST_QUERY_DURATION:
443 if (qtdemux->pullbased && qtdemux->duration != 0
444 && qtdemux->timescale != 0) {
447 duration = gst_util_uint64_scale_int (qtdemux->duration,
448 GST_SECOND, qtdemux->timescale);
450 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
459 gst_object_unref (qtdemux);
464 /* push event on all source pads; takes ownership of the event */
466 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
470 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
471 GST_EVENT_TYPE_NAME (event));
473 for (n = 0; n < qtdemux->n_streams; n++) {
474 gst_pad_push_event (qtdemux->streams[n]->pad, gst_event_ref (event));
476 gst_event_unref (event);
479 /* move all streams back on the keyframe before @offset.
481 * If @end is FALSE, the search is started from the current
482 * sample_index position of each stream.
483 * If @end is TRUE, the search is started from the last sample
486 * Returns: the minimum of the timestamps of the positions of all streams.
488 /* FIXME, binary search would be nice here */
490 gst_qtdemux_go_back (GstQTDemux * qtdemux, gboolean end, guint64 offset)
493 guint64 min_time = G_MAXUINT64;
495 /* resync to new time */
496 for (n = 0; n < qtdemux->n_streams; n++) {
501 str = qtdemux->streams[n];
502 keyframe = str->all_keyframe;
504 /* start from the last sample if @end == TRUE */
506 if (str->n_samples == 0)
509 search = str->n_samples - 1;
511 search = str->sample_index;
513 for (; search > 0; search--) {
516 timestamp = str->samples[search].timestamp;
518 /* Seek to the sample just before the desired offset and
519 * let downstream throw away bits outside of the segment */
520 if (timestamp <= offset) {
521 /* update the keyframe flag */
522 keyframe = keyframe | str->samples[search].keyframe;
524 GST_DEBUG_OBJECT (qtdemux,
525 "found keyframe at sample %d, %" GST_TIME_FORMAT, search,
526 GST_TIME_ARGS (timestamp));
527 /* update min_time */
528 if (timestamp < min_time)
529 min_time = timestamp;
535 /* did not find anything or we're at the beginning, position to beginning */
540 /* and set stream to the index */
541 if (search != str->sample_index) {
542 str->sample_index = search;
543 /* position changed, we have a discont */
552 * We always go to the keyframe before the desired seek position. If
553 * the seek was to a keyframe, we update the last_stop and time with
554 * the position of the keyframe, else we leve the event as-is and it
555 * will be clipped automatically to the right segment boundaries by
556 * downstream elements.
559 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
561 gint64 desired_offset;
564 desired_offset = segment->last_stop;
566 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
567 GST_TIME_ARGS (desired_offset));
569 /* position all streams to key unit before the desired time,
570 * start searching from the last sample in the stream. */
571 min = gst_qtdemux_go_back (qtdemux, TRUE, desired_offset);
573 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
574 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %" GST_TIME_FORMAT,
575 GST_TIME_ARGS (min));
576 /* key unit, we seek to min, so back off streams to this new
577 * position. We start from our current position. */
578 gst_qtdemux_go_back (qtdemux, FALSE, min);
580 /* update the segment values to the position of the keyframes */
581 segment->last_stop = min;
585 /* and we stop at the end */
586 if (segment->stop == -1)
587 segment->stop = segment->duration;
592 /* do a seek in pull based mode */
594 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
599 GstSeekType cur_type, stop_type;
604 GstSegment seeksegment;
605 GstEvent *newsegment;
608 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
610 gst_event_parse_seek (event, &rate, &format, &flags,
611 &cur_type, &cur, &stop_type, &stop);
613 /* we have to have a format as the segment format. Try to convert
615 if (format != GST_FORMAT_TIME) {
618 fmt = GST_FORMAT_TIME;
620 if (cur_type != GST_SEEK_TYPE_NONE)
621 res = gst_pad_query_convert (pad, format, cur, &fmt, &cur);
622 if (res && stop_type != GST_SEEK_TYPE_NONE)
623 res = gst_pad_query_convert (pad, format, stop, &fmt, &stop);
630 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
634 flush = flags & GST_SEEK_FLAG_FLUSH;
636 GST_DEBUG_OBJECT (qtdemux, "seek format %d", format);
638 /* stop streaming, either by flushing or by pausing the task */
640 /* unlock upstream pull_range */
641 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
642 /* make sure out loop function exits */
643 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
645 /* non flushing seek, pause the task */
646 qtdemux->segment_running = FALSE;
647 gst_pad_pause_task (qtdemux->sinkpad);
650 /* wait for streaming to finish */
651 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
653 /* copy segment, we need this because we still need the old
654 * segment when we close the current segment. */
655 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
658 /* configure the segment with the seek variables */
659 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
660 gst_segment_set_seek (&seeksegment, rate, format, flags,
661 cur_type, cur, stop_type, stop, &update);
664 /* now do the seek, this actually never returns FALSE */
665 res = gst_qtdemux_perform_seek (qtdemux, &seeksegment);
667 /* prepare for streaming again */
669 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop ());
670 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop ());
671 } else if (qtdemux->segment_running) {
672 /* we are running the current segment and doing a non-flushing seek,
673 * close the segment first based on the last_stop. */
674 GST_DEBUG_OBJECT (qtdemux, "closing running segment %" G_GINT64_FORMAT
675 " to %" G_GINT64_FORMAT, qtdemux->segment.start,
676 qtdemux->segment.last_stop);
678 gst_qtdemux_push_event (qtdemux,
679 gst_event_new_new_segment (TRUE,
680 qtdemux->segment.rate, qtdemux->segment.format,
681 qtdemux->segment.start, qtdemux->segment.last_stop,
682 qtdemux->segment.time));
685 /* commit the new segment */
686 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
688 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
689 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
690 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
691 qtdemux->segment.format, qtdemux->segment.last_stop));
694 /* send the newsegment */
695 GST_DEBUG_OBJECT (qtdemux, "Sending newsegment from %" GST_TIME_FORMAT
696 " to %" GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.start),
697 GST_TIME_ARGS (qtdemux->segment.stop));
700 gst_event_new_new_segment (FALSE, qtdemux->segment.rate,
701 qtdemux->segment.format, qtdemux->segment.last_stop,
702 qtdemux->segment.stop, qtdemux->segment.time);
704 gst_qtdemux_push_event (qtdemux, newsegment);
706 /* restart streaming */
707 qtdemux->segment_running = TRUE;
708 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
711 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
718 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
724 gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
727 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
729 switch (GST_EVENT_TYPE (event)) {
731 res = gst_qtdemux_do_seek (qtdemux, pad, event);
738 gst_object_unref (qtdemux);
740 gst_event_unref (event);
745 GST_DEBUG_CATEGORY (qtdemux_debug);
748 plugin_init (GstPlugin * plugin)
750 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
752 return gst_element_register (plugin, "qtdemux",
753 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX);
756 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
759 "Quicktime stream demuxer",
760 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
763 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
765 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
766 gboolean res = FALSE;
768 switch (GST_EVENT_TYPE (event)) {
769 case GST_EVENT_NEWSEGMENT:
770 /* We need to convert it to a GST_FORMAT_TIME new segment */
772 gst_pad_event_default (demux->sinkpad, event);
776 gst_event_unref (event);
780 static GstStateChangeReturn
781 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
783 GstQTDemux *qtdemux = GST_QTDEMUX (element);
784 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
786 switch (transition) {
787 case GST_STATE_CHANGE_PAUSED_TO_READY:
793 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
795 switch (transition) {
796 case GST_STATE_CHANGE_PAUSED_TO_READY:{
799 qtdemux->state = QTDEMUX_STATE_INITIAL;
800 qtdemux->last_ts = GST_CLOCK_TIME_NONE;
801 qtdemux->neededbytes = 16;
803 qtdemux->pullbased = FALSE;
805 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
806 if (qtdemux->mdatbuffer)
807 gst_buffer_unref (qtdemux->mdatbuffer);
808 qtdemux->mdatbuffer = NULL;
809 gst_adapter_clear (qtdemux->adapter);
810 for (n = 0; n < qtdemux->n_streams; n++) {
811 gst_element_remove_pad (element, qtdemux->streams[n]->pad);
812 g_free (qtdemux->streams[n]->samples);
813 if (qtdemux->streams[n]->caps)
814 gst_caps_unref (qtdemux->streams[n]->caps);
815 g_free (qtdemux->streams[n]);
817 qtdemux->n_streams = 0;
818 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
829 extract_initial_length_and_fourcc (guint8 * data, guint32 * plength,
835 length = GST_READ_UINT32_BE (data);
836 GST_DEBUG ("length %08x", length);
837 fourcc = GST_READ_UINT32_LE (data + 4);
838 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
841 length = G_MAXUINT32;
844 /* this means we have an extended size, which is the 64 bit value of
845 * the next 8 bytes */
846 guint32 length1, length2;
848 length1 = GST_READ_UINT32_BE (data + 8);
849 GST_DEBUG ("length1 %08x", length1);
850 length2 = GST_READ_UINT32_BE (data + 12);
851 GST_DEBUG ("length2 %08x", length2);
853 /* FIXME: I guess someone didn't want to make 64 bit size work :) */
864 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
868 GstBuffer *buf = NULL;
869 GstFlowReturn ret = GST_FLOW_OK;
870 guint64 cur_offset = qtdemux->offset;
872 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
873 if (ret != GST_FLOW_OK)
875 extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf), &length, &fourcc);
876 gst_buffer_unref (buf);
880 case GST_MAKE_FOURCC ('m', 'd', 'a', 't'):
881 case GST_MAKE_FOURCC ('f', 'r', 'e', 'e'):
882 case GST_MAKE_FOURCC ('w', 'i', 'd', 'e'):
883 case GST_MAKE_FOURCC ('P', 'I', 'C', 'T'):
884 case GST_MAKE_FOURCC ('p', 'n', 'o', 't'):
885 goto ed_edd_and_eddy;
886 case GST_MAKE_FOURCC ('m', 'o', 'o', 'v'):{
889 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
890 if (ret != GST_FLOW_OK)
892 if (length != GST_BUFFER_SIZE (moov)) {
893 GST_WARNING_OBJECT (qtdemux,
894 "We got less than expected (received %d, wanted %d)",
895 GST_BUFFER_SIZE (moov), length);
896 ret = GST_FLOW_ERROR;
899 cur_offset += length;
900 qtdemux->offset += length;
902 qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
904 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
906 qtdemux_parse_tree (qtdemux);
907 g_node_destroy (qtdemux->moov_node);
908 gst_buffer_unref (moov);
909 qtdemux->moov_node = NULL;
910 qtdemux->state = QTDEMUX_STATE_MOVIE;
911 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
917 GST_LOG ("unknown %08x '%" GST_FOURCC_FORMAT "' at %d",
918 fourcc, GST_FOURCC_ARGS (fourcc), cur_offset);
919 cur_offset += length;
920 qtdemux->offset += length;
930 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
932 GstFlowReturn ret = GST_FLOW_OK;
933 GstBuffer *buf = NULL;
934 QtDemuxStream *stream;
942 /* Figure out the next stream sample to output */
943 min_time = G_MAXUINT64;
945 for (i = 0; i < qtdemux->n_streams; i++) {
946 stream = qtdemux->streams[i];
947 if (stream->sample_index < stream->n_samples) {
949 timestamp = stream->samples[stream->sample_index].timestamp;
951 GST_LOG_OBJECT (qtdemux,
952 "stream %d: sample_index %d, timestamp %" GST_TIME_FORMAT, i,
953 stream->sample_index, GST_TIME_ARGS (timestamp));
955 if (timestamp < min_time) {
956 min_time = timestamp;
964 /* check for segment end */
965 if (qtdemux->segment.stop != -1 && qtdemux->segment.stop < min_time)
968 stream = qtdemux->streams[index];
970 offset = stream->samples[stream->sample_index].offset;
971 size = stream->samples[stream->sample_index].size;
972 timestamp = stream->samples[stream->sample_index].timestamp;
974 GST_LOG_OBJECT (qtdemux,
975 "pushing from stream %d, sample_index=%d offset=%" G_GUINT64_FORMAT
976 ",size=%d timestamp=%" GST_TIME_FORMAT,
977 index, stream->sample_index, offset, size, GST_TIME_ARGS (timestamp));
979 if (G_UNLIKELY (size <= 0))
982 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
985 ret = gst_pad_pull_range (qtdemux->sinkpad, offset, size, &buf);
986 if (ret != GST_FLOW_OK)
989 buf = gst_buffer_make_metadata_writable (buf);
992 /* hum... FIXME changing framerate breaks horribly, better set
993 * an average framerate, or get rid of the framerate property. */
994 if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e')) {
996 1. * GST_SECOND / stream->samples[stream->sample_index].duration;
997 if (fps != stream->fps) {
998 gst_caps_set_simple (stream->caps, "framerate", G_TYPE_DOUBLE, fps, NULL);
1000 gst_pad_set_explicit_caps (stream->pad, stream->caps);
1006 if (qtdemux->last_ts == GST_CLOCK_TIME_NONE) {
1007 gst_qtdemux_push_event (qtdemux,
1008 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
1009 0, GST_CLOCK_TIME_NONE, 0));
1012 if (stream->discont) {
1013 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
1014 stream->discont = FALSE;
1017 /* timestamps of AMR aren't known... */
1018 if (stream->fourcc == GST_MAKE_FOURCC ('s', 'a', 'm', 'r')) {
1019 if (stream->sample_index == 0)
1020 GST_BUFFER_TIMESTAMP (buf) = 0;
1022 GST_BUFFER_TIMESTAMP (buf) = timestamp;
1023 qtdemux->last_ts = GST_BUFFER_TIMESTAMP (buf);
1024 GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int
1025 (stream->samples[stream->sample_index].duration, GST_SECOND,
1028 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME,
1031 if (!(stream->all_keyframe || stream->samples[stream->sample_index].keyframe))
1032 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
1034 GST_LOG_OBJECT (qtdemux,
1035 "Pushing buffer with time %" GST_TIME_FORMAT " on pad %p",
1036 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), stream->pad);
1037 gst_buffer_set_caps (buf, stream->caps);
1039 ret = gst_pad_push (stream->pad, buf);
1041 stream->sample_index++;
1049 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
1050 ret = GST_FLOW_UNEXPECTED;
1056 gst_qtdemux_loop (GstPad * pad)
1058 GstQTDemux *qtdemux;
1062 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
1064 cur_offset = qtdemux->offset;
1065 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
1066 cur_offset, qtdemux->state);
1068 switch (qtdemux->state) {
1069 case QTDEMUX_STATE_INITIAL:
1070 case QTDEMUX_STATE_HEADER:
1071 ret = gst_qtdemux_loop_state_header (qtdemux);
1073 case QTDEMUX_STATE_MOVIE:
1074 ret = gst_qtdemux_loop_state_movie (qtdemux);
1081 /* if all is fine, continue */
1082 if (G_LIKELY (ret == GST_FLOW_OK))
1085 /* we don't care about unlinked pads */
1086 if (ret == GST_FLOW_NOT_LINKED)
1089 /* other errors make us stop */
1090 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", gst_flow_get_name (ret));
1092 qtdemux->segment_running = FALSE;
1093 gst_pad_pause_task (pad);
1095 /* fatal errors need special actions */
1096 if (GST_FLOW_IS_FATAL (ret)) {
1098 if (ret == GST_FLOW_UNEXPECTED) {
1099 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1100 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
1101 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1102 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
1103 GST_FORMAT_TIME, qtdemux->last_ts));
1105 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
1106 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
1109 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
1110 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
1111 (NULL), ("streaming stopped, reason %s", gst_flow_get_name (ret)));
1116 gst_object_unref (qtdemux);
1122 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
1123 (NULL), ("streaming stopped, invalid state"));
1124 qtdemux->segment_running = FALSE;
1125 gst_pad_pause_task (pad);
1126 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
1134 Returns the size of the first entry at the current offset.
1135 If -1, there are none (which means EOS or empty file).
1139 next_entry_size (GstQTDemux * demux)
1141 QtDemuxStream *stream;
1144 guint64 smalloffs = -1;
1146 GST_LOG_OBJECT (demux, "Finding entry at offset %lld", demux->offset);
1148 for (i = 0; i < demux->n_streams; i++) {
1149 stream = demux->streams[i];
1151 GST_LOG_OBJECT (demux,
1152 "Checking Stream %d (sample_index:%d / offset:%lld / size:%d / chunk:%d)",
1153 i, stream->sample_index, stream->samples[stream->sample_index].offset,
1154 stream->samples[stream->sample_index].size,
1155 stream->samples[stream->sample_index].chunk);
1157 if (((smalloffs == -1)
1158 || (stream->samples[stream->sample_index].offset < smalloffs))
1159 && (stream->samples[stream->sample_index].size)) {
1161 smalloffs = stream->samples[stream->sample_index].offset;
1165 GST_LOG_OBJECT (demux, "stream %d offset %lld demux->offset :%lld",
1166 smallidx, smalloffs, demux->offset);
1170 stream = demux->streams[smallidx];
1172 if (stream->samples[stream->sample_index].offset >= demux->offset) {
1174 stream->samples[stream->sample_index].offset - demux->offset;
1175 return stream->samples[stream->sample_index].size + demux->todrop;
1178 GST_DEBUG_OBJECT (demux, "There wasn't any entry at offset %lld",
1184 gst_qtdemux_post_buffering (GstQTDemux * demux, gint num, gint denom)
1186 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
1188 gst_element_post_message (GST_ELEMENT (demux),
1189 gst_message_new_custom (GST_MESSAGE_BUFFERING,
1191 gst_structure_new ("GstMessageBuffering",
1192 "buffer-percent", G_TYPE_INT, perc, NULL)));
1195 static GstFlowReturn
1196 gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
1199 GstFlowReturn ret = GST_FLOW_OK;
1201 demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad));
1203 gst_adapter_push (demux->adapter, inbuf);
1205 GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
1206 inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
1208 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
1209 (ret == GST_FLOW_OK)) {
1211 GST_DEBUG_OBJECT (demux,
1212 "state:%d , demux->neededbytes:%d, demux->offset:%lld", demux->state,
1213 demux->neededbytes, demux->offset);
1215 switch (demux->state) {
1216 case QTDEMUX_STATE_INITIAL:{
1221 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
1223 /* get fourcc/length, set neededbytes */
1224 extract_initial_length_and_fourcc ((guint8 *) data, &size, &fourcc);
1225 GST_DEBUG_OBJECT (demux,
1226 "Peeking found [%" GST_FOURCC_FORMAT "] size:%ld",
1227 GST_FOURCC_ARGS (fourcc), size);
1228 if ((fourcc == GST_MAKE_FOURCC ('m', 'd', 'a', 't'))) {
1229 if (demux->n_streams > 0) {
1230 demux->state = QTDEMUX_STATE_MOVIE;
1231 demux->neededbytes = next_entry_size (demux);
1233 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
1234 demux->neededbytes = size;
1235 demux->mdatoffset = demux->offset;
1238 demux->neededbytes = size;
1239 demux->state = QTDEMUX_STATE_HEADER;
1243 case QTDEMUX_STATE_HEADER:{
1247 GST_DEBUG_OBJECT (demux, "In header");
1249 data = gst_adapter_take (demux->adapter, demux->neededbytes);
1251 /* parse the header */
1252 extract_initial_length_and_fourcc (data, NULL, &fourcc);
1253 if (fourcc == GST_MAKE_FOURCC ('m', 'o', 'o', 'v')) {
1254 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
1256 qtdemux_parse_moov (demux, data, demux->neededbytes);
1257 qtdemux_node_dump (demux, demux->moov_node);
1258 qtdemux_parse_tree (demux);
1260 g_node_destroy (demux->moov_node);
1262 demux->moov_node = NULL;
1264 GST_WARNING_OBJECT (demux,
1265 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
1266 GST_FOURCC_ARGS (fourcc));
1267 /* Let's jump that one and go back to initial state */
1270 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
1271 if (demux->mdatbuffer && demux->n_streams) {
1272 /* the mdat was before the header */
1273 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
1274 demux->n_streams, demux->mdatbuffer);
1275 gst_adapter_clear (demux->adapter);
1276 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
1277 GST_FOURCC_ARGS (GST_READ_UINT32_BE (demux->mdatbuffer)));
1278 gst_adapter_push (demux->adapter, demux->mdatbuffer);
1279 demux->mdatbuffer = NULL;
1280 demux->offset = demux->mdatoffset;
1281 demux->neededbytes = next_entry_size (demux);
1282 demux->state = QTDEMUX_STATE_MOVIE;
1284 GST_DEBUG_OBJECT (demux, "Carrying on normally");
1285 demux->offset += demux->neededbytes;
1286 demux->neededbytes = 16;
1287 demux->state = QTDEMUX_STATE_INITIAL;
1292 case QTDEMUX_STATE_BUFFER_MDAT:{
1293 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %lld",
1295 if (demux->mdatbuffer)
1296 gst_buffer_unref (demux->mdatbuffer);
1297 demux->mdatbuffer = gst_buffer_new ();
1298 gst_buffer_set_data (demux->mdatbuffer,
1299 gst_adapter_take (demux->adapter, demux->neededbytes),
1300 demux->neededbytes);
1301 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
1302 GST_FOURCC_ARGS (GST_READ_UINT32_BE (demux->mdatbuffer)));
1303 demux->offset += demux->neededbytes;
1304 demux->neededbytes = 16;
1305 demux->state = QTDEMUX_STATE_INITIAL;
1306 gst_qtdemux_post_buffering (demux, 1, 1);
1310 case QTDEMUX_STATE_MOVIE:{
1313 QtDemuxStream *stream = NULL;
1316 GST_DEBUG_OBJECT (demux, "BEGIN // in MOVIE for offset %lld",
1319 if (demux->todrop) {
1320 gst_adapter_flush (demux->adapter, demux->todrop);
1321 demux->neededbytes -= demux->todrop;
1322 demux->offset += demux->todrop;
1325 /* Figure out which stream this is packet belongs to */
1326 for (i = 0; i < demux->n_streams; i++) {
1327 stream = demux->streams[i];
1328 GST_LOG_OBJECT (demux,
1329 "Checking stream %d (sample_index:%d / offset:%lld / size:%d / chunk:%d)",
1330 i, stream->sample_index,
1331 stream->samples[stream->sample_index].offset,
1332 stream->samples[stream->sample_index].size,
1333 stream->samples[stream->sample_index].chunk);
1335 if (stream->samples[stream->sample_index].offset == demux->offset)
1340 goto unknown_stream;
1343 /* FIXME : this should be handled in sink_event */
1344 if (demux->last_ts == GST_CLOCK_TIME_NONE) {
1345 gst_qtdemux_push_event (demux,
1346 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
1347 0, GST_CLOCK_TIME_NONE, 0));
1351 data = gst_adapter_take (demux->adapter, demux->neededbytes);
1353 /* Put data in a buffer, set timestamps, caps, ... */
1354 outbuf = gst_buffer_new ();
1355 gst_buffer_set_data (outbuf, data, demux->neededbytes);
1356 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
1357 GST_FOURCC_ARGS (stream->fourcc));
1359 if (stream->fourcc != GST_MAKE_FOURCC ('s', 'a', 'm', 'r')) {
1360 GST_BUFFER_TIMESTAMP (outbuf) =
1361 stream->samples[stream->sample_index].timestamp;
1362 demux->last_ts = GST_BUFFER_TIMESTAMP (outbuf);
1363 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int
1364 (stream->samples[stream->sample_index].duration, GST_SECOND,
1368 if (stream->sample_index == 0)
1369 GST_BUFFER_TIMESTAMP (outbuf) = 0;
1373 GST_LOG_OBJECT (demux,
1374 "Pushing buffer with time %" GST_TIME_FORMAT " on pad %p",
1375 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), stream->pad);
1376 gst_buffer_set_caps (outbuf, stream->caps);
1377 ret = gst_pad_push (stream->pad, outbuf);
1379 stream->sample_index++;
1381 /* update current offset and figure out size of next buffer */
1382 GST_LOG_OBJECT (demux, "bumping offset:%lld up by %lld",
1383 demux->offset, demux->neededbytes);
1384 demux->offset += demux->neededbytes;
1385 GST_LOG_OBJECT (demux, "offset is now %lld", demux->offset);
1387 if ((demux->neededbytes = next_entry_size (demux)) == -1)
1396 /* when buffering movie data, at least show user something is happening */
1397 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
1398 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
1399 gst_qtdemux_post_buffering (demux, gst_adapter_available (demux->adapter),
1400 demux->neededbytes);
1404 gst_object_unref (demux);
1411 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
1412 ret = GST_FLOW_ERROR;
1417 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
1418 ret = GST_FLOW_UNEXPECTED;
1423 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1424 (NULL), ("qtdemuxer invalid state %d", demux->state));
1425 ret = GST_FLOW_ERROR;
1431 qtdemux_sink_activate (GstPad * sinkpad)
1433 if (gst_pad_check_pull_range (sinkpad))
1434 return gst_pad_activate_pull (sinkpad, TRUE);
1436 return gst_pad_activate_push (sinkpad, TRUE);
1440 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
1442 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1445 /* if we have a scheduler we can start the task */
1446 demux->pullbased = TRUE;
1447 demux->segment_running = TRUE;
1448 gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop, sinkpad);
1450 demux->segment_running = FALSE;
1451 gst_pad_stop_task (sinkpad);
1458 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
1460 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1462 demux->pullbased = FALSE;
1468 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
1469 QtDemuxStream * stream, GstTagList * list)
1471 if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e')) {
1472 gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
1475 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
1477 if ((stream->n_samples == 1) && (stream->samples[0].duration == 0)) {
1481 stream->fps_n = stream->timescale;
1482 if (stream->samples[0].duration == 0)
1485 stream->fps_d = stream->samples[0].duration;
1489 gst_caps_set_simple (stream->caps,
1490 "width", G_TYPE_INT, stream->width,
1491 "height", G_TYPE_INT, stream->height,
1492 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
1493 if ((stream->bits_per_sample & 0x1F) == 8) {
1494 const guint32 *palette_data = NULL;
1496 if ((stream->bits_per_sample & 0x20) != 0)
1497 palette_data = ff_qt_grayscale_palette_256;
1498 if ((stream->color_table_id & 0x08) != 0)
1499 palette_data = ff_qt_default_palette_256;
1502 GstBuffer *palette = gst_buffer_new ();
1504 GST_BUFFER_DATA (palette) = (guint8 *) palette_data;
1505 GST_BUFFER_SIZE (palette) = sizeof (guint32) * 256;
1506 gst_caps_set_simple (stream->caps, "palette_data",
1507 GST_TYPE_BUFFER, palette, NULL);
1508 gst_buffer_unref (palette);
1512 qtdemux->n_video_streams++;
1514 gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
1517 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
1520 gst_caps_set_simple (stream->caps,
1521 "rate", G_TYPE_INT, (int) stream->rate,
1522 "channels", G_TYPE_INT, stream->n_channels, NULL);
1524 qtdemux->n_audio_streams++;
1527 gst_pad_use_fixed_caps (stream->pad);
1529 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
1530 qtdemux->streams[qtdemux->n_streams] = stream;
1531 qtdemux->n_streams++;
1532 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
1534 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
1535 gst_pad_set_query_type_function (stream->pad,
1536 gst_qtdemux_get_src_query_types);
1537 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
1539 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
1540 gst_pad_set_caps (stream->pad, stream->caps);
1542 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
1543 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
1544 gst_element_add_pad (GST_ELEMENT (qtdemux), stream->pad);
1546 gst_element_found_tags_for_pad (GST_ELEMENT (qtdemux), stream->pad, list);
1551 #define QT_CONTAINER 1
1553 #define FOURCC_moov GST_MAKE_FOURCC('m','o','o','v')
1554 #define FOURCC_mvhd GST_MAKE_FOURCC('m','v','h','d')
1555 #define FOURCC_clip GST_MAKE_FOURCC('c','l','i','p')
1556 #define FOURCC_trak GST_MAKE_FOURCC('t','r','a','k')
1557 #define FOURCC_udta GST_MAKE_FOURCC('u','d','t','a')
1558 #define FOURCC_ctab GST_MAKE_FOURCC('c','t','a','b')
1559 #define FOURCC_tkhd GST_MAKE_FOURCC('t','k','h','d')
1560 #define FOURCC_crgn GST_MAKE_FOURCC('c','r','g','n')
1561 #define FOURCC_matt GST_MAKE_FOURCC('m','a','t','t')
1562 #define FOURCC_kmat GST_MAKE_FOURCC('k','m','a','t')
1563 #define FOURCC_edts GST_MAKE_FOURCC('e','d','t','s')
1564 #define FOURCC_elst GST_MAKE_FOURCC('e','l','s','t')
1565 #define FOURCC_load GST_MAKE_FOURCC('l','o','a','d')
1566 #define FOURCC_tref GST_MAKE_FOURCC('t','r','e','f')
1567 #define FOURCC_imap GST_MAKE_FOURCC('i','m','a','p')
1568 #define FOURCC___in GST_MAKE_FOURCC(' ',' ','i','n')
1569 #define FOURCC___ty GST_MAKE_FOURCC(' ',' ','t','y')
1570 #define FOURCC_mdia GST_MAKE_FOURCC('m','d','i','a')
1571 #define FOURCC_mdhd GST_MAKE_FOURCC('m','d','h','d')
1572 #define FOURCC_hdlr GST_MAKE_FOURCC('h','d','l','r')
1573 #define FOURCC_minf GST_MAKE_FOURCC('m','i','n','f')
1574 #define FOURCC_vmhd GST_MAKE_FOURCC('v','m','h','d')
1575 #define FOURCC_smhd GST_MAKE_FOURCC('s','m','h','d')
1576 #define FOURCC_gmhd GST_MAKE_FOURCC('g','m','h','d')
1577 #define FOURCC_gmin GST_MAKE_FOURCC('g','m','i','n')
1578 #define FOURCC_dinf GST_MAKE_FOURCC('d','i','n','f')
1579 #define FOURCC_dref GST_MAKE_FOURCC('d','r','e','f')
1580 #define FOURCC_stbl GST_MAKE_FOURCC('s','t','b','l')
1581 #define FOURCC_stsd GST_MAKE_FOURCC('s','t','s','d')
1582 #define FOURCC_stts GST_MAKE_FOURCC('s','t','t','s')
1583 #define FOURCC_stss GST_MAKE_FOURCC('s','t','s','s')
1584 #define FOURCC_stsc GST_MAKE_FOURCC('s','t','s','c')
1585 #define FOURCC_stsz GST_MAKE_FOURCC('s','t','s','z')
1586 #define FOURCC_stco GST_MAKE_FOURCC('s','t','c','o')
1587 #define FOURCC_vide GST_MAKE_FOURCC('v','i','d','e')
1588 #define FOURCC_soun GST_MAKE_FOURCC('s','o','u','n')
1589 #define FOURCC_co64 GST_MAKE_FOURCC('c','o','6','4')
1590 #define FOURCC_cmov GST_MAKE_FOURCC('c','m','o','v')
1591 #define FOURCC_dcom GST_MAKE_FOURCC('d','c','o','m')
1592 #define FOURCC_cmvd GST_MAKE_FOURCC('c','m','v','d')
1593 #define FOURCC_hint GST_MAKE_FOURCC('h','i','n','t')
1594 #define FOURCC_mp4a GST_MAKE_FOURCC('m','p','4','a')
1595 #define FOURCC_mp4v GST_MAKE_FOURCC('m','p','4','v')
1596 #define FOURCC_wave GST_MAKE_FOURCC('w','a','v','e')
1597 #define FOURCC_appl GST_MAKE_FOURCC('a','p','p','l')
1598 #define FOURCC_esds GST_MAKE_FOURCC('e','s','d','s')
1599 #define FOURCC_hnti GST_MAKE_FOURCC('h','n','t','i')
1600 #define FOURCC_rtp_ GST_MAKE_FOURCC('r','t','p',' ')
1601 #define FOURCC_sdp_ GST_MAKE_FOURCC('s','d','p',' ')
1602 #define FOURCC_meta GST_MAKE_FOURCC('m','e','t','a')
1603 #define FOURCC_ilst GST_MAKE_FOURCC('i','l','s','t')
1604 #define FOURCC__nam GST_MAKE_FOURCC(0xa9,'n','a','m')
1605 #define FOURCC__ART GST_MAKE_FOURCC(0xa9,'A','R','T')
1606 #define FOURCC__wrt GST_MAKE_FOURCC(0xa9,'w','r','t')
1607 #define FOURCC__grp GST_MAKE_FOURCC(0xa9,'g','r','p')
1608 #define FOURCC__alb GST_MAKE_FOURCC(0xa9,'a','l','b')
1609 #define FOURCC_gnre GST_MAKE_FOURCC('g','n','r','e')
1610 #define FOURCC_disc GST_MAKE_FOURCC('d','i','s','c')
1611 #define FOURCC_disk GST_MAKE_FOURCC('d','i','s','k')
1612 #define FOURCC_trkn GST_MAKE_FOURCC('t','r','k','n')
1613 #define FOURCC_cpil GST_MAKE_FOURCC('c','p','i','l')
1614 #define FOURCC_tmpo GST_MAKE_FOURCC('t','m','p','o')
1615 #define FOURCC__too GST_MAKE_FOURCC(0xa9,'t','o','o')
1616 #define FOURCC_____ GST_MAKE_FOURCC('-','-','-','-')
1617 #define FOURCC_free GST_MAKE_FOURCC('f','r','e','e')
1618 #define FOURCC_data GST_MAKE_FOURCC('d','a','t','a')
1619 #define FOURCC_SVQ3 GST_MAKE_FOURCC('S','V','Q','3')
1620 #define FOURCC_rmra GST_MAKE_FOURCC('r','m','r','a')
1621 #define FOURCC_rmda GST_MAKE_FOURCC('r','m','d','a')
1622 #define FOURCC_rdrf GST_MAKE_FOURCC('r','d','r','f')
1623 #define FOURCC__gen GST_MAKE_FOURCC(0xa9, 'g', 'e', 'n')
1625 static void qtdemux_dump_mvhd (GstQTDemux * qtdemux, void *buffer, int depth);
1626 static void qtdemux_dump_tkhd (GstQTDemux * qtdemux, void *buffer, int depth);
1627 static void qtdemux_dump_elst (GstQTDemux * qtdemux, void *buffer, int depth);
1628 static void qtdemux_dump_mdhd (GstQTDemux * qtdemux, void *buffer, int depth);
1629 static void qtdemux_dump_hdlr (GstQTDemux * qtdemux, void *buffer, int depth);
1630 static void qtdemux_dump_vmhd (GstQTDemux * qtdemux, void *buffer, int depth);
1631 static void qtdemux_dump_dref (GstQTDemux * qtdemux, void *buffer, int depth);
1632 static void qtdemux_dump_stsd (GstQTDemux * qtdemux, void *buffer, int depth);
1633 static void qtdemux_dump_stts (GstQTDemux * qtdemux, void *buffer, int depth);
1634 static void qtdemux_dump_stss (GstQTDemux * qtdemux, void *buffer, int depth);
1635 static void qtdemux_dump_stsc (GstQTDemux * qtdemux, void *buffer, int depth);
1636 static void qtdemux_dump_stsz (GstQTDemux * qtdemux, void *buffer, int depth);
1637 static void qtdemux_dump_stco (GstQTDemux * qtdemux, void *buffer, int depth);
1638 static void qtdemux_dump_co64 (GstQTDemux * qtdemux, void *buffer, int depth);
1639 static void qtdemux_dump_dcom (GstQTDemux * qtdemux, void *buffer, int depth);
1640 static void qtdemux_dump_cmvd (GstQTDemux * qtdemux, void *buffer, int depth);
1641 static void qtdemux_dump_unknown (GstQTDemux * qtdemux, void *buffer,
1644 QtNodeType qt_node_types[] = {
1645 {FOURCC_moov, "movie", QT_CONTAINER,},
1646 {FOURCC_mvhd, "movie header", 0,
1648 {FOURCC_clip, "clipping", QT_CONTAINER,},
1649 {FOURCC_trak, "track", QT_CONTAINER,},
1650 {FOURCC_udta, "user data", QT_CONTAINER,}, /* special container */
1651 {FOURCC_ctab, "color table", 0,},
1652 {FOURCC_tkhd, "track header", 0,
1654 {FOURCC_crgn, "clipping region", 0,},
1655 {FOURCC_matt, "track matte", QT_CONTAINER,},
1656 {FOURCC_kmat, "compressed matte", 0,},
1657 {FOURCC_edts, "edit", QT_CONTAINER,},
1658 {FOURCC_elst, "edit list", 0,
1660 {FOURCC_load, "track load settings", 0,},
1661 {FOURCC_tref, "track reference", QT_CONTAINER,},
1662 {FOURCC_imap, "track input map", QT_CONTAINER,},
1663 {FOURCC___in, "track input", 0,}, /* special container */
1664 {FOURCC___ty, "input type", 0,},
1665 {FOURCC_mdia, "media", QT_CONTAINER},
1666 {FOURCC_mdhd, "media header", 0,
1668 {FOURCC_hdlr, "handler reference", 0,
1670 {FOURCC_minf, "media information", QT_CONTAINER},
1671 {FOURCC_vmhd, "video media information", 0,
1673 {FOURCC_smhd, "sound media information", 0},
1674 {FOURCC_gmhd, "base media information header", 0},
1675 {FOURCC_gmin, "base media info", 0},
1676 {FOURCC_dinf, "data information", QT_CONTAINER},
1677 {FOURCC_dref, "data reference", 0,
1679 {FOURCC_stbl, "sample table", QT_CONTAINER},
1680 {FOURCC_stsd, "sample description", 0,
1682 {FOURCC_stts, "time-to-sample", 0,
1684 {FOURCC_stss, "sync sample", 0,
1686 {FOURCC_stsc, "sample-to-chunk", 0,
1688 {FOURCC_stsz, "sample size", 0,
1690 {FOURCC_stco, "chunk offset", 0,
1692 {FOURCC_co64, "64-bit chunk offset", 0,
1694 {FOURCC_vide, "video media", 0},
1695 {FOURCC_cmov, "compressed movie", QT_CONTAINER},
1696 {FOURCC_dcom, "compressed data", 0, qtdemux_dump_dcom},
1697 {FOURCC_cmvd, "compressed movie data", 0, qtdemux_dump_cmvd},
1698 {FOURCC_hint, "hint", 0,},
1699 {FOURCC_mp4a, "mp4a", 0,},
1700 {FOURCC_mp4v, "mp4v", 0,},
1701 {FOURCC_wave, "wave", QT_CONTAINER},
1702 {FOURCC_appl, "appl", QT_CONTAINER},
1703 {FOURCC_esds, "esds", 0},
1704 {FOURCC_hnti, "hnti", QT_CONTAINER},
1705 {FOURCC_rtp_, "rtp ", 0, qtdemux_dump_unknown},
1706 {FOURCC_sdp_, "sdp ", 0, qtdemux_dump_unknown},
1707 {FOURCC_meta, "meta", 0, qtdemux_dump_unknown},
1708 {FOURCC_ilst, "ilst", QT_CONTAINER,},
1709 {FOURCC__nam, "Name", QT_CONTAINER,},
1710 {FOURCC__ART, "Artist", QT_CONTAINER,},
1711 {FOURCC__wrt, "Writer", QT_CONTAINER,},
1712 {FOURCC__grp, "Group", QT_CONTAINER,},
1713 {FOURCC__alb, "Album", QT_CONTAINER,},
1714 {FOURCC_gnre, "Genre", QT_CONTAINER,},
1715 {FOURCC_trkn, "Track Number", QT_CONTAINER,},
1716 {FOURCC_disc, "Disc Number", QT_CONTAINER,},
1717 {FOURCC_disk, "Disc Number", QT_CONTAINER,},
1718 {FOURCC_cpil, "cpil", QT_CONTAINER,},
1719 {FOURCC_tmpo, "Tempo", QT_CONTAINER,},
1720 {FOURCC__too, "too", QT_CONTAINER,},
1721 {FOURCC_____, "----", QT_CONTAINER,},
1722 {FOURCC_data, "data", 0, qtdemux_dump_unknown},
1723 {FOURCC_free, "free", 0,},
1724 {FOURCC_SVQ3, "SVQ3", 0,},
1725 {FOURCC_rmra, "rmra", QT_CONTAINER,},
1726 {FOURCC_rmda, "rmda", QT_CONTAINER,},
1727 {FOURCC_rdrf, "rdrf", 0,},
1728 {FOURCC__gen, "Custom Genre", QT_CONTAINER,},
1731 static int n_qt_node_types = sizeof (qt_node_types) / sizeof (qt_node_types[0]);
1735 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
1737 return g_malloc (items * size);
1741 qtdemux_zfree (void *opaque, void *addr)
1747 qtdemux_inflate (void *z_buffer, int z_length, int length)
1753 z = g_new0 (z_stream, 1);
1754 z->zalloc = qtdemux_zalloc;
1755 z->zfree = qtdemux_zfree;
1758 z->next_in = z_buffer;
1759 z->avail_in = z_length;
1761 buffer = g_malloc (length);
1762 ret = inflateInit (z);
1763 while (z->avail_in > 0) {
1764 if (z->avail_out == 0) {
1766 buffer = realloc (buffer, length);
1767 z->next_out = buffer + z->total_out;
1768 z->avail_out = 1024;
1770 ret = inflate (z, Z_SYNC_FLUSH);
1774 if (ret != Z_STREAM_END) {
1775 g_warning ("inflate() returned %d", ret);
1783 qtdemux_parse_moov (GstQTDemux * qtdemux, void *buffer, int length)
1787 qtdemux->moov_node = g_node_new (buffer);
1789 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
1790 qtdemux_parse (qtdemux, qtdemux->moov_node, buffer, length);
1792 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
1797 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
1798 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
1800 if (QTDEMUX_FOURCC_GET (dcom->data + 8) == GST_MAKE_FOURCC ('z', 'l', 'i',
1802 int uncompressed_length;
1803 int compressed_length;
1806 uncompressed_length = QTDEMUX_GUINT32_GET (cmvd->data + 8);
1807 compressed_length = QTDEMUX_GUINT32_GET (cmvd->data + 4) - 12;
1808 GST_LOG ("length = %d", uncompressed_length);
1810 buf = qtdemux_inflate (cmvd->data + 12, compressed_length,
1811 uncompressed_length);
1813 qtdemux->moov_node_compressed = qtdemux->moov_node;
1814 qtdemux->moov_node = g_node_new (buf);
1816 qtdemux_parse (qtdemux, qtdemux->moov_node, buf, uncompressed_length);
1818 GST_LOG ("unknown header compression type");
1824 qtdemux_parse (GstQTDemux * qtdemux, GNode * node, void *buffer, int length)
1827 guint32 node_length;
1831 GST_LOG ("qtdemux_parse buffer %p length %d", buffer, length);
1833 node_length = QTDEMUX_GUINT32_GET (buffer);
1834 fourcc = QTDEMUX_FOURCC_GET (buffer + 4);
1836 type = qtdemux_type_get (fourcc);
1838 if (fourcc == 0 || node_length == 8)
1841 GST_LOG ("parsing '%" GST_FOURCC_FORMAT "', length=%d",
1842 GST_FOURCC_ARGS (fourcc), node_length);
1844 if (type->flags & QT_CONTAINER) {
1849 end = buffer + length;
1853 if (buf + 8 >= end) {
1854 /* FIXME: get annoyed */
1855 GST_LOG ("buffer overrun");
1857 len = QTDEMUX_GUINT32_GET (buf);
1859 GST_WARNING ("atom length too short (%d < 8)", len);
1862 if (len > (end - buf)) {
1863 GST_WARNING ("atom length too long (%d > %d)", len, end - buf);
1867 child = g_node_new (buf);
1868 g_node_append (node, child);
1869 qtdemux_parse (qtdemux, child, buf, len);
1874 if (fourcc == FOURCC_stsd) {
1878 GST_DEBUG_OBJECT (qtdemux,
1879 "parsing stsd (sample table, sample description) atom");
1881 end = buffer + length;
1885 if (buf + 8 >= end) {
1886 /* FIXME: get annoyed */
1887 GST_LOG ("buffer overrun");
1889 len = QTDEMUX_GUINT32_GET (buf);
1891 GST_WARNING ("length too short (%d < 8)");
1894 if (len > (end - buf)) {
1895 GST_WARNING ("length too long (%d > %d)", len, end - buf);
1899 child = g_node_new (buf);
1900 g_node_append (node, child);
1901 qtdemux_parse (qtdemux, child, buf, len);
1905 } else if (fourcc == FOURCC_mp4a) {
1910 version = QTDEMUX_GUINT32_GET (buffer + 16);
1911 if (version == 0x00010000 || 1) {
1912 buf = buffer + 0x24;
1913 end = buffer + length;
1918 if (buf + 8 >= end) {
1919 /* FIXME: get annoyed */
1920 GST_LOG ("buffer overrun");
1922 len = QTDEMUX_GUINT32_GET (buf);
1924 GST_WARNING ("length too short (%d < 8)");
1927 if (len > (end - buf)) {
1928 GST_WARNING ("length too long (%d > %d)", len, end - buf);
1932 child = g_node_new (buf);
1933 g_node_append (node, child);
1934 qtdemux_parse (qtdemux, child, buf, len);
1939 } else if (fourcc == FOURCC_mp4v) {
1945 GST_DEBUG_OBJECT (qtdemux, "parsing in mp4v");
1946 version = QTDEMUX_GUINT32_GET (buffer + 16);
1947 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
1948 if (1 || version == 0x00000000) {
1950 buf = buffer + 0x32;
1951 end = buffer + length;
1953 /* FIXME Quicktime uses PASCAL string while
1954 * the iso format uses C strings. Check the file
1955 * type before attempting to parse the string here. */
1956 tlen = QTDEMUX_GUINT8_GET (buf);
1957 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
1959 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
1960 /* the string has a reserved space of 32 bytes so skip
1961 * the remaining 31 */
1963 buf += 4; /* and 4 bytes reserved */
1965 gst_util_dump_mem (buf, end - buf);
1969 if (buf + 8 >= end) {
1970 /* FIXME: get annoyed */
1971 GST_LOG ("buffer overrun");
1973 len = QTDEMUX_GUINT32_GET (buf);
1977 GST_WARNING ("length too short (%d < 8)");
1980 if (len > (end - buf)) {
1981 GST_WARNING ("length too long (%d > %d)", len, end - buf);
1985 child = g_node_new (buf);
1986 g_node_append (node, child);
1987 qtdemux_parse (qtdemux, child, buf, len);
1992 } else if (fourcc == FOURCC_meta) {
1997 end = buffer + length;
2001 if (buf + 8 >= end) {
2002 /* FIXME: get annoyed */
2003 GST_LOG ("buffer overrun");
2005 len = QTDEMUX_GUINT32_GET (buf);
2007 GST_WARNING ("length too short (%d < 8)");
2010 if (len > (end - buf)) {
2011 GST_WARNING ("length too long (%d > %d)", len, end - buf);
2015 child = g_node_new (buf);
2016 g_node_append (node, child);
2017 qtdemux_parse (qtdemux, child, buf, len);
2021 } else if (fourcc == FOURCC_SVQ3) {
2027 GST_LOG ("parsing in SVQ3");
2029 end = buffer + length;
2030 version = QTDEMUX_GUINT32_GET (buffer + 16);
2031 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
2032 if (1 || version == 0x00000000) {
2034 buf = buffer + 0x32;
2035 end = buffer + length;
2037 tlen = QTDEMUX_GUINT8_GET (buf);
2038 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
2040 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
2044 gst_util_dump_mem (buf, end - buf);
2048 if (buf + 8 >= end) {
2049 /* FIXME: get annoyed */
2050 GST_LOG ("buffer overrun");
2052 len = QTDEMUX_GUINT32_GET (buf);
2056 GST_WARNING ("length too short (%d < 8)");
2059 if (len > (end - buf)) {
2060 GST_WARNING ("length too long (%d > %d)", len, end - buf);
2064 child = g_node_new (buf);
2065 g_node_append (node, child);
2066 qtdemux_parse (qtdemux, child, buf, len);
2073 if (fourcc == FOURCC_cmvd) {
2074 int uncompressed_length;
2077 uncompressed_length = QTDEMUX_GUINT32_GET (buffer + 8);
2078 GST_LOG ("length = %d", uncompressed_length);
2081 qtdemux_inflate (buffer + 12, node_length - 12, uncompressed_length);
2083 end = buf + uncompressed_length;
2088 if (buf + 8 >= end) {
2089 /* FIXME: get annoyed */
2090 GST_LOG ("buffer overrun");
2092 len = QTDEMUX_GUINT32_GET (buf);
2094 child = g_node_new (buf);
2095 g_node_append (node, child);
2096 qtdemux_parse (qtdemux, child, buf, len);
2106 qtdemux_type_get (guint32 fourcc)
2110 for (i = 0; i < n_qt_node_types; i++) {
2111 if (qt_node_types[i].fourcc == fourcc)
2112 return qt_node_types + i;
2115 GST_WARNING ("unknown QuickTime node type %" GST_FOURCC_FORMAT,
2116 GST_FOURCC_ARGS (fourcc));
2117 return qt_node_types + n_qt_node_types - 1;
2121 qtdemux_node_dump_foreach (GNode * node, gpointer data)
2123 void *buffer = node->data;
2124 guint32 node_length;
2129 node_length = GST_READ_UINT32_BE (buffer);
2130 fourcc = GST_READ_UINT32_LE (buffer + 4);
2132 type = qtdemux_type_get (fourcc);
2134 depth = (g_node_depth (node) - 1) * 2;
2135 GST_LOG ("%*s'%" GST_FOURCC_FORMAT "', [%d], %s",
2136 depth, "", GST_FOURCC_ARGS (fourcc), node_length, type->name);
2139 type->dump (data, buffer, depth);
2145 qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node)
2147 g_node_traverse (qtdemux->moov_node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
2148 qtdemux_node_dump_foreach, qtdemux);
2152 qtdemux_dump_mvhd (GstQTDemux * qtdemux, void *buffer, int depth)
2154 GST_LOG ("%*s version/flags: %08x", depth, "",
2155 QTDEMUX_GUINT32_GET (buffer + 8));
2156 GST_LOG ("%*s creation time: %u", depth, "",
2157 QTDEMUX_GUINT32_GET (buffer + 12));
2158 GST_LOG ("%*s modify time: %u", depth, "",
2159 QTDEMUX_GUINT32_GET (buffer + 16));
2160 qtdemux->duration = QTDEMUX_GUINT32_GET (buffer + 24);
2161 qtdemux->timescale = QTDEMUX_GUINT32_GET (buffer + 20);
2162 GST_LOG ("%*s time scale: 1/%u sec", depth, "", qtdemux->timescale);
2163 GST_LOG ("%*s duration: %u", depth, "", qtdemux->duration);
2164 GST_LOG ("%*s pref. rate: %g", depth, "", QTDEMUX_FP32_GET (buffer + 28));
2165 GST_LOG ("%*s pref. volume: %g", depth, "", QTDEMUX_FP16_GET (buffer + 32));
2166 GST_LOG ("%*s preview time: %u", depth, "",
2167 QTDEMUX_GUINT32_GET (buffer + 80));
2168 GST_LOG ("%*s preview dur.: %u", depth, "",
2169 QTDEMUX_GUINT32_GET (buffer + 84));
2170 GST_LOG ("%*s poster time: %u", depth, "",
2171 QTDEMUX_GUINT32_GET (buffer + 88));
2172 GST_LOG ("%*s select time: %u", depth, "",
2173 QTDEMUX_GUINT32_GET (buffer + 92));
2174 GST_LOG ("%*s select dur.: %u", depth, "",
2175 QTDEMUX_GUINT32_GET (buffer + 96));
2176 GST_LOG ("%*s current time: %u", depth, "",
2177 QTDEMUX_GUINT32_GET (buffer + 100));
2178 GST_LOG ("%*s next track ID: %d", depth, "",
2179 QTDEMUX_GUINT32_GET (buffer + 104));
2183 qtdemux_dump_tkhd (GstQTDemux * qtdemux, void *buffer, int depth)
2185 GST_LOG ("%*s version/flags: %08x", depth, "",
2186 QTDEMUX_GUINT32_GET (buffer + 8));
2187 GST_LOG ("%*s creation time: %u", depth, "",
2188 QTDEMUX_GUINT32_GET (buffer + 12));
2189 GST_LOG ("%*s modify time: %u", depth, "",
2190 QTDEMUX_GUINT32_GET (buffer + 16));
2191 GST_LOG ("%*s track ID: %u", depth, "",
2192 QTDEMUX_GUINT32_GET (buffer + 20));
2193 GST_LOG ("%*s duration: %u", depth, "",
2194 QTDEMUX_GUINT32_GET (buffer + 28));
2195 GST_LOG ("%*s layer: %u", depth, "",
2196 QTDEMUX_GUINT16_GET (buffer + 36));
2197 GST_LOG ("%*s alt group: %u", depth, "",
2198 QTDEMUX_GUINT16_GET (buffer + 38));
2199 GST_LOG ("%*s volume: %g", depth, "", QTDEMUX_FP16_GET (buffer + 44));
2200 GST_LOG ("%*s track width: %g", depth, "", QTDEMUX_FP32_GET (buffer + 84));
2201 GST_LOG ("%*s track height: %g", depth, "", QTDEMUX_FP32_GET (buffer + 88));
2206 qtdemux_dump_elst (GstQTDemux * qtdemux, void *buffer, int depth)
2211 GST_LOG ("%*s version/flags: %08x", depth, "",
2212 QTDEMUX_GUINT32_GET (buffer + 8));
2213 GST_LOG ("%*s n entries: %u", depth, "",
2214 QTDEMUX_GUINT32_GET (buffer + 12));
2215 n = QTDEMUX_GUINT32_GET (buffer + 12);
2216 for (i = 0; i < n; i++) {
2217 GST_LOG ("%*s track dur: %u", depth, "",
2218 QTDEMUX_GUINT32_GET (buffer + 16 + i * 12));
2219 GST_LOG ("%*s media time: %u", depth, "",
2220 QTDEMUX_GUINT32_GET (buffer + 20 + i * 12));
2221 GST_LOG ("%*s media rate: %g", depth, "",
2222 QTDEMUX_FP32_GET (buffer + 24 + i * 12));
2227 qtdemux_dump_mdhd (GstQTDemux * qtdemux, void *buffer, int depth)
2229 GST_LOG ("%*s version/flags: %08x", depth, "",
2230 QTDEMUX_GUINT32_GET (buffer + 8));
2231 GST_LOG ("%*s creation time: %u", depth, "",
2232 QTDEMUX_GUINT32_GET (buffer + 12));
2233 GST_LOG ("%*s modify time: %u", depth, "",
2234 QTDEMUX_GUINT32_GET (buffer + 16));
2235 GST_LOG ("%*s time scale: 1/%u sec", depth, "",
2236 QTDEMUX_GUINT32_GET (buffer + 20));
2237 GST_LOG ("%*s duration: %u", depth, "",
2238 QTDEMUX_GUINT32_GET (buffer + 24));
2239 GST_LOG ("%*s language: %u", depth, "",
2240 QTDEMUX_GUINT16_GET (buffer + 28));
2241 GST_LOG ("%*s quality: %u", depth, "",
2242 QTDEMUX_GUINT16_GET (buffer + 30));
2247 qtdemux_dump_hdlr (GstQTDemux * qtdemux, void *buffer, int depth)
2249 GST_LOG ("%*s version/flags: %08x", depth, "",
2250 QTDEMUX_GUINT32_GET (buffer + 8));
2251 GST_LOG ("%*s type: %" GST_FOURCC_FORMAT, depth, "",
2252 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 12)));
2253 GST_LOG ("%*s subtype: %" GST_FOURCC_FORMAT, depth, "",
2254 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 16)));
2255 GST_LOG ("%*s manufacturer: %" GST_FOURCC_FORMAT, depth, "",
2256 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 20)));
2257 GST_LOG ("%*s flags: %08x", depth, "",
2258 QTDEMUX_GUINT32_GET (buffer + 24));
2259 GST_LOG ("%*s flags mask: %08x", depth, "",
2260 QTDEMUX_GUINT32_GET (buffer + 28));
2261 GST_LOG ("%*s name: %*s", depth, "",
2262 QTDEMUX_GUINT8_GET (buffer + 32), (char *) (buffer + 33));
2267 qtdemux_dump_vmhd (GstQTDemux * qtdemux, void *buffer, int depth)
2269 GST_LOG ("%*s version/flags: %08x", depth, "",
2270 QTDEMUX_GUINT32_GET (buffer + 8));
2271 GST_LOG ("%*s mode/color: %08x", depth, "",
2272 QTDEMUX_GUINT32_GET (buffer + 16));
2276 qtdemux_dump_dref (GstQTDemux * qtdemux, void *buffer, int depth)
2282 GST_LOG ("%*s version/flags: %08x", depth, "",
2283 QTDEMUX_GUINT32_GET (buffer + 8));
2284 GST_LOG ("%*s n entries: %u", depth, "",
2285 QTDEMUX_GUINT32_GET (buffer + 12));
2286 n = QTDEMUX_GUINT32_GET (buffer + 12);
2288 for (i = 0; i < n; i++) {
2289 GST_LOG ("%*s size: %u", depth, "",
2290 QTDEMUX_GUINT32_GET (buffer + offset));
2291 GST_LOG ("%*s type: %" GST_FOURCC_FORMAT, depth, "",
2292 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + offset + 4)));
2293 offset += QTDEMUX_GUINT32_GET (buffer + offset);
2298 qtdemux_dump_stsd (GstQTDemux * qtdemux, void *buffer, int depth)
2304 GST_LOG ("%*s version/flags: %08x", depth, "",
2305 QTDEMUX_GUINT32_GET (buffer + 8));
2306 GST_LOG ("%*s n entries: %d", depth, "",
2307 QTDEMUX_GUINT32_GET (buffer + 12));
2308 n = QTDEMUX_GUINT32_GET (buffer + 12);
2310 for (i = 0; i < n; i++) {
2311 GST_LOG ("%*s size: %u", depth, "",
2312 QTDEMUX_GUINT32_GET (buffer + offset));
2313 GST_LOG ("%*s type: %" GST_FOURCC_FORMAT, depth, "",
2314 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + offset + 4)));
2315 GST_LOG ("%*s data reference:%d", depth, "",
2316 QTDEMUX_GUINT16_GET (buffer + offset + 14));
2318 GST_LOG ("%*s version/rev.: %08x", depth, "",
2319 QTDEMUX_GUINT32_GET (buffer + offset + 16));
2320 GST_LOG ("%*s vendor: %" GST_FOURCC_FORMAT, depth, "",
2321 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + offset + 20)));
2322 GST_LOG ("%*s temporal qual: %u", depth, "",
2323 QTDEMUX_GUINT32_GET (buffer + offset + 24));
2324 GST_LOG ("%*s spatial qual: %u", depth, "",
2325 QTDEMUX_GUINT32_GET (buffer + offset + 28));
2326 GST_LOG ("%*s width: %u", depth, "",
2327 QTDEMUX_GUINT16_GET (buffer + offset + 32));
2328 GST_LOG ("%*s height: %u", depth, "",
2329 QTDEMUX_GUINT16_GET (buffer + offset + 34));
2330 GST_LOG ("%*s horiz. resol: %g", depth, "",
2331 QTDEMUX_FP32_GET (buffer + offset + 36));
2332 GST_LOG ("%*s vert. resol.: %g", depth, "",
2333 QTDEMUX_FP32_GET (buffer + offset + 40));
2334 GST_LOG ("%*s data size: %u", depth, "",
2335 QTDEMUX_GUINT32_GET (buffer + offset + 44));
2336 GST_LOG ("%*s frame count: %u", depth, "",
2337 QTDEMUX_GUINT16_GET (buffer + offset + 48));
2338 GST_LOG ("%*s compressor: %d %d %d", depth, "",
2339 QTDEMUX_GUINT8_GET (buffer + offset + 49),
2340 QTDEMUX_GUINT8_GET (buffer + offset + 50),
2341 QTDEMUX_GUINT8_GET (buffer + offset + 51));
2342 //(char *) (buffer + offset + 51));
2343 GST_LOG ("%*s depth: %u", depth, "",
2344 QTDEMUX_GUINT16_GET (buffer + offset + 82));
2345 GST_LOG ("%*s color table ID:%u", depth, "",
2346 QTDEMUX_GUINT16_GET (buffer + offset + 84));
2348 offset += QTDEMUX_GUINT32_GET (buffer + offset);
2353 qtdemux_dump_stts (GstQTDemux * qtdemux, void *buffer, int depth)
2359 GST_LOG ("%*s version/flags: %08x", depth, "",
2360 QTDEMUX_GUINT32_GET (buffer + 8));
2361 GST_LOG ("%*s n entries: %d", depth, "",
2362 QTDEMUX_GUINT32_GET (buffer + 12));
2363 n = QTDEMUX_GUINT32_GET (buffer + 12);
2365 for (i = 0; i < n; i++) {
2366 GST_LOG ("%*s count: %u", depth, "",
2367 QTDEMUX_GUINT32_GET (buffer + offset));
2368 GST_LOG ("%*s duration: %u", depth, "",
2369 QTDEMUX_GUINT32_GET (buffer + offset + 4));
2376 qtdemux_dump_stss (GstQTDemux * qtdemux, void *buffer, int depth)
2382 GST_LOG ("%*s version/flags: %08x", depth, "",
2383 QTDEMUX_GUINT32_GET (buffer + 8));
2384 GST_LOG ("%*s n entries: %d", depth, "",
2385 QTDEMUX_GUINT32_GET (buffer + 12));
2386 n = QTDEMUX_GUINT32_GET (buffer + 12);
2388 for (i = 0; i < n; i++) {
2389 GST_LOG ("%*s sample: %u", depth, "",
2390 QTDEMUX_GUINT32_GET (buffer + offset));
2397 qtdemux_dump_stsc (GstQTDemux * qtdemux, void *buffer, int depth)
2403 GST_LOG ("%*s version/flags: %08x", depth, "",
2404 QTDEMUX_GUINT32_GET (buffer + 8));
2405 GST_LOG ("%*s n entries: %d", depth, "",
2406 QTDEMUX_GUINT32_GET (buffer + 12));
2407 n = QTDEMUX_GUINT32_GET (buffer + 12);
2409 for (i = 0; i < n; i++) {
2410 GST_LOG ("%*s first chunk: %u", depth, "",
2411 QTDEMUX_GUINT32_GET (buffer + offset));
2412 GST_LOG ("%*s sample per ch: %u", depth, "",
2413 QTDEMUX_GUINT32_GET (buffer + offset + 4));
2414 GST_LOG ("%*s sample desc id:%08x", depth, "",
2415 QTDEMUX_GUINT32_GET (buffer + offset + 8));
2422 qtdemux_dump_stsz (GstQTDemux * qtdemux, void *buffer, int depth)
2429 GST_LOG ("%*s version/flags: %08x", depth, "",
2430 QTDEMUX_GUINT32_GET (buffer + 8));
2431 GST_LOG ("%*s sample size: %d", depth, "",
2432 QTDEMUX_GUINT32_GET (buffer + 12));
2433 sample_size = QTDEMUX_GUINT32_GET (buffer + 12);
2434 if (sample_size == 0) {
2435 GST_LOG ("%*s n entries: %d", depth, "",
2436 QTDEMUX_GUINT32_GET (buffer + 16));
2437 n = QTDEMUX_GUINT32_GET (buffer + 16);
2440 for (i = 0; i < n; i++) {
2441 GST_LOG ("%*s sample size: %u", depth, "",
2442 QTDEMUX_GUINT32_GET (buffer + offset));
2451 qtdemux_dump_stco (GstQTDemux * qtdemux, void *buffer, int depth)
2457 GST_LOG ("%*s version/flags: %08x", depth, "",
2458 QTDEMUX_GUINT32_GET (buffer + 8));
2459 GST_LOG ("%*s n entries: %d", depth, "",
2460 QTDEMUX_GUINT32_GET (buffer + 12));
2461 n = QTDEMUX_GUINT32_GET (buffer + 12);
2464 for (i = 0; i < n; i++) {
2465 GST_LOG ("%*s chunk offset: %08x", depth, "",
2466 QTDEMUX_GUINT32_GET (buffer + offset));
2474 qtdemux_dump_co64 (GstQTDemux * qtdemux, void *buffer, int depth)
2480 GST_LOG ("%*s version/flags: %08x", depth, "",
2481 QTDEMUX_GUINT32_GET (buffer + 8));
2482 GST_LOG ("%*s n entries: %d", depth, "",
2483 QTDEMUX_GUINT32_GET (buffer + 12));
2484 n = QTDEMUX_GUINT32_GET (buffer + 12);
2487 for (i = 0; i < n; i++) {
2488 GST_LOG ("%*s chunk offset: %" G_GUINT64_FORMAT, depth, "",
2489 QTDEMUX_GUINT64_GET (buffer + offset));
2497 qtdemux_dump_dcom (GstQTDemux * qtdemux, void *buffer, int depth)
2499 GST_LOG ("%*s compression type: %" GST_FOURCC_FORMAT, depth, "",
2500 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 8)));
2504 qtdemux_dump_cmvd (GstQTDemux * qtdemux, void *buffer, int depth)
2506 GST_LOG ("%*s length: %d", depth, "", QTDEMUX_GUINT32_GET (buffer + 8));
2510 qtdemux_dump_unknown (GstQTDemux * qtdemux, void *buffer, int depth)
2514 GST_LOG ("%*s length: %d", depth, "", QTDEMUX_GUINT32_GET (buffer + 0));
2516 len = QTDEMUX_GUINT32_GET (buffer + 0);
2517 gst_util_dump_mem (buffer, len);
2523 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
2527 guint32 child_fourcc;
2529 for (child = g_node_first_child (node); child;
2530 child = g_node_next_sibling (child)) {
2531 buffer = child->data;
2533 child_fourcc = GST_READ_UINT32_LE (buffer);
2534 GST_LOG ("First chunk of buffer %p is [%" GST_FOURCC_FORMAT "]",
2535 buffer, GST_FOURCC_ARGS (child_fourcc));
2537 child_fourcc = GST_READ_UINT32_LE (buffer + 4);
2538 GST_LOG ("buffer %p has fourcc [%" GST_FOURCC_FORMAT "]",
2539 buffer, GST_FOURCC_ARGS (child_fourcc));
2541 if (child_fourcc == fourcc) {
2549 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
2553 guint32 child_fourcc;
2555 for (child = g_node_next_sibling (node); child;
2556 child = g_node_next_sibling (child)) {
2557 buffer = child->data;
2559 child_fourcc = GST_READ_UINT32_LE (buffer + 4);
2561 if (child_fourcc == fourcc) {
2568 static void qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak);
2571 qtdemux_parse_tree (GstQTDemux * qtdemux)
2577 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
2579 GNode *rmra, *rmda, *rdrf;
2581 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
2583 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
2585 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
2590 GST_LOG ("New location: %s", (char *) rdrf->data + 20);
2591 s = gst_structure_new ("redirect", "new-location", G_TYPE_STRING,
2592 (char *) rdrf->data + 20, NULL);
2593 msg = gst_message_new_element (GST_OBJECT (qtdemux), s);
2594 gst_element_post_message (GST_ELEMENT (qtdemux), msg);
2600 GST_LOG ("No mvhd node found.");
2604 qtdemux->timescale = QTDEMUX_GUINT32_GET (mvhd->data + 20);
2605 qtdemux->duration = QTDEMUX_GUINT32_GET (mvhd->data + 24);
2607 GST_INFO_OBJECT (qtdemux, "timescale: %d", qtdemux->timescale);
2608 GST_INFO_OBJECT (qtdemux, "duration: %d", qtdemux->duration);
2610 if (qtdemux->timescale != 0 && qtdemux->duration != 0) {
2613 duration = gst_util_uint64_scale_int (qtdemux->duration,
2614 GST_SECOND, qtdemux->timescale);
2616 gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
2619 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
2620 qtdemux_parse_trak (qtdemux, trak);
2622 /* trak = qtdemux_tree_get_sibling_by_type(trak, FOURCC_trak);
2623 if(trak)qtdemux_parse_trak(qtdemux, trak);*/
2626 while ((trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak)) != NULL)
2627 qtdemux_parse_trak (qtdemux, trak);
2628 gst_element_no_more_pads (GST_ELEMENT (qtdemux));
2631 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
2633 qtdemux_parse_udta (qtdemux, udta);
2635 if (qtdemux->tag_list) {
2636 GST_DEBUG_OBJECT (qtdemux,
2637 "calling gst_element_found_tags with %" GST_PTR_FORMAT,
2639 gst_element_found_tags (GST_ELEMENT (qtdemux), qtdemux->tag_list);
2640 qtdemux->tag_list = NULL;
2643 GST_LOG ("No udta node found.");
2648 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
2669 QtDemuxSample *samples;
2670 int n_samples_per_chunk;
2673 QtDemuxStream *stream;
2678 GstTagList *list = NULL;
2679 const gchar *codec = NULL;
2681 tkhd = qtdemux_tree_get_child_by_type (trak, FOURCC_tkhd);
2682 g_return_if_fail (tkhd);
2684 GST_LOG ("track[tkhd] version/flags: 0x%08x",
2685 QTDEMUX_GUINT32_GET (tkhd->data + 8));
2687 /* track duration? */
2689 mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia);
2692 mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd);
2695 /* new streams always need a discont */
2696 stream = g_new0 (QtDemuxStream, 1);
2697 stream->discont = TRUE;
2699 stream->timescale = QTDEMUX_GUINT32_GET (mdhd->data + 20);
2700 GST_LOG ("track timescale: %d", stream->timescale);
2701 GST_LOG ("track duration: %d", QTDEMUX_GUINT32_GET (mdhd->data + 24));
2704 * some of those trailers, nowadays, have prologue images that are
2705 * themselves vide tracks as well. I haven't really found a way to
2706 * identify those yet, except for just looking at their duration. */
2707 if (stream->timescale * qtdemux->duration != 0 &&
2708 (guint64) QTDEMUX_GUINT32_GET (mdhd->data + 24) *
2709 qtdemux->timescale * 10 / (stream->timescale * qtdemux->duration) < 2) {
2710 GST_WARNING ("Track shorter than 20%% (%d/%d vs. %d/%d) of the stream "
2711 "found, assuming preview image or something; skipping track",
2712 QTDEMUX_GUINT32_GET (mdhd->data + 24), stream->timescale,
2713 qtdemux->duration, qtdemux->timescale);
2718 hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr);
2721 GST_LOG ("track type: %" GST_FOURCC_FORMAT,
2722 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (hdlr->data + 12)));
2723 GST_LOG ("track subtype: %" GST_FOURCC_FORMAT,
2724 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (hdlr->data + 16)));
2726 stream->subtype = QTDEMUX_FOURCC_GET (hdlr->data + 16);
2728 minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf);
2731 stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl);
2734 stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd);
2737 if (stream->subtype == FOURCC_vide) {
2741 GST_LOG ("st type: %" GST_FOURCC_FORMAT,
2742 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd->data + offset + 4)));
2744 stream->width = QTDEMUX_GUINT16_GET (stsd->data + offset + 32);
2745 stream->height = QTDEMUX_GUINT16_GET (stsd->data + offset + 34);
2746 stream->fps_n = 0; /* this is filled in later */
2747 stream->fps_d = 0; /* this is filled in later */
2748 stream->bits_per_sample = QTDEMUX_GUINT16_GET (stsd->data + offset + 82);
2749 stream->color_table_id = QTDEMUX_GUINT16_GET (stsd->data + offset + 84);
2751 GST_LOG ("frame count: %u",
2752 QTDEMUX_GUINT16_GET (stsd->data + offset + 48));
2754 stream->fourcc = fourcc = QTDEMUX_FOURCC_GET (stsd->data + offset + 4);
2755 stream->caps = qtdemux_video_caps (qtdemux, fourcc, stsd->data, &codec);
2757 list = gst_tag_list_new ();
2758 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
2759 GST_TAG_VIDEO_CODEC, codec, NULL);
2763 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4v);
2765 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
2768 gst_qtdemux_handle_esds (qtdemux, stream, esds);
2770 if (QTDEMUX_FOURCC_GET ((char *) stsd->data + 16 + 4) ==
2771 GST_MAKE_FOURCC ('a', 'v', 'c', '1')) {
2772 gint len = QTDEMUX_GUINT32_GET (stsd->data) - 0x66;
2773 guint8 *stsddata = stsd->data + 0x66;
2776 while (len >= 0x8 &&
2777 QTDEMUX_FOURCC_GET (stsddata + 0x4) !=
2778 GST_MAKE_FOURCC ('a', 'v', 'c', 'C') &&
2779 QTDEMUX_GUINT32_GET (stsddata) < len) {
2780 len -= QTDEMUX_GUINT32_GET (stsddata);
2781 stsddata += QTDEMUX_GUINT32_GET (stsddata);
2784 /* parse, if found */
2786 QTDEMUX_FOURCC_GET (stsddata + 0x4) ==
2787 GST_MAKE_FOURCC ('a', 'v', 'c', 'C')) {
2791 if (QTDEMUX_GUINT32_GET (stsddata) < len)
2792 size = QTDEMUX_GUINT32_GET (stsddata) - 0x8;
2796 buf = gst_buffer_new_and_alloc (size);
2797 memcpy (GST_BUFFER_DATA (buf), stsddata + 0x8, size);
2798 gst_caps_set_simple (stream->caps,
2799 "codec_data", GST_TYPE_BUFFER, buf, NULL);
2800 gst_buffer_unref (buf);
2802 } else if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2803 GST_MAKE_FOURCC ('S', 'V', 'Q', '3')) {
2805 gint len = QTDEMUX_GUINT32_GET (stsd->data);
2807 buf = gst_buffer_new_and_alloc (len);
2808 memcpy (GST_BUFFER_DATA (buf), stsd->data, len);
2809 gst_caps_set_simple (stream->caps,
2810 "codec_data", GST_TYPE_BUFFER, buf, NULL);
2811 gst_buffer_unref (buf);
2812 } else if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2813 GST_MAKE_FOURCC ('V', 'P', '3', '1')) {
2815 gint len = QTDEMUX_GUINT32_GET (stsd->data);
2817 buf = gst_buffer_new_and_alloc (len);
2818 memcpy (GST_BUFFER_DATA (buf), stsd->data, len);
2819 gst_caps_set_simple (stream->caps,
2820 "codec_data", GST_TYPE_BUFFER, buf, NULL);
2821 gst_buffer_unref (buf);
2822 } else if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2823 GST_MAKE_FOURCC ('r', 'l', 'e', ' ')) {
2824 gst_caps_set_simple (stream->caps,
2825 "depth", G_TYPE_INT, QTDEMUX_GUINT16_GET (stsd->data + offset + 82),
2830 GST_INFO_OBJECT (qtdemux,
2831 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
2832 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd->data + offset + 4)),
2834 } else if (stream->subtype == FOURCC_soun) {
2835 int version, samplesize;
2839 len = QTDEMUX_GUINT32_GET (stsd->data + 16);
2840 GST_LOG ("st type: %" GST_FOURCC_FORMAT,
2841 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4)));
2843 stream->fourcc = fourcc = QTDEMUX_FOURCC_GET (stsd->data + 16 + 4);
2846 GST_LOG ("version/rev: %08x",
2847 QTDEMUX_GUINT32_GET (stsd->data + offset));
2848 version = QTDEMUX_GUINT32_GET (stsd->data + offset);
2849 GST_LOG ("vendor: %08x",
2850 QTDEMUX_GUINT32_GET (stsd->data + offset + 4));
2851 GST_LOG ("n_channels: %d",
2852 QTDEMUX_GUINT16_GET (stsd->data + offset + 8));
2853 stream->n_channels = QTDEMUX_GUINT16_GET (stsd->data + offset + 8);
2854 GST_LOG ("sample_size: %d",
2855 QTDEMUX_GUINT16_GET (stsd->data + offset + 10));
2856 samplesize = QTDEMUX_GUINT16_GET (stsd->data + offset + 10);
2857 GST_LOG ("compression_id: %d",
2858 QTDEMUX_GUINT16_GET (stsd->data + offset + 12));
2859 GST_LOG ("packet size: %d",
2860 QTDEMUX_GUINT16_GET (stsd->data + offset + 14));
2861 GST_LOG ("sample rate: %g",
2862 QTDEMUX_FP32_GET (stsd->data + offset + 16));
2863 stream->rate = QTDEMUX_FP32_GET (stsd->data + offset + 16);
2866 if (version == 0x00010000) {
2867 GST_LOG ("samples/packet: %d",
2868 QTDEMUX_GUINT32_GET (stsd->data + offset));
2869 stream->samples_per_packet = QTDEMUX_GUINT32_GET (stsd->data + offset);
2870 GST_LOG ("bytes/packet: %d",
2871 QTDEMUX_GUINT32_GET (stsd->data + offset + 4));
2872 GST_LOG ("bytes/frame: %d",
2873 QTDEMUX_GUINT32_GET (stsd->data + offset + 8));
2874 stream->bytes_per_frame = QTDEMUX_GUINT32_GET (stsd->data + offset + 8);
2875 GST_LOG ("bytes/sample: %d",
2876 QTDEMUX_GUINT32_GET (stsd->data + offset + 12));
2877 stream->compression = 1;
2879 } else if (version == 0x00000000) {
2880 stream->bytes_per_frame = stream->n_channels * samplesize / 8;
2881 stream->samples_per_packet = 1;
2882 stream->compression = 1;
2884 /* Yes, these have to be hard-coded */
2885 if (fourcc == GST_MAKE_FOURCC ('M', 'A', 'C', '6'))
2886 stream->compression = 6;
2887 if (fourcc == GST_MAKE_FOURCC ('M', 'A', 'C', '3'))
2888 stream->compression = 3;
2889 if (fourcc == GST_MAKE_FOURCC ('i', 'm', 'a', '4'))
2890 stream->compression = 4;
2891 if (fourcc == GST_MAKE_FOURCC ('s', 'a', 'm', 'r')) {
2892 stream->n_channels = 1;
2893 stream->rate = 8000;
2894 stream->bytes_per_frame <<= 3;
2896 if (fourcc == GST_MAKE_FOURCC ('u', 'l', 'a', 'w'))
2897 stream->compression = 2;
2898 if (fourcc == GST_MAKE_FOURCC ('a', 'g', 's', 'm')) {
2899 stream->bytes_per_frame *= 33;
2900 stream->compression = 320;
2903 GST_WARNING ("unknown version %08x", version);
2906 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
2910 list = gst_tag_list_new ();
2911 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
2912 GST_TAG_AUDIO_CODEC, codec, NULL);
2915 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
2918 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
2922 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
2924 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
2927 gst_qtdemux_handle_esds (qtdemux, stream, esds);
2930 int len = QTDEMUX_GUINT32_GET (esds->data);
2932 buffer = gst_buffer_new_and_alloc (len - 8);
2933 memcpy (GST_BUFFER_DATA (buffer), esds->data + 8, len - 8);
2935 gst_caps_set_simple (stream->caps, "codec_data",
2936 GST_TYPE_BUFFER, buffer, NULL);
2939 if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2940 GST_MAKE_FOURCC ('Q', 'D', 'M', '2')) {
2941 gint len = QTDEMUX_GUINT32_GET (stsd->data);
2944 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
2946 memcpy (GST_BUFFER_DATA (buf),
2947 (guint8 *) stsd->data + 0x4C, len - 0x4C);
2948 gst_caps_set_simple (stream->caps,
2949 "codec_data", GST_TYPE_BUFFER, buf, NULL);
2950 gst_buffer_unref (buf);
2952 gst_caps_set_simple (stream->caps,
2953 "samplesize", G_TYPE_INT, samplesize, NULL);
2954 } else if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2955 GST_MAKE_FOURCC ('a', 'l', 'a', 'c')) {
2956 gint len = QTDEMUX_GUINT32_GET (stsd->data);
2959 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
2961 memcpy (GST_BUFFER_DATA (buf),
2962 (guint8 *) stsd->data + 0x34, len - 0x34);
2963 gst_caps_set_simple (stream->caps,
2964 "codec_data", GST_TYPE_BUFFER, buf, NULL);
2965 gst_buffer_unref (buf);
2967 gst_caps_set_simple (stream->caps,
2968 "samplesize", G_TYPE_INT, samplesize, NULL);
2971 GST_INFO_OBJECT (qtdemux,
2972 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
2973 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4)),
2976 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
2977 GST_FOURCC_ARGS (stream->subtype));
2982 /* sample to chunk */
2983 stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc);
2986 stsz = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsz);
2989 stco = qtdemux_tree_get_child_by_type (stbl, FOURCC_stco);
2990 co64 = qtdemux_tree_get_child_by_type (stbl, FOURCC_co64);
2991 g_assert (stco || co64);
2993 stts = qtdemux_tree_get_child_by_type (stbl, FOURCC_stts);
2995 /* sample sync, can be NULL */
2996 stss = qtdemux_tree_get_child_by_type (stbl, FOURCC_stss);
2998 sample_size = QTDEMUX_GUINT32_GET (stsz->data + 12);
2999 if (sample_size == 0) {
3000 n_samples = QTDEMUX_GUINT32_GET (stsz->data + 16);
3001 GST_DEBUG_OBJECT (qtdemux, "stsz sample_size 0, allocating n_samples %d",
3003 stream->n_samples = n_samples;
3004 samples = g_malloc (sizeof (QtDemuxSample) * n_samples);
3005 stream->samples = samples;
3007 for (i = 0; i < n_samples; i++) {
3008 samples[i].size = QTDEMUX_GUINT32_GET (stsz->data + i * 4 + 20);
3009 GST_LOG_OBJECT (qtdemux, "sample %d has size %d", i, samples[i].size);
3010 /* init other fields to defaults for this sample */
3011 samples[i].keyframe = FALSE;
3013 n_samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 12);
3016 for (i = 0; i < n_samples_per_chunk; i++) {
3017 int first_chunk, last_chunk;
3018 int samples_per_chunk;
3020 first_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 0) - 1;
3021 if (i == n_samples_per_chunk - 1) {
3022 last_chunk = INT_MAX;
3024 last_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 12) - 1;
3026 samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 4);
3028 for (j = first_chunk; j < last_chunk; j++) {
3029 guint64 chunk_offset;
3032 chunk_offset = QTDEMUX_GUINT32_GET (stco->data + 16 + j * 4);
3034 chunk_offset = QTDEMUX_GUINT64_GET (co64->data + 16 + j * 8);
3036 for (k = 0; k < samples_per_chunk; k++) {
3037 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld",
3038 index, chunk_offset);
3039 samples[index].chunk = j;
3040 samples[index].offset = chunk_offset;
3041 chunk_offset += samples[index].size;
3043 if (index >= n_samples)
3050 n_sample_times = QTDEMUX_GUINT32_GET (stts->data + 12);
3053 for (i = 0; i < n_sample_times; i++) {
3058 n = QTDEMUX_GUINT32_GET (stts->data + 16 + 8 * i);
3059 duration = QTDEMUX_GUINT32_GET (stts->data + 16 + 8 * i + 4);
3061 gst_util_uint64_scale_int (duration, GST_SECOND, stream->timescale);
3062 for (j = 0; j < n; j++) {
3063 //GST_INFO("moo %lld", timestamp);
3064 samples[index].timestamp = timestamp;
3065 samples[index].duration = duration;
3071 /* mark keyframes */
3072 guint32 n_sample_syncs;
3074 n_sample_syncs = QTDEMUX_GUINT32_GET (stss->data + 12);
3075 if (n_sample_syncs == 0) {
3076 stream->all_keyframe = TRUE;
3079 for (i = 0; i < n_sample_syncs; i++) {
3080 /* not that the first sample is index 1, not 0 */
3081 index = QTDEMUX_GUINT32_GET (stss->data + offset);
3082 samples[index - 1].keyframe = TRUE;
3087 /* no stss, all samples are keyframes */
3088 stream->all_keyframe = TRUE;
3091 guint64 timestamp = 0;
3093 GST_DEBUG_OBJECT (qtdemux,
3094 "stsz sample_size %d != 0, treating chunks as samples", sample_size);
3096 /* treat chunks as samples */
3098 n_samples = QTDEMUX_GUINT32_GET (stco->data + 12);
3100 n_samples = QTDEMUX_GUINT32_GET (co64->data + 12);
3102 stream->n_samples = n_samples;
3103 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %d", n_samples);
3104 samples = g_malloc (sizeof (QtDemuxSample) * n_samples);
3105 stream->samples = samples;
3107 n_samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 12);
3108 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %d", n_samples_per_chunk);
3111 for (i = 0; i < n_samples_per_chunk; i++) {
3112 int first_chunk, last_chunk;
3113 int samples_per_chunk;
3115 first_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 0) - 1;
3116 /* the last chunk of each entry is calculated by taking the first chunk
3117 * of the next entry; except if there is no next, where we fake it with
3119 if (i == n_samples_per_chunk - 1) {
3120 last_chunk = INT_MAX;
3122 last_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 12) - 1;
3124 samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 4);
3126 GST_LOG_OBJECT (qtdemux,
3127 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
3128 first_chunk, last_chunk, samples_per_chunk);
3130 for (j = first_chunk; j < last_chunk; j++) {
3131 guint64 chunk_offset;
3136 chunk_offset = QTDEMUX_GUINT32_GET (stco->data + 16 + j * 4);
3137 GST_LOG_OBJECT (qtdemux, "stco chunk %d offset %x", j, chunk_offset);
3139 chunk_offset = QTDEMUX_GUINT64_GET (co64->data + 16 + j * 8);
3140 GST_LOG_OBJECT (qtdemux, "co64 chunk %d offset %" G_GUINT64_FORMAT, j,
3143 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld",
3145 samples[j].chunk = j;
3146 samples[j].offset = chunk_offset;
3147 if (stream->samples_per_packet * stream->compression != 0)
3149 samples_per_chunk * stream->bytes_per_frame /
3150 stream->samples_per_packet / stream->compression;
3151 else if (stream->bytes_per_frame)
3152 samples[j].size = stream->bytes_per_frame;
3154 samples[j].size = sample_size;
3155 samples[j].duration =
3156 samples_per_chunk * stream->timescale / (stream->rate / 2);
3157 samples[j].timestamp = timestamp;
3158 samples[j].keyframe = TRUE;
3160 if (stream->rate > 0) {
3161 timestamp += gst_util_uint64_scale_int (samples_per_chunk,
3162 GST_SECOND, stream->rate);
3165 GST_INFO_OBJECT (qtdemux,
3166 "moo samples_per_chunk=%d rate=%d dur=%lld %lld",
3167 (int) samples_per_chunk, (int) stream->rate,
3168 (long long) ((samples_per_chunk * GST_SECOND) / stream->rate),
3169 (long long) timestamp);
3171 samples[j].sample_index = sample_index;
3172 sample_index += samples_per_chunk;
3178 for (i = 0; i < n_samples; i++) {
3179 GST_LOG ("%d: %d %d %d %d %" G_GUINT64_FORMAT, i,
3180 samples[i].sample_index, samples[i].chunk,
3181 samples[i].offset, samples[i].size, samples[i].timestamp);
3186 gst_qtdemux_add_stream (qtdemux, stream, list);
3190 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
3196 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
3198 GST_LOG ("no meta");
3202 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
3204 GST_LOG ("no ilst");
3208 GST_DEBUG_OBJECT (qtdemux, "new tag list");
3209 qtdemux->tag_list = gst_tag_list_new ();
3211 node = qtdemux_tree_get_child_by_type (ilst, FOURCC__nam);
3213 qtdemux_tag_add_str (qtdemux, GST_TAG_TITLE, node);
3216 node = qtdemux_tree_get_child_by_type (ilst, FOURCC__ART);
3218 qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
3220 node = qtdemux_tree_get_child_by_type (ilst, FOURCC__wrt);
3222 qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
3224 node = qtdemux_tree_get_child_by_type (ilst, FOURCC__grp);
3226 qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
3231 node = qtdemux_tree_get_child_by_type (ilst, FOURCC__alb);
3233 qtdemux_tag_add_str (qtdemux, GST_TAG_ALBUM, node);
3236 node = qtdemux_tree_get_child_by_type (ilst, FOURCC_trkn);
3238 qtdemux_tag_add_num (qtdemux, GST_TAG_TRACK_NUMBER,
3239 GST_TAG_TRACK_COUNT, node);
3242 node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disc);
3244 qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER,
3245 GST_TAG_ALBUM_VOLUME_COUNT, node);
3247 node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disk);
3249 qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER,
3250 GST_TAG_ALBUM_VOLUME_COUNT, node);
3254 node = qtdemux_tree_get_child_by_type (ilst, FOURCC_gnre);
3256 qtdemux_tag_add_gnre (qtdemux, GST_TAG_GENRE, node);
3258 node = qtdemux_tree_get_child_by_type (ilst, FOURCC__gen);
3260 qtdemux_tag_add_str (qtdemux, GST_TAG_GENRE, node);
3266 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag, GNode * node)
3273 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3275 len = QTDEMUX_GUINT32_GET (data->data);
3276 type = QTDEMUX_GUINT32_GET (data->data + 8);
3277 if (type == 0x00000001) {
3278 s = g_strndup ((char *) data->data + 16, len - 16);
3279 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", s);
3280 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
3287 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
3288 const char *tag2, GNode * node)
3295 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3297 len = QTDEMUX_GUINT32_GET (data->data);
3298 type = QTDEMUX_GUINT32_GET (data->data + 8);
3299 if (type == 0x00000000 && len >= 22) {
3300 n1 = GST_READ_UINT16_BE (data->data + 18);
3301 n2 = GST_READ_UINT16_BE (data->data + 20);
3302 GST_DEBUG_OBJECT (qtdemux, "adding tag %d/%d", n1, n2);
3303 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
3304 tag1, n1, tag2, n2, NULL);
3310 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, GNode * node)
3312 const gchar *genres[] = {
3313 "N/A", "Blues", "Classic Rock", "Country", "Dance", "Disco",
3314 "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
3315 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno",
3316 "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
3317 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
3318 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
3319 "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
3320 "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative",
3321 "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
3322 "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk",
3323 "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
3324 "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American",
3325 "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes",
3326 "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka",
3327 "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
3328 "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob",
3329 "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde",
3330 "Gothic Rock", "Progressive Rock", "Psychedelic Rock",
3331 "Symphonic Rock", "Slow Rock", "Big Band", "Chorus",
3332 "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
3333 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
3334 "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango",
3335 "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul",
3336 "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella",
3337 "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club House",
3338 "Hardcore", "Terror", "Indie", "BritPop", "NegerPunk",
3339 "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal",
3340 "Black Metal", "Crossover", "Contemporary C", "Christian Rock",
3341 "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop"
3348 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3350 len = QTDEMUX_GUINT32_GET (data->data);
3351 type = QTDEMUX_GUINT32_GET (data->data + 8);
3352 if (type == 0x00000000 && len >= 18) {
3353 n = GST_READ_UINT16_BE (data->data + 16);
3354 if (n > 0 && n < sizeof (genres) / sizeof (char *)) {
3355 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genres[n]);
3356 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
3357 tag, genres[n], NULL);
3363 /* taken from ffmpeg */
3365 get_size (guint8 * ptr, guint8 ** end)
3374 len = (len << 7) | (c & 0x7f);
3384 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
3387 int len = QTDEMUX_GUINT32_GET (esds->data);
3388 guint8 *ptr = esds->data;
3389 guint8 *end = ptr + len;
3391 guint8 *data_ptr = NULL;
3394 gst_util_dump_mem (ptr, len);
3396 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QTDEMUX_GUINT32_GET (ptr));
3399 tag = QTDEMUX_GUINT8_GET (ptr);
3400 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
3402 len = get_size (ptr, &ptr);
3403 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
3407 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QTDEMUX_GUINT16_GET (ptr));
3408 GST_DEBUG_OBJECT (qtdemux, "priority %04x",
3409 QTDEMUX_GUINT8_GET (ptr + 2));
3413 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x",
3414 QTDEMUX_GUINT8_GET (ptr));
3415 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x",
3416 QTDEMUX_GUINT8_GET (ptr + 1));
3417 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x",
3418 QTDEMUX_GUINT24_GET (ptr + 2));
3419 GST_DEBUG_OBJECT (qtdemux, "max bitrate %d",
3420 QTDEMUX_GUINT32_GET (ptr + 5));
3421 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %d",
3422 QTDEMUX_GUINT32_GET (ptr + 9));
3426 GST_DEBUG_OBJECT (qtdemux, "data:");
3427 gst_util_dump_mem (ptr, len);
3433 GST_DEBUG_OBJECT (qtdemux, "data %02x", QTDEMUX_GUINT8_GET (ptr));
3437 GST_ERROR ("parse error");
3444 buffer = gst_buffer_new_and_alloc (data_len);
3445 memcpy (GST_BUFFER_DATA (buffer), data_ptr, data_len);
3446 gst_util_dump_mem (GST_BUFFER_DATA (buffer), data_len);
3448 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
3450 gst_buffer_unref (buffer);
3454 #define _codec(name) \
3457 *codec_name = name; \
3462 qtdemux_video_caps (GstQTDemux * qtdemux, guint32 fourcc,
3463 const guint8 * stsd_data, const gchar ** codec_name)
3466 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
3467 _codec ("PNG still images");
3468 return gst_caps_from_string ("image/png");
3469 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
3470 _codec ("JPEG still images");
3471 return gst_caps_from_string ("image/jpeg");
3472 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
3473 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
3474 _codec ("Motion-JPEG");
3475 return gst_caps_from_string ("image/jpeg");
3476 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
3477 _codec ("Motion-JPEG format B");
3478 return gst_caps_from_string ("video/x-mjpeg-b");
3479 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
3480 _codec ("Sorensen video v.3");
3481 return gst_caps_from_string ("video/x-svq, " "svqversion = (int) 3");
3482 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
3483 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
3484 _codec ("Sorensen video v.1");
3485 return gst_caps_from_string ("video/x-svq, " "svqversion = (int) 1");
3486 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
3487 _codec ("Raw RGB video");
3488 return gst_caps_from_string ("video/x-raw-rgb, "
3489 "endianness = (int) BIG_ENDIAN");
3490 /*"bpp", GST_PROPS_INT(x),
3491 "depth", GST_PROPS_INT(x),
3492 "red_mask", GST_PROPS_INT(x),
3493 "green_mask", GST_PROPS_INT(x),
3494 "blue_mask", GST_PROPS_INT(x), FIXME! */
3495 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
3496 _codec ("Raw packed YUV 4:2:2");
3497 return gst_caps_from_string ("video/x-raw-yuv, "
3498 "format = (fourcc) YUY2");
3499 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
3500 _codec ("MPEG-1 video");
3501 return gst_caps_from_string ("video/mpeg, "
3502 "systemstream = (boolean) false, " "mpegversion = (int) 1");
3503 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
3504 _codec ("GIF still images");
3505 return gst_caps_from_string ("image/gif");
3506 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
3507 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
3509 /* ffmpeg uses the height/width props, don't know why */
3510 return gst_caps_from_string ("video/x-h263");
3511 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
3512 _codec ("MPEG-4 video");
3513 return gst_caps_from_string ("video/mpeg, "
3514 "mpegversion = (int) 4, " "systemstream = (boolean) false");
3515 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
3516 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
3517 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
3518 return gst_caps_from_string ("video/x-msmpeg, msmpegversion = (int) 43");
3519 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
3520 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
3521 _codec ("3ivX video");
3522 return gst_caps_from_string ("video/x-3ivx");
3523 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
3525 return gst_caps_from_string ("video/x-divx," "divxversion= (int) 3");
3526 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
3528 return gst_caps_from_string ("video/x-divx," "divxversion= (int) 4");
3530 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
3532 return gst_caps_from_string ("video/x-divx," "divxversion= (int) 5");
3533 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
3535 return gst_caps_from_string ("video/x-cinepak");
3536 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
3537 _codec ("Apple video");
3538 return gst_caps_from_string ("video/x-apple-video");
3539 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
3540 _codec ("H.264 / AVC");
3541 return gst_caps_from_string ("video/x-h264");
3542 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
3543 _codec ("Run-length encoding");
3544 return gst_caps_from_string ("video/x-rle, layout=(string)quicktime");
3545 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
3546 _codec ("Indeo Video 3");
3547 return gst_caps_from_string ("video/x-indeo, indeoversion=(int)3");
3548 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
3549 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
3550 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
3551 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
3552 _codec ("DV Video");
3553 return gst_caps_from_string ("video/x-dv, systemstream=(boolean)false");
3554 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
3555 _codec ("Apple Graphics (SMC)");
3556 return gst_caps_from_string ("video/x-smc");
3557 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
3559 return gst_caps_from_string ("video/x-vp3");
3560 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
3563 g_critical ("Don't know how to convert fourcc '%" GST_FOURCC_FORMAT
3564 "' to caps", GST_FOURCC_ARGS (fourcc));
3570 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
3571 GST_FOURCC_ARGS (fourcc));
3572 return gst_caps_new_simple (s, NULL);
3578 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
3579 guint32 fourcc, const guint8 * data, int len, const gchar ** codec_name)
3583 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
3584 return NULL; /*gst_caps_from_string ("audio/raw"); */
3586 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
3587 _codec ("Raw 8-bit PCM audio");
3589 return gst_caps_from_string ("audio/x-raw-int, "
3590 "width = (int) 8, " "depth = (int) 8, " "signed = (boolean) false");
3591 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
3592 if (stream->bytes_per_frame == 1) {
3593 _codec ("Raw 8-bit PCM audio");
3594 return gst_caps_from_string ("audio/x-raw-int, "
3595 "width = (int) 8, " "depth = (int) 8, " "signed = (boolean) true");
3597 _codec ("Raw 16-bit PCM audio");
3599 return gst_caps_from_string ("audio/x-raw-int, "
3600 "width = (int) 16, "
3601 "depth = (int) 16, "
3602 "endianness = (int) BIG_ENDIAN, " "signed = (boolean) true");
3604 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
3605 if (stream->bytes_per_frame == 1) {
3606 _codec ("Raw 8-bit PCM audio");
3607 return gst_caps_from_string ("audio/x-raw-int, "
3608 "width = (int) 8, " "depth = (int) 8, " "signed = (boolean) true");
3610 _codec ("Raw 16-bit PCM audio");
3612 return gst_caps_from_string ("audio/x-raw-int, "
3613 "width = (int) 16, "
3614 "depth = (int) 16, "
3615 "endianness = (int) LITTLE_ENDIAN, " "signed = (boolean) true");
3617 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
3618 _codec ("Raw 64-bit floating-point audio");
3619 return gst_caps_from_string ("audio/x-raw-float, "
3620 "width = (int) 64, " "endianness = (int) BIG_ENDIAN");
3621 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
3622 _codec ("Raw 32-bit floating-point audio");
3623 return gst_caps_from_string ("audio/x-raw-float, "
3624 "width = (int) 32, " "endianness = (int) BIG_ENDIAN");
3625 case GST_MAKE_FOURCC ('i', 'n', '2', '4'):
3626 _codec ("Raw 24-bit PCM audio");
3628 return gst_caps_from_string ("audio/x-raw-int, "
3629 "width = (int) 24, "
3630 "depth = (int) 32, "
3631 "endianness = (int) BIG_ENDIAN, " "signed = (boolean) true");
3632 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
3633 _codec ("Raw 32-bit PCM audio");
3635 return gst_caps_from_string ("audio/x-raw-int, "
3636 "width = (int) 32, "
3637 "depth = (int) 32, "
3638 "endianness = (int) BIG_ENDIAN, " "signed = (boolean) true");
3639 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
3640 _codec ("Mu-law audio");
3642 return gst_caps_from_string ("audio/x-mulaw");
3643 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
3644 _codec ("A-law audio");
3646 return gst_caps_from_string ("audio/x-alaw");
3648 _codec ("Microsoft ADPCM");
3649 /* Microsoft ADPCM-ACM code 2 */
3650 return gst_caps_from_string ("audio/x-adpcm, "
3651 "layout = (string) microsoft");
3654 _codec ("DVI/Intel IMA ADPCM");
3655 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
3656 return gst_caps_from_string ("audio/x-adpcm, "
3657 "layout = (string) quicktime");
3659 /* MPEG layer 3, CBR only (pre QT4.1) */
3661 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
3662 _codec ("MPEG-1 layer 3");
3663 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
3664 return gst_caps_from_string ("audio/mpeg, "
3665 "layer = (int) 3, " "mpegversion = (int) 1");
3666 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
3668 return gst_caps_from_string ("audio/x-mace, " "maceversion = (int) 3");
3669 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
3671 return gst_caps_from_string ("audio/x-mace, " "maceversion = (int) 6");
3672 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
3674 return gst_caps_from_string ("application/ogg");
3675 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
3676 _codec ("DV audio");
3677 return gst_caps_from_string ("audio/x-dv");
3678 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
3679 _codec ("MPEG-4 AAC audio");
3680 return gst_caps_new_simple ("audio/mpeg",
3681 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
3682 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
3683 _codec ("QDesign Music v.2");
3684 /* FIXME: QDesign music version 2 (no constant) */
3686 return gst_caps_new_simple ("audio/x-qdm2",
3687 "framesize", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 52),
3688 "bitrate", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 40),
3689 "blocksize", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 44), NULL);
3691 return gst_caps_new_simple ("audio/x-qdm2", NULL);
3693 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
3694 _codec ("GSM audio");
3695 return gst_caps_new_simple ("audio/x-gsm", NULL);
3696 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
3697 _codec ("AMR audio");
3698 return gst_caps_new_simple ("audio/AMR", NULL);
3699 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
3700 _codec ("Quicktime IMA ADPCM");
3701 return gst_caps_new_simple ("audio/x-adpcm",
3702 "layout", G_TYPE_STRING, "quicktime", NULL);
3703 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
3704 _codec ("Apple lossless audio");
3705 return gst_caps_new_simple ("audio/x-alac", NULL);
3706 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
3708 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
3710 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
3711 /* QUALCOMM PureVoice */
3714 g_critical ("Don't know how to convert fourcc '%" GST_FOURCC_FORMAT
3715 "' to caps", GST_FOURCC_ARGS (fourcc));
3721 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
3722 GST_FOURCC_ARGS (fourcc));
3723 return gst_caps_new_simple (s, NULL);