Unify the long descriptions in the plugin details (#337263).
[platform/upstream/gst-plugins-good.git] / gst / qtdemux / qtdemux.c
1 /* GStreamer
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>
5  *
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.
10  *
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.
15  *
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.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include "qtdemux.h"
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <zlib.h>
30
31 GST_DEBUG_CATEGORY_EXTERN (qtdemux_debug);
32 #define GST_CAT_DEFAULT qtdemux_debug
33
34 /* temporary hack */
35 #define gst_util_dump_mem(a,b)  /* */
36
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))
44
45 #define QTDEMUX_GUINT64_GET(a) ((((guint64)QTDEMUX_GUINT32_GET(a))<<32)|QTDEMUX_GUINT32_GET(((void *)a)+4))
46
47 typedef struct _QtNode QtNode;
48 typedef struct _QtNodeType QtNodeType;
49 typedef struct _QtDemuxSample QtDemuxSample;
50
51 //typedef struct _QtDemuxStream QtDemuxStream;
52
53 struct _QtNode
54 {
55   guint32 type;
56   gpointer data;
57   gint len;
58 };
59
60 struct _QtNodeType
61 {
62   guint32 fourcc;
63   gchar *name;
64   gint flags;
65   void (*dump) (GstQTDemux * qtdemux, void *buffer, int depth);
66 };
67
68 struct _QtDemuxSample
69 {
70   gint sample_index;
71   gint chunk;
72   gint size;
73   guint64 offset;
74   guint64 timestamp;            /* In GstClockTime */
75   guint32 duration;             /* in stream->timescale units */
76   gboolean keyframe;            /* TRUE when this packet is a keyframe */
77 };
78
79 struct _QtDemuxStream
80 {
81   guint32 subtype;
82   GstCaps *caps;
83   guint32 fourcc;
84   GstPad *pad;
85   gint n_samples;
86   QtDemuxSample *samples;
87   gint timescale;
88   gboolean all_keyframe;        /* TRUE when all packets are keyframes (no stss) */
89
90   gint sample_index;
91
92   gint width;
93   gint height;
94   /* Numerator/denominator framerate */
95   gint fps_n;
96   gint fps_d;
97
98   gdouble rate;
99   gint n_channels;
100   guint bytes_per_frame;
101   guint compression;
102   guint samples_per_packet;
103   guint16 bits_per_sample;
104   guint16 color_table_id;
105
106   /* when a discontinuity is pending */
107   gboolean discont;
108 };
109
110 enum QtDemuxState
111 {
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 */
116 };
117
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);
120
121 static GstElementDetails gst_qtdemux_details =
122 GST_ELEMENT_DETAILS ("QuickTime demuxer",
123     "Codec/Demuxer",
124     "Demultiplex a QuickTime file into audio and video streams",
125     "David Schleef <ds@schleef.org>");
126
127 static GstStaticPadTemplate gst_qtdemux_sink_template =
128     GST_STATIC_PAD_TEMPLATE ("sink",
129     GST_PAD_SINK,
130     GST_PAD_ALWAYS,
131     GST_STATIC_CAPS ("video/quicktime; audio/x-m4a; application/x-3gp")
132     );
133
134 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
135 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
136     GST_PAD_SRC,
137     GST_PAD_SOMETIMES,
138     GST_STATIC_CAPS_ANY);
139
140 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
141 GST_STATIC_PAD_TEMPLATE ("video_%02d",
142     GST_PAD_SRC,
143     GST_PAD_SOMETIMES,
144     GST_STATIC_CAPS_ANY);
145
146 static GstElementClass *parent_class = NULL;
147
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
194 };
195
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
234 };
235
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);
248
249 static void qtdemux_parse_moov (GstQTDemux * qtdemux, void *buffer, int length);
250 static void qtdemux_parse (GstQTDemux * qtdemux, GNode * node, void *buffer,
251     int length);
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,
257     GNode * node);
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,
261     GNode * node);
262
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);
270
271 static GType
272 gst_qtdemux_get_type (void)
273 {
274   static GType qtdemux_type = 0;
275
276   if (!qtdemux_type) {
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,
283     };
284
285     qtdemux_type =
286         g_type_register_static (GST_TYPE_ELEMENT, "GstQTDemux", &qtdemux_info,
287         0);
288   }
289   return qtdemux_type;
290 }
291
292 static void
293 gst_qtdemux_base_init (GstQTDemuxClass * klass)
294 {
295   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
296
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);
304
305 }
306
307 static void
308 gst_qtdemux_class_init (GstQTDemuxClass * klass)
309 {
310   GObjectClass *gobject_class;
311   GstElementClass *gstelement_class;
312
313   gobject_class = (GObjectClass *) klass;
314   gstelement_class = (GstElementClass *) klass;
315
316   parent_class = g_type_class_peek_parent (klass);
317
318   gobject_class->dispose = gst_qtdemux_dispose;
319
320   gstelement_class->change_state = gst_qtdemux_change_state;
321 }
322
323 static void
324 gst_qtdemux_init (GstQTDemux * qtdemux)
325 {
326   qtdemux->sinkpad =
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);
336
337   qtdemux->state = QTDEMUX_STATE_INITIAL;
338   qtdemux->last_ts = GST_CLOCK_TIME_NONE;
339   qtdemux->pullbased = FALSE;
340   qtdemux->neededbytes = 16;
341   qtdemux->todrop = 0;
342   qtdemux->adapter = gst_adapter_new ();
343   qtdemux->offset = 0;
344   qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
345   qtdemux->mdatbuffer = NULL;
346   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
347 }
348
349 static void
350 gst_qtdemux_dispose (GObject * object)
351 {
352   GstQTDemux *qtdemux = GST_QTDEMUX (object);
353
354   if (qtdemux->adapter) {
355     g_object_unref (G_OBJECT (qtdemux->adapter));
356     qtdemux->adapter = NULL;
357   }
358
359   G_OBJECT_CLASS (parent_class)->dispose (object);
360 }
361
362 #if 0
363 static gboolean
364 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
365     GstFormat * dest_format, gint64 * dest_value)
366 {
367   gboolean res = TRUE;
368   QtDemuxStream *stream = gst_pad_get_element_private (pad);
369
370   if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e') &&
371       (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
372     return FALSE;
373
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 */
379           break;
380         case GST_FORMAT_DEFAULT:
381           *dest_value = src_value * 1;  /* FIXME */
382           break;
383         default:
384           res = FALSE;
385           break;
386       }
387       break;
388     case GST_FORMAT_BYTES:
389       switch (*dest_format) {
390         case GST_FORMAT_TIME:
391           *dest_value = src_value * 1;  /* FIXME */
392           break;
393         default:
394           res = FALSE;
395           break;
396       }
397       break;
398     case GST_FORMAT_DEFAULT:
399       switch (*dest_format) {
400         case GST_FORMAT_TIME:
401           *dest_value = src_value * 1;  /* FIXME */
402           break;
403         default:
404           res = FALSE;
405           break;
406       }
407       break;
408     default:
409       res = FALSE;
410   }
411
412   return res;
413 }
414 #endif
415
416 static const GstQueryType *
417 gst_qtdemux_get_src_query_types (GstPad * pad)
418 {
419   static const GstQueryType src_types[] = {
420     GST_QUERY_POSITION,
421     GST_QUERY_DURATION,
422     0
423   };
424
425   return src_types;
426 }
427
428 static gboolean
429 gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
430 {
431   gboolean res = FALSE;
432   GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
433
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);
438         res = TRUE;
439       }
440       break;
441     case GST_QUERY_DURATION:
442       if (qtdemux->pullbased && qtdemux->duration != 0
443           && qtdemux->timescale != 0) {
444         gint64 duration;
445
446         duration = gst_util_uint64_scale_int (qtdemux->duration,
447             GST_SECOND, qtdemux->timescale);
448
449         gst_query_set_duration (query, GST_FORMAT_TIME, duration);
450         res = TRUE;
451       }
452       break;
453     default:
454       res = FALSE;
455       break;
456   }
457
458   gst_object_unref (qtdemux);
459
460   return res;
461 }
462
463 /* push event on all source pads; takes ownership of the event */
464 static void
465 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
466 {
467   guint n;
468
469   GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
470       GST_EVENT_TYPE_NAME (event));
471
472   for (n = 0; n < qtdemux->n_streams; n++) {
473     gst_pad_push_event (qtdemux->streams[n]->pad, gst_event_ref (event));
474   }
475   gst_event_unref (event);
476 }
477
478 /* move all streams back on the keyframe before @offset.
479  * 
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
483  * of each stream.
484  *
485  * Returns: the minimum of the timestamps of the positions of all streams.
486  */
487 /* FIXME, binary search would be nice here */
488 static guint64
489 gst_qtdemux_go_back (GstQTDemux * qtdemux, gboolean end, guint64 offset)
490 {
491   gint n;
492   guint64 min_time = G_MAXUINT64;
493
494   /* resync to new time */
495   for (n = 0; n < qtdemux->n_streams; n++) {
496     QtDemuxStream *str;
497     gboolean keyframe;
498     gint search;
499
500     str = qtdemux->streams[n];
501     keyframe = str->all_keyframe;
502
503     /* start from the last sample if @end == TRUE */
504     if (end) {
505       if (str->n_samples == 0)
506         search = 0;
507       else
508         search = str->n_samples - 1;
509     } else
510       search = str->sample_index;
511
512     for (; search > 0; search--) {
513       guint64 timestamp;
514
515       timestamp = str->samples[search].timestamp;
516
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;
522         if (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;
529           break;
530         }
531       }
532     }
533
534     /* did not find anything or we're at the beginning, position to beginning */
535     if (search <= 0) {
536       search = 0;
537       min_time = 0;
538     }
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 */
543       str->discont = TRUE;
544     }
545   }
546   return min_time;
547 }
548
549 /* perform the seek.
550  *
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.
556  */
557 static gboolean
558 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
559 {
560   gint64 desired_offset;
561   guint64 min;
562
563   desired_offset = segment->last_stop;
564
565   GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
566       GST_TIME_ARGS (desired_offset));
567
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);
571
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);
578
579     /* update the segment values to the position of the keyframes */
580     segment->last_stop = min;
581     segment->time = min;
582   }
583
584   /* and we stop at the end */
585   if (segment->stop == -1)
586     segment->stop = segment->duration;
587
588   return TRUE;
589 }
590
591 /* do a seek in pull based mode */
592 static gboolean
593 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
594 {
595   gdouble rate;
596   GstFormat format;
597   GstSeekFlags flags;
598   GstSeekType cur_type, stop_type;
599   gint64 cur, stop;
600   gboolean flush;
601   gboolean res;
602   gboolean update;
603   GstSegment seeksegment;
604   GstEvent *newsegment;
605
606   if (event) {
607     GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
608
609     gst_event_parse_seek (event, &rate, &format, &flags,
610         &cur_type, &cur, &stop_type, &stop);
611
612     /* we have to have a format as the segment format. Try to convert
613      * if not. */
614     if (format != GST_FORMAT_TIME) {
615       GstFormat fmt;
616
617       fmt = GST_FORMAT_TIME;
618       res = TRUE;
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);
623       if (!res)
624         goto no_format;
625
626       format = fmt;
627     }
628   } else {
629     GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
630     flags = 0;
631   }
632
633   flush = flags & GST_SEEK_FLAG_FLUSH;
634
635   GST_DEBUG_OBJECT (qtdemux, "seek format %d", format);
636
637   /* stop streaming, either by flushing or by pausing the task */
638   if (flush) {
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 ());
643   } else {
644     /* non flushing seek, pause the task */
645     qtdemux->segment_running = FALSE;
646     gst_pad_pause_task (qtdemux->sinkpad);
647   }
648
649   /* wait for streaming to finish */
650   GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
651
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));
655
656   if (event) {
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);
661   }
662
663   /* now do the seek, this actually never returns FALSE */
664   res = gst_qtdemux_perform_seek (qtdemux, &seeksegment);
665
666   /* prepare for streaming again */
667   if (flush) {
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);
676
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));
682   }
683
684   /* commit the new segment */
685   memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
686
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));
691   }
692
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));
697
698   newsegment =
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);
702
703   gst_qtdemux_push_event (qtdemux, newsegment);
704
705   /* restart streaming */
706   qtdemux->segment_running = TRUE;
707   gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
708       qtdemux->sinkpad);
709
710   GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
711
712   return TRUE;
713
714   /* ERRORS */
715 no_format:
716   {
717     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
718     return FALSE;
719   }
720 }
721
722 static gboolean
723 gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
724 {
725   gboolean res = TRUE;
726   GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
727
728   switch (GST_EVENT_TYPE (event)) {
729     case GST_EVENT_SEEK:
730       res = gst_qtdemux_do_seek (qtdemux, pad, event);
731       break;
732     default:
733       res = FALSE;
734       break;
735   }
736
737   gst_object_unref (qtdemux);
738
739   gst_event_unref (event);
740
741   return res;
742 }
743
744 GST_DEBUG_CATEGORY (qtdemux_debug);
745
746 static gboolean
747 plugin_init (GstPlugin * plugin)
748 {
749   GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
750
751   return gst_element_register (plugin, "qtdemux",
752       GST_RANK_PRIMARY, GST_TYPE_QTDEMUX);
753 }
754
755 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
756     GST_VERSION_MINOR,
757     "qtdemux",
758     "Quicktime stream demuxer",
759     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
760
761 static gboolean
762 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
763 {
764   GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
765   gboolean res = FALSE;
766
767   switch (GST_EVENT_TYPE (event)) {
768     case GST_EVENT_NEWSEGMENT:
769       /* We need to convert it to a GST_FORMAT_TIME new segment */
770     default:
771       gst_pad_event_default (demux->sinkpad, event);
772       return TRUE;
773   }
774
775   gst_event_unref (event);
776   return res;
777 }
778
779 static GstStateChangeReturn
780 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
781 {
782   GstQTDemux *qtdemux = GST_QTDEMUX (element);
783   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
784
785   switch (transition) {
786     case GST_STATE_CHANGE_PAUSED_TO_READY:
787       break;
788     default:
789       break;
790   }
791
792   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
793
794   switch (transition) {
795     case GST_STATE_CHANGE_PAUSED_TO_READY:{
796       gint n;
797
798       qtdemux->state = QTDEMUX_STATE_INITIAL;
799       qtdemux->last_ts = GST_CLOCK_TIME_NONE;
800       qtdemux->neededbytes = 16;
801       qtdemux->todrop = 0;
802       qtdemux->pullbased = FALSE;
803       qtdemux->offset = 0;
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]);
815       }
816       qtdemux->n_streams = 0;
817       gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
818       break;
819     }
820     default:
821       break;
822   }
823
824   return result;
825 }
826
827 static void
828 extract_initial_length_and_fourcc (guint8 * data, guint32 * plength,
829     guint32 * pfourcc)
830 {
831   guint32 length;
832   guint32 fourcc;
833
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));
838
839   if (length == 0) {
840     length = G_MAXUINT32;
841   }
842   if (length == 1) {
843     /* this means we have an extended size, which is the 64 bit value of
844      * the next 8 bytes */
845     guint32 length1, length2;
846
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);
851
852     /* FIXME: I guess someone didn't want to make 64 bit size work :) */
853     length = length2;
854   }
855
856   if (plength)
857     *plength = length;
858   if (pfourcc)
859     *pfourcc = fourcc;
860 }
861
862 static GstFlowReturn
863 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
864 {
865   guint32 length;
866   guint32 fourcc;
867   GstBuffer *buf = NULL;
868   GstFlowReturn ret = GST_FLOW_OK;
869   guint64 cur_offset = qtdemux->offset;
870
871   ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
872   if (ret != GST_FLOW_OK)
873     goto beach;
874   extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf), &length, &fourcc);
875   gst_buffer_unref (buf);
876
877
878   switch (fourcc) {
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'):{
886       GstBuffer *moov;
887
888       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
889       if (ret != GST_FLOW_OK)
890         goto beach;
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;
896         goto beach;
897       }
898       cur_offset += length;
899       qtdemux->offset += length;
900
901       qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
902       if (1) {
903         qtdemux_node_dump (qtdemux, qtdemux->moov_node);
904       }
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)",
911           qtdemux->state);
912     }
913       break;
914     ed_edd_and_eddy:
915     default:{
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;
920       break;
921     }
922   }
923
924 beach:
925   return ret;
926 }
927
928 static GstFlowReturn
929 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
930 {
931   GstFlowReturn ret = GST_FLOW_OK;
932   GstBuffer *buf = NULL;
933   QtDemuxStream *stream;
934   guint64 min_time;
935   guint64 offset;
936   guint64 timestamp;
937   gint size;
938   gint index = -1;
939   gint i;
940
941   /* Figure out the next stream sample to output */
942   min_time = G_MAXUINT64;
943
944   for (i = 0; i < qtdemux->n_streams; i++) {
945     stream = qtdemux->streams[i];
946     if (stream->sample_index < stream->n_samples) {
947
948       timestamp = stream->samples[stream->sample_index].timestamp;
949
950       GST_LOG_OBJECT (qtdemux,
951           "stream %d: sample_index %d, timestamp %" GST_TIME_FORMAT, i,
952           stream->sample_index, GST_TIME_ARGS (timestamp));
953
954       if (timestamp < min_time) {
955         min_time = timestamp;
956         index = i;
957       }
958     }
959   }
960   if (index == -1)
961     goto eos;
962
963   /* check for segment end */
964   if (qtdemux->segment.stop != -1 && qtdemux->segment.stop < min_time)
965     goto eos;
966
967   stream = qtdemux->streams[index];
968
969   offset = stream->samples[stream->sample_index].offset;
970   size = stream->samples[stream->sample_index].size;
971   timestamp = stream->samples[stream->sample_index].timestamp;
972
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));
977
978   if (G_UNLIKELY (size <= 0))
979     goto beach;
980
981   GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
982       offset);
983
984   ret = gst_pad_pull_range (qtdemux->sinkpad, offset, size, &buf);
985   if (ret != GST_FLOW_OK)
986     goto beach;
987
988   buf = gst_buffer_make_metadata_writable (buf);
989
990 #if 0
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')) {
994     float fps =
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);
998       stream->fps = fps;
999       gst_pad_set_explicit_caps (stream->pad, stream->caps);
1000     }
1001   }
1002 #endif
1003
1004   /* first buffer? */
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));
1009   }
1010
1011   if (stream->discont) {
1012     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
1013     stream->discont = FALSE;
1014   }
1015
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;
1020   } else {
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,
1025         stream->timescale);
1026   }
1027   gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME,
1028       qtdemux->last_ts);
1029
1030   if (!(stream->all_keyframe || stream->samples[stream->sample_index].keyframe))
1031     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
1032
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);
1037
1038   ret = gst_pad_push (stream->pad, buf);
1039
1040   stream->sample_index++;
1041
1042 beach:
1043   return ret;
1044
1045   /* special cases */
1046 eos:
1047   {
1048     GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
1049     ret = GST_FLOW_UNEXPECTED;
1050     goto beach;
1051   }
1052 }
1053
1054 static void
1055 gst_qtdemux_loop (GstPad * pad)
1056 {
1057   GstQTDemux *qtdemux;
1058   guint64 cur_offset;
1059   GstFlowReturn ret;
1060
1061   qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
1062
1063   cur_offset = qtdemux->offset;
1064   GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
1065       cur_offset, qtdemux->state);
1066
1067   switch (qtdemux->state) {
1068     case QTDEMUX_STATE_INITIAL:
1069     case QTDEMUX_STATE_HEADER:
1070       ret = gst_qtdemux_loop_state_header (qtdemux);
1071       break;
1072     case QTDEMUX_STATE_MOVIE:
1073       ret = gst_qtdemux_loop_state_movie (qtdemux);
1074       break;
1075     default:
1076       /* ouch */
1077       goto invalid_state;
1078   }
1079
1080   /* if all is fine, continue */
1081   if (G_LIKELY (ret == GST_FLOW_OK))
1082     goto done;
1083
1084   /* we don't care about unlinked pads */
1085   if (ret == GST_FLOW_NOT_LINKED)
1086     goto done;
1087
1088   /* other errors make us stop */
1089   GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", gst_flow_get_name (ret));
1090
1091   qtdemux->segment_running = FALSE;
1092   gst_pad_pause_task (pad);
1093
1094   /* fatal errors need special actions */
1095   if (GST_FLOW_IS_FATAL (ret)) {
1096     /* check EOS */
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));
1103       } else {
1104         GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
1105         gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
1106       }
1107     } else {
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)));
1111     }
1112   }
1113
1114 done:
1115   gst_object_unref (qtdemux);
1116   return;
1117
1118   /* ERRORS */
1119 invalid_state:
1120   {
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 ());
1126     goto done;
1127   }
1128 }
1129
1130 /*
1131   next_entry_size
1132   
1133   Returns the size of the first entry at the current offset.
1134   If -1, there are none (which means EOS or empty file).
1135 */
1136
1137 static guint64
1138 next_entry_size (GstQTDemux * demux)
1139 {
1140   QtDemuxStream *stream;
1141   int i;
1142   int smallidx = -1;
1143   guint64 smalloffs = -1;
1144
1145   GST_LOG_OBJECT (demux, "Finding entry at offset %lld", demux->offset);
1146
1147   for (i = 0; i < demux->n_streams; i++) {
1148     stream = demux->streams[i];
1149
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);
1155
1156     if (((smalloffs == -1)
1157             || (stream->samples[stream->sample_index].offset < smalloffs))
1158         && (stream->samples[stream->sample_index].size)) {
1159       smallidx = i;
1160       smalloffs = stream->samples[stream->sample_index].offset;
1161     }
1162   }
1163
1164   GST_LOG_OBJECT (demux, "stream %d offset %lld demux->offset :%lld",
1165       smallidx, smalloffs, demux->offset);
1166
1167   if (smallidx == -1)
1168     return -1;
1169   stream = demux->streams[smallidx];
1170
1171   if (stream->samples[stream->sample_index].offset >= demux->offset) {
1172     demux->todrop =
1173         stream->samples[stream->sample_index].offset - demux->offset;
1174     return stream->samples[stream->sample_index].size + demux->todrop;
1175   }
1176
1177   GST_DEBUG_OBJECT (demux, "There wasn't any entry at offset %lld",
1178       demux->offset);
1179   return -1;
1180 }
1181
1182 static void
1183 gst_qtdemux_post_buffering (GstQTDemux * demux, gint num, gint denom)
1184 {
1185   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
1186
1187   gst_element_post_message (GST_ELEMENT (demux),
1188       gst_message_new_custom (GST_MESSAGE_BUFFERING,
1189           GST_OBJECT (demux),
1190           gst_structure_new ("GstMessageBuffering",
1191               "buffer-percent", G_TYPE_INT, perc, NULL)));
1192 }
1193
1194 static GstFlowReturn
1195 gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
1196 {
1197   GstQTDemux *demux;
1198   GstFlowReturn ret = GST_FLOW_OK;
1199
1200   demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad));
1201
1202   gst_adapter_push (demux->adapter, inbuf);
1203
1204   GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
1205       inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
1206
1207   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
1208       (ret == GST_FLOW_OK)) {
1209
1210     GST_DEBUG_OBJECT (demux,
1211         "state:%d , demux->neededbytes:%d, demux->offset:%lld", demux->state,
1212         demux->neededbytes, demux->offset);
1213
1214     switch (demux->state) {
1215       case QTDEMUX_STATE_INITIAL:{
1216         const guint8 *data;
1217         guint32 fourcc;
1218         guint32 size;
1219
1220         data = gst_adapter_peek (demux->adapter, demux->neededbytes);
1221
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);
1231           } else {
1232             demux->state = QTDEMUX_STATE_BUFFER_MDAT;
1233             demux->neededbytes = size;
1234             demux->mdatoffset = demux->offset;
1235           }
1236         } else {
1237           demux->neededbytes = size;
1238           demux->state = QTDEMUX_STATE_HEADER;
1239         }
1240         break;
1241       }
1242       case QTDEMUX_STATE_HEADER:{
1243         guint8 *data;
1244         guint32 fourcc;
1245
1246         GST_DEBUG_OBJECT (demux, "In header");
1247
1248         data = gst_adapter_take (demux->adapter, demux->neededbytes);
1249
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]");
1254
1255           qtdemux_parse_moov (demux, data, demux->neededbytes);
1256           qtdemux_node_dump (demux, demux->moov_node);
1257           qtdemux_parse_tree (demux);
1258
1259           g_node_destroy (demux->moov_node);
1260           g_free (data);
1261           demux->moov_node = NULL;
1262         } else {
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 */
1267         }
1268
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;
1282         } else {
1283           GST_DEBUG_OBJECT (demux, "Carrying on normally");
1284           demux->offset += demux->neededbytes;
1285           demux->neededbytes = 16;
1286           demux->state = QTDEMUX_STATE_INITIAL;
1287         }
1288
1289         break;
1290       }
1291       case QTDEMUX_STATE_BUFFER_MDAT:{
1292         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %lld",
1293             demux->mdatoffset);
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);
1306
1307         break;
1308       }
1309       case QTDEMUX_STATE_MOVIE:{
1310         guint8 *data;
1311         GstBuffer *outbuf;
1312         QtDemuxStream *stream = NULL;
1313         int i = -1;
1314
1315         GST_DEBUG_OBJECT (demux, "BEGIN // in MOVIE for offset %lld",
1316             demux->offset);
1317
1318         if (demux->todrop) {
1319           gst_adapter_flush (demux->adapter, demux->todrop);
1320           demux->neededbytes -= demux->todrop;
1321           demux->offset += demux->todrop;
1322         }
1323
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);
1333
1334           if (stream->samples[stream->sample_index].offset == demux->offset)
1335             break;
1336         }
1337
1338         if (stream == NULL)
1339           goto unknown_stream;
1340
1341         /* first buffer? */
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));
1347         }
1348
1349         /* get data */
1350         data = gst_adapter_take (demux->adapter, demux->neededbytes);
1351
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));
1357
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,
1364               stream->timescale);
1365
1366         } else {
1367           if (stream->sample_index == 0)
1368             GST_BUFFER_TIMESTAMP (outbuf) = 0;
1369         }
1370
1371         /* send buffer */
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);
1377
1378         stream->sample_index++;
1379
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);
1385
1386         if ((demux->neededbytes = next_entry_size (demux)) == -1)
1387           goto eos;
1388         break;
1389       }
1390       default:
1391         goto invalid_state;
1392     }
1393   }
1394
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);
1400   }
1401
1402 done:
1403   gst_object_unref (demux);
1404
1405   return ret;
1406
1407   /* ERRORS */
1408 unknown_stream:
1409   {
1410     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
1411     ret = GST_FLOW_ERROR;
1412     goto done;
1413   }
1414 eos:
1415   {
1416     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
1417     ret = GST_FLOW_UNEXPECTED;
1418     goto done;
1419   }
1420 invalid_state:
1421   {
1422     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1423         (NULL), ("qtdemuxer invalid state %d", demux->state));
1424     ret = GST_FLOW_ERROR;
1425     goto done;
1426   }
1427 }
1428
1429 static gboolean
1430 qtdemux_sink_activate (GstPad * sinkpad)
1431 {
1432   if (gst_pad_check_pull_range (sinkpad))
1433     return gst_pad_activate_pull (sinkpad, TRUE);
1434   else
1435     return gst_pad_activate_push (sinkpad, TRUE);
1436 }
1437
1438 static gboolean
1439 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
1440 {
1441   GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1442
1443   if (active) {
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);
1448   } else {
1449     demux->segment_running = FALSE;
1450     gst_pad_stop_task (sinkpad);
1451   }
1452
1453   return TRUE;
1454 }
1455
1456 static gboolean
1457 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
1458 {
1459   GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1460
1461   demux->pullbased = FALSE;
1462
1463   return TRUE;
1464 }
1465
1466 static void
1467 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
1468     QtDemuxStream * stream, GstTagList * list)
1469 {
1470   if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e')) {
1471     gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
1472
1473     stream->pad =
1474         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
1475     g_free (name);
1476     if ((stream->n_samples == 1) && (stream->samples[0].duration == 0)) {
1477       stream->fps_n = 0;
1478       stream->fps_d = 1;
1479     } else {
1480       stream->fps_n = stream->timescale;
1481       if (stream->samples[0].duration == 0)
1482         stream->fps_d = 1;
1483       else
1484         stream->fps_d = stream->samples[0].duration;
1485     }
1486
1487     if (stream->caps) {
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;
1494
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;
1499
1500         if (palette_data) {
1501           GstBuffer *palette = gst_buffer_new ();
1502
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);
1508         }
1509       }
1510     }
1511     qtdemux->n_video_streams++;
1512   } else {
1513     gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
1514
1515     stream->pad =
1516         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
1517     g_free (name);
1518     if (stream->caps) {
1519       gst_caps_set_simple (stream->caps,
1520           "rate", G_TYPE_INT, (int) stream->rate,
1521           "channels", G_TYPE_INT, stream->n_channels, NULL);
1522     }
1523     qtdemux->n_audio_streams++;
1524   }
1525
1526   gst_pad_use_fixed_caps (stream->pad);
1527
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);
1532
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);
1537
1538   GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
1539   gst_pad_set_caps (stream->pad, stream->caps);
1540
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);
1544   if (list) {
1545     gst_element_found_tags_for_pad (GST_ELEMENT (qtdemux), stream->pad, list);
1546   }
1547 }
1548
1549
1550 #define QT_CONTAINER 1
1551
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')
1623
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,
1641     int depth);
1642
1643 QtNodeType qt_node_types[] = {
1644   {FOURCC_moov, "movie", QT_CONTAINER,},
1645   {FOURCC_mvhd, "movie header", 0,
1646       qtdemux_dump_mvhd},
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,
1652       qtdemux_dump_tkhd},
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,
1658       qtdemux_dump_elst},
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,
1666       qtdemux_dump_mdhd},
1667   {FOURCC_hdlr, "handler reference", 0,
1668       qtdemux_dump_hdlr},
1669   {FOURCC_minf, "media information", QT_CONTAINER},
1670   {FOURCC_vmhd, "video media information", 0,
1671       qtdemux_dump_vmhd},
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,
1677       qtdemux_dump_dref},
1678   {FOURCC_stbl, "sample table", QT_CONTAINER},
1679   {FOURCC_stsd, "sample description", 0,
1680       qtdemux_dump_stsd},
1681   {FOURCC_stts, "time-to-sample", 0,
1682       qtdemux_dump_stts},
1683   {FOURCC_stss, "sync sample", 0,
1684       qtdemux_dump_stss},
1685   {FOURCC_stsc, "sample-to-chunk", 0,
1686       qtdemux_dump_stsc},
1687   {FOURCC_stsz, "sample size", 0,
1688       qtdemux_dump_stsz},
1689   {FOURCC_stco, "chunk offset", 0,
1690       qtdemux_dump_stco},
1691   {FOURCC_co64, "64-bit chunk offset", 0,
1692       qtdemux_dump_co64},
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,},
1728   {0, "unknown", 0},
1729 };
1730 static int n_qt_node_types = sizeof (qt_node_types) / sizeof (qt_node_types[0]);
1731
1732
1733 static void *
1734 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
1735 {
1736   return g_malloc (items * size);
1737 }
1738
1739 static void
1740 qtdemux_zfree (void *opaque, void *addr)
1741 {
1742   g_free (addr);
1743 }
1744
1745 static void *
1746 qtdemux_inflate (void *z_buffer, int z_length, int length)
1747 {
1748   void *buffer;
1749   z_stream *z;
1750   int ret;
1751
1752   z = g_new0 (z_stream, 1);
1753   z->zalloc = qtdemux_zalloc;
1754   z->zfree = qtdemux_zfree;
1755   z->opaque = NULL;
1756
1757   z->next_in = z_buffer;
1758   z->avail_in = z_length;
1759
1760   buffer = g_malloc (length);
1761   ret = inflateInit (z);
1762   while (z->avail_in > 0) {
1763     if (z->avail_out == 0) {
1764       length += 1024;
1765       buffer = realloc (buffer, length);
1766       z->next_out = buffer + z->total_out;
1767       z->avail_out = 1024;
1768     }
1769     ret = inflate (z, Z_SYNC_FLUSH);
1770     if (ret != Z_OK)
1771       break;
1772   }
1773   if (ret != Z_STREAM_END) {
1774     g_warning ("inflate() returned %d", ret);
1775   }
1776
1777   g_free (z);
1778   return buffer;
1779 }
1780
1781 static void
1782 qtdemux_parse_moov (GstQTDemux * qtdemux, void *buffer, int length)
1783 {
1784   GNode *cmov;
1785
1786   qtdemux->moov_node = g_node_new (buffer);
1787
1788   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
1789   qtdemux_parse (qtdemux, qtdemux->moov_node, buffer, length);
1790
1791   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
1792   if (cmov) {
1793     GNode *dcom;
1794     GNode *cmvd;
1795
1796     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
1797     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
1798
1799     if (QTDEMUX_FOURCC_GET (dcom->data + 8) == GST_MAKE_FOURCC ('z', 'l', 'i',
1800             'b')) {
1801       int uncompressed_length;
1802       int compressed_length;
1803       void *buf;
1804
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);
1808
1809       buf = qtdemux_inflate (cmvd->data + 12, compressed_length,
1810           uncompressed_length);
1811
1812       qtdemux->moov_node_compressed = qtdemux->moov_node;
1813       qtdemux->moov_node = g_node_new (buf);
1814
1815       qtdemux_parse (qtdemux, qtdemux->moov_node, buf, uncompressed_length);
1816     } else {
1817       GST_LOG ("unknown header compression type");
1818     }
1819   }
1820 }
1821
1822 static void
1823 qtdemux_parse (GstQTDemux * qtdemux, GNode * node, void *buffer, int length)
1824 {
1825   guint32 fourcc;
1826   guint32 node_length;
1827   QtNodeType *type;
1828   void *end;
1829
1830   GST_LOG ("qtdemux_parse buffer %p length %d", buffer, length);
1831
1832   node_length = QTDEMUX_GUINT32_GET (buffer);
1833   fourcc = QTDEMUX_FOURCC_GET (buffer + 4);
1834
1835   type = qtdemux_type_get (fourcc);
1836
1837   if (fourcc == 0 || node_length == 8)
1838     return;
1839
1840   GST_LOG ("parsing '%" GST_FOURCC_FORMAT "', length=%d",
1841       GST_FOURCC_ARGS (fourcc), node_length);
1842
1843   if (type->flags & QT_CONTAINER) {
1844     void *buf;
1845     guint32 len;
1846
1847     buf = buffer + 8;
1848     end = buffer + length;
1849     while (buf < end) {
1850       GNode *child;
1851
1852       if (buf + 8 >= end) {
1853         /* FIXME: get annoyed */
1854         GST_LOG ("buffer overrun");
1855       }
1856       len = QTDEMUX_GUINT32_GET (buf);
1857       if (len < 8) {
1858         GST_WARNING ("atom length too short (%d < 8)", len);
1859         break;
1860       }
1861       if (len > (end - buf)) {
1862         GST_WARNING ("atom length too long (%d > %d)", len, end - buf);
1863         break;
1864       }
1865
1866       child = g_node_new (buf);
1867       g_node_append (node, child);
1868       qtdemux_parse (qtdemux, child, buf, len);
1869
1870       buf += len;
1871     }
1872   } else {
1873     if (fourcc == FOURCC_stsd) {
1874       void *buf;
1875       guint32 len;
1876
1877       GST_DEBUG_OBJECT (qtdemux,
1878           "parsing stsd (sample table, sample description) atom");
1879       buf = buffer + 16;
1880       end = buffer + length;
1881       while (buf < end) {
1882         GNode *child;
1883
1884         if (buf + 8 >= end) {
1885           /* FIXME: get annoyed */
1886           GST_LOG ("buffer overrun");
1887         }
1888         len = QTDEMUX_GUINT32_GET (buf);
1889         if (len < 8) {
1890           GST_WARNING ("length too short (%d < 8)");
1891           break;
1892         }
1893         if (len > (end - buf)) {
1894           GST_WARNING ("length too long (%d > %d)", len, end - buf);
1895           break;
1896         }
1897
1898         child = g_node_new (buf);
1899         g_node_append (node, child);
1900         qtdemux_parse (qtdemux, child, buf, len);
1901
1902         buf += len;
1903       }
1904     } else if (fourcc == FOURCC_mp4a) {
1905       void *buf;
1906       guint32 len;
1907       guint32 version;
1908
1909       version = QTDEMUX_GUINT32_GET (buffer + 16);
1910       if (version == 0x00010000 || 1) {
1911         buf = buffer + 0x24;
1912         end = buffer + length;
1913
1914         while (buf < end) {
1915           GNode *child;
1916
1917           if (buf + 8 >= end) {
1918             /* FIXME: get annoyed */
1919             GST_LOG ("buffer overrun");
1920           }
1921           len = QTDEMUX_GUINT32_GET (buf);
1922           if (len < 8) {
1923             GST_WARNING ("length too short (%d < 8)");
1924             break;
1925           }
1926           if (len > (end - buf)) {
1927             GST_WARNING ("length too long (%d > %d)", len, end - buf);
1928             break;
1929           }
1930
1931           child = g_node_new (buf);
1932           g_node_append (node, child);
1933           qtdemux_parse (qtdemux, child, buf, len);
1934
1935           buf += len;
1936         }
1937       }
1938     } else if (fourcc == FOURCC_mp4v) {
1939       void *buf;
1940       guint32 len;
1941       guint32 version;
1942       int tlen;
1943
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) {
1948
1949         buf = buffer + 0x32;
1950         end = buffer + length;
1951
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);
1957         buf++;
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 */
1961         buf += 31;
1962         buf += 4;               /* and 4 bytes reserved */
1963
1964         gst_util_dump_mem (buf, end - buf);
1965         while (buf < end) {
1966           GNode *child;
1967
1968           if (buf + 8 >= end) {
1969             /* FIXME: get annoyed */
1970             GST_LOG ("buffer overrun");
1971           }
1972           len = QTDEMUX_GUINT32_GET (buf);
1973           if (len == 0)
1974             break;
1975           if (len < 8) {
1976             GST_WARNING ("length too short (%d < 8)");
1977             break;
1978           }
1979           if (len > (end - buf)) {
1980             GST_WARNING ("length too long (%d > %d)", len, end - buf);
1981             break;
1982           }
1983
1984           child = g_node_new (buf);
1985           g_node_append (node, child);
1986           qtdemux_parse (qtdemux, child, buf, len);
1987
1988           buf += len;
1989         }
1990       }
1991     } else if (fourcc == FOURCC_meta) {
1992       void *buf;
1993       guint32 len;
1994
1995       buf = buffer + 12;
1996       end = buffer + length;
1997       while (buf < end) {
1998         GNode *child;
1999
2000         if (buf + 8 >= end) {
2001           /* FIXME: get annoyed */
2002           GST_LOG ("buffer overrun");
2003         }
2004         len = QTDEMUX_GUINT32_GET (buf);
2005         if (len < 8) {
2006           GST_WARNING ("length too short (%d < 8)");
2007           break;
2008         }
2009         if (len > (end - buf)) {
2010           GST_WARNING ("length too long (%d > %d)", len, end - buf);
2011           break;
2012         }
2013
2014         child = g_node_new (buf);
2015         g_node_append (node, child);
2016         qtdemux_parse (qtdemux, child, buf, len);
2017
2018         buf += len;
2019       }
2020     } else if (fourcc == FOURCC_SVQ3) {
2021       void *buf;
2022       guint32 len;
2023       guint32 version;
2024       int tlen;
2025
2026       GST_LOG ("parsing in SVQ3");
2027       buf = buffer + 12;
2028       end = buffer + length;
2029       version = QTDEMUX_GUINT32_GET (buffer + 16);
2030       GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
2031       if (1 || version == 0x00000000) {
2032
2033         buf = buffer + 0x32;
2034         end = buffer + length;
2035
2036         tlen = QTDEMUX_GUINT8_GET (buf);
2037         GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
2038         buf++;
2039         GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
2040         buf += tlen;
2041         buf += 23;
2042
2043         gst_util_dump_mem (buf, end - buf);
2044         while (buf < end) {
2045           GNode *child;
2046
2047           if (buf + 8 >= end) {
2048             /* FIXME: get annoyed */
2049             GST_LOG ("buffer overrun");
2050           }
2051           len = QTDEMUX_GUINT32_GET (buf);
2052           if (len == 0)
2053             break;
2054           if (len < 8) {
2055             GST_WARNING ("length too short (%d < 8)");
2056             break;
2057           }
2058           if (len > (end - buf)) {
2059             GST_WARNING ("length too long (%d > %d)", len, end - buf);
2060             break;
2061           }
2062
2063           child = g_node_new (buf);
2064           g_node_append (node, child);
2065           qtdemux_parse (qtdemux, child, buf, len);
2066
2067           buf += len;
2068         }
2069       }
2070     }
2071 #if 0
2072     if (fourcc == FOURCC_cmvd) {
2073       int uncompressed_length;
2074       void *buf;
2075
2076       uncompressed_length = QTDEMUX_GUINT32_GET (buffer + 8);
2077       GST_LOG ("length = %d", uncompressed_length);
2078
2079       buf =
2080           qtdemux_inflate (buffer + 12, node_length - 12, uncompressed_length);
2081
2082       end = buf + uncompressed_length;
2083       while (buf < end) {
2084         GNode *child;
2085         guint32 len;
2086
2087         if (buf + 8 >= end) {
2088           /* FIXME: get annoyed */
2089           GST_LOG ("buffer overrun");
2090         }
2091         len = QTDEMUX_GUINT32_GET (buf);
2092
2093         child = g_node_new (buf);
2094         g_node_append (node, child);
2095         qtdemux_parse (qtdemux, child, buf, len);
2096
2097         buf += len;
2098       }
2099     }
2100 #endif
2101   }
2102 }
2103
2104 static QtNodeType *
2105 qtdemux_type_get (guint32 fourcc)
2106 {
2107   int i;
2108
2109   for (i = 0; i < n_qt_node_types; i++) {
2110     if (qt_node_types[i].fourcc == fourcc)
2111       return qt_node_types + i;
2112   }
2113
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;
2117 }
2118
2119 static gboolean
2120 qtdemux_node_dump_foreach (GNode * node, gpointer data)
2121 {
2122   void *buffer = node->data;
2123   guint32 node_length;
2124   guint32 fourcc;
2125   QtNodeType *type;
2126   int depth;
2127
2128   node_length = GST_READ_UINT32_BE (buffer);
2129   fourcc = GST_READ_UINT32_LE (buffer + 4);
2130
2131   type = qtdemux_type_get (fourcc);
2132
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);
2136
2137   if (type->dump)
2138     type->dump (data, buffer, depth);
2139
2140   return FALSE;
2141 }
2142
2143 static void
2144 qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node)
2145 {
2146   g_node_traverse (qtdemux->moov_node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
2147       qtdemux_node_dump_foreach, qtdemux);
2148 }
2149
2150 static void
2151 qtdemux_dump_mvhd (GstQTDemux * qtdemux, void *buffer, int depth)
2152 {
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));
2179 }
2180
2181 static void
2182 qtdemux_dump_tkhd (GstQTDemux * qtdemux, void *buffer, int depth)
2183 {
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));
2201
2202 }
2203
2204 static void
2205 qtdemux_dump_elst (GstQTDemux * qtdemux, void *buffer, int depth)
2206 {
2207   int i;
2208   int n;
2209
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));
2222   }
2223 }
2224
2225 static void
2226 qtdemux_dump_mdhd (GstQTDemux * qtdemux, void *buffer, int depth)
2227 {
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));
2242
2243 }
2244
2245 static void
2246 qtdemux_dump_hdlr (GstQTDemux * qtdemux, void *buffer, int depth)
2247 {
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));
2262
2263 }
2264
2265 static void
2266 qtdemux_dump_vmhd (GstQTDemux * qtdemux, void *buffer, int depth)
2267 {
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));
2272 }
2273
2274 static void
2275 qtdemux_dump_dref (GstQTDemux * qtdemux, void *buffer, int depth)
2276 {
2277   int n;
2278   int i;
2279   int offset;
2280
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);
2286   offset = 16;
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);
2293   }
2294 }
2295
2296 static void
2297 qtdemux_dump_stsd (GstQTDemux * qtdemux, void *buffer, int depth)
2298 {
2299   int i;
2300   int n;
2301   int offset;
2302
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);
2308   offset = 16;
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));
2316
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));
2346
2347     offset += QTDEMUX_GUINT32_GET (buffer + offset);
2348   }
2349 }
2350
2351 static void
2352 qtdemux_dump_stts (GstQTDemux * qtdemux, void *buffer, int depth)
2353 {
2354   int i;
2355   int n;
2356   int offset;
2357
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);
2363   offset = 16;
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));
2369
2370     offset += 8;
2371   }
2372 }
2373
2374 static void
2375 qtdemux_dump_stss (GstQTDemux * qtdemux, void *buffer, int depth)
2376 {
2377   int i;
2378   int n;
2379   int offset;
2380
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);
2386   offset = 16;
2387   for (i = 0; i < n; i++) {
2388     GST_LOG ("%*s    sample:        %u", depth, "",
2389         QTDEMUX_GUINT32_GET (buffer + offset));
2390
2391     offset += 4;
2392   }
2393 }
2394
2395 static void
2396 qtdemux_dump_stsc (GstQTDemux * qtdemux, void *buffer, int depth)
2397 {
2398   int i;
2399   int n;
2400   int offset;
2401
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);
2407   offset = 16;
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));
2415
2416     offset += 12;
2417   }
2418 }
2419
2420 static void
2421 qtdemux_dump_stsz (GstQTDemux * qtdemux, void *buffer, int depth)
2422 {
2423   //int i;
2424   int n;
2425   int offset;
2426   int sample_size;
2427
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);
2437     offset = 20;
2438 #if 0
2439     for (i = 0; i < n; i++) {
2440       GST_LOG ("%*s    sample size:   %u", depth, "",
2441           QTDEMUX_GUINT32_GET (buffer + offset));
2442
2443       offset += 4;
2444     }
2445 #endif
2446   }
2447 }
2448
2449 static void
2450 qtdemux_dump_stco (GstQTDemux * qtdemux, void *buffer, int depth)
2451 {
2452   //int i;
2453   int n;
2454   int offset;
2455
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);
2461   offset = 16;
2462 #if 0
2463   for (i = 0; i < n; i++) {
2464     GST_LOG ("%*s    chunk offset:  %08x", depth, "",
2465         QTDEMUX_GUINT32_GET (buffer + offset));
2466
2467     offset += 4;
2468   }
2469 #endif
2470 }
2471
2472 static void
2473 qtdemux_dump_co64 (GstQTDemux * qtdemux, void *buffer, int depth)
2474 {
2475   //int i;
2476   int n;
2477   int offset;
2478
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);
2484   offset = 16;
2485 #if 0
2486   for (i = 0; i < n; i++) {
2487     GST_LOG ("%*s    chunk offset:  %" G_GUINT64_FORMAT, depth, "",
2488         QTDEMUX_GUINT64_GET (buffer + offset));
2489
2490     offset += 8;
2491   }
2492 #endif
2493 }
2494
2495 static void
2496 qtdemux_dump_dcom (GstQTDemux * qtdemux, void *buffer, int depth)
2497 {
2498   GST_LOG ("%*s  compression type: %" GST_FOURCC_FORMAT, depth, "",
2499       GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 8)));
2500 }
2501
2502 static void
2503 qtdemux_dump_cmvd (GstQTDemux * qtdemux, void *buffer, int depth)
2504 {
2505   GST_LOG ("%*s  length: %d", depth, "", QTDEMUX_GUINT32_GET (buffer + 8));
2506 }
2507
2508 static void
2509 qtdemux_dump_unknown (GstQTDemux * qtdemux, void *buffer, int depth)
2510 {
2511   int len;
2512
2513   GST_LOG ("%*s  length: %d", depth, "", QTDEMUX_GUINT32_GET (buffer + 0));
2514
2515   len = QTDEMUX_GUINT32_GET (buffer + 0);
2516   gst_util_dump_mem (buffer, len);
2517
2518 }
2519
2520
2521 static GNode *
2522 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
2523 {
2524   GNode *child;
2525   void *buffer;
2526   guint32 child_fourcc;
2527
2528   for (child = g_node_first_child (node); child;
2529       child = g_node_next_sibling (child)) {
2530     buffer = child->data;
2531
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));
2535
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));
2539
2540     if (child_fourcc == fourcc) {
2541       return child;
2542     }
2543   }
2544   return NULL;
2545 }
2546
2547 static GNode *
2548 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
2549 {
2550   GNode *child;
2551   void *buffer;
2552   guint32 child_fourcc;
2553
2554   for (child = g_node_next_sibling (node); child;
2555       child = g_node_next_sibling (child)) {
2556     buffer = child->data;
2557
2558     child_fourcc = GST_READ_UINT32_LE (buffer + 4);
2559
2560     if (child_fourcc == fourcc) {
2561       return child;
2562     }
2563   }
2564   return NULL;
2565 }
2566
2567 static void qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak);
2568
2569 static void
2570 qtdemux_parse_tree (GstQTDemux * qtdemux)
2571 {
2572   GNode *mvhd;
2573   GNode *trak;
2574   GNode *udta;
2575
2576   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
2577   if (mvhd == NULL) {
2578     GNode *rmra, *rmda, *rdrf;
2579
2580     rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
2581     if (rmra) {
2582       rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
2583       if (rmra) {
2584         rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
2585         if (rdrf) {
2586           GstStructure *s;
2587           GstMessage *msg;
2588
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);
2594           return;
2595         }
2596       }
2597     }
2598
2599     GST_LOG ("No mvhd node found.");
2600     return;
2601   }
2602
2603   qtdemux->timescale = QTDEMUX_GUINT32_GET (mvhd->data + 20);
2604   qtdemux->duration = QTDEMUX_GUINT32_GET (mvhd->data + 24);
2605
2606   GST_INFO_OBJECT (qtdemux, "timescale: %d", qtdemux->timescale);
2607   GST_INFO_OBJECT (qtdemux, "duration: %d", qtdemux->duration);
2608
2609   if (qtdemux->timescale != 0 && qtdemux->duration != 0) {
2610     gint64 duration;
2611
2612     duration = gst_util_uint64_scale_int (qtdemux->duration,
2613         GST_SECOND, qtdemux->timescale);
2614
2615     gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
2616   }
2617
2618   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
2619   qtdemux_parse_trak (qtdemux, trak);
2620
2621 /*  trak = qtdemux_tree_get_sibling_by_type(trak, FOURCC_trak);
2622   if(trak)qtdemux_parse_trak(qtdemux, trak);*/
2623
2624   /* kid pads */
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));
2628
2629   /* tags */
2630   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
2631   if (udta) {
2632     qtdemux_parse_udta (qtdemux, udta);
2633
2634     if (qtdemux->tag_list) {
2635       GST_DEBUG_OBJECT (qtdemux,
2636           "calling gst_element_found_tags with %" GST_PTR_FORMAT,
2637           qtdemux->tag_list);
2638       gst_element_found_tags (GST_ELEMENT (qtdemux), qtdemux->tag_list);
2639       qtdemux->tag_list = NULL;
2640     }
2641   } else {
2642     GST_LOG ("No udta node found.");
2643   }
2644 }
2645
2646 static void
2647 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
2648 {
2649   int offset;
2650   GNode *tkhd;
2651   GNode *mdia;
2652   GNode *mdhd;
2653   GNode *hdlr;
2654   GNode *minf;
2655   GNode *stbl;
2656   GNode *stsd;
2657   GNode *stsc;
2658   GNode *stss;
2659   GNode *stsz;
2660   GNode *stco;
2661   GNode *co64;
2662   GNode *stts;
2663   GNode *mp4a;
2664   GNode *mp4v;
2665   GNode *wave;
2666   GNode *esds;
2667   int n_samples;
2668   QtDemuxSample *samples;
2669   int n_samples_per_chunk;
2670   int index;
2671   int i, j, k;
2672   QtDemuxStream *stream;
2673   int n_sample_times;
2674   guint64 timestamp;
2675   int sample_size;
2676   int sample_index;
2677   GstTagList *list = NULL;
2678   const gchar *codec = NULL;
2679
2680   tkhd = qtdemux_tree_get_child_by_type (trak, FOURCC_tkhd);
2681   g_return_if_fail (tkhd);
2682
2683   GST_LOG ("track[tkhd] version/flags: 0x%08x",
2684       QTDEMUX_GUINT32_GET (tkhd->data + 8));
2685
2686   /* track duration? */
2687
2688   mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia);
2689   g_assert (mdia);
2690
2691   mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd);
2692   g_assert (mdhd);
2693
2694   /* new streams always need a discont */
2695   stream = g_new0 (QtDemuxStream, 1);
2696   stream->discont = TRUE;
2697
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));
2701
2702   /* HACK:
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);
2713     g_free (stream);
2714     return;
2715   }
2716
2717   hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr);
2718   g_assert (hdlr);
2719
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)));
2724
2725   stream->subtype = QTDEMUX_FOURCC_GET (hdlr->data + 16);
2726
2727   minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf);
2728   g_assert (minf);
2729
2730   stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl);
2731   g_assert (stbl);
2732
2733   stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd);
2734   g_assert (stsd);
2735
2736   if (stream->subtype == FOURCC_vide) {
2737     guint32 fourcc;
2738
2739     offset = 16;
2740     GST_LOG ("st type:          %" GST_FOURCC_FORMAT,
2741         GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd->data + offset + 4)));
2742
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);
2749
2750     GST_LOG ("frame count:   %u",
2751         QTDEMUX_GUINT16_GET (stsd->data + offset + 48));
2752
2753     stream->fourcc = fourcc = QTDEMUX_FOURCC_GET (stsd->data + offset + 4);
2754     stream->caps = qtdemux_video_caps (qtdemux, fourcc, stsd->data, &codec);
2755     if (codec) {
2756       list = gst_tag_list_new ();
2757       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
2758           GST_TAG_VIDEO_CODEC, codec, NULL);
2759     }
2760
2761     esds = NULL;
2762     mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4v);
2763     if (mp4v)
2764       esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
2765
2766     if (esds) {
2767       gst_qtdemux_handle_esds (qtdemux, stream, esds);
2768     } else {
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;
2773
2774         /* find avcC */
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);
2781         }
2782
2783         /* parse, if found */
2784         if (len > 0x8 &&
2785             QTDEMUX_FOURCC_GET (stsddata + 0x4) ==
2786             GST_MAKE_FOURCC ('a', 'v', 'c', 'C')) {
2787           GstBuffer *buf;
2788           gint size;
2789
2790           if (QTDEMUX_GUINT32_GET (stsddata) < len)
2791             size = QTDEMUX_GUINT32_GET (stsddata) - 0x8;
2792           else
2793             size = len - 0x8;
2794
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);
2800         }
2801       } else if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2802           GST_MAKE_FOURCC ('S', 'V', 'Q', '3')) {
2803         GstBuffer *buf;
2804         gint len = QTDEMUX_GUINT32_GET (stsd->data);
2805
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')) {
2813         GstBuffer *buf;
2814         gint len = QTDEMUX_GUINT32_GET (stsd->data);
2815
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),
2825             NULL);
2826       }
2827     }
2828
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)),
2832         stream->caps);
2833   } else if (stream->subtype == FOURCC_soun) {
2834     int version, samplesize;
2835     guint32 fourcc;
2836     int len;
2837
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)));
2841
2842     stream->fourcc = fourcc = QTDEMUX_FOURCC_GET (stsd->data + 16 + 4);
2843     offset = 32;
2844
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);
2863
2864     offset = 52;
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;
2877       offset = 68;
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;
2882
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;
2894       }
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;
2900       }
2901     } else {
2902       GST_WARNING ("unknown version %08x", version);
2903     }
2904
2905     stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
2906         &codec);
2907
2908     if (codec) {
2909       list = gst_tag_list_new ();
2910       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
2911           GST_TAG_AUDIO_CODEC, codec, NULL);
2912     }
2913
2914     mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
2915     wave = NULL;
2916     if (mp4a)
2917       wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
2918
2919     esds = NULL;
2920     if (wave)
2921       esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
2922     else if (mp4a)
2923       esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
2924
2925     if (esds) {
2926       gst_qtdemux_handle_esds (qtdemux, stream, esds);
2927 #if 0
2928       GstBuffer *buffer;
2929       int len = QTDEMUX_GUINT32_GET (esds->data);
2930
2931       buffer = gst_buffer_new_and_alloc (len - 8);
2932       memcpy (GST_BUFFER_DATA (buffer), esds->data + 8, len - 8);
2933
2934       gst_caps_set_simple (stream->caps, "codec_data",
2935           GST_TYPE_BUFFER, buffer, NULL);
2936 #endif
2937     } else {
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);
2941
2942         if (len > 0x4C) {
2943           GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
2944
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);
2950         }
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);
2956
2957         if (len > 0x34) {
2958           GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
2959
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);
2965         }
2966         gst_caps_set_simple (stream->caps,
2967             "samplesize", G_TYPE_INT, samplesize, NULL);
2968       }
2969     }
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)),
2973         stream->caps);
2974   } else {
2975     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
2976         GST_FOURCC_ARGS (stream->subtype));
2977     g_free (stream);
2978     return;
2979   }
2980
2981   /* sample to chunk */
2982   stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc);
2983   g_assert (stsc);
2984   /* sample size */
2985   stsz = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsz);
2986   g_assert (stsz);
2987   /* chunk offsets */
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);
2991   /* sample time */
2992   stts = qtdemux_tree_get_child_by_type (stbl, FOURCC_stts);
2993   g_assert (stts);
2994   /* sample sync, can be NULL */
2995   stss = qtdemux_tree_get_child_by_type (stbl, FOURCC_stss);
2996
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",
3001         n_samples);
3002     stream->n_samples = n_samples;
3003     samples = g_malloc (sizeof (QtDemuxSample) * n_samples);
3004     stream->samples = samples;
3005
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;
3011     }
3012     n_samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 12);
3013     index = 0;
3014     offset = 16;
3015     for (i = 0; i < n_samples_per_chunk; i++) {
3016       int first_chunk, last_chunk;
3017       int samples_per_chunk;
3018
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;
3022       } else {
3023         last_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 12) - 1;
3024       }
3025       samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 4);
3026
3027       for (j = first_chunk; j < last_chunk; j++) {
3028         guint64 chunk_offset;
3029
3030         if (stco) {
3031           chunk_offset = QTDEMUX_GUINT32_GET (stco->data + 16 + j * 4);
3032         } else {
3033           chunk_offset = QTDEMUX_GUINT64_GET (co64->data + 16 + j * 8);
3034         }
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;
3041           index++;
3042           if (index >= n_samples)
3043             goto done;
3044         }
3045       }
3046     }
3047   done:
3048
3049     n_sample_times = QTDEMUX_GUINT32_GET (stts->data + 12);
3050     timestamp = 0;
3051     index = 0;
3052     for (i = 0; i < n_sample_times; i++) {
3053       int n;
3054       int duration;
3055       guint64 time;
3056
3057       n = QTDEMUX_GUINT32_GET (stts->data + 16 + 8 * i);
3058       duration = QTDEMUX_GUINT32_GET (stts->data + 16 + 8 * i + 4);
3059       time =
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;
3065         timestamp += time;
3066         index++;
3067       }
3068     }
3069     if (stss) {
3070       /* mark keyframes */
3071       guint32 n_sample_syncs;
3072
3073       n_sample_syncs = QTDEMUX_GUINT32_GET (stss->data + 12);
3074       if (n_sample_syncs == 0) {
3075         stream->all_keyframe = TRUE;
3076       } else {
3077         offset = 16;
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;
3082           offset += 4;
3083         }
3084       }
3085     } else {
3086       /* no stss, all samples are keyframes */
3087       stream->all_keyframe = TRUE;
3088     }
3089   } else {
3090     guint64 timestamp = 0;
3091
3092     GST_DEBUG_OBJECT (qtdemux,
3093         "stsz sample_size %d != 0, treating chunks as samples", sample_size);
3094
3095     /* treat chunks as samples */
3096     if (stco) {
3097       n_samples = QTDEMUX_GUINT32_GET (stco->data + 12);
3098     } else {
3099       n_samples = QTDEMUX_GUINT32_GET (co64->data + 12);
3100     }
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;
3105
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);
3108     offset = 16;
3109     sample_index = 0;
3110     for (i = 0; i < n_samples_per_chunk; i++) {
3111       int first_chunk, last_chunk;
3112       int samples_per_chunk;
3113
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
3117        * INT_MAX */
3118       if (i == n_samples_per_chunk - 1) {
3119         last_chunk = INT_MAX;
3120       } else {
3121         last_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 12) - 1;
3122       }
3123       samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 4);
3124
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);
3128
3129       for (j = first_chunk; j < last_chunk; j++) {
3130         guint64 chunk_offset;
3131
3132         if (j >= n_samples)
3133           goto done2;
3134         if (stco) {
3135           chunk_offset = QTDEMUX_GUINT32_GET (stco->data + 16 + j * 4);
3136           GST_LOG_OBJECT (qtdemux, "stco chunk %d offset %x", j, chunk_offset);
3137         } else {
3138           chunk_offset = QTDEMUX_GUINT64_GET (co64->data + 16 + j * 8);
3139           GST_LOG_OBJECT (qtdemux, "co64 chunk %d offset %" G_GUINT64_FORMAT, j,
3140               chunk_offset);
3141         }
3142         GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld",
3143             j, chunk_offset);
3144         samples[j].chunk = j;
3145         samples[j].offset = chunk_offset;
3146         if (stream->samples_per_packet * stream->compression != 0)
3147           samples[j].size =
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;
3152         else
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;
3158
3159         if (stream->rate > 0) {
3160           timestamp += gst_util_uint64_scale_int (samples_per_chunk,
3161               GST_SECOND, stream->rate);
3162         }
3163 #if 0
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);
3169 #endif
3170         samples[j].sample_index = sample_index;
3171         sample_index += samples_per_chunk;
3172       }
3173     }
3174   }
3175 done2:
3176 #if 0
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);
3181     if (i > 10)
3182       break;
3183   }
3184 #endif
3185   gst_qtdemux_add_stream (qtdemux, stream, list);
3186 }
3187
3188 static void
3189 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
3190 {
3191   GNode *meta;
3192   GNode *ilst;
3193   GNode *node;
3194
3195   meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
3196   if (meta == NULL) {
3197     GST_LOG ("no meta");
3198     return;
3199   }
3200
3201   ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
3202   if (ilst == NULL) {
3203     GST_LOG ("no ilst");
3204     return;
3205   }
3206
3207   GST_DEBUG_OBJECT (qtdemux, "new tag list");
3208   qtdemux->tag_list = gst_tag_list_new ();
3209
3210   node = qtdemux_tree_get_child_by_type (ilst, FOURCC__nam);
3211   if (node) {
3212     qtdemux_tag_add_str (qtdemux, GST_TAG_TITLE, node);
3213   }
3214
3215   node = qtdemux_tree_get_child_by_type (ilst, FOURCC__ART);
3216   if (node) {
3217     qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
3218   } else {
3219     node = qtdemux_tree_get_child_by_type (ilst, FOURCC__wrt);
3220     if (node) {
3221       qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
3222     } else {
3223       node = qtdemux_tree_get_child_by_type (ilst, FOURCC__grp);
3224       if (node) {
3225         qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
3226       }
3227     }
3228   }
3229
3230   node = qtdemux_tree_get_child_by_type (ilst, FOURCC__alb);
3231   if (node) {
3232     qtdemux_tag_add_str (qtdemux, GST_TAG_ALBUM, node);
3233   }
3234
3235   node = qtdemux_tree_get_child_by_type (ilst, FOURCC_trkn);
3236   if (node) {
3237     qtdemux_tag_add_num (qtdemux, GST_TAG_TRACK_NUMBER,
3238         GST_TAG_TRACK_COUNT, node);
3239   }
3240
3241   node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disc);
3242   if (node) {
3243     qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER,
3244         GST_TAG_ALBUM_VOLUME_COUNT, node);
3245   } else {
3246     node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disk);
3247     if (node) {
3248       qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER,
3249           GST_TAG_ALBUM_VOLUME_COUNT, node);
3250     }
3251   }
3252
3253   node = qtdemux_tree_get_child_by_type (ilst, FOURCC_gnre);
3254   if (node) {
3255     qtdemux_tag_add_gnre (qtdemux, GST_TAG_GENRE, node);
3256   } else {
3257     node = qtdemux_tree_get_child_by_type (ilst, FOURCC__gen);
3258     if (node) {
3259       qtdemux_tag_add_str (qtdemux, GST_TAG_GENRE, node);
3260     }
3261   }
3262 }
3263
3264 static void
3265 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag, GNode * node)
3266 {
3267   GNode *data;
3268   char *s;
3269   int len;
3270   int type;
3271
3272   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3273   if (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);
3280       g_free (s);
3281     }
3282   }
3283 }
3284
3285 static void
3286 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
3287     const char *tag2, GNode * node)
3288 {
3289   GNode *data;
3290   int len;
3291   int type;
3292   int n1, n2;
3293
3294   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3295   if (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);
3304     }
3305   }
3306 }
3307
3308 static void
3309 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, GNode * node)
3310 {
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"
3341   };
3342   GNode *data;
3343   int len;
3344   int type;
3345   int n;
3346
3347   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3348   if (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);
3357       }
3358     }
3359   }
3360 }
3361
3362 /* taken from ffmpeg */
3363 static unsigned int
3364 get_size (guint8 * ptr, guint8 ** end)
3365 {
3366   int count = 4;
3367   int len = 0;
3368
3369   while (count--) {
3370     int c = *ptr;
3371
3372     ptr++;
3373     len = (len << 7) | (c & 0x7f);
3374     if (!(c & 0x80))
3375       break;
3376   }
3377   if (end)
3378     *end = ptr;
3379   return len;
3380 }
3381
3382 static void
3383 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
3384     GNode * esds)
3385 {
3386   int len = QTDEMUX_GUINT32_GET (esds->data);
3387   guint8 *ptr = esds->data;
3388   guint8 *end = ptr + len;
3389   int tag;
3390   guint8 *data_ptr = NULL;
3391   int data_len = 0;
3392
3393   gst_util_dump_mem (ptr, len);
3394   ptr += 8;
3395   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QTDEMUX_GUINT32_GET (ptr));
3396   ptr += 4;
3397   while (ptr < end) {
3398     tag = QTDEMUX_GUINT8_GET (ptr);
3399     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
3400     ptr++;
3401     len = get_size (ptr, &ptr);
3402     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
3403
3404     switch (tag) {
3405       case 0x03:
3406         GST_DEBUG_OBJECT (qtdemux, "ID %04x", QTDEMUX_GUINT16_GET (ptr));
3407         GST_DEBUG_OBJECT (qtdemux, "priority %04x",
3408             QTDEMUX_GUINT8_GET (ptr + 2));
3409         ptr += 3;
3410         break;
3411       case 0x04:
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));
3422         ptr += 13;
3423         break;
3424       case 0x05:
3425         GST_DEBUG_OBJECT (qtdemux, "data:");
3426         gst_util_dump_mem (ptr, len);
3427         data_ptr = ptr;
3428         data_len = len;
3429         ptr += len;
3430         break;
3431       case 0x06:
3432         GST_DEBUG_OBJECT (qtdemux, "data %02x", QTDEMUX_GUINT8_GET (ptr));
3433         ptr += 1;
3434         break;
3435       default:
3436         GST_ERROR ("parse error");
3437     }
3438   }
3439
3440   if (data_ptr) {
3441     GstBuffer *buffer;
3442
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);
3446
3447     gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
3448         buffer, NULL);
3449     gst_buffer_unref (buffer);
3450   }
3451 }
3452
3453 #define _codec(name) \
3454   do { \
3455     if (codec_name) { \
3456       *codec_name = name; \
3457     } \
3458   } while (0)
3459
3460 static GstCaps *
3461 qtdemux_video_caps (GstQTDemux * qtdemux, guint32 fourcc,
3462     const guint8 * stsd_data, const gchar ** codec_name)
3463 {
3464   switch (fourcc) {
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'):
3507       _codec ("H.263");
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'):
3523       _codec ("DivX 3");
3524       return gst_caps_from_string ("video/x-divx," "divxversion= (int) 3");
3525     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
3526       _codec ("DivX 4");
3527       return gst_caps_from_string ("video/x-divx," "divxversion= (int) 4");
3528
3529     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
3530       _codec ("DivX 5");
3531       return gst_caps_from_string ("video/x-divx," "divxversion= (int) 5");
3532     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
3533       _codec ("Cinepak");
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'):
3557       _codec ("VP3");
3558       return gst_caps_from_string ("video/x-vp3");
3559     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
3560     default:
3561 #if 0
3562       g_critical ("Don't know how to convert fourcc '%" GST_FOURCC_FORMAT
3563           "' to caps", GST_FOURCC_ARGS (fourcc));
3564       return NULL;
3565 #endif
3566       {
3567         char *s;
3568
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);
3572       }
3573   }
3574 }
3575
3576 static GstCaps *
3577 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
3578     guint32 fourcc, const guint8 * data, int len, const gchar ** codec_name)
3579 {
3580   switch (fourcc) {
3581 #if 0
3582     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
3583       return NULL;              /*gst_caps_from_string ("audio/raw"); */
3584 #endif
3585     case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
3586       _codec ("Raw 8-bit PCM audio");
3587       /* FIXME */
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");
3595       } else {
3596         _codec ("Raw 16-bit PCM audio");
3597         /* FIXME */
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");
3602       }
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");
3608       } else {
3609         _codec ("Raw 16-bit PCM audio");
3610         /* FIXME */
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");
3615       }
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");
3626       /* FIXME */
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");
3633       /* FIXME */
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");
3640       /* FIXME */
3641       return gst_caps_from_string ("audio/x-mulaw");
3642     case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
3643       _codec ("A-law audio");
3644       /* FIXME */
3645       return gst_caps_from_string ("audio/x-alaw");
3646     case 0x6d730002:
3647       _codec ("Microsoft ADPCM");
3648       /* Microsoft ADPCM-ACM code 2 */
3649       return gst_caps_from_string ("audio/x-adpcm, "
3650           "layout = (string) microsoft");
3651     case 0x6d730011:
3652     case 0x6d730017:
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");
3657     case 0x6d730055:
3658       /* MPEG layer 3, CBR only (pre QT4.1) */
3659     case 0x5500736d:
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'):
3666       _codec ("MACE-3");
3667       return gst_caps_from_string ("audio/x-mace, " "maceversion = (int) 3");
3668     case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
3669       _codec ("MACE-6");
3670       return gst_caps_from_string ("audio/x-mace, " "maceversion = (int) 6");
3671     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
3672       /* ogg/vorbis */
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) */
3684       if (data) {
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);
3689       } else {
3690         return gst_caps_new_simple ("audio/x-qdm2", NULL);
3691       }
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'):
3706       /* ? */
3707     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
3708       /* QDesign music */
3709     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
3710       /* QUALCOMM PureVoice */
3711     default:
3712 #if 0
3713       g_critical ("Don't know how to convert fourcc '%" GST_FOURCC_FORMAT
3714           "' to caps", GST_FOURCC_ARGS (fourcc));
3715       return NULL;
3716 #endif
3717       {
3718         char *s;
3719
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);
3723       }
3724   }
3725 }