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 =
122 GST_ELEMENT_DETAILS ("QuickTime demuxer",
124 "Demultiplex a QuickTime file into audio and video streams",
125 "David Schleef <ds@schleef.org>");
127 static GstStaticPadTemplate gst_qtdemux_sink_template =
128 GST_STATIC_PAD_TEMPLATE ("sink",
131 GST_STATIC_CAPS ("video/quicktime; audio/x-m4a; application/x-3gp")
134 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
135 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
138 GST_STATIC_CAPS_ANY);
140 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
141 GST_STATIC_PAD_TEMPLATE ("video_%02d",
144 GST_STATIC_CAPS_ANY);
146 static GstElementClass *parent_class = NULL;
148 /* we could generate these programmatically, but the generation code
149 * is only a few lines shorter than the tables, and much uglier */
150 static const guint32 ff_qt_default_palette_256[256] = {
151 0xFFFFFF, 0xFFFFCC, 0xFFFF99, 0xFFFF66, 0xFFFF33, 0xFFFF00,
152 0xFFCCFF, 0xFFCCCC, 0xFFCC99, 0xFFCC66, 0xFFCC33, 0xFFCC00,
153 0xFF99FF, 0xFF99CC, 0xFF9999, 0xFF9966, 0xFF9933, 0xFF9900,
154 0xFF66FF, 0xFF66CC, 0xFF6699, 0xFF6666, 0xFF6633, 0xFF6600,
155 0xFF33FF, 0xFF33CC, 0xFF3399, 0xFF3366, 0xFF3333, 0xFF3300,
156 0xFF00FF, 0xFF00CC, 0xFF0099, 0xFF0066, 0xFF0033, 0xFF0000,
157 0xCCFFFF, 0xCCFFCC, 0xCCFF99, 0xCCFF66, 0xCCFF33, 0xCCFF00,
158 0xCCCCFF, 0xCCCCCC, 0xCCCC99, 0xCCCC66, 0xCCCC33, 0xCCCC00,
159 0xCC99FF, 0xCC99CC, 0xCC9999, 0xCC9966, 0xCC9933, 0xCC9900,
160 0xCC66FF, 0xCC66CC, 0xCC6699, 0xCC6666, 0xCC6633, 0xCC6600,
161 0xCC33FF, 0xCC33CC, 0xCC3399, 0xCC3366, 0xCC3333, 0xCC3300,
162 0xCC00FF, 0xCC00CC, 0xCC0099, 0xCC0066, 0xCC0033, 0xCC0000,
163 0x99FFFF, 0x99FFCC, 0x99FF99, 0x99FF66, 0x99FF33, 0x99FF00,
164 0x99CCFF, 0x99CCCC, 0x99CC99, 0x99CC66, 0x99CC33, 0x99CC00,
165 0x9999FF, 0x9999CC, 0x999999, 0x999966, 0x999933, 0x999900,
166 0x9966FF, 0x9966CC, 0x996699, 0x996666, 0x996633, 0x996600,
167 0x9933FF, 0x9933CC, 0x993399, 0x993366, 0x993333, 0x993300,
168 0x9900FF, 0x9900CC, 0x990099, 0x990066, 0x990033, 0x990000,
169 0x66FFFF, 0x66FFCC, 0x66FF99, 0x66FF66, 0x66FF33, 0x66FF00,
170 0x66CCFF, 0x66CCCC, 0x66CC99, 0x66CC66, 0x66CC33, 0x66CC00,
171 0x6699FF, 0x6699CC, 0x669999, 0x669966, 0x669933, 0x669900,
172 0x6666FF, 0x6666CC, 0x666699, 0x666666, 0x666633, 0x666600,
173 0x6633FF, 0x6633CC, 0x663399, 0x663366, 0x663333, 0x663300,
174 0x6600FF, 0x6600CC, 0x660099, 0x660066, 0x660033, 0x660000,
175 0x33FFFF, 0x33FFCC, 0x33FF99, 0x33FF66, 0x33FF33, 0x33FF00,
176 0x33CCFF, 0x33CCCC, 0x33CC99, 0x33CC66, 0x33CC33, 0x33CC00,
177 0x3399FF, 0x3399CC, 0x339999, 0x339966, 0x339933, 0x339900,
178 0x3366FF, 0x3366CC, 0x336699, 0x336666, 0x336633, 0x336600,
179 0x3333FF, 0x3333CC, 0x333399, 0x333366, 0x333333, 0x333300,
180 0x3300FF, 0x3300CC, 0x330099, 0x330066, 0x330033, 0x330000,
181 0x00FFFF, 0x00FFCC, 0x00FF99, 0x00FF66, 0x00FF33, 0x00FF00,
182 0x00CCFF, 0x00CCCC, 0x00CC99, 0x00CC66, 0x00CC33, 0x00CC00,
183 0x0099FF, 0x0099CC, 0x009999, 0x009966, 0x009933, 0x009900,
184 0x0066FF, 0x0066CC, 0x006699, 0x006666, 0x006633, 0x006600,
185 0x0033FF, 0x0033CC, 0x003399, 0x003366, 0x003333, 0x003300,
186 0x0000FF, 0x0000CC, 0x000099, 0x000066, 0x000033, 0xEE0000,
187 0xDD0000, 0xBB0000, 0xAA0000, 0x880000, 0x770000, 0x550000,
188 0x440000, 0x220000, 0x110000, 0x00EE00, 0x00DD00, 0x00BB00,
189 0x00AA00, 0x008800, 0x007700, 0x005500, 0x004400, 0x002200,
190 0x001100, 0x0000EE, 0x0000DD, 0x0000BB, 0x0000AA, 0x000088,
191 0x000077, 0x000055, 0x000044, 0x000022, 0x000011, 0xEEEEEE,
192 0xDDDDDD, 0xBBBBBB, 0xAAAAAA, 0x888888, 0x777777, 0x555555,
193 0x444444, 0x222222, 0x111111, 0x000000
196 static const guint32 ff_qt_grayscale_palette_256[256] = {
197 0xffffff, 0xfefefe, 0xfdfdfd, 0xfcfcfc, 0xfbfbfb, 0xfafafa, 0xf9f9f9,
198 0xf8f8f8, 0xf7f7f7, 0xf6f6f6, 0xf5f5f5, 0xf4f4f4, 0xf3f3f3, 0xf2f2f2,
199 0xf1f1f1, 0xf0f0f0, 0xefefef, 0xeeeeee, 0xededed, 0xececec, 0xebebeb,
200 0xeaeaea, 0xe9e9e9, 0xe8e8e8, 0xe7e7e7, 0xe6e6e6, 0xe5e5e5, 0xe4e4e4,
201 0xe3e3e3, 0xe2e2e2, 0xe1e1e1, 0xe0e0e0, 0xdfdfdf, 0xdedede, 0xdddddd,
202 0xdcdcdc, 0xdbdbdb, 0xdadada, 0xd9d9d9, 0xd8d8d8, 0xd7d7d7, 0xd6d6d6,
203 0xd5d5d5, 0xd4d4d4, 0xd3d3d3, 0xd2d2d2, 0xd1d1d1, 0xd0d0d0, 0xcfcfcf,
204 0xcecece, 0xcdcdcd, 0xcccccc, 0xcbcbcb, 0xcacaca, 0xc9c9c9, 0xc8c8c8,
205 0xc7c7c7, 0xc6c6c6, 0xc5c5c5, 0xc4c4c4, 0xc3c3c3, 0xc2c2c2, 0xc1c1c1,
206 0xc0c0c0, 0xbfbfbf, 0xbebebe, 0xbdbdbd, 0xbcbcbc, 0xbbbbbb, 0xbababa,
207 0xb9b9b9, 0xb8b8b8, 0xb7b7b7, 0xb6b6b6, 0xb5b5b5, 0xb4b4b4, 0xb3b3b3,
208 0xb2b2b2, 0xb1b1b1, 0xb0b0b0, 0xafafaf, 0xaeaeae, 0xadadad, 0xacacac,
209 0xababab, 0xaaaaaa, 0xa9a9a9, 0xa8a8a8, 0xa7a7a7, 0xa6a6a6, 0xa5a5a5,
210 0xa4a4a4, 0xa3a3a3, 0xa2a2a2, 0xa1a1a1, 0xa0a0a0, 0x9f9f9f, 0x9e9e9e,
211 0x9d9d9d, 0x9c9c9c, 0x9b9b9b, 0x9a9a9a, 0x999999, 0x989898, 0x979797,
212 0x969696, 0x959595, 0x949494, 0x939393, 0x929292, 0x919191, 0x909090,
213 0x8f8f8f, 0x8e8e8e, 0x8d8d8d, 0x8c8c8c, 0x8b8b8b, 0x8a8a8a, 0x898989,
214 0x888888, 0x878787, 0x868686, 0x858585, 0x848484, 0x838383, 0x828282,
215 0x818181, 0x808080, 0x7f7f7f, 0x7e7e7e, 0x7d7d7d, 0x7c7c7c, 0x7b7b7b,
216 0x7a7a7a, 0x797979, 0x787878, 0x777777, 0x767676, 0x757575, 0x747474,
217 0x737373, 0x727272, 0x717171, 0x707070, 0x6f6f6f, 0x6e6e6e, 0x6d6d6d,
218 0x6c6c6c, 0x6b6b6b, 0x6a6a6a, 0x696969, 0x686868, 0x676767, 0x666666,
219 0x656565, 0x646464, 0x636363, 0x626262, 0x616161, 0x606060, 0x5f5f5f,
220 0x5e5e5e, 0x5d5d5d, 0x5c5c5c, 0x5b5b5b, 0x5a5a5a, 0x595959, 0x585858,
221 0x575757, 0x565656, 0x555555, 0x545454, 0x535353, 0x525252, 0x515151,
222 0x505050, 0x4f4f4f, 0x4e4e4e, 0x4d4d4d, 0x4c4c4c, 0x4b4b4b, 0x4a4a4a,
223 0x494949, 0x484848, 0x474747, 0x464646, 0x454545, 0x444444, 0x434343,
224 0x424242, 0x414141, 0x404040, 0x3f3f3f, 0x3e3e3e, 0x3d3d3d, 0x3c3c3c,
225 0x3b3b3b, 0x3a3a3a, 0x393939, 0x383838, 0x373737, 0x363636, 0x353535,
226 0x343434, 0x333333, 0x323232, 0x313131, 0x303030, 0x2f2f2f, 0x2e2e2e,
227 0x2d2d2d, 0x2c2c2c, 0x2b2b2b, 0x2a2a2a, 0x292929, 0x282828, 0x272727,
228 0x262626, 0x252525, 0x242424, 0x232323, 0x222222, 0x212121, 0x202020,
229 0x1f1f1f, 0x1e1e1e, 0x1d1d1d, 0x1c1c1c, 0x1b1b1b, 0x1a1a1a, 0x191919,
230 0x181818, 0x171717, 0x161616, 0x151515, 0x141414, 0x131313, 0x121212,
231 0x111111, 0x101010, 0x0f0f0f, 0x0e0e0e, 0x0d0d0d, 0x0c0c0c, 0x0b0b0b,
232 0x0a0a0a, 0x090909, 0x080808, 0x070707, 0x060606, 0x050505, 0x040404,
233 0x030303, 0x020202, 0x010101, 0x000000
236 static void gst_qtdemux_class_init (GstQTDemuxClass * klass);
237 static void gst_qtdemux_base_init (GstQTDemuxClass * klass);
238 static void gst_qtdemux_init (GstQTDemux * quicktime_demux);
239 static void gst_qtdemux_dispose (GObject * object);
240 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
241 GstStateChange transition);
242 static void gst_qtdemux_loop (GstPad * pad);
243 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf);
244 static gboolean qtdemux_sink_activate (GstPad * sinkpad);
245 static gboolean qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active);
246 static gboolean qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active);
247 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstEvent * event);
249 static void qtdemux_parse_moov (GstQTDemux * qtdemux, void *buffer, int length);
250 static void qtdemux_parse (GstQTDemux * qtdemux, GNode * node, void *buffer,
252 static QtNodeType *qtdemux_type_get (guint32 fourcc);
253 static void qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node);
254 static void qtdemux_parse_tree (GstQTDemux * qtdemux);
255 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta);
256 static void qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
258 static void qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
259 const char *tag2, GNode * node);
260 static void qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag,
263 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
264 QtDemuxStream * stream, GNode * esds);
265 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux, guint32 fourcc,
266 const guint8 * stsd_data, const gchar ** codec_name);
267 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
268 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
269 const gchar ** codec_name);
272 gst_qtdemux_get_type (void)
274 static GType qtdemux_type = 0;
277 static const GTypeInfo qtdemux_info = {
278 sizeof (GstQTDemuxClass),
279 (GBaseInitFunc) gst_qtdemux_base_init, NULL,
280 (GClassInitFunc) gst_qtdemux_class_init,
281 NULL, NULL, sizeof (GstQTDemux), 0,
282 (GInstanceInitFunc) gst_qtdemux_init,
286 g_type_register_static (GST_TYPE_ELEMENT, "GstQTDemux", &qtdemux_info,
293 gst_qtdemux_base_init (GstQTDemuxClass * klass)
295 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
297 gst_element_class_add_pad_template (element_class,
298 gst_static_pad_template_get (&gst_qtdemux_sink_template));
299 gst_element_class_add_pad_template (element_class,
300 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
301 gst_element_class_add_pad_template (element_class,
302 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
303 gst_element_class_set_details (element_class, &gst_qtdemux_details);
308 gst_qtdemux_class_init (GstQTDemuxClass * klass)
310 GObjectClass *gobject_class;
311 GstElementClass *gstelement_class;
313 gobject_class = (GObjectClass *) klass;
314 gstelement_class = (GstElementClass *) klass;
316 parent_class = g_type_class_peek_parent (klass);
318 gobject_class->dispose = gst_qtdemux_dispose;
320 gstelement_class->change_state = gst_qtdemux_change_state;
324 gst_qtdemux_init (GstQTDemux * qtdemux)
327 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
328 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
329 gst_pad_set_activatepull_function (qtdemux->sinkpad,
330 qtdemux_sink_activate_pull);
331 gst_pad_set_activatepush_function (qtdemux->sinkpad,
332 qtdemux_sink_activate_push);
333 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
334 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
335 gst_element_add_pad (GST_ELEMENT (qtdemux), qtdemux->sinkpad);
337 qtdemux->state = QTDEMUX_STATE_INITIAL;
338 qtdemux->last_ts = GST_CLOCK_TIME_NONE;
339 qtdemux->pullbased = FALSE;
340 qtdemux->neededbytes = 16;
342 qtdemux->adapter = gst_adapter_new ();
344 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
345 qtdemux->mdatbuffer = NULL;
346 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
350 gst_qtdemux_dispose (GObject * object)
352 GstQTDemux *qtdemux = GST_QTDEMUX (object);
354 if (qtdemux->adapter) {
355 g_object_unref (G_OBJECT (qtdemux->adapter));
356 qtdemux->adapter = NULL;
359 G_OBJECT_CLASS (parent_class)->dispose (object);
364 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
365 GstFormat * dest_format, gint64 * dest_value)
368 QtDemuxStream *stream = gst_pad_get_element_private (pad);
370 if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e') &&
371 (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
374 switch (src_format) {
375 case GST_FORMAT_TIME:
376 switch (*dest_format) {
377 case GST_FORMAT_BYTES:
378 *dest_value = src_value * 1; /* FIXME */
380 case GST_FORMAT_DEFAULT:
381 *dest_value = src_value * 1; /* FIXME */
388 case GST_FORMAT_BYTES:
389 switch (*dest_format) {
390 case GST_FORMAT_TIME:
391 *dest_value = src_value * 1; /* FIXME */
398 case GST_FORMAT_DEFAULT:
399 switch (*dest_format) {
400 case GST_FORMAT_TIME:
401 *dest_value = src_value * 1; /* FIXME */
416 static const GstQueryType *
417 gst_qtdemux_get_src_query_types (GstPad * pad)
419 static const GstQueryType src_types[] = {
429 gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
431 gboolean res = FALSE;
432 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
434 switch (GST_QUERY_TYPE (query)) {
435 case GST_QUERY_POSITION:
436 if (GST_CLOCK_TIME_IS_VALID (qtdemux->last_ts)) {
437 gst_query_set_position (query, GST_FORMAT_TIME, qtdemux->last_ts);
441 case GST_QUERY_DURATION:
442 if (qtdemux->pullbased && qtdemux->duration != 0
443 && qtdemux->timescale != 0) {
446 duration = gst_util_uint64_scale_int (qtdemux->duration,
447 GST_SECOND, qtdemux->timescale);
449 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
458 gst_object_unref (qtdemux);
463 /* push event on all source pads; takes ownership of the event */
465 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
469 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
470 GST_EVENT_TYPE_NAME (event));
472 for (n = 0; n < qtdemux->n_streams; n++) {
473 gst_pad_push_event (qtdemux->streams[n]->pad, gst_event_ref (event));
475 gst_event_unref (event);
478 /* move all streams back on the keyframe before @offset.
480 * If @end is FALSE, the search is started from the current
481 * sample_index position of each stream.
482 * If @end is TRUE, the search is started from the last sample
485 * Returns: the minimum of the timestamps of the positions of all streams.
487 /* FIXME, binary search would be nice here */
489 gst_qtdemux_go_back (GstQTDemux * qtdemux, gboolean end, guint64 offset)
492 guint64 min_time = G_MAXUINT64;
494 /* resync to new time */
495 for (n = 0; n < qtdemux->n_streams; n++) {
500 str = qtdemux->streams[n];
501 keyframe = str->all_keyframe;
503 /* start from the last sample if @end == TRUE */
505 if (str->n_samples == 0)
508 search = str->n_samples - 1;
510 search = str->sample_index;
512 for (; search > 0; search--) {
515 timestamp = str->samples[search].timestamp;
517 /* Seek to the sample just before the desired offset and
518 * let downstream throw away bits outside of the segment */
519 if (timestamp <= offset) {
520 /* update the keyframe flag */
521 keyframe = keyframe | str->samples[search].keyframe;
523 GST_DEBUG_OBJECT (qtdemux,
524 "found keyframe at sample %d, %" GST_TIME_FORMAT, search,
525 GST_TIME_ARGS (timestamp));
526 /* update min_time */
527 if (timestamp < min_time)
528 min_time = timestamp;
534 /* did not find anything or we're at the beginning, position to beginning */
539 /* and set stream to the index */
540 if (search != str->sample_index) {
541 str->sample_index = search;
542 /* position changed, we have a discont */
551 * We always go to the keyframe before the desired seek position. If
552 * the seek was to a keyframe, we update the last_stop and time with
553 * the position of the keyframe, else we leve the event as-is and it
554 * will be clipped automatically to the right segment boundaries by
555 * downstream elements.
558 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
560 gint64 desired_offset;
563 desired_offset = segment->last_stop;
565 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
566 GST_TIME_ARGS (desired_offset));
568 /* position all streams to key unit before the desired time,
569 * start searching from the last sample in the stream. */
570 min = gst_qtdemux_go_back (qtdemux, TRUE, desired_offset);
572 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
573 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %" GST_TIME_FORMAT,
574 GST_TIME_ARGS (min));
575 /* key unit, we seek to min, so back off streams to this new
576 * position. We start from our current position. */
577 gst_qtdemux_go_back (qtdemux, FALSE, min);
579 /* update the segment values to the position of the keyframes */
580 segment->last_stop = min;
584 /* and we stop at the end */
585 if (segment->stop == -1)
586 segment->stop = segment->duration;
591 /* do a seek in pull based mode */
593 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
598 GstSeekType cur_type, stop_type;
603 GstSegment seeksegment;
604 GstEvent *newsegment;
607 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
609 gst_event_parse_seek (event, &rate, &format, &flags,
610 &cur_type, &cur, &stop_type, &stop);
612 /* we have to have a format as the segment format. Try to convert
614 if (format != GST_FORMAT_TIME) {
617 fmt = GST_FORMAT_TIME;
619 if (cur_type != GST_SEEK_TYPE_NONE)
620 res = gst_pad_query_convert (pad, format, cur, &fmt, &cur);
621 if (res && stop_type != GST_SEEK_TYPE_NONE)
622 res = gst_pad_query_convert (pad, format, stop, &fmt, &stop);
629 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
633 flush = flags & GST_SEEK_FLAG_FLUSH;
635 GST_DEBUG_OBJECT (qtdemux, "seek format %d", format);
637 /* stop streaming, either by flushing or by pausing the task */
639 /* unlock upstream pull_range */
640 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
641 /* make sure out loop function exits */
642 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
644 /* non flushing seek, pause the task */
645 qtdemux->segment_running = FALSE;
646 gst_pad_pause_task (qtdemux->sinkpad);
649 /* wait for streaming to finish */
650 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
652 /* copy segment, we need this because we still need the old
653 * segment when we close the current segment. */
654 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
657 /* configure the segment with the seek variables */
658 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
659 gst_segment_set_seek (&seeksegment, rate, format, flags,
660 cur_type, cur, stop_type, stop, &update);
663 /* now do the seek, this actually never returns FALSE */
664 res = gst_qtdemux_perform_seek (qtdemux, &seeksegment);
666 /* prepare for streaming again */
668 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop ());
669 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop ());
670 } else if (qtdemux->segment_running) {
671 /* we are running the current segment and doing a non-flushing seek,
672 * close the segment first based on the last_stop. */
673 GST_DEBUG_OBJECT (qtdemux, "closing running segment %" G_GINT64_FORMAT
674 " to %" G_GINT64_FORMAT, qtdemux->segment.start,
675 qtdemux->segment.last_stop);
677 gst_qtdemux_push_event (qtdemux,
678 gst_event_new_new_segment (TRUE,
679 qtdemux->segment.rate, qtdemux->segment.format,
680 qtdemux->segment.start, qtdemux->segment.last_stop,
681 qtdemux->segment.time));
684 /* commit the new segment */
685 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
687 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
688 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
689 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
690 qtdemux->segment.format, qtdemux->segment.last_stop));
693 /* send the newsegment */
694 GST_DEBUG_OBJECT (qtdemux, "Sending newsegment from %" GST_TIME_FORMAT
695 " to %" GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.start),
696 GST_TIME_ARGS (qtdemux->segment.stop));
699 gst_event_new_new_segment (FALSE, qtdemux->segment.rate,
700 qtdemux->segment.format, qtdemux->segment.last_stop,
701 qtdemux->segment.stop, qtdemux->segment.time);
703 gst_qtdemux_push_event (qtdemux, newsegment);
705 /* restart streaming */
706 qtdemux->segment_running = TRUE;
707 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
710 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
717 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
723 gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
726 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
728 switch (GST_EVENT_TYPE (event)) {
730 res = gst_qtdemux_do_seek (qtdemux, pad, event);
737 gst_object_unref (qtdemux);
739 gst_event_unref (event);
744 GST_DEBUG_CATEGORY (qtdemux_debug);
747 plugin_init (GstPlugin * plugin)
749 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
751 return gst_element_register (plugin, "qtdemux",
752 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX);
755 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
758 "Quicktime stream demuxer",
759 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
762 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
764 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
765 gboolean res = FALSE;
767 switch (GST_EVENT_TYPE (event)) {
768 case GST_EVENT_NEWSEGMENT:
769 /* We need to convert it to a GST_FORMAT_TIME new segment */
771 gst_pad_event_default (demux->sinkpad, event);
775 gst_event_unref (event);
779 static GstStateChangeReturn
780 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
782 GstQTDemux *qtdemux = GST_QTDEMUX (element);
783 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
785 switch (transition) {
786 case GST_STATE_CHANGE_PAUSED_TO_READY:
792 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
794 switch (transition) {
795 case GST_STATE_CHANGE_PAUSED_TO_READY:{
798 qtdemux->state = QTDEMUX_STATE_INITIAL;
799 qtdemux->last_ts = GST_CLOCK_TIME_NONE;
800 qtdemux->neededbytes = 16;
802 qtdemux->pullbased = FALSE;
804 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
805 if (qtdemux->mdatbuffer)
806 gst_buffer_unref (qtdemux->mdatbuffer);
807 qtdemux->mdatbuffer = NULL;
808 gst_adapter_clear (qtdemux->adapter);
809 for (n = 0; n < qtdemux->n_streams; n++) {
810 gst_element_remove_pad (element, qtdemux->streams[n]->pad);
811 g_free (qtdemux->streams[n]->samples);
812 if (qtdemux->streams[n]->caps)
813 gst_caps_unref (qtdemux->streams[n]->caps);
814 g_free (qtdemux->streams[n]);
816 qtdemux->n_streams = 0;
817 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
828 extract_initial_length_and_fourcc (guint8 * data, guint32 * plength,
834 length = GST_READ_UINT32_BE (data);
835 GST_DEBUG ("length %08x", length);
836 fourcc = GST_READ_UINT32_LE (data + 4);
837 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
840 length = G_MAXUINT32;
843 /* this means we have an extended size, which is the 64 bit value of
844 * the next 8 bytes */
845 guint32 length1, length2;
847 length1 = GST_READ_UINT32_BE (data + 8);
848 GST_DEBUG ("length1 %08x", length1);
849 length2 = GST_READ_UINT32_BE (data + 12);
850 GST_DEBUG ("length2 %08x", length2);
852 /* FIXME: I guess someone didn't want to make 64 bit size work :) */
863 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
867 GstBuffer *buf = NULL;
868 GstFlowReturn ret = GST_FLOW_OK;
869 guint64 cur_offset = qtdemux->offset;
871 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
872 if (ret != GST_FLOW_OK)
874 extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf), &length, &fourcc);
875 gst_buffer_unref (buf);
879 case GST_MAKE_FOURCC ('m', 'd', 'a', 't'):
880 case GST_MAKE_FOURCC ('f', 'r', 'e', 'e'):
881 case GST_MAKE_FOURCC ('w', 'i', 'd', 'e'):
882 case GST_MAKE_FOURCC ('P', 'I', 'C', 'T'):
883 case GST_MAKE_FOURCC ('p', 'n', 'o', 't'):
884 goto ed_edd_and_eddy;
885 case GST_MAKE_FOURCC ('m', 'o', 'o', 'v'):{
888 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
889 if (ret != GST_FLOW_OK)
891 if (length != GST_BUFFER_SIZE (moov)) {
892 GST_WARNING_OBJECT (qtdemux,
893 "We got less than expected (received %d, wanted %d)",
894 GST_BUFFER_SIZE (moov), length);
895 ret = GST_FLOW_ERROR;
898 cur_offset += length;
899 qtdemux->offset += length;
901 qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
903 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
905 qtdemux_parse_tree (qtdemux);
906 g_node_destroy (qtdemux->moov_node);
907 gst_buffer_unref (moov);
908 qtdemux->moov_node = NULL;
909 qtdemux->state = QTDEMUX_STATE_MOVIE;
910 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
916 GST_LOG ("unknown %08x '%" GST_FOURCC_FORMAT "' at %d",
917 fourcc, GST_FOURCC_ARGS (fourcc), cur_offset);
918 cur_offset += length;
919 qtdemux->offset += length;
929 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
931 GstFlowReturn ret = GST_FLOW_OK;
932 GstBuffer *buf = NULL;
933 QtDemuxStream *stream;
941 /* Figure out the next stream sample to output */
942 min_time = G_MAXUINT64;
944 for (i = 0; i < qtdemux->n_streams; i++) {
945 stream = qtdemux->streams[i];
946 if (stream->sample_index < stream->n_samples) {
948 timestamp = stream->samples[stream->sample_index].timestamp;
950 GST_LOG_OBJECT (qtdemux,
951 "stream %d: sample_index %d, timestamp %" GST_TIME_FORMAT, i,
952 stream->sample_index, GST_TIME_ARGS (timestamp));
954 if (timestamp < min_time) {
955 min_time = timestamp;
963 /* check for segment end */
964 if (qtdemux->segment.stop != -1 && qtdemux->segment.stop < min_time)
967 stream = qtdemux->streams[index];
969 offset = stream->samples[stream->sample_index].offset;
970 size = stream->samples[stream->sample_index].size;
971 timestamp = stream->samples[stream->sample_index].timestamp;
973 GST_LOG_OBJECT (qtdemux,
974 "pushing from stream %d, sample_index=%d offset=%" G_GUINT64_FORMAT
975 ",size=%d timestamp=%" GST_TIME_FORMAT,
976 index, stream->sample_index, offset, size, GST_TIME_ARGS (timestamp));
978 if (G_UNLIKELY (size <= 0))
981 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
984 ret = gst_pad_pull_range (qtdemux->sinkpad, offset, size, &buf);
985 if (ret != GST_FLOW_OK)
988 buf = gst_buffer_make_metadata_writable (buf);
991 /* hum... FIXME changing framerate breaks horribly, better set
992 * an average framerate, or get rid of the framerate property. */
993 if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e')) {
995 1. * GST_SECOND / stream->samples[stream->sample_index].duration;
996 if (fps != stream->fps) {
997 gst_caps_set_simple (stream->caps, "framerate", G_TYPE_DOUBLE, fps, NULL);
999 gst_pad_set_explicit_caps (stream->pad, stream->caps);
1005 if (qtdemux->last_ts == GST_CLOCK_TIME_NONE) {
1006 gst_qtdemux_push_event (qtdemux,
1007 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
1008 0, GST_CLOCK_TIME_NONE, 0));
1011 if (stream->discont) {
1012 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
1013 stream->discont = FALSE;
1016 /* timestamps of AMR aren't known... */
1017 if (stream->fourcc == GST_MAKE_FOURCC ('s', 'a', 'm', 'r')) {
1018 if (stream->sample_index == 0)
1019 GST_BUFFER_TIMESTAMP (buf) = 0;
1021 GST_BUFFER_TIMESTAMP (buf) = timestamp;
1022 qtdemux->last_ts = GST_BUFFER_TIMESTAMP (buf);
1023 GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int
1024 (stream->samples[stream->sample_index].duration, GST_SECOND,
1027 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME,
1030 if (!(stream->all_keyframe || stream->samples[stream->sample_index].keyframe))
1031 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
1033 GST_LOG_OBJECT (qtdemux,
1034 "Pushing buffer with time %" GST_TIME_FORMAT " on pad %p",
1035 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), stream->pad);
1036 gst_buffer_set_caps (buf, stream->caps);
1038 ret = gst_pad_push (stream->pad, buf);
1040 stream->sample_index++;
1048 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
1049 ret = GST_FLOW_UNEXPECTED;
1055 gst_qtdemux_loop (GstPad * pad)
1057 GstQTDemux *qtdemux;
1061 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
1063 cur_offset = qtdemux->offset;
1064 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
1065 cur_offset, qtdemux->state);
1067 switch (qtdemux->state) {
1068 case QTDEMUX_STATE_INITIAL:
1069 case QTDEMUX_STATE_HEADER:
1070 ret = gst_qtdemux_loop_state_header (qtdemux);
1072 case QTDEMUX_STATE_MOVIE:
1073 ret = gst_qtdemux_loop_state_movie (qtdemux);
1080 /* if all is fine, continue */
1081 if (G_LIKELY (ret == GST_FLOW_OK))
1084 /* we don't care about unlinked pads */
1085 if (ret == GST_FLOW_NOT_LINKED)
1088 /* other errors make us stop */
1089 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", gst_flow_get_name (ret));
1091 qtdemux->segment_running = FALSE;
1092 gst_pad_pause_task (pad);
1094 /* fatal errors need special actions */
1095 if (GST_FLOW_IS_FATAL (ret)) {
1097 if (ret == GST_FLOW_UNEXPECTED) {
1098 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1099 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
1100 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1101 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
1102 GST_FORMAT_TIME, qtdemux->last_ts));
1104 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
1105 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
1108 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
1109 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
1110 (NULL), ("streaming stopped, reason %s", gst_flow_get_name (ret)));
1115 gst_object_unref (qtdemux);
1121 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
1122 (NULL), ("streaming stopped, invalid state"));
1123 qtdemux->segment_running = FALSE;
1124 gst_pad_pause_task (pad);
1125 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
1133 Returns the size of the first entry at the current offset.
1134 If -1, there are none (which means EOS or empty file).
1138 next_entry_size (GstQTDemux * demux)
1140 QtDemuxStream *stream;
1143 guint64 smalloffs = -1;
1145 GST_LOG_OBJECT (demux, "Finding entry at offset %lld", demux->offset);
1147 for (i = 0; i < demux->n_streams; i++) {
1148 stream = demux->streams[i];
1150 GST_LOG_OBJECT (demux,
1151 "Checking Stream %d (sample_index:%d / offset:%lld / size:%d / chunk:%d)",
1152 i, stream->sample_index, stream->samples[stream->sample_index].offset,
1153 stream->samples[stream->sample_index].size,
1154 stream->samples[stream->sample_index].chunk);
1156 if (((smalloffs == -1)
1157 || (stream->samples[stream->sample_index].offset < smalloffs))
1158 && (stream->samples[stream->sample_index].size)) {
1160 smalloffs = stream->samples[stream->sample_index].offset;
1164 GST_LOG_OBJECT (demux, "stream %d offset %lld demux->offset :%lld",
1165 smallidx, smalloffs, demux->offset);
1169 stream = demux->streams[smallidx];
1171 if (stream->samples[stream->sample_index].offset >= demux->offset) {
1173 stream->samples[stream->sample_index].offset - demux->offset;
1174 return stream->samples[stream->sample_index].size + demux->todrop;
1177 GST_DEBUG_OBJECT (demux, "There wasn't any entry at offset %lld",
1183 gst_qtdemux_post_buffering (GstQTDemux * demux, gint num, gint denom)
1185 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
1187 gst_element_post_message (GST_ELEMENT (demux),
1188 gst_message_new_custom (GST_MESSAGE_BUFFERING,
1190 gst_structure_new ("GstMessageBuffering",
1191 "buffer-percent", G_TYPE_INT, perc, NULL)));
1194 static GstFlowReturn
1195 gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
1198 GstFlowReturn ret = GST_FLOW_OK;
1200 demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad));
1202 gst_adapter_push (demux->adapter, inbuf);
1204 GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
1205 inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
1207 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
1208 (ret == GST_FLOW_OK)) {
1210 GST_DEBUG_OBJECT (demux,
1211 "state:%d , demux->neededbytes:%d, demux->offset:%lld", demux->state,
1212 demux->neededbytes, demux->offset);
1214 switch (demux->state) {
1215 case QTDEMUX_STATE_INITIAL:{
1220 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
1222 /* get fourcc/length, set neededbytes */
1223 extract_initial_length_and_fourcc ((guint8 *) data, &size, &fourcc);
1224 GST_DEBUG_OBJECT (demux,
1225 "Peeking found [%" GST_FOURCC_FORMAT "] size:%ld",
1226 GST_FOURCC_ARGS (fourcc), size);
1227 if ((fourcc == GST_MAKE_FOURCC ('m', 'd', 'a', 't'))) {
1228 if (demux->n_streams > 0) {
1229 demux->state = QTDEMUX_STATE_MOVIE;
1230 demux->neededbytes = next_entry_size (demux);
1232 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
1233 demux->neededbytes = size;
1234 demux->mdatoffset = demux->offset;
1237 demux->neededbytes = size;
1238 demux->state = QTDEMUX_STATE_HEADER;
1242 case QTDEMUX_STATE_HEADER:{
1246 GST_DEBUG_OBJECT (demux, "In header");
1248 data = gst_adapter_take (demux->adapter, demux->neededbytes);
1250 /* parse the header */
1251 extract_initial_length_and_fourcc (data, NULL, &fourcc);
1252 if (fourcc == GST_MAKE_FOURCC ('m', 'o', 'o', 'v')) {
1253 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
1255 qtdemux_parse_moov (demux, data, demux->neededbytes);
1256 qtdemux_node_dump (demux, demux->moov_node);
1257 qtdemux_parse_tree (demux);
1259 g_node_destroy (demux->moov_node);
1261 demux->moov_node = NULL;
1263 GST_WARNING_OBJECT (demux,
1264 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
1265 GST_FOURCC_ARGS (fourcc));
1266 /* Let's jump that one and go back to initial state */
1269 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
1270 if (demux->mdatbuffer && demux->n_streams) {
1271 /* the mdat was before the header */
1272 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
1273 demux->n_streams, demux->mdatbuffer);
1274 gst_adapter_clear (demux->adapter);
1275 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
1276 GST_FOURCC_ARGS (GST_READ_UINT32_BE (demux->mdatbuffer)));
1277 gst_adapter_push (demux->adapter, demux->mdatbuffer);
1278 demux->mdatbuffer = NULL;
1279 demux->offset = demux->mdatoffset;
1280 demux->neededbytes = next_entry_size (demux);
1281 demux->state = QTDEMUX_STATE_MOVIE;
1283 GST_DEBUG_OBJECT (demux, "Carrying on normally");
1284 demux->offset += demux->neededbytes;
1285 demux->neededbytes = 16;
1286 demux->state = QTDEMUX_STATE_INITIAL;
1291 case QTDEMUX_STATE_BUFFER_MDAT:{
1292 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %lld",
1294 if (demux->mdatbuffer)
1295 gst_buffer_unref (demux->mdatbuffer);
1296 demux->mdatbuffer = gst_buffer_new ();
1297 gst_buffer_set_data (demux->mdatbuffer,
1298 gst_adapter_take (demux->adapter, demux->neededbytes),
1299 demux->neededbytes);
1300 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
1301 GST_FOURCC_ARGS (GST_READ_UINT32_BE (demux->mdatbuffer)));
1302 demux->offset += demux->neededbytes;
1303 demux->neededbytes = 16;
1304 demux->state = QTDEMUX_STATE_INITIAL;
1305 gst_qtdemux_post_buffering (demux, 1, 1);
1309 case QTDEMUX_STATE_MOVIE:{
1312 QtDemuxStream *stream = NULL;
1315 GST_DEBUG_OBJECT (demux, "BEGIN // in MOVIE for offset %lld",
1318 if (demux->todrop) {
1319 gst_adapter_flush (demux->adapter, demux->todrop);
1320 demux->neededbytes -= demux->todrop;
1321 demux->offset += demux->todrop;
1324 /* Figure out which stream this is packet belongs to */
1325 for (i = 0; i < demux->n_streams; i++) {
1326 stream = demux->streams[i];
1327 GST_LOG_OBJECT (demux,
1328 "Checking stream %d (sample_index:%d / offset:%lld / size:%d / chunk:%d)",
1329 i, stream->sample_index,
1330 stream->samples[stream->sample_index].offset,
1331 stream->samples[stream->sample_index].size,
1332 stream->samples[stream->sample_index].chunk);
1334 if (stream->samples[stream->sample_index].offset == demux->offset)
1339 goto unknown_stream;
1342 /* FIXME : this should be handled in sink_event */
1343 if (demux->last_ts == GST_CLOCK_TIME_NONE) {
1344 gst_qtdemux_push_event (demux,
1345 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
1346 0, GST_CLOCK_TIME_NONE, 0));
1350 data = gst_adapter_take (demux->adapter, demux->neededbytes);
1352 /* Put data in a buffer, set timestamps, caps, ... */
1353 outbuf = gst_buffer_new ();
1354 gst_buffer_set_data (outbuf, data, demux->neededbytes);
1355 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
1356 GST_FOURCC_ARGS (stream->fourcc));
1358 if (stream->fourcc != GST_MAKE_FOURCC ('s', 'a', 'm', 'r')) {
1359 GST_BUFFER_TIMESTAMP (outbuf) =
1360 stream->samples[stream->sample_index].timestamp;
1361 demux->last_ts = GST_BUFFER_TIMESTAMP (outbuf);
1362 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int
1363 (stream->samples[stream->sample_index].duration, GST_SECOND,
1367 if (stream->sample_index == 0)
1368 GST_BUFFER_TIMESTAMP (outbuf) = 0;
1372 GST_LOG_OBJECT (demux,
1373 "Pushing buffer with time %" GST_TIME_FORMAT " on pad %p",
1374 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), stream->pad);
1375 gst_buffer_set_caps (outbuf, stream->caps);
1376 ret = gst_pad_push (stream->pad, outbuf);
1378 stream->sample_index++;
1380 /* update current offset and figure out size of next buffer */
1381 GST_LOG_OBJECT (demux, "bumping offset:%lld up by %lld",
1382 demux->offset, demux->neededbytes);
1383 demux->offset += demux->neededbytes;
1384 GST_LOG_OBJECT (demux, "offset is now %lld", demux->offset);
1386 if ((demux->neededbytes = next_entry_size (demux)) == -1)
1395 /* when buffering movie data, at least show user something is happening */
1396 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
1397 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
1398 gst_qtdemux_post_buffering (demux, gst_adapter_available (demux->adapter),
1399 demux->neededbytes);
1403 gst_object_unref (demux);
1410 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
1411 ret = GST_FLOW_ERROR;
1416 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
1417 ret = GST_FLOW_UNEXPECTED;
1422 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1423 (NULL), ("qtdemuxer invalid state %d", demux->state));
1424 ret = GST_FLOW_ERROR;
1430 qtdemux_sink_activate (GstPad * sinkpad)
1432 if (gst_pad_check_pull_range (sinkpad))
1433 return gst_pad_activate_pull (sinkpad, TRUE);
1435 return gst_pad_activate_push (sinkpad, TRUE);
1439 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
1441 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1444 /* if we have a scheduler we can start the task */
1445 demux->pullbased = TRUE;
1446 demux->segment_running = TRUE;
1447 gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop, sinkpad);
1449 demux->segment_running = FALSE;
1450 gst_pad_stop_task (sinkpad);
1457 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
1459 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1461 demux->pullbased = FALSE;
1467 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
1468 QtDemuxStream * stream, GstTagList * list)
1470 if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e')) {
1471 gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
1474 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
1476 if ((stream->n_samples == 1) && (stream->samples[0].duration == 0)) {
1480 stream->fps_n = stream->timescale;
1481 if (stream->samples[0].duration == 0)
1484 stream->fps_d = stream->samples[0].duration;
1488 gst_caps_set_simple (stream->caps,
1489 "width", G_TYPE_INT, stream->width,
1490 "height", G_TYPE_INT, stream->height,
1491 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
1492 if ((stream->bits_per_sample & 0x1F) == 8) {
1493 const guint32 *palette_data = NULL;
1495 if ((stream->bits_per_sample & 0x20) != 0)
1496 palette_data = ff_qt_grayscale_palette_256;
1497 if ((stream->color_table_id & 0x08) != 0)
1498 palette_data = ff_qt_default_palette_256;
1501 GstBuffer *palette = gst_buffer_new ();
1503 GST_BUFFER_DATA (palette) = (guint8 *) palette_data;
1504 GST_BUFFER_SIZE (palette) = sizeof (guint32) * 256;
1505 gst_caps_set_simple (stream->caps, "palette_data",
1506 GST_TYPE_BUFFER, palette, NULL);
1507 gst_buffer_unref (palette);
1511 qtdemux->n_video_streams++;
1513 gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
1516 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
1519 gst_caps_set_simple (stream->caps,
1520 "rate", G_TYPE_INT, (int) stream->rate,
1521 "channels", G_TYPE_INT, stream->n_channels, NULL);
1523 qtdemux->n_audio_streams++;
1526 gst_pad_use_fixed_caps (stream->pad);
1528 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
1529 qtdemux->streams[qtdemux->n_streams] = stream;
1530 qtdemux->n_streams++;
1531 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
1533 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
1534 gst_pad_set_query_type_function (stream->pad,
1535 gst_qtdemux_get_src_query_types);
1536 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
1538 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
1539 gst_pad_set_caps (stream->pad, stream->caps);
1541 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
1542 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
1543 gst_element_add_pad (GST_ELEMENT (qtdemux), stream->pad);
1545 gst_element_found_tags_for_pad (GST_ELEMENT (qtdemux), stream->pad, list);
1550 #define QT_CONTAINER 1
1552 #define FOURCC_moov GST_MAKE_FOURCC('m','o','o','v')
1553 #define FOURCC_mvhd GST_MAKE_FOURCC('m','v','h','d')
1554 #define FOURCC_clip GST_MAKE_FOURCC('c','l','i','p')
1555 #define FOURCC_trak GST_MAKE_FOURCC('t','r','a','k')
1556 #define FOURCC_udta GST_MAKE_FOURCC('u','d','t','a')
1557 #define FOURCC_ctab GST_MAKE_FOURCC('c','t','a','b')
1558 #define FOURCC_tkhd GST_MAKE_FOURCC('t','k','h','d')
1559 #define FOURCC_crgn GST_MAKE_FOURCC('c','r','g','n')
1560 #define FOURCC_matt GST_MAKE_FOURCC('m','a','t','t')
1561 #define FOURCC_kmat GST_MAKE_FOURCC('k','m','a','t')
1562 #define FOURCC_edts GST_MAKE_FOURCC('e','d','t','s')
1563 #define FOURCC_elst GST_MAKE_FOURCC('e','l','s','t')
1564 #define FOURCC_load GST_MAKE_FOURCC('l','o','a','d')
1565 #define FOURCC_tref GST_MAKE_FOURCC('t','r','e','f')
1566 #define FOURCC_imap GST_MAKE_FOURCC('i','m','a','p')
1567 #define FOURCC___in GST_MAKE_FOURCC(' ',' ','i','n')
1568 #define FOURCC___ty GST_MAKE_FOURCC(' ',' ','t','y')
1569 #define FOURCC_mdia GST_MAKE_FOURCC('m','d','i','a')
1570 #define FOURCC_mdhd GST_MAKE_FOURCC('m','d','h','d')
1571 #define FOURCC_hdlr GST_MAKE_FOURCC('h','d','l','r')
1572 #define FOURCC_minf GST_MAKE_FOURCC('m','i','n','f')
1573 #define FOURCC_vmhd GST_MAKE_FOURCC('v','m','h','d')
1574 #define FOURCC_smhd GST_MAKE_FOURCC('s','m','h','d')
1575 #define FOURCC_gmhd GST_MAKE_FOURCC('g','m','h','d')
1576 #define FOURCC_gmin GST_MAKE_FOURCC('g','m','i','n')
1577 #define FOURCC_dinf GST_MAKE_FOURCC('d','i','n','f')
1578 #define FOURCC_dref GST_MAKE_FOURCC('d','r','e','f')
1579 #define FOURCC_stbl GST_MAKE_FOURCC('s','t','b','l')
1580 #define FOURCC_stsd GST_MAKE_FOURCC('s','t','s','d')
1581 #define FOURCC_stts GST_MAKE_FOURCC('s','t','t','s')
1582 #define FOURCC_stss GST_MAKE_FOURCC('s','t','s','s')
1583 #define FOURCC_stsc GST_MAKE_FOURCC('s','t','s','c')
1584 #define FOURCC_stsz GST_MAKE_FOURCC('s','t','s','z')
1585 #define FOURCC_stco GST_MAKE_FOURCC('s','t','c','o')
1586 #define FOURCC_vide GST_MAKE_FOURCC('v','i','d','e')
1587 #define FOURCC_soun GST_MAKE_FOURCC('s','o','u','n')
1588 #define FOURCC_co64 GST_MAKE_FOURCC('c','o','6','4')
1589 #define FOURCC_cmov GST_MAKE_FOURCC('c','m','o','v')
1590 #define FOURCC_dcom GST_MAKE_FOURCC('d','c','o','m')
1591 #define FOURCC_cmvd GST_MAKE_FOURCC('c','m','v','d')
1592 #define FOURCC_hint GST_MAKE_FOURCC('h','i','n','t')
1593 #define FOURCC_mp4a GST_MAKE_FOURCC('m','p','4','a')
1594 #define FOURCC_mp4v GST_MAKE_FOURCC('m','p','4','v')
1595 #define FOURCC_wave GST_MAKE_FOURCC('w','a','v','e')
1596 #define FOURCC_appl GST_MAKE_FOURCC('a','p','p','l')
1597 #define FOURCC_esds GST_MAKE_FOURCC('e','s','d','s')
1598 #define FOURCC_hnti GST_MAKE_FOURCC('h','n','t','i')
1599 #define FOURCC_rtp_ GST_MAKE_FOURCC('r','t','p',' ')
1600 #define FOURCC_sdp_ GST_MAKE_FOURCC('s','d','p',' ')
1601 #define FOURCC_meta GST_MAKE_FOURCC('m','e','t','a')
1602 #define FOURCC_ilst GST_MAKE_FOURCC('i','l','s','t')
1603 #define FOURCC__nam GST_MAKE_FOURCC(0xa9,'n','a','m')
1604 #define FOURCC__ART GST_MAKE_FOURCC(0xa9,'A','R','T')
1605 #define FOURCC__wrt GST_MAKE_FOURCC(0xa9,'w','r','t')
1606 #define FOURCC__grp GST_MAKE_FOURCC(0xa9,'g','r','p')
1607 #define FOURCC__alb GST_MAKE_FOURCC(0xa9,'a','l','b')
1608 #define FOURCC_gnre GST_MAKE_FOURCC('g','n','r','e')
1609 #define FOURCC_disc GST_MAKE_FOURCC('d','i','s','c')
1610 #define FOURCC_disk GST_MAKE_FOURCC('d','i','s','k')
1611 #define FOURCC_trkn GST_MAKE_FOURCC('t','r','k','n')
1612 #define FOURCC_cpil GST_MAKE_FOURCC('c','p','i','l')
1613 #define FOURCC_tmpo GST_MAKE_FOURCC('t','m','p','o')
1614 #define FOURCC__too GST_MAKE_FOURCC(0xa9,'t','o','o')
1615 #define FOURCC_____ GST_MAKE_FOURCC('-','-','-','-')
1616 #define FOURCC_free GST_MAKE_FOURCC('f','r','e','e')
1617 #define FOURCC_data GST_MAKE_FOURCC('d','a','t','a')
1618 #define FOURCC_SVQ3 GST_MAKE_FOURCC('S','V','Q','3')
1619 #define FOURCC_rmra GST_MAKE_FOURCC('r','m','r','a')
1620 #define FOURCC_rmda GST_MAKE_FOURCC('r','m','d','a')
1621 #define FOURCC_rdrf GST_MAKE_FOURCC('r','d','r','f')
1622 #define FOURCC__gen GST_MAKE_FOURCC(0xa9, 'g', 'e', 'n')
1624 static void qtdemux_dump_mvhd (GstQTDemux * qtdemux, void *buffer, int depth);
1625 static void qtdemux_dump_tkhd (GstQTDemux * qtdemux, void *buffer, int depth);
1626 static void qtdemux_dump_elst (GstQTDemux * qtdemux, void *buffer, int depth);
1627 static void qtdemux_dump_mdhd (GstQTDemux * qtdemux, void *buffer, int depth);
1628 static void qtdemux_dump_hdlr (GstQTDemux * qtdemux, void *buffer, int depth);
1629 static void qtdemux_dump_vmhd (GstQTDemux * qtdemux, void *buffer, int depth);
1630 static void qtdemux_dump_dref (GstQTDemux * qtdemux, void *buffer, int depth);
1631 static void qtdemux_dump_stsd (GstQTDemux * qtdemux, void *buffer, int depth);
1632 static void qtdemux_dump_stts (GstQTDemux * qtdemux, void *buffer, int depth);
1633 static void qtdemux_dump_stss (GstQTDemux * qtdemux, void *buffer, int depth);
1634 static void qtdemux_dump_stsc (GstQTDemux * qtdemux, void *buffer, int depth);
1635 static void qtdemux_dump_stsz (GstQTDemux * qtdemux, void *buffer, int depth);
1636 static void qtdemux_dump_stco (GstQTDemux * qtdemux, void *buffer, int depth);
1637 static void qtdemux_dump_co64 (GstQTDemux * qtdemux, void *buffer, int depth);
1638 static void qtdemux_dump_dcom (GstQTDemux * qtdemux, void *buffer, int depth);
1639 static void qtdemux_dump_cmvd (GstQTDemux * qtdemux, void *buffer, int depth);
1640 static void qtdemux_dump_unknown (GstQTDemux * qtdemux, void *buffer,
1643 QtNodeType qt_node_types[] = {
1644 {FOURCC_moov, "movie", QT_CONTAINER,},
1645 {FOURCC_mvhd, "movie header", 0,
1647 {FOURCC_clip, "clipping", QT_CONTAINER,},
1648 {FOURCC_trak, "track", QT_CONTAINER,},
1649 {FOURCC_udta, "user data", QT_CONTAINER,}, /* special container */
1650 {FOURCC_ctab, "color table", 0,},
1651 {FOURCC_tkhd, "track header", 0,
1653 {FOURCC_crgn, "clipping region", 0,},
1654 {FOURCC_matt, "track matte", QT_CONTAINER,},
1655 {FOURCC_kmat, "compressed matte", 0,},
1656 {FOURCC_edts, "edit", QT_CONTAINER,},
1657 {FOURCC_elst, "edit list", 0,
1659 {FOURCC_load, "track load settings", 0,},
1660 {FOURCC_tref, "track reference", QT_CONTAINER,},
1661 {FOURCC_imap, "track input map", QT_CONTAINER,},
1662 {FOURCC___in, "track input", 0,}, /* special container */
1663 {FOURCC___ty, "input type", 0,},
1664 {FOURCC_mdia, "media", QT_CONTAINER},
1665 {FOURCC_mdhd, "media header", 0,
1667 {FOURCC_hdlr, "handler reference", 0,
1669 {FOURCC_minf, "media information", QT_CONTAINER},
1670 {FOURCC_vmhd, "video media information", 0,
1672 {FOURCC_smhd, "sound media information", 0},
1673 {FOURCC_gmhd, "base media information header", 0},
1674 {FOURCC_gmin, "base media info", 0},
1675 {FOURCC_dinf, "data information", QT_CONTAINER},
1676 {FOURCC_dref, "data reference", 0,
1678 {FOURCC_stbl, "sample table", QT_CONTAINER},
1679 {FOURCC_stsd, "sample description", 0,
1681 {FOURCC_stts, "time-to-sample", 0,
1683 {FOURCC_stss, "sync sample", 0,
1685 {FOURCC_stsc, "sample-to-chunk", 0,
1687 {FOURCC_stsz, "sample size", 0,
1689 {FOURCC_stco, "chunk offset", 0,
1691 {FOURCC_co64, "64-bit chunk offset", 0,
1693 {FOURCC_vide, "video media", 0},
1694 {FOURCC_cmov, "compressed movie", QT_CONTAINER},
1695 {FOURCC_dcom, "compressed data", 0, qtdemux_dump_dcom},
1696 {FOURCC_cmvd, "compressed movie data", 0, qtdemux_dump_cmvd},
1697 {FOURCC_hint, "hint", 0,},
1698 {FOURCC_mp4a, "mp4a", 0,},
1699 {FOURCC_mp4v, "mp4v", 0,},
1700 {FOURCC_wave, "wave", QT_CONTAINER},
1701 {FOURCC_appl, "appl", QT_CONTAINER},
1702 {FOURCC_esds, "esds", 0},
1703 {FOURCC_hnti, "hnti", QT_CONTAINER},
1704 {FOURCC_rtp_, "rtp ", 0, qtdemux_dump_unknown},
1705 {FOURCC_sdp_, "sdp ", 0, qtdemux_dump_unknown},
1706 {FOURCC_meta, "meta", 0, qtdemux_dump_unknown},
1707 {FOURCC_ilst, "ilst", QT_CONTAINER,},
1708 {FOURCC__nam, "Name", QT_CONTAINER,},
1709 {FOURCC__ART, "Artist", QT_CONTAINER,},
1710 {FOURCC__wrt, "Writer", QT_CONTAINER,},
1711 {FOURCC__grp, "Group", QT_CONTAINER,},
1712 {FOURCC__alb, "Album", QT_CONTAINER,},
1713 {FOURCC_gnre, "Genre", QT_CONTAINER,},
1714 {FOURCC_trkn, "Track Number", QT_CONTAINER,},
1715 {FOURCC_disc, "Disc Number", QT_CONTAINER,},
1716 {FOURCC_disk, "Disc Number", QT_CONTAINER,},
1717 {FOURCC_cpil, "cpil", QT_CONTAINER,},
1718 {FOURCC_tmpo, "Tempo", QT_CONTAINER,},
1719 {FOURCC__too, "too", QT_CONTAINER,},
1720 {FOURCC_____, "----", QT_CONTAINER,},
1721 {FOURCC_data, "data", 0, qtdemux_dump_unknown},
1722 {FOURCC_free, "free", 0,},
1723 {FOURCC_SVQ3, "SVQ3", 0,},
1724 {FOURCC_rmra, "rmra", QT_CONTAINER,},
1725 {FOURCC_rmda, "rmda", QT_CONTAINER,},
1726 {FOURCC_rdrf, "rdrf", 0,},
1727 {FOURCC__gen, "Custom Genre", QT_CONTAINER,},
1730 static int n_qt_node_types = sizeof (qt_node_types) / sizeof (qt_node_types[0]);
1734 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
1736 return g_malloc (items * size);
1740 qtdemux_zfree (void *opaque, void *addr)
1746 qtdemux_inflate (void *z_buffer, int z_length, int length)
1752 z = g_new0 (z_stream, 1);
1753 z->zalloc = qtdemux_zalloc;
1754 z->zfree = qtdemux_zfree;
1757 z->next_in = z_buffer;
1758 z->avail_in = z_length;
1760 buffer = g_malloc (length);
1761 ret = inflateInit (z);
1762 while (z->avail_in > 0) {
1763 if (z->avail_out == 0) {
1765 buffer = realloc (buffer, length);
1766 z->next_out = buffer + z->total_out;
1767 z->avail_out = 1024;
1769 ret = inflate (z, Z_SYNC_FLUSH);
1773 if (ret != Z_STREAM_END) {
1774 g_warning ("inflate() returned %d", ret);
1782 qtdemux_parse_moov (GstQTDemux * qtdemux, void *buffer, int length)
1786 qtdemux->moov_node = g_node_new (buffer);
1788 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
1789 qtdemux_parse (qtdemux, qtdemux->moov_node, buffer, length);
1791 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
1796 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
1797 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
1799 if (QTDEMUX_FOURCC_GET (dcom->data + 8) == GST_MAKE_FOURCC ('z', 'l', 'i',
1801 int uncompressed_length;
1802 int compressed_length;
1805 uncompressed_length = QTDEMUX_GUINT32_GET (cmvd->data + 8);
1806 compressed_length = QTDEMUX_GUINT32_GET (cmvd->data + 4) - 12;
1807 GST_LOG ("length = %d", uncompressed_length);
1809 buf = qtdemux_inflate (cmvd->data + 12, compressed_length,
1810 uncompressed_length);
1812 qtdemux->moov_node_compressed = qtdemux->moov_node;
1813 qtdemux->moov_node = g_node_new (buf);
1815 qtdemux_parse (qtdemux, qtdemux->moov_node, buf, uncompressed_length);
1817 GST_LOG ("unknown header compression type");
1823 qtdemux_parse (GstQTDemux * qtdemux, GNode * node, void *buffer, int length)
1826 guint32 node_length;
1830 GST_LOG ("qtdemux_parse buffer %p length %d", buffer, length);
1832 node_length = QTDEMUX_GUINT32_GET (buffer);
1833 fourcc = QTDEMUX_FOURCC_GET (buffer + 4);
1835 type = qtdemux_type_get (fourcc);
1837 if (fourcc == 0 || node_length == 8)
1840 GST_LOG ("parsing '%" GST_FOURCC_FORMAT "', length=%d",
1841 GST_FOURCC_ARGS (fourcc), node_length);
1843 if (type->flags & QT_CONTAINER) {
1848 end = buffer + length;
1852 if (buf + 8 >= end) {
1853 /* FIXME: get annoyed */
1854 GST_LOG ("buffer overrun");
1856 len = QTDEMUX_GUINT32_GET (buf);
1858 GST_WARNING ("atom length too short (%d < 8)", len);
1861 if (len > (end - buf)) {
1862 GST_WARNING ("atom length too long (%d > %d)", len, end - buf);
1866 child = g_node_new (buf);
1867 g_node_append (node, child);
1868 qtdemux_parse (qtdemux, child, buf, len);
1873 if (fourcc == FOURCC_stsd) {
1877 GST_DEBUG_OBJECT (qtdemux,
1878 "parsing stsd (sample table, sample description) atom");
1880 end = buffer + length;
1884 if (buf + 8 >= end) {
1885 /* FIXME: get annoyed */
1886 GST_LOG ("buffer overrun");
1888 len = QTDEMUX_GUINT32_GET (buf);
1890 GST_WARNING ("length too short (%d < 8)");
1893 if (len > (end - buf)) {
1894 GST_WARNING ("length too long (%d > %d)", len, end - buf);
1898 child = g_node_new (buf);
1899 g_node_append (node, child);
1900 qtdemux_parse (qtdemux, child, buf, len);
1904 } else if (fourcc == FOURCC_mp4a) {
1909 version = QTDEMUX_GUINT32_GET (buffer + 16);
1910 if (version == 0x00010000 || 1) {
1911 buf = buffer + 0x24;
1912 end = buffer + length;
1917 if (buf + 8 >= end) {
1918 /* FIXME: get annoyed */
1919 GST_LOG ("buffer overrun");
1921 len = QTDEMUX_GUINT32_GET (buf);
1923 GST_WARNING ("length too short (%d < 8)");
1926 if (len > (end - buf)) {
1927 GST_WARNING ("length too long (%d > %d)", len, end - buf);
1931 child = g_node_new (buf);
1932 g_node_append (node, child);
1933 qtdemux_parse (qtdemux, child, buf, len);
1938 } else if (fourcc == FOURCC_mp4v) {
1944 GST_DEBUG_OBJECT (qtdemux, "parsing in mp4v");
1945 version = QTDEMUX_GUINT32_GET (buffer + 16);
1946 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
1947 if (1 || version == 0x00000000) {
1949 buf = buffer + 0x32;
1950 end = buffer + length;
1952 /* FIXME Quicktime uses PASCAL string while
1953 * the iso format uses C strings. Check the file
1954 * type before attempting to parse the string here. */
1955 tlen = QTDEMUX_GUINT8_GET (buf);
1956 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
1958 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
1959 /* the string has a reserved space of 32 bytes so skip
1960 * the remaining 31 */
1962 buf += 4; /* and 4 bytes reserved */
1964 gst_util_dump_mem (buf, end - buf);
1968 if (buf + 8 >= end) {
1969 /* FIXME: get annoyed */
1970 GST_LOG ("buffer overrun");
1972 len = QTDEMUX_GUINT32_GET (buf);
1976 GST_WARNING ("length too short (%d < 8)");
1979 if (len > (end - buf)) {
1980 GST_WARNING ("length too long (%d > %d)", len, end - buf);
1984 child = g_node_new (buf);
1985 g_node_append (node, child);
1986 qtdemux_parse (qtdemux, child, buf, len);
1991 } else if (fourcc == FOURCC_meta) {
1996 end = buffer + length;
2000 if (buf + 8 >= end) {
2001 /* FIXME: get annoyed */
2002 GST_LOG ("buffer overrun");
2004 len = QTDEMUX_GUINT32_GET (buf);
2006 GST_WARNING ("length too short (%d < 8)");
2009 if (len > (end - buf)) {
2010 GST_WARNING ("length too long (%d > %d)", len, end - buf);
2014 child = g_node_new (buf);
2015 g_node_append (node, child);
2016 qtdemux_parse (qtdemux, child, buf, len);
2020 } else if (fourcc == FOURCC_SVQ3) {
2026 GST_LOG ("parsing in SVQ3");
2028 end = buffer + length;
2029 version = QTDEMUX_GUINT32_GET (buffer + 16);
2030 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
2031 if (1 || version == 0x00000000) {
2033 buf = buffer + 0x32;
2034 end = buffer + length;
2036 tlen = QTDEMUX_GUINT8_GET (buf);
2037 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
2039 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
2043 gst_util_dump_mem (buf, end - buf);
2047 if (buf + 8 >= end) {
2048 /* FIXME: get annoyed */
2049 GST_LOG ("buffer overrun");
2051 len = QTDEMUX_GUINT32_GET (buf);
2055 GST_WARNING ("length too short (%d < 8)");
2058 if (len > (end - buf)) {
2059 GST_WARNING ("length too long (%d > %d)", len, end - buf);
2063 child = g_node_new (buf);
2064 g_node_append (node, child);
2065 qtdemux_parse (qtdemux, child, buf, len);
2072 if (fourcc == FOURCC_cmvd) {
2073 int uncompressed_length;
2076 uncompressed_length = QTDEMUX_GUINT32_GET (buffer + 8);
2077 GST_LOG ("length = %d", uncompressed_length);
2080 qtdemux_inflate (buffer + 12, node_length - 12, uncompressed_length);
2082 end = buf + uncompressed_length;
2087 if (buf + 8 >= end) {
2088 /* FIXME: get annoyed */
2089 GST_LOG ("buffer overrun");
2091 len = QTDEMUX_GUINT32_GET (buf);
2093 child = g_node_new (buf);
2094 g_node_append (node, child);
2095 qtdemux_parse (qtdemux, child, buf, len);
2105 qtdemux_type_get (guint32 fourcc)
2109 for (i = 0; i < n_qt_node_types; i++) {
2110 if (qt_node_types[i].fourcc == fourcc)
2111 return qt_node_types + i;
2114 GST_WARNING ("unknown QuickTime node type %" GST_FOURCC_FORMAT,
2115 GST_FOURCC_ARGS (fourcc));
2116 return qt_node_types + n_qt_node_types - 1;
2120 qtdemux_node_dump_foreach (GNode * node, gpointer data)
2122 void *buffer = node->data;
2123 guint32 node_length;
2128 node_length = GST_READ_UINT32_BE (buffer);
2129 fourcc = GST_READ_UINT32_LE (buffer + 4);
2131 type = qtdemux_type_get (fourcc);
2133 depth = (g_node_depth (node) - 1) * 2;
2134 GST_LOG ("%*s'%" GST_FOURCC_FORMAT "', [%d], %s",
2135 depth, "", GST_FOURCC_ARGS (fourcc), node_length, type->name);
2138 type->dump (data, buffer, depth);
2144 qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node)
2146 g_node_traverse (qtdemux->moov_node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
2147 qtdemux_node_dump_foreach, qtdemux);
2151 qtdemux_dump_mvhd (GstQTDemux * qtdemux, void *buffer, int depth)
2153 GST_LOG ("%*s version/flags: %08x", depth, "",
2154 QTDEMUX_GUINT32_GET (buffer + 8));
2155 GST_LOG ("%*s creation time: %u", depth, "",
2156 QTDEMUX_GUINT32_GET (buffer + 12));
2157 GST_LOG ("%*s modify time: %u", depth, "",
2158 QTDEMUX_GUINT32_GET (buffer + 16));
2159 qtdemux->duration = QTDEMUX_GUINT32_GET (buffer + 24);
2160 qtdemux->timescale = QTDEMUX_GUINT32_GET (buffer + 20);
2161 GST_LOG ("%*s time scale: 1/%u sec", depth, "", qtdemux->timescale);
2162 GST_LOG ("%*s duration: %u", depth, "", qtdemux->duration);
2163 GST_LOG ("%*s pref. rate: %g", depth, "", QTDEMUX_FP32_GET (buffer + 28));
2164 GST_LOG ("%*s pref. volume: %g", depth, "", QTDEMUX_FP16_GET (buffer + 32));
2165 GST_LOG ("%*s preview time: %u", depth, "",
2166 QTDEMUX_GUINT32_GET (buffer + 80));
2167 GST_LOG ("%*s preview dur.: %u", depth, "",
2168 QTDEMUX_GUINT32_GET (buffer + 84));
2169 GST_LOG ("%*s poster time: %u", depth, "",
2170 QTDEMUX_GUINT32_GET (buffer + 88));
2171 GST_LOG ("%*s select time: %u", depth, "",
2172 QTDEMUX_GUINT32_GET (buffer + 92));
2173 GST_LOG ("%*s select dur.: %u", depth, "",
2174 QTDEMUX_GUINT32_GET (buffer + 96));
2175 GST_LOG ("%*s current time: %u", depth, "",
2176 QTDEMUX_GUINT32_GET (buffer + 100));
2177 GST_LOG ("%*s next track ID: %d", depth, "",
2178 QTDEMUX_GUINT32_GET (buffer + 104));
2182 qtdemux_dump_tkhd (GstQTDemux * qtdemux, void *buffer, int depth)
2184 GST_LOG ("%*s version/flags: %08x", depth, "",
2185 QTDEMUX_GUINT32_GET (buffer + 8));
2186 GST_LOG ("%*s creation time: %u", depth, "",
2187 QTDEMUX_GUINT32_GET (buffer + 12));
2188 GST_LOG ("%*s modify time: %u", depth, "",
2189 QTDEMUX_GUINT32_GET (buffer + 16));
2190 GST_LOG ("%*s track ID: %u", depth, "",
2191 QTDEMUX_GUINT32_GET (buffer + 20));
2192 GST_LOG ("%*s duration: %u", depth, "",
2193 QTDEMUX_GUINT32_GET (buffer + 28));
2194 GST_LOG ("%*s layer: %u", depth, "",
2195 QTDEMUX_GUINT16_GET (buffer + 36));
2196 GST_LOG ("%*s alt group: %u", depth, "",
2197 QTDEMUX_GUINT16_GET (buffer + 38));
2198 GST_LOG ("%*s volume: %g", depth, "", QTDEMUX_FP16_GET (buffer + 44));
2199 GST_LOG ("%*s track width: %g", depth, "", QTDEMUX_FP32_GET (buffer + 84));
2200 GST_LOG ("%*s track height: %g", depth, "", QTDEMUX_FP32_GET (buffer + 88));
2205 qtdemux_dump_elst (GstQTDemux * qtdemux, void *buffer, int depth)
2210 GST_LOG ("%*s version/flags: %08x", depth, "",
2211 QTDEMUX_GUINT32_GET (buffer + 8));
2212 GST_LOG ("%*s n entries: %u", depth, "",
2213 QTDEMUX_GUINT32_GET (buffer + 12));
2214 n = QTDEMUX_GUINT32_GET (buffer + 12);
2215 for (i = 0; i < n; i++) {
2216 GST_LOG ("%*s track dur: %u", depth, "",
2217 QTDEMUX_GUINT32_GET (buffer + 16 + i * 12));
2218 GST_LOG ("%*s media time: %u", depth, "",
2219 QTDEMUX_GUINT32_GET (buffer + 20 + i * 12));
2220 GST_LOG ("%*s media rate: %g", depth, "",
2221 QTDEMUX_FP32_GET (buffer + 24 + i * 12));
2226 qtdemux_dump_mdhd (GstQTDemux * qtdemux, void *buffer, int depth)
2228 GST_LOG ("%*s version/flags: %08x", depth, "",
2229 QTDEMUX_GUINT32_GET (buffer + 8));
2230 GST_LOG ("%*s creation time: %u", depth, "",
2231 QTDEMUX_GUINT32_GET (buffer + 12));
2232 GST_LOG ("%*s modify time: %u", depth, "",
2233 QTDEMUX_GUINT32_GET (buffer + 16));
2234 GST_LOG ("%*s time scale: 1/%u sec", depth, "",
2235 QTDEMUX_GUINT32_GET (buffer + 20));
2236 GST_LOG ("%*s duration: %u", depth, "",
2237 QTDEMUX_GUINT32_GET (buffer + 24));
2238 GST_LOG ("%*s language: %u", depth, "",
2239 QTDEMUX_GUINT16_GET (buffer + 28));
2240 GST_LOG ("%*s quality: %u", depth, "",
2241 QTDEMUX_GUINT16_GET (buffer + 30));
2246 qtdemux_dump_hdlr (GstQTDemux * qtdemux, void *buffer, int depth)
2248 GST_LOG ("%*s version/flags: %08x", depth, "",
2249 QTDEMUX_GUINT32_GET (buffer + 8));
2250 GST_LOG ("%*s type: %" GST_FOURCC_FORMAT, depth, "",
2251 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 12)));
2252 GST_LOG ("%*s subtype: %" GST_FOURCC_FORMAT, depth, "",
2253 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 16)));
2254 GST_LOG ("%*s manufacturer: %" GST_FOURCC_FORMAT, depth, "",
2255 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 20)));
2256 GST_LOG ("%*s flags: %08x", depth, "",
2257 QTDEMUX_GUINT32_GET (buffer + 24));
2258 GST_LOG ("%*s flags mask: %08x", depth, "",
2259 QTDEMUX_GUINT32_GET (buffer + 28));
2260 GST_LOG ("%*s name: %*s", depth, "",
2261 QTDEMUX_GUINT8_GET (buffer + 32), (char *) (buffer + 33));
2266 qtdemux_dump_vmhd (GstQTDemux * qtdemux, void *buffer, int depth)
2268 GST_LOG ("%*s version/flags: %08x", depth, "",
2269 QTDEMUX_GUINT32_GET (buffer + 8));
2270 GST_LOG ("%*s mode/color: %08x", depth, "",
2271 QTDEMUX_GUINT32_GET (buffer + 16));
2275 qtdemux_dump_dref (GstQTDemux * qtdemux, void *buffer, int depth)
2281 GST_LOG ("%*s version/flags: %08x", depth, "",
2282 QTDEMUX_GUINT32_GET (buffer + 8));
2283 GST_LOG ("%*s n entries: %u", depth, "",
2284 QTDEMUX_GUINT32_GET (buffer + 12));
2285 n = QTDEMUX_GUINT32_GET (buffer + 12);
2287 for (i = 0; i < n; i++) {
2288 GST_LOG ("%*s size: %u", depth, "",
2289 QTDEMUX_GUINT32_GET (buffer + offset));
2290 GST_LOG ("%*s type: %" GST_FOURCC_FORMAT, depth, "",
2291 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + offset + 4)));
2292 offset += QTDEMUX_GUINT32_GET (buffer + offset);
2297 qtdemux_dump_stsd (GstQTDemux * qtdemux, void *buffer, int depth)
2303 GST_LOG ("%*s version/flags: %08x", depth, "",
2304 QTDEMUX_GUINT32_GET (buffer + 8));
2305 GST_LOG ("%*s n entries: %d", depth, "",
2306 QTDEMUX_GUINT32_GET (buffer + 12));
2307 n = QTDEMUX_GUINT32_GET (buffer + 12);
2309 for (i = 0; i < n; i++) {
2310 GST_LOG ("%*s size: %u", depth, "",
2311 QTDEMUX_GUINT32_GET (buffer + offset));
2312 GST_LOG ("%*s type: %" GST_FOURCC_FORMAT, depth, "",
2313 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + offset + 4)));
2314 GST_LOG ("%*s data reference:%d", depth, "",
2315 QTDEMUX_GUINT16_GET (buffer + offset + 14));
2317 GST_LOG ("%*s version/rev.: %08x", depth, "",
2318 QTDEMUX_GUINT32_GET (buffer + offset + 16));
2319 GST_LOG ("%*s vendor: %" GST_FOURCC_FORMAT, depth, "",
2320 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + offset + 20)));
2321 GST_LOG ("%*s temporal qual: %u", depth, "",
2322 QTDEMUX_GUINT32_GET (buffer + offset + 24));
2323 GST_LOG ("%*s spatial qual: %u", depth, "",
2324 QTDEMUX_GUINT32_GET (buffer + offset + 28));
2325 GST_LOG ("%*s width: %u", depth, "",
2326 QTDEMUX_GUINT16_GET (buffer + offset + 32));
2327 GST_LOG ("%*s height: %u", depth, "",
2328 QTDEMUX_GUINT16_GET (buffer + offset + 34));
2329 GST_LOG ("%*s horiz. resol: %g", depth, "",
2330 QTDEMUX_FP32_GET (buffer + offset + 36));
2331 GST_LOG ("%*s vert. resol.: %g", depth, "",
2332 QTDEMUX_FP32_GET (buffer + offset + 40));
2333 GST_LOG ("%*s data size: %u", depth, "",
2334 QTDEMUX_GUINT32_GET (buffer + offset + 44));
2335 GST_LOG ("%*s frame count: %u", depth, "",
2336 QTDEMUX_GUINT16_GET (buffer + offset + 48));
2337 GST_LOG ("%*s compressor: %d %d %d", depth, "",
2338 QTDEMUX_GUINT8_GET (buffer + offset + 49),
2339 QTDEMUX_GUINT8_GET (buffer + offset + 50),
2340 QTDEMUX_GUINT8_GET (buffer + offset + 51));
2341 //(char *) (buffer + offset + 51));
2342 GST_LOG ("%*s depth: %u", depth, "",
2343 QTDEMUX_GUINT16_GET (buffer + offset + 82));
2344 GST_LOG ("%*s color table ID:%u", depth, "",
2345 QTDEMUX_GUINT16_GET (buffer + offset + 84));
2347 offset += QTDEMUX_GUINT32_GET (buffer + offset);
2352 qtdemux_dump_stts (GstQTDemux * qtdemux, void *buffer, int depth)
2358 GST_LOG ("%*s version/flags: %08x", depth, "",
2359 QTDEMUX_GUINT32_GET (buffer + 8));
2360 GST_LOG ("%*s n entries: %d", depth, "",
2361 QTDEMUX_GUINT32_GET (buffer + 12));
2362 n = QTDEMUX_GUINT32_GET (buffer + 12);
2364 for (i = 0; i < n; i++) {
2365 GST_LOG ("%*s count: %u", depth, "",
2366 QTDEMUX_GUINT32_GET (buffer + offset));
2367 GST_LOG ("%*s duration: %u", depth, "",
2368 QTDEMUX_GUINT32_GET (buffer + offset + 4));
2375 qtdemux_dump_stss (GstQTDemux * qtdemux, void *buffer, int depth)
2381 GST_LOG ("%*s version/flags: %08x", depth, "",
2382 QTDEMUX_GUINT32_GET (buffer + 8));
2383 GST_LOG ("%*s n entries: %d", depth, "",
2384 QTDEMUX_GUINT32_GET (buffer + 12));
2385 n = QTDEMUX_GUINT32_GET (buffer + 12);
2387 for (i = 0; i < n; i++) {
2388 GST_LOG ("%*s sample: %u", depth, "",
2389 QTDEMUX_GUINT32_GET (buffer + offset));
2396 qtdemux_dump_stsc (GstQTDemux * qtdemux, void *buffer, int depth)
2402 GST_LOG ("%*s version/flags: %08x", depth, "",
2403 QTDEMUX_GUINT32_GET (buffer + 8));
2404 GST_LOG ("%*s n entries: %d", depth, "",
2405 QTDEMUX_GUINT32_GET (buffer + 12));
2406 n = QTDEMUX_GUINT32_GET (buffer + 12);
2408 for (i = 0; i < n; i++) {
2409 GST_LOG ("%*s first chunk: %u", depth, "",
2410 QTDEMUX_GUINT32_GET (buffer + offset));
2411 GST_LOG ("%*s sample per ch: %u", depth, "",
2412 QTDEMUX_GUINT32_GET (buffer + offset + 4));
2413 GST_LOG ("%*s sample desc id:%08x", depth, "",
2414 QTDEMUX_GUINT32_GET (buffer + offset + 8));
2421 qtdemux_dump_stsz (GstQTDemux * qtdemux, void *buffer, int depth)
2428 GST_LOG ("%*s version/flags: %08x", depth, "",
2429 QTDEMUX_GUINT32_GET (buffer + 8));
2430 GST_LOG ("%*s sample size: %d", depth, "",
2431 QTDEMUX_GUINT32_GET (buffer + 12));
2432 sample_size = QTDEMUX_GUINT32_GET (buffer + 12);
2433 if (sample_size == 0) {
2434 GST_LOG ("%*s n entries: %d", depth, "",
2435 QTDEMUX_GUINT32_GET (buffer + 16));
2436 n = QTDEMUX_GUINT32_GET (buffer + 16);
2439 for (i = 0; i < n; i++) {
2440 GST_LOG ("%*s sample size: %u", depth, "",
2441 QTDEMUX_GUINT32_GET (buffer + offset));
2450 qtdemux_dump_stco (GstQTDemux * qtdemux, void *buffer, int depth)
2456 GST_LOG ("%*s version/flags: %08x", depth, "",
2457 QTDEMUX_GUINT32_GET (buffer + 8));
2458 GST_LOG ("%*s n entries: %d", depth, "",
2459 QTDEMUX_GUINT32_GET (buffer + 12));
2460 n = QTDEMUX_GUINT32_GET (buffer + 12);
2463 for (i = 0; i < n; i++) {
2464 GST_LOG ("%*s chunk offset: %08x", depth, "",
2465 QTDEMUX_GUINT32_GET (buffer + offset));
2473 qtdemux_dump_co64 (GstQTDemux * qtdemux, void *buffer, int depth)
2479 GST_LOG ("%*s version/flags: %08x", depth, "",
2480 QTDEMUX_GUINT32_GET (buffer + 8));
2481 GST_LOG ("%*s n entries: %d", depth, "",
2482 QTDEMUX_GUINT32_GET (buffer + 12));
2483 n = QTDEMUX_GUINT32_GET (buffer + 12);
2486 for (i = 0; i < n; i++) {
2487 GST_LOG ("%*s chunk offset: %" G_GUINT64_FORMAT, depth, "",
2488 QTDEMUX_GUINT64_GET (buffer + offset));
2496 qtdemux_dump_dcom (GstQTDemux * qtdemux, void *buffer, int depth)
2498 GST_LOG ("%*s compression type: %" GST_FOURCC_FORMAT, depth, "",
2499 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 8)));
2503 qtdemux_dump_cmvd (GstQTDemux * qtdemux, void *buffer, int depth)
2505 GST_LOG ("%*s length: %d", depth, "", QTDEMUX_GUINT32_GET (buffer + 8));
2509 qtdemux_dump_unknown (GstQTDemux * qtdemux, void *buffer, int depth)
2513 GST_LOG ("%*s length: %d", depth, "", QTDEMUX_GUINT32_GET (buffer + 0));
2515 len = QTDEMUX_GUINT32_GET (buffer + 0);
2516 gst_util_dump_mem (buffer, len);
2522 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
2526 guint32 child_fourcc;
2528 for (child = g_node_first_child (node); child;
2529 child = g_node_next_sibling (child)) {
2530 buffer = child->data;
2532 child_fourcc = GST_READ_UINT32_LE (buffer);
2533 GST_LOG ("First chunk of buffer %p is [%" GST_FOURCC_FORMAT "]",
2534 buffer, GST_FOURCC_ARGS (child_fourcc));
2536 child_fourcc = GST_READ_UINT32_LE (buffer + 4);
2537 GST_LOG ("buffer %p has fourcc [%" GST_FOURCC_FORMAT "]",
2538 buffer, GST_FOURCC_ARGS (child_fourcc));
2540 if (child_fourcc == fourcc) {
2548 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
2552 guint32 child_fourcc;
2554 for (child = g_node_next_sibling (node); child;
2555 child = g_node_next_sibling (child)) {
2556 buffer = child->data;
2558 child_fourcc = GST_READ_UINT32_LE (buffer + 4);
2560 if (child_fourcc == fourcc) {
2567 static void qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak);
2570 qtdemux_parse_tree (GstQTDemux * qtdemux)
2576 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
2578 GNode *rmra, *rmda, *rdrf;
2580 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
2582 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
2584 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
2589 GST_LOG ("New location: %s", (char *) rdrf->data + 20);
2590 s = gst_structure_new ("redirect", "new-location", G_TYPE_STRING,
2591 (char *) rdrf->data + 20, NULL);
2592 msg = gst_message_new_element (GST_OBJECT (qtdemux), s);
2593 gst_element_post_message (GST_ELEMENT (qtdemux), msg);
2599 GST_LOG ("No mvhd node found.");
2603 qtdemux->timescale = QTDEMUX_GUINT32_GET (mvhd->data + 20);
2604 qtdemux->duration = QTDEMUX_GUINT32_GET (mvhd->data + 24);
2606 GST_INFO_OBJECT (qtdemux, "timescale: %d", qtdemux->timescale);
2607 GST_INFO_OBJECT (qtdemux, "duration: %d", qtdemux->duration);
2609 if (qtdemux->timescale != 0 && qtdemux->duration != 0) {
2612 duration = gst_util_uint64_scale_int (qtdemux->duration,
2613 GST_SECOND, qtdemux->timescale);
2615 gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
2618 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
2619 qtdemux_parse_trak (qtdemux, trak);
2621 /* trak = qtdemux_tree_get_sibling_by_type(trak, FOURCC_trak);
2622 if(trak)qtdemux_parse_trak(qtdemux, trak);*/
2625 while ((trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak)) != NULL)
2626 qtdemux_parse_trak (qtdemux, trak);
2627 gst_element_no_more_pads (GST_ELEMENT (qtdemux));
2630 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
2632 qtdemux_parse_udta (qtdemux, udta);
2634 if (qtdemux->tag_list) {
2635 GST_DEBUG_OBJECT (qtdemux,
2636 "calling gst_element_found_tags with %" GST_PTR_FORMAT,
2638 gst_element_found_tags (GST_ELEMENT (qtdemux), qtdemux->tag_list);
2639 qtdemux->tag_list = NULL;
2642 GST_LOG ("No udta node found.");
2647 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
2668 QtDemuxSample *samples;
2669 int n_samples_per_chunk;
2672 QtDemuxStream *stream;
2677 GstTagList *list = NULL;
2678 const gchar *codec = NULL;
2680 tkhd = qtdemux_tree_get_child_by_type (trak, FOURCC_tkhd);
2681 g_return_if_fail (tkhd);
2683 GST_LOG ("track[tkhd] version/flags: 0x%08x",
2684 QTDEMUX_GUINT32_GET (tkhd->data + 8));
2686 /* track duration? */
2688 mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia);
2691 mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd);
2694 /* new streams always need a discont */
2695 stream = g_new0 (QtDemuxStream, 1);
2696 stream->discont = TRUE;
2698 stream->timescale = QTDEMUX_GUINT32_GET (mdhd->data + 20);
2699 GST_LOG ("track timescale: %d", stream->timescale);
2700 GST_LOG ("track duration: %d", QTDEMUX_GUINT32_GET (mdhd->data + 24));
2703 * some of those trailers, nowadays, have prologue images that are
2704 * themselves vide tracks as well. I haven't really found a way to
2705 * identify those yet, except for just looking at their duration. */
2706 if (stream->timescale * qtdemux->duration != 0 &&
2707 (guint64) QTDEMUX_GUINT32_GET (mdhd->data + 24) *
2708 qtdemux->timescale * 10 / (stream->timescale * qtdemux->duration) < 2) {
2709 GST_WARNING ("Track shorter than 20%% (%d/%d vs. %d/%d) of the stream "
2710 "found, assuming preview image or something; skipping track",
2711 QTDEMUX_GUINT32_GET (mdhd->data + 24), stream->timescale,
2712 qtdemux->duration, qtdemux->timescale);
2717 hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr);
2720 GST_LOG ("track type: %" GST_FOURCC_FORMAT,
2721 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (hdlr->data + 12)));
2722 GST_LOG ("track subtype: %" GST_FOURCC_FORMAT,
2723 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (hdlr->data + 16)));
2725 stream->subtype = QTDEMUX_FOURCC_GET (hdlr->data + 16);
2727 minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf);
2730 stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl);
2733 stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd);
2736 if (stream->subtype == FOURCC_vide) {
2740 GST_LOG ("st type: %" GST_FOURCC_FORMAT,
2741 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd->data + offset + 4)));
2743 stream->width = QTDEMUX_GUINT16_GET (stsd->data + offset + 32);
2744 stream->height = QTDEMUX_GUINT16_GET (stsd->data + offset + 34);
2745 stream->fps_n = 0; /* this is filled in later */
2746 stream->fps_d = 0; /* this is filled in later */
2747 stream->bits_per_sample = QTDEMUX_GUINT16_GET (stsd->data + offset + 82);
2748 stream->color_table_id = QTDEMUX_GUINT16_GET (stsd->data + offset + 84);
2750 GST_LOG ("frame count: %u",
2751 QTDEMUX_GUINT16_GET (stsd->data + offset + 48));
2753 stream->fourcc = fourcc = QTDEMUX_FOURCC_GET (stsd->data + offset + 4);
2754 stream->caps = qtdemux_video_caps (qtdemux, fourcc, stsd->data, &codec);
2756 list = gst_tag_list_new ();
2757 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
2758 GST_TAG_VIDEO_CODEC, codec, NULL);
2762 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4v);
2764 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
2767 gst_qtdemux_handle_esds (qtdemux, stream, esds);
2769 if (QTDEMUX_FOURCC_GET ((char *) stsd->data + 16 + 4) ==
2770 GST_MAKE_FOURCC ('a', 'v', 'c', '1')) {
2771 gint len = QTDEMUX_GUINT32_GET (stsd->data) - 0x66;
2772 guint8 *stsddata = stsd->data + 0x66;
2775 while (len >= 0x8 &&
2776 QTDEMUX_FOURCC_GET (stsddata + 0x4) !=
2777 GST_MAKE_FOURCC ('a', 'v', 'c', 'C') &&
2778 QTDEMUX_GUINT32_GET (stsddata) < len) {
2779 len -= QTDEMUX_GUINT32_GET (stsddata);
2780 stsddata += QTDEMUX_GUINT32_GET (stsddata);
2783 /* parse, if found */
2785 QTDEMUX_FOURCC_GET (stsddata + 0x4) ==
2786 GST_MAKE_FOURCC ('a', 'v', 'c', 'C')) {
2790 if (QTDEMUX_GUINT32_GET (stsddata) < len)
2791 size = QTDEMUX_GUINT32_GET (stsddata) - 0x8;
2795 buf = gst_buffer_new_and_alloc (size);
2796 memcpy (GST_BUFFER_DATA (buf), stsddata + 0x8, size);
2797 gst_caps_set_simple (stream->caps,
2798 "codec_data", GST_TYPE_BUFFER, buf, NULL);
2799 gst_buffer_unref (buf);
2801 } else if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2802 GST_MAKE_FOURCC ('S', 'V', 'Q', '3')) {
2804 gint len = QTDEMUX_GUINT32_GET (stsd->data);
2806 buf = gst_buffer_new_and_alloc (len);
2807 memcpy (GST_BUFFER_DATA (buf), stsd->data, len);
2808 gst_caps_set_simple (stream->caps,
2809 "codec_data", GST_TYPE_BUFFER, buf, NULL);
2810 gst_buffer_unref (buf);
2811 } else if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2812 GST_MAKE_FOURCC ('V', 'P', '3', '1')) {
2814 gint len = QTDEMUX_GUINT32_GET (stsd->data);
2816 buf = gst_buffer_new_and_alloc (len);
2817 memcpy (GST_BUFFER_DATA (buf), stsd->data, len);
2818 gst_caps_set_simple (stream->caps,
2819 "codec_data", GST_TYPE_BUFFER, buf, NULL);
2820 gst_buffer_unref (buf);
2821 } else if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2822 GST_MAKE_FOURCC ('r', 'l', 'e', ' ')) {
2823 gst_caps_set_simple (stream->caps,
2824 "depth", G_TYPE_INT, QTDEMUX_GUINT16_GET (stsd->data + offset + 82),
2829 GST_INFO_OBJECT (qtdemux,
2830 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
2831 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd->data + offset + 4)),
2833 } else if (stream->subtype == FOURCC_soun) {
2834 int version, samplesize;
2838 len = QTDEMUX_GUINT32_GET (stsd->data + 16);
2839 GST_LOG ("st type: %" GST_FOURCC_FORMAT,
2840 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4)));
2842 stream->fourcc = fourcc = QTDEMUX_FOURCC_GET (stsd->data + 16 + 4);
2845 GST_LOG ("version/rev: %08x",
2846 QTDEMUX_GUINT32_GET (stsd->data + offset));
2847 version = QTDEMUX_GUINT32_GET (stsd->data + offset);
2848 GST_LOG ("vendor: %08x",
2849 QTDEMUX_GUINT32_GET (stsd->data + offset + 4));
2850 GST_LOG ("n_channels: %d",
2851 QTDEMUX_GUINT16_GET (stsd->data + offset + 8));
2852 stream->n_channels = QTDEMUX_GUINT16_GET (stsd->data + offset + 8);
2853 GST_LOG ("sample_size: %d",
2854 QTDEMUX_GUINT16_GET (stsd->data + offset + 10));
2855 samplesize = QTDEMUX_GUINT16_GET (stsd->data + offset + 10);
2856 GST_LOG ("compression_id: %d",
2857 QTDEMUX_GUINT16_GET (stsd->data + offset + 12));
2858 GST_LOG ("packet size: %d",
2859 QTDEMUX_GUINT16_GET (stsd->data + offset + 14));
2860 GST_LOG ("sample rate: %g",
2861 QTDEMUX_FP32_GET (stsd->data + offset + 16));
2862 stream->rate = QTDEMUX_FP32_GET (stsd->data + offset + 16);
2865 if (version == 0x00010000) {
2866 GST_LOG ("samples/packet: %d",
2867 QTDEMUX_GUINT32_GET (stsd->data + offset));
2868 stream->samples_per_packet = QTDEMUX_GUINT32_GET (stsd->data + offset);
2869 GST_LOG ("bytes/packet: %d",
2870 QTDEMUX_GUINT32_GET (stsd->data + offset + 4));
2871 GST_LOG ("bytes/frame: %d",
2872 QTDEMUX_GUINT32_GET (stsd->data + offset + 8));
2873 stream->bytes_per_frame = QTDEMUX_GUINT32_GET (stsd->data + offset + 8);
2874 GST_LOG ("bytes/sample: %d",
2875 QTDEMUX_GUINT32_GET (stsd->data + offset + 12));
2876 stream->compression = 1;
2878 } else if (version == 0x00000000) {
2879 stream->bytes_per_frame = stream->n_channels * samplesize / 8;
2880 stream->samples_per_packet = 1;
2881 stream->compression = 1;
2883 /* Yes, these have to be hard-coded */
2884 if (fourcc == GST_MAKE_FOURCC ('M', 'A', 'C', '6'))
2885 stream->compression = 6;
2886 if (fourcc == GST_MAKE_FOURCC ('M', 'A', 'C', '3'))
2887 stream->compression = 3;
2888 if (fourcc == GST_MAKE_FOURCC ('i', 'm', 'a', '4'))
2889 stream->compression = 4;
2890 if (fourcc == GST_MAKE_FOURCC ('s', 'a', 'm', 'r')) {
2891 stream->n_channels = 1;
2892 stream->rate = 8000;
2893 stream->bytes_per_frame <<= 3;
2895 if (fourcc == GST_MAKE_FOURCC ('u', 'l', 'a', 'w'))
2896 stream->compression = 2;
2897 if (fourcc == GST_MAKE_FOURCC ('a', 'g', 's', 'm')) {
2898 stream->bytes_per_frame *= 33;
2899 stream->compression = 320;
2902 GST_WARNING ("unknown version %08x", version);
2905 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
2909 list = gst_tag_list_new ();
2910 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
2911 GST_TAG_AUDIO_CODEC, codec, NULL);
2914 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
2917 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
2921 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
2923 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
2926 gst_qtdemux_handle_esds (qtdemux, stream, esds);
2929 int len = QTDEMUX_GUINT32_GET (esds->data);
2931 buffer = gst_buffer_new_and_alloc (len - 8);
2932 memcpy (GST_BUFFER_DATA (buffer), esds->data + 8, len - 8);
2934 gst_caps_set_simple (stream->caps, "codec_data",
2935 GST_TYPE_BUFFER, buffer, NULL);
2938 if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2939 GST_MAKE_FOURCC ('Q', 'D', 'M', '2')) {
2940 gint len = QTDEMUX_GUINT32_GET (stsd->data);
2943 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
2945 memcpy (GST_BUFFER_DATA (buf),
2946 (guint8 *) stsd->data + 0x4C, len - 0x4C);
2947 gst_caps_set_simple (stream->caps,
2948 "codec_data", GST_TYPE_BUFFER, buf, NULL);
2949 gst_buffer_unref (buf);
2951 gst_caps_set_simple (stream->caps,
2952 "samplesize", G_TYPE_INT, samplesize, NULL);
2953 } else if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2954 GST_MAKE_FOURCC ('a', 'l', 'a', 'c')) {
2955 gint len = QTDEMUX_GUINT32_GET (stsd->data);
2958 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
2960 memcpy (GST_BUFFER_DATA (buf),
2961 (guint8 *) stsd->data + 0x34, len - 0x34);
2962 gst_caps_set_simple (stream->caps,
2963 "codec_data", GST_TYPE_BUFFER, buf, NULL);
2964 gst_buffer_unref (buf);
2966 gst_caps_set_simple (stream->caps,
2967 "samplesize", G_TYPE_INT, samplesize, NULL);
2970 GST_INFO_OBJECT (qtdemux,
2971 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
2972 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4)),
2975 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
2976 GST_FOURCC_ARGS (stream->subtype));
2981 /* sample to chunk */
2982 stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc);
2985 stsz = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsz);
2988 stco = qtdemux_tree_get_child_by_type (stbl, FOURCC_stco);
2989 co64 = qtdemux_tree_get_child_by_type (stbl, FOURCC_co64);
2990 g_assert (stco || co64);
2992 stts = qtdemux_tree_get_child_by_type (stbl, FOURCC_stts);
2994 /* sample sync, can be NULL */
2995 stss = qtdemux_tree_get_child_by_type (stbl, FOURCC_stss);
2997 sample_size = QTDEMUX_GUINT32_GET (stsz->data + 12);
2998 if (sample_size == 0) {
2999 n_samples = QTDEMUX_GUINT32_GET (stsz->data + 16);
3000 GST_DEBUG_OBJECT (qtdemux, "stsz sample_size 0, allocating n_samples %d",
3002 stream->n_samples = n_samples;
3003 samples = g_malloc (sizeof (QtDemuxSample) * n_samples);
3004 stream->samples = samples;
3006 for (i = 0; i < n_samples; i++) {
3007 samples[i].size = QTDEMUX_GUINT32_GET (stsz->data + i * 4 + 20);
3008 GST_LOG_OBJECT (qtdemux, "sample %d has size %d", i, samples[i].size);
3009 /* init other fields to defaults for this sample */
3010 samples[i].keyframe = FALSE;
3012 n_samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 12);
3015 for (i = 0; i < n_samples_per_chunk; i++) {
3016 int first_chunk, last_chunk;
3017 int samples_per_chunk;
3019 first_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 0) - 1;
3020 if (i == n_samples_per_chunk - 1) {
3021 last_chunk = INT_MAX;
3023 last_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 12) - 1;
3025 samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 4);
3027 for (j = first_chunk; j < last_chunk; j++) {
3028 guint64 chunk_offset;
3031 chunk_offset = QTDEMUX_GUINT32_GET (stco->data + 16 + j * 4);
3033 chunk_offset = QTDEMUX_GUINT64_GET (co64->data + 16 + j * 8);
3035 for (k = 0; k < samples_per_chunk; k++) {
3036 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld",
3037 index, chunk_offset);
3038 samples[index].chunk = j;
3039 samples[index].offset = chunk_offset;
3040 chunk_offset += samples[index].size;
3042 if (index >= n_samples)
3049 n_sample_times = QTDEMUX_GUINT32_GET (stts->data + 12);
3052 for (i = 0; i < n_sample_times; i++) {
3057 n = QTDEMUX_GUINT32_GET (stts->data + 16 + 8 * i);
3058 duration = QTDEMUX_GUINT32_GET (stts->data + 16 + 8 * i + 4);
3060 gst_util_uint64_scale_int (duration, GST_SECOND, stream->timescale);
3061 for (j = 0; j < n; j++) {
3062 //GST_INFO("moo %lld", timestamp);
3063 samples[index].timestamp = timestamp;
3064 samples[index].duration = duration;
3070 /* mark keyframes */
3071 guint32 n_sample_syncs;
3073 n_sample_syncs = QTDEMUX_GUINT32_GET (stss->data + 12);
3074 if (n_sample_syncs == 0) {
3075 stream->all_keyframe = TRUE;
3078 for (i = 0; i < n_sample_syncs; i++) {
3079 /* not that the first sample is index 1, not 0 */
3080 index = QTDEMUX_GUINT32_GET (stss->data + offset);
3081 samples[index - 1].keyframe = TRUE;
3086 /* no stss, all samples are keyframes */
3087 stream->all_keyframe = TRUE;
3090 guint64 timestamp = 0;
3092 GST_DEBUG_OBJECT (qtdemux,
3093 "stsz sample_size %d != 0, treating chunks as samples", sample_size);
3095 /* treat chunks as samples */
3097 n_samples = QTDEMUX_GUINT32_GET (stco->data + 12);
3099 n_samples = QTDEMUX_GUINT32_GET (co64->data + 12);
3101 stream->n_samples = n_samples;
3102 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %d", n_samples);
3103 samples = g_malloc (sizeof (QtDemuxSample) * n_samples);
3104 stream->samples = samples;
3106 n_samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 12);
3107 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %d", n_samples_per_chunk);
3110 for (i = 0; i < n_samples_per_chunk; i++) {
3111 int first_chunk, last_chunk;
3112 int samples_per_chunk;
3114 first_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 0) - 1;
3115 /* the last chunk of each entry is calculated by taking the first chunk
3116 * of the next entry; except if there is no next, where we fake it with
3118 if (i == n_samples_per_chunk - 1) {
3119 last_chunk = INT_MAX;
3121 last_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 12) - 1;
3123 samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 4);
3125 GST_LOG_OBJECT (qtdemux,
3126 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
3127 first_chunk, last_chunk, samples_per_chunk);
3129 for (j = first_chunk; j < last_chunk; j++) {
3130 guint64 chunk_offset;
3135 chunk_offset = QTDEMUX_GUINT32_GET (stco->data + 16 + j * 4);
3136 GST_LOG_OBJECT (qtdemux, "stco chunk %d offset %x", j, chunk_offset);
3138 chunk_offset = QTDEMUX_GUINT64_GET (co64->data + 16 + j * 8);
3139 GST_LOG_OBJECT (qtdemux, "co64 chunk %d offset %" G_GUINT64_FORMAT, j,
3142 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld",
3144 samples[j].chunk = j;
3145 samples[j].offset = chunk_offset;
3146 if (stream->samples_per_packet * stream->compression != 0)
3148 samples_per_chunk * stream->bytes_per_frame /
3149 stream->samples_per_packet / stream->compression;
3150 else if (stream->bytes_per_frame)
3151 samples[j].size = stream->bytes_per_frame;
3153 samples[j].size = sample_size;
3154 samples[j].duration =
3155 samples_per_chunk * stream->timescale / (stream->rate / 2);
3156 samples[j].timestamp = timestamp;
3157 samples[j].keyframe = TRUE;
3159 if (stream->rate > 0) {
3160 timestamp += gst_util_uint64_scale_int (samples_per_chunk,
3161 GST_SECOND, stream->rate);
3164 GST_INFO_OBJECT (qtdemux,
3165 "moo samples_per_chunk=%d rate=%d dur=%lld %lld",
3166 (int) samples_per_chunk, (int) stream->rate,
3167 (long long) ((samples_per_chunk * GST_SECOND) / stream->rate),
3168 (long long) timestamp);
3170 samples[j].sample_index = sample_index;
3171 sample_index += samples_per_chunk;
3177 for (i = 0; i < n_samples; i++) {
3178 GST_LOG ("%d: %d %d %d %d %" G_GUINT64_FORMAT, i,
3179 samples[i].sample_index, samples[i].chunk,
3180 samples[i].offset, samples[i].size, samples[i].timestamp);
3185 gst_qtdemux_add_stream (qtdemux, stream, list);
3189 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
3195 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
3197 GST_LOG ("no meta");
3201 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
3203 GST_LOG ("no ilst");
3207 GST_DEBUG_OBJECT (qtdemux, "new tag list");
3208 qtdemux->tag_list = gst_tag_list_new ();
3210 node = qtdemux_tree_get_child_by_type (ilst, FOURCC__nam);
3212 qtdemux_tag_add_str (qtdemux, GST_TAG_TITLE, node);
3215 node = qtdemux_tree_get_child_by_type (ilst, FOURCC__ART);
3217 qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
3219 node = qtdemux_tree_get_child_by_type (ilst, FOURCC__wrt);
3221 qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
3223 node = qtdemux_tree_get_child_by_type (ilst, FOURCC__grp);
3225 qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
3230 node = qtdemux_tree_get_child_by_type (ilst, FOURCC__alb);
3232 qtdemux_tag_add_str (qtdemux, GST_TAG_ALBUM, node);
3235 node = qtdemux_tree_get_child_by_type (ilst, FOURCC_trkn);
3237 qtdemux_tag_add_num (qtdemux, GST_TAG_TRACK_NUMBER,
3238 GST_TAG_TRACK_COUNT, node);
3241 node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disc);
3243 qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER,
3244 GST_TAG_ALBUM_VOLUME_COUNT, node);
3246 node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disk);
3248 qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER,
3249 GST_TAG_ALBUM_VOLUME_COUNT, node);
3253 node = qtdemux_tree_get_child_by_type (ilst, FOURCC_gnre);
3255 qtdemux_tag_add_gnre (qtdemux, GST_TAG_GENRE, node);
3257 node = qtdemux_tree_get_child_by_type (ilst, FOURCC__gen);
3259 qtdemux_tag_add_str (qtdemux, GST_TAG_GENRE, node);
3265 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag, GNode * node)
3272 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3274 len = QTDEMUX_GUINT32_GET (data->data);
3275 type = QTDEMUX_GUINT32_GET (data->data + 8);
3276 if (type == 0x00000001) {
3277 s = g_strndup ((char *) data->data + 16, len - 16);
3278 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", s);
3279 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
3286 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
3287 const char *tag2, GNode * node)
3294 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3296 len = QTDEMUX_GUINT32_GET (data->data);
3297 type = QTDEMUX_GUINT32_GET (data->data + 8);
3298 if (type == 0x00000000 && len >= 22) {
3299 n1 = GST_READ_UINT16_BE (data->data + 18);
3300 n2 = GST_READ_UINT16_BE (data->data + 20);
3301 GST_DEBUG_OBJECT (qtdemux, "adding tag %d/%d", n1, n2);
3302 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
3303 tag1, n1, tag2, n2, NULL);
3309 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, GNode * node)
3311 const gchar *genres[] = {
3312 "N/A", "Blues", "Classic Rock", "Country", "Dance", "Disco",
3313 "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
3314 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno",
3315 "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
3316 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
3317 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
3318 "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
3319 "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative",
3320 "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
3321 "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk",
3322 "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
3323 "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American",
3324 "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes",
3325 "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka",
3326 "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
3327 "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob",
3328 "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde",
3329 "Gothic Rock", "Progressive Rock", "Psychedelic Rock",
3330 "Symphonic Rock", "Slow Rock", "Big Band", "Chorus",
3331 "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
3332 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
3333 "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango",
3334 "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul",
3335 "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella",
3336 "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club House",
3337 "Hardcore", "Terror", "Indie", "BritPop", "NegerPunk",
3338 "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal",
3339 "Black Metal", "Crossover", "Contemporary C", "Christian Rock",
3340 "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop"
3347 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3349 len = QTDEMUX_GUINT32_GET (data->data);
3350 type = QTDEMUX_GUINT32_GET (data->data + 8);
3351 if (type == 0x00000000 && len >= 18) {
3352 n = GST_READ_UINT16_BE (data->data + 16);
3353 if (n > 0 && n < sizeof (genres) / sizeof (char *)) {
3354 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genres[n]);
3355 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
3356 tag, genres[n], NULL);
3362 /* taken from ffmpeg */
3364 get_size (guint8 * ptr, guint8 ** end)
3373 len = (len << 7) | (c & 0x7f);
3383 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
3386 int len = QTDEMUX_GUINT32_GET (esds->data);
3387 guint8 *ptr = esds->data;
3388 guint8 *end = ptr + len;
3390 guint8 *data_ptr = NULL;
3393 gst_util_dump_mem (ptr, len);
3395 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QTDEMUX_GUINT32_GET (ptr));
3398 tag = QTDEMUX_GUINT8_GET (ptr);
3399 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
3401 len = get_size (ptr, &ptr);
3402 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
3406 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QTDEMUX_GUINT16_GET (ptr));
3407 GST_DEBUG_OBJECT (qtdemux, "priority %04x",
3408 QTDEMUX_GUINT8_GET (ptr + 2));
3412 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x",
3413 QTDEMUX_GUINT8_GET (ptr));
3414 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x",
3415 QTDEMUX_GUINT8_GET (ptr + 1));
3416 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x",
3417 QTDEMUX_GUINT24_GET (ptr + 2));
3418 GST_DEBUG_OBJECT (qtdemux, "max bitrate %d",
3419 QTDEMUX_GUINT32_GET (ptr + 5));
3420 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %d",
3421 QTDEMUX_GUINT32_GET (ptr + 9));
3425 GST_DEBUG_OBJECT (qtdemux, "data:");
3426 gst_util_dump_mem (ptr, len);
3432 GST_DEBUG_OBJECT (qtdemux, "data %02x", QTDEMUX_GUINT8_GET (ptr));
3436 GST_ERROR ("parse error");
3443 buffer = gst_buffer_new_and_alloc (data_len);
3444 memcpy (GST_BUFFER_DATA (buffer), data_ptr, data_len);
3445 gst_util_dump_mem (GST_BUFFER_DATA (buffer), data_len);
3447 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
3449 gst_buffer_unref (buffer);
3453 #define _codec(name) \
3456 *codec_name = name; \
3461 qtdemux_video_caps (GstQTDemux * qtdemux, guint32 fourcc,
3462 const guint8 * stsd_data, const gchar ** codec_name)
3465 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
3466 _codec ("PNG still images");
3467 return gst_caps_from_string ("image/png");
3468 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
3469 _codec ("JPEG still images");
3470 return gst_caps_from_string ("image/jpeg");
3471 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
3472 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
3473 _codec ("Motion-JPEG");
3474 return gst_caps_from_string ("image/jpeg");
3475 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
3476 _codec ("Motion-JPEG format B");
3477 return gst_caps_from_string ("video/x-mjpeg-b");
3478 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
3479 _codec ("Sorensen video v.3");
3480 return gst_caps_from_string ("video/x-svq, " "svqversion = (int) 3");
3481 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
3482 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
3483 _codec ("Sorensen video v.1");
3484 return gst_caps_from_string ("video/x-svq, " "svqversion = (int) 1");
3485 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
3486 _codec ("Raw RGB video");
3487 return gst_caps_from_string ("video/x-raw-rgb, "
3488 "endianness = (int) BIG_ENDIAN");
3489 /*"bpp", GST_PROPS_INT(x),
3490 "depth", GST_PROPS_INT(x),
3491 "red_mask", GST_PROPS_INT(x),
3492 "green_mask", GST_PROPS_INT(x),
3493 "blue_mask", GST_PROPS_INT(x), FIXME! */
3494 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
3495 _codec ("Raw packed YUV 4:2:2");
3496 return gst_caps_from_string ("video/x-raw-yuv, "
3497 "format = (fourcc) YUY2");
3498 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
3499 _codec ("MPEG-1 video");
3500 return gst_caps_from_string ("video/mpeg, "
3501 "systemstream = (boolean) false, " "mpegversion = (int) 1");
3502 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
3503 _codec ("GIF still images");
3504 return gst_caps_from_string ("image/gif");
3505 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
3506 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
3508 /* ffmpeg uses the height/width props, don't know why */
3509 return gst_caps_from_string ("video/x-h263");
3510 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
3511 _codec ("MPEG-4 video");
3512 return gst_caps_from_string ("video/mpeg, "
3513 "mpegversion = (int) 4, " "systemstream = (boolean) false");
3514 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
3515 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
3516 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
3517 return gst_caps_from_string ("video/x-msmpeg, msmpegversion = (int) 43");
3518 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
3519 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
3520 _codec ("3ivX video");
3521 return gst_caps_from_string ("video/x-3ivx");
3522 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
3524 return gst_caps_from_string ("video/x-divx," "divxversion= (int) 3");
3525 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
3527 return gst_caps_from_string ("video/x-divx," "divxversion= (int) 4");
3529 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
3531 return gst_caps_from_string ("video/x-divx," "divxversion= (int) 5");
3532 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
3534 return gst_caps_from_string ("video/x-cinepak");
3535 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
3536 _codec ("Apple video");
3537 return gst_caps_from_string ("video/x-apple-video");
3538 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
3539 _codec ("H.264 / AVC");
3540 return gst_caps_from_string ("video/x-h264");
3541 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
3542 _codec ("Run-length encoding");
3543 return gst_caps_from_string ("video/x-rle, layout=(string)quicktime");
3544 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
3545 _codec ("Indeo Video 3");
3546 return gst_caps_from_string ("video/x-indeo, indeoversion=(int)3");
3547 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
3548 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
3549 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
3550 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
3551 _codec ("DV Video");
3552 return gst_caps_from_string ("video/x-dv, systemstream=(boolean)false");
3553 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
3554 _codec ("Apple Graphics (SMC)");
3555 return gst_caps_from_string ("video/x-smc");
3556 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
3558 return gst_caps_from_string ("video/x-vp3");
3559 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
3562 g_critical ("Don't know how to convert fourcc '%" GST_FOURCC_FORMAT
3563 "' to caps", GST_FOURCC_ARGS (fourcc));
3569 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
3570 GST_FOURCC_ARGS (fourcc));
3571 return gst_caps_new_simple (s, NULL);
3577 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
3578 guint32 fourcc, const guint8 * data, int len, const gchar ** codec_name)
3582 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
3583 return NULL; /*gst_caps_from_string ("audio/raw"); */
3585 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
3586 _codec ("Raw 8-bit PCM audio");
3588 return gst_caps_from_string ("audio/x-raw-int, "
3589 "width = (int) 8, " "depth = (int) 8, " "signed = (boolean) false");
3590 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
3591 if (stream->bytes_per_frame == 1) {
3592 _codec ("Raw 8-bit PCM audio");
3593 return gst_caps_from_string ("audio/x-raw-int, "
3594 "width = (int) 8, " "depth = (int) 8, " "signed = (boolean) true");
3596 _codec ("Raw 16-bit PCM audio");
3598 return gst_caps_from_string ("audio/x-raw-int, "
3599 "width = (int) 16, "
3600 "depth = (int) 16, "
3601 "endianness = (int) BIG_ENDIAN, " "signed = (boolean) true");
3603 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
3604 if (stream->bytes_per_frame == 1) {
3605 _codec ("Raw 8-bit PCM audio");
3606 return gst_caps_from_string ("audio/x-raw-int, "
3607 "width = (int) 8, " "depth = (int) 8, " "signed = (boolean) true");
3609 _codec ("Raw 16-bit PCM audio");
3611 return gst_caps_from_string ("audio/x-raw-int, "
3612 "width = (int) 16, "
3613 "depth = (int) 16, "
3614 "endianness = (int) LITTLE_ENDIAN, " "signed = (boolean) true");
3616 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
3617 _codec ("Raw 64-bit floating-point audio");
3618 return gst_caps_from_string ("audio/x-raw-float, "
3619 "width = (int) 64, " "endianness = (int) BIG_ENDIAN");
3620 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
3621 _codec ("Raw 32-bit floating-point audio");
3622 return gst_caps_from_string ("audio/x-raw-float, "
3623 "width = (int) 32, " "endianness = (int) BIG_ENDIAN");
3624 case GST_MAKE_FOURCC ('i', 'n', '2', '4'):
3625 _codec ("Raw 24-bit PCM audio");
3627 return gst_caps_from_string ("audio/x-raw-int, "
3628 "width = (int) 24, "
3629 "depth = (int) 32, "
3630 "endianness = (int) BIG_ENDIAN, " "signed = (boolean) true");
3631 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
3632 _codec ("Raw 32-bit PCM audio");
3634 return gst_caps_from_string ("audio/x-raw-int, "
3635 "width = (int) 32, "
3636 "depth = (int) 32, "
3637 "endianness = (int) BIG_ENDIAN, " "signed = (boolean) true");
3638 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
3639 _codec ("Mu-law audio");
3641 return gst_caps_from_string ("audio/x-mulaw");
3642 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
3643 _codec ("A-law audio");
3645 return gst_caps_from_string ("audio/x-alaw");
3647 _codec ("Microsoft ADPCM");
3648 /* Microsoft ADPCM-ACM code 2 */
3649 return gst_caps_from_string ("audio/x-adpcm, "
3650 "layout = (string) microsoft");
3653 _codec ("DVI/Intel IMA ADPCM");
3654 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
3655 return gst_caps_from_string ("audio/x-adpcm, "
3656 "layout = (string) quicktime");
3658 /* MPEG layer 3, CBR only (pre QT4.1) */
3660 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
3661 _codec ("MPEG-1 layer 3");
3662 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
3663 return gst_caps_from_string ("audio/mpeg, "
3664 "layer = (int) 3, " "mpegversion = (int) 1");
3665 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
3667 return gst_caps_from_string ("audio/x-mace, " "maceversion = (int) 3");
3668 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
3670 return gst_caps_from_string ("audio/x-mace, " "maceversion = (int) 6");
3671 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
3673 return gst_caps_from_string ("application/ogg");
3674 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
3675 _codec ("DV audio");
3676 return gst_caps_from_string ("audio/x-dv");
3677 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
3678 _codec ("MPEG-4 AAC audio");
3679 return gst_caps_new_simple ("audio/mpeg",
3680 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
3681 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
3682 _codec ("QDesign Music v.2");
3683 /* FIXME: QDesign music version 2 (no constant) */
3685 return gst_caps_new_simple ("audio/x-qdm2",
3686 "framesize", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 52),
3687 "bitrate", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 40),
3688 "blocksize", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 44), NULL);
3690 return gst_caps_new_simple ("audio/x-qdm2", NULL);
3692 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
3693 _codec ("GSM audio");
3694 return gst_caps_new_simple ("audio/x-gsm", NULL);
3695 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
3696 _codec ("AMR audio");
3697 return gst_caps_new_simple ("audio/AMR", NULL);
3698 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
3699 _codec ("Quicktime IMA ADPCM");
3700 return gst_caps_new_simple ("audio/x-adpcm",
3701 "layout", G_TYPE_STRING, "quicktime", NULL);
3702 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
3703 _codec ("Apple lossless audio");
3704 return gst_caps_new_simple ("audio/x-alac", NULL);
3705 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
3707 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
3709 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
3710 /* QUALCOMM PureVoice */
3713 g_critical ("Don't know how to convert fourcc '%" GST_FOURCC_FORMAT
3714 "' to caps", GST_FOURCC_ARGS (fourcc));
3720 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
3721 GST_FOURCC_ARGS (fourcc));
3722 return gst_caps_new_simple (s, NULL);