4637cd232069b3429580350edf95e69d97273bb2
[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   "QuickTime Demuxer",
123   "Codec/Demuxer",
124   "Demultiplex a QuickTime file into audio and video streams",
125   "David Schleef <ds@schleef.org>"
126 };
127
128 static GstStaticPadTemplate gst_qtdemux_sink_template =
129     GST_STATIC_PAD_TEMPLATE ("sink",
130     GST_PAD_SINK,
131     GST_PAD_ALWAYS,
132     GST_STATIC_CAPS ("video/quicktime; audio/x-m4a; application/x-3gp")
133     );
134
135 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
136 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
137     GST_PAD_SRC,
138     GST_PAD_SOMETIMES,
139     GST_STATIC_CAPS_ANY);
140
141 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
142 GST_STATIC_PAD_TEMPLATE ("video_%02d",
143     GST_PAD_SRC,
144     GST_PAD_SOMETIMES,
145     GST_STATIC_CAPS_ANY);
146
147 static GstElementClass *parent_class = NULL;
148
149 /* we could generate these programmatically, but the generation code
150  * is only a few lines shorter than the tables, and much uglier */
151 static const guint32 ff_qt_default_palette_256[256] = {
152   0xFFFFFF, 0xFFFFCC, 0xFFFF99, 0xFFFF66, 0xFFFF33, 0xFFFF00,
153   0xFFCCFF, 0xFFCCCC, 0xFFCC99, 0xFFCC66, 0xFFCC33, 0xFFCC00,
154   0xFF99FF, 0xFF99CC, 0xFF9999, 0xFF9966, 0xFF9933, 0xFF9900,
155   0xFF66FF, 0xFF66CC, 0xFF6699, 0xFF6666, 0xFF6633, 0xFF6600,
156   0xFF33FF, 0xFF33CC, 0xFF3399, 0xFF3366, 0xFF3333, 0xFF3300,
157   0xFF00FF, 0xFF00CC, 0xFF0099, 0xFF0066, 0xFF0033, 0xFF0000,
158   0xCCFFFF, 0xCCFFCC, 0xCCFF99, 0xCCFF66, 0xCCFF33, 0xCCFF00,
159   0xCCCCFF, 0xCCCCCC, 0xCCCC99, 0xCCCC66, 0xCCCC33, 0xCCCC00,
160   0xCC99FF, 0xCC99CC, 0xCC9999, 0xCC9966, 0xCC9933, 0xCC9900,
161   0xCC66FF, 0xCC66CC, 0xCC6699, 0xCC6666, 0xCC6633, 0xCC6600,
162   0xCC33FF, 0xCC33CC, 0xCC3399, 0xCC3366, 0xCC3333, 0xCC3300,
163   0xCC00FF, 0xCC00CC, 0xCC0099, 0xCC0066, 0xCC0033, 0xCC0000,
164   0x99FFFF, 0x99FFCC, 0x99FF99, 0x99FF66, 0x99FF33, 0x99FF00,
165   0x99CCFF, 0x99CCCC, 0x99CC99, 0x99CC66, 0x99CC33, 0x99CC00,
166   0x9999FF, 0x9999CC, 0x999999, 0x999966, 0x999933, 0x999900,
167   0x9966FF, 0x9966CC, 0x996699, 0x996666, 0x996633, 0x996600,
168   0x9933FF, 0x9933CC, 0x993399, 0x993366, 0x993333, 0x993300,
169   0x9900FF, 0x9900CC, 0x990099, 0x990066, 0x990033, 0x990000,
170   0x66FFFF, 0x66FFCC, 0x66FF99, 0x66FF66, 0x66FF33, 0x66FF00,
171   0x66CCFF, 0x66CCCC, 0x66CC99, 0x66CC66, 0x66CC33, 0x66CC00,
172   0x6699FF, 0x6699CC, 0x669999, 0x669966, 0x669933, 0x669900,
173   0x6666FF, 0x6666CC, 0x666699, 0x666666, 0x666633, 0x666600,
174   0x6633FF, 0x6633CC, 0x663399, 0x663366, 0x663333, 0x663300,
175   0x6600FF, 0x6600CC, 0x660099, 0x660066, 0x660033, 0x660000,
176   0x33FFFF, 0x33FFCC, 0x33FF99, 0x33FF66, 0x33FF33, 0x33FF00,
177   0x33CCFF, 0x33CCCC, 0x33CC99, 0x33CC66, 0x33CC33, 0x33CC00,
178   0x3399FF, 0x3399CC, 0x339999, 0x339966, 0x339933, 0x339900,
179   0x3366FF, 0x3366CC, 0x336699, 0x336666, 0x336633, 0x336600,
180   0x3333FF, 0x3333CC, 0x333399, 0x333366, 0x333333, 0x333300,
181   0x3300FF, 0x3300CC, 0x330099, 0x330066, 0x330033, 0x330000,
182   0x00FFFF, 0x00FFCC, 0x00FF99, 0x00FF66, 0x00FF33, 0x00FF00,
183   0x00CCFF, 0x00CCCC, 0x00CC99, 0x00CC66, 0x00CC33, 0x00CC00,
184   0x0099FF, 0x0099CC, 0x009999, 0x009966, 0x009933, 0x009900,
185   0x0066FF, 0x0066CC, 0x006699, 0x006666, 0x006633, 0x006600,
186   0x0033FF, 0x0033CC, 0x003399, 0x003366, 0x003333, 0x003300,
187   0x0000FF, 0x0000CC, 0x000099, 0x000066, 0x000033, 0xEE0000,
188   0xDD0000, 0xBB0000, 0xAA0000, 0x880000, 0x770000, 0x550000,
189   0x440000, 0x220000, 0x110000, 0x00EE00, 0x00DD00, 0x00BB00,
190   0x00AA00, 0x008800, 0x007700, 0x005500, 0x004400, 0x002200,
191   0x001100, 0x0000EE, 0x0000DD, 0x0000BB, 0x0000AA, 0x000088,
192   0x000077, 0x000055, 0x000044, 0x000022, 0x000011, 0xEEEEEE,
193   0xDDDDDD, 0xBBBBBB, 0xAAAAAA, 0x888888, 0x777777, 0x555555,
194   0x444444, 0x222222, 0x111111, 0x000000
195 };
196
197 static const guint32 ff_qt_grayscale_palette_256[256] = {
198   0xffffff, 0xfefefe, 0xfdfdfd, 0xfcfcfc, 0xfbfbfb, 0xfafafa, 0xf9f9f9,
199   0xf8f8f8, 0xf7f7f7, 0xf6f6f6, 0xf5f5f5, 0xf4f4f4, 0xf3f3f3, 0xf2f2f2,
200   0xf1f1f1, 0xf0f0f0, 0xefefef, 0xeeeeee, 0xededed, 0xececec, 0xebebeb,
201   0xeaeaea, 0xe9e9e9, 0xe8e8e8, 0xe7e7e7, 0xe6e6e6, 0xe5e5e5, 0xe4e4e4,
202   0xe3e3e3, 0xe2e2e2, 0xe1e1e1, 0xe0e0e0, 0xdfdfdf, 0xdedede, 0xdddddd,
203   0xdcdcdc, 0xdbdbdb, 0xdadada, 0xd9d9d9, 0xd8d8d8, 0xd7d7d7, 0xd6d6d6,
204   0xd5d5d5, 0xd4d4d4, 0xd3d3d3, 0xd2d2d2, 0xd1d1d1, 0xd0d0d0, 0xcfcfcf,
205   0xcecece, 0xcdcdcd, 0xcccccc, 0xcbcbcb, 0xcacaca, 0xc9c9c9, 0xc8c8c8,
206   0xc7c7c7, 0xc6c6c6, 0xc5c5c5, 0xc4c4c4, 0xc3c3c3, 0xc2c2c2, 0xc1c1c1,
207   0xc0c0c0, 0xbfbfbf, 0xbebebe, 0xbdbdbd, 0xbcbcbc, 0xbbbbbb, 0xbababa,
208   0xb9b9b9, 0xb8b8b8, 0xb7b7b7, 0xb6b6b6, 0xb5b5b5, 0xb4b4b4, 0xb3b3b3,
209   0xb2b2b2, 0xb1b1b1, 0xb0b0b0, 0xafafaf, 0xaeaeae, 0xadadad, 0xacacac,
210   0xababab, 0xaaaaaa, 0xa9a9a9, 0xa8a8a8, 0xa7a7a7, 0xa6a6a6, 0xa5a5a5,
211   0xa4a4a4, 0xa3a3a3, 0xa2a2a2, 0xa1a1a1, 0xa0a0a0, 0x9f9f9f, 0x9e9e9e,
212   0x9d9d9d, 0x9c9c9c, 0x9b9b9b, 0x9a9a9a, 0x999999, 0x989898, 0x979797,
213   0x969696, 0x959595, 0x949494, 0x939393, 0x929292, 0x919191, 0x909090,
214   0x8f8f8f, 0x8e8e8e, 0x8d8d8d, 0x8c8c8c, 0x8b8b8b, 0x8a8a8a, 0x898989,
215   0x888888, 0x878787, 0x868686, 0x858585, 0x848484, 0x838383, 0x828282,
216   0x818181, 0x808080, 0x7f7f7f, 0x7e7e7e, 0x7d7d7d, 0x7c7c7c, 0x7b7b7b,
217   0x7a7a7a, 0x797979, 0x787878, 0x777777, 0x767676, 0x757575, 0x747474,
218   0x737373, 0x727272, 0x717171, 0x707070, 0x6f6f6f, 0x6e6e6e, 0x6d6d6d,
219   0x6c6c6c, 0x6b6b6b, 0x6a6a6a, 0x696969, 0x686868, 0x676767, 0x666666,
220   0x656565, 0x646464, 0x636363, 0x626262, 0x616161, 0x606060, 0x5f5f5f,
221   0x5e5e5e, 0x5d5d5d, 0x5c5c5c, 0x5b5b5b, 0x5a5a5a, 0x595959, 0x585858,
222   0x575757, 0x565656, 0x555555, 0x545454, 0x535353, 0x525252, 0x515151,
223   0x505050, 0x4f4f4f, 0x4e4e4e, 0x4d4d4d, 0x4c4c4c, 0x4b4b4b, 0x4a4a4a,
224   0x494949, 0x484848, 0x474747, 0x464646, 0x454545, 0x444444, 0x434343,
225   0x424242, 0x414141, 0x404040, 0x3f3f3f, 0x3e3e3e, 0x3d3d3d, 0x3c3c3c,
226   0x3b3b3b, 0x3a3a3a, 0x393939, 0x383838, 0x373737, 0x363636, 0x353535,
227   0x343434, 0x333333, 0x323232, 0x313131, 0x303030, 0x2f2f2f, 0x2e2e2e,
228   0x2d2d2d, 0x2c2c2c, 0x2b2b2b, 0x2a2a2a, 0x292929, 0x282828, 0x272727,
229   0x262626, 0x252525, 0x242424, 0x232323, 0x222222, 0x212121, 0x202020,
230   0x1f1f1f, 0x1e1e1e, 0x1d1d1d, 0x1c1c1c, 0x1b1b1b, 0x1a1a1a, 0x191919,
231   0x181818, 0x171717, 0x161616, 0x151515, 0x141414, 0x131313, 0x121212,
232   0x111111, 0x101010, 0x0f0f0f, 0x0e0e0e, 0x0d0d0d, 0x0c0c0c, 0x0b0b0b,
233   0x0a0a0a, 0x090909, 0x080808, 0x070707, 0x060606, 0x050505, 0x040404,
234   0x030303, 0x020202, 0x010101, 0x000000
235 };
236
237 static void gst_qtdemux_class_init (GstQTDemuxClass * klass);
238 static void gst_qtdemux_base_init (GstQTDemuxClass * klass);
239 static void gst_qtdemux_init (GstQTDemux * quicktime_demux);
240 static void gst_qtdemux_dispose (GObject * object);
241 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
242     GstStateChange transition);
243 static void gst_qtdemux_loop (GstPad * pad);
244 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf);
245 static gboolean qtdemux_sink_activate (GstPad * sinkpad);
246 static gboolean qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active);
247 static gboolean qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active);
248 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstEvent * event);
249
250 static void qtdemux_parse_moov (GstQTDemux * qtdemux, void *buffer, int length);
251 static void qtdemux_parse (GstQTDemux * qtdemux, GNode * node, void *buffer,
252     int length);
253 static QtNodeType *qtdemux_type_get (guint32 fourcc);
254 static void qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node);
255 static void qtdemux_parse_tree (GstQTDemux * qtdemux);
256 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta);
257 static void qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
258     GNode * node);
259 static void qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
260     const char *tag2, GNode * node);
261 static void qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag,
262     GNode * node);
263
264 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
265     QtDemuxStream * stream, GNode * esds);
266 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux, guint32 fourcc,
267     const guint8 * stsd_data, const gchar ** codec_name);
268 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
269     QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
270     const gchar ** codec_name);
271
272 static GType
273 gst_qtdemux_get_type (void)
274 {
275   static GType qtdemux_type = 0;
276
277   if (!qtdemux_type) {
278     static const GTypeInfo qtdemux_info = {
279       sizeof (GstQTDemuxClass),
280       (GBaseInitFunc) gst_qtdemux_base_init, NULL,
281       (GClassInitFunc) gst_qtdemux_class_init,
282       NULL, NULL, sizeof (GstQTDemux), 0,
283       (GInstanceInitFunc) gst_qtdemux_init,
284     };
285
286     qtdemux_type =
287         g_type_register_static (GST_TYPE_ELEMENT, "GstQTDemux", &qtdemux_info,
288         0);
289   }
290   return qtdemux_type;
291 }
292
293 static void
294 gst_qtdemux_base_init (GstQTDemuxClass * klass)
295 {
296   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
297
298   gst_element_class_add_pad_template (element_class,
299       gst_static_pad_template_get (&gst_qtdemux_sink_template));
300   gst_element_class_add_pad_template (element_class,
301       gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
302   gst_element_class_add_pad_template (element_class,
303       gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
304   gst_element_class_set_details (element_class, &gst_qtdemux_details);
305
306 }
307
308 static void
309 gst_qtdemux_class_init (GstQTDemuxClass * klass)
310 {
311   GObjectClass *gobject_class;
312   GstElementClass *gstelement_class;
313
314   gobject_class = (GObjectClass *) klass;
315   gstelement_class = (GstElementClass *) klass;
316
317   parent_class = g_type_class_peek_parent (klass);
318
319   gobject_class->dispose = gst_qtdemux_dispose;
320
321   gstelement_class->change_state = gst_qtdemux_change_state;
322 }
323
324 static void
325 gst_qtdemux_init (GstQTDemux * qtdemux)
326 {
327   qtdemux->sinkpad =
328       gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
329   gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
330   gst_pad_set_activatepull_function (qtdemux->sinkpad,
331       qtdemux_sink_activate_pull);
332   gst_pad_set_activatepush_function (qtdemux->sinkpad,
333       qtdemux_sink_activate_push);
334   gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
335   gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
336   gst_element_add_pad (GST_ELEMENT (qtdemux), qtdemux->sinkpad);
337
338   qtdemux->state = QTDEMUX_STATE_INITIAL;
339   qtdemux->last_ts = GST_CLOCK_TIME_NONE;
340   qtdemux->pullbased = FALSE;
341   qtdemux->neededbytes = 16;
342   qtdemux->todrop = 0;
343   qtdemux->adapter = gst_adapter_new ();
344   qtdemux->offset = 0;
345   qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
346   qtdemux->mdatbuffer = NULL;
347   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
348 }
349
350 static void
351 gst_qtdemux_dispose (GObject * object)
352 {
353   GstQTDemux *qtdemux = GST_QTDEMUX (object);
354
355   if (qtdemux->adapter) {
356     g_object_unref (G_OBJECT (qtdemux->adapter));
357     qtdemux->adapter = NULL;
358   }
359
360   G_OBJECT_CLASS (parent_class)->dispose (object);
361 }
362
363 #if 0
364 static gboolean
365 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
366     GstFormat * dest_format, gint64 * dest_value)
367 {
368   gboolean res = TRUE;
369   QtDemuxStream *stream = gst_pad_get_element_private (pad);
370
371   if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e') &&
372       (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
373     return FALSE;
374
375   switch (src_format) {
376     case GST_FORMAT_TIME:
377       switch (*dest_format) {
378         case GST_FORMAT_BYTES:
379           *dest_value = src_value * 1;  /* FIXME */
380           break;
381         case GST_FORMAT_DEFAULT:
382           *dest_value = src_value * 1;  /* FIXME */
383           break;
384         default:
385           res = FALSE;
386           break;
387       }
388       break;
389     case GST_FORMAT_BYTES:
390       switch (*dest_format) {
391         case GST_FORMAT_TIME:
392           *dest_value = src_value * 1;  /* FIXME */
393           break;
394         default:
395           res = FALSE;
396           break;
397       }
398       break;
399     case GST_FORMAT_DEFAULT:
400       switch (*dest_format) {
401         case GST_FORMAT_TIME:
402           *dest_value = src_value * 1;  /* FIXME */
403           break;
404         default:
405           res = FALSE;
406           break;
407       }
408       break;
409     default:
410       res = FALSE;
411   }
412
413   return res;
414 }
415 #endif
416
417 static const GstQueryType *
418 gst_qtdemux_get_src_query_types (GstPad * pad)
419 {
420   static const GstQueryType src_types[] = {
421     GST_QUERY_POSITION,
422     GST_QUERY_DURATION,
423     0
424   };
425
426   return src_types;
427 }
428
429 static gboolean
430 gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
431 {
432   gboolean res = FALSE;
433   GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
434
435   switch (GST_QUERY_TYPE (query)) {
436     case GST_QUERY_POSITION:
437       if (GST_CLOCK_TIME_IS_VALID (qtdemux->last_ts)) {
438         gst_query_set_position (query, GST_FORMAT_TIME, qtdemux->last_ts);
439         res = TRUE;
440       }
441       break;
442     case GST_QUERY_DURATION:
443       if (qtdemux->pullbased && qtdemux->duration != 0
444           && qtdemux->timescale != 0) {
445         gint64 duration;
446
447         duration = gst_util_uint64_scale_int (qtdemux->duration,
448             GST_SECOND, qtdemux->timescale);
449
450         gst_query_set_duration (query, GST_FORMAT_TIME, duration);
451         res = TRUE;
452       }
453       break;
454     default:
455       res = FALSE;
456       break;
457   }
458
459   gst_object_unref (qtdemux);
460
461   return res;
462 }
463
464 /* push event on all source pads; takes ownership of the event */
465 static void
466 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
467 {
468   guint n;
469
470   GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
471       GST_EVENT_TYPE_NAME (event));
472
473   for (n = 0; n < qtdemux->n_streams; n++) {
474     gst_pad_push_event (qtdemux->streams[n]->pad, gst_event_ref (event));
475   }
476   gst_event_unref (event);
477 }
478
479 /* move all streams back on the keyframe before @offset.
480  * 
481  * If @end is FALSE, the search is started from the current 
482  * sample_index position of each stream.
483  * If @end is TRUE, the search is started from the last sample
484  * of each stream.
485  *
486  * Returns: the minimum of the timestamps of the positions of all streams.
487  */
488 /* FIXME, binary search would be nice here */
489 static guint64
490 gst_qtdemux_go_back (GstQTDemux * qtdemux, gboolean end, guint64 offset)
491 {
492   gint n;
493   guint64 min_time = G_MAXUINT64;
494
495   /* resync to new time */
496   for (n = 0; n < qtdemux->n_streams; n++) {
497     QtDemuxStream *str;
498     gboolean keyframe;
499     gint search;
500
501     str = qtdemux->streams[n];
502     keyframe = str->all_keyframe;
503
504     /* start from the last sample if @end == TRUE */
505     if (end) {
506       if (str->n_samples == 0)
507         search = 0;
508       else
509         search = str->n_samples - 1;
510     } else
511       search = str->sample_index;
512
513     for (; search > 0; search--) {
514       guint64 timestamp;
515
516       timestamp = str->samples[search].timestamp;
517
518       /* Seek to the sample just before the desired offset and
519        * let downstream throw away bits outside of the segment */
520       if (timestamp <= offset) {
521         /* update the keyframe flag */
522         keyframe = keyframe | str->samples[search].keyframe;
523         if (keyframe) {
524           GST_DEBUG_OBJECT (qtdemux,
525               "found keyframe at sample %d, %" GST_TIME_FORMAT, search,
526               GST_TIME_ARGS (timestamp));
527           /* update min_time */
528           if (timestamp < min_time)
529             min_time = timestamp;
530           break;
531         }
532       }
533     }
534
535     /* did not find anything or we're at the beginning, position to beginning */
536     if (search <= 0) {
537       search = 0;
538       min_time = 0;
539     }
540     /* and set stream to the index */
541     if (search != str->sample_index) {
542       str->sample_index = search;
543       /* position changed, we have a discont */
544       str->discont = TRUE;
545     }
546   }
547   return min_time;
548 }
549
550 /* perform the seek.
551  *
552  * We always go to the keyframe before the desired seek position. If
553  * the seek was to a keyframe, we update the last_stop and time with 
554  * the position of the keyframe, else we leve the event as-is and it 
555  * will be clipped automatically to the right segment boundaries by 
556  * downstream elements.
557  */
558 static gboolean
559 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
560 {
561   gint64 desired_offset;
562   guint64 min;
563
564   desired_offset = segment->last_stop;
565
566   GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
567       GST_TIME_ARGS (desired_offset));
568
569   /* position all streams to key unit before the desired time,
570    * start searching from the last sample in the stream. */
571   min = gst_qtdemux_go_back (qtdemux, TRUE, desired_offset);
572
573   if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
574     GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %" GST_TIME_FORMAT,
575         GST_TIME_ARGS (min));
576     /* key unit, we seek to min, so back off streams to this new
577      * position. We start from our current position. */
578     gst_qtdemux_go_back (qtdemux, FALSE, min);
579
580     /* update the segment values to the position of the keyframes */
581     segment->last_stop = min;
582     segment->time = min;
583   }
584
585   /* and we stop at the end */
586   if (segment->stop == -1)
587     segment->stop = segment->duration;
588
589   return TRUE;
590 }
591
592 /* do a seek in pull based mode */
593 static gboolean
594 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
595 {
596   gdouble rate;
597   GstFormat format;
598   GstSeekFlags flags;
599   GstSeekType cur_type, stop_type;
600   gint64 cur, stop;
601   gboolean flush;
602   gboolean res;
603   gboolean update;
604   GstSegment seeksegment;
605   GstEvent *newsegment;
606
607   if (event) {
608     GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
609
610     gst_event_parse_seek (event, &rate, &format, &flags,
611         &cur_type, &cur, &stop_type, &stop);
612
613     /* we have to have a format as the segment format. Try to convert
614      * if not. */
615     if (format != GST_FORMAT_TIME) {
616       GstFormat fmt;
617
618       fmt = GST_FORMAT_TIME;
619       res = TRUE;
620       if (cur_type != GST_SEEK_TYPE_NONE)
621         res = gst_pad_query_convert (pad, format, cur, &fmt, &cur);
622       if (res && stop_type != GST_SEEK_TYPE_NONE)
623         res = gst_pad_query_convert (pad, format, stop, &fmt, &stop);
624       if (!res)
625         goto no_format;
626
627       format = fmt;
628     }
629   } else {
630     GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
631     flags = 0;
632   }
633
634   flush = flags & GST_SEEK_FLAG_FLUSH;
635
636   GST_DEBUG_OBJECT (qtdemux, "seek format %d", format);
637
638   /* stop streaming, either by flushing or by pausing the task */
639   if (flush) {
640     /* unlock upstream pull_range */
641     gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
642     /* make sure out loop function exits */
643     gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
644   } else {
645     /* non flushing seek, pause the task */
646     qtdemux->segment_running = FALSE;
647     gst_pad_pause_task (qtdemux->sinkpad);
648   }
649
650   /* wait for streaming to finish */
651   GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
652
653   /* copy segment, we need this because we still need the old
654    * segment when we close the current segment. */
655   memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
656
657   if (event) {
658     /* configure the segment with the seek variables */
659     GST_DEBUG_OBJECT (qtdemux, "configuring seek");
660     gst_segment_set_seek (&seeksegment, rate, format, flags,
661         cur_type, cur, stop_type, stop, &update);
662   }
663
664   /* now do the seek, this actually never returns FALSE */
665   res = gst_qtdemux_perform_seek (qtdemux, &seeksegment);
666
667   /* prepare for streaming again */
668   if (flush) {
669     gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop ());
670     gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop ());
671   } else if (qtdemux->segment_running) {
672     /* we are running the current segment and doing a non-flushing seek,
673      * close the segment first based on the last_stop. */
674     GST_DEBUG_OBJECT (qtdemux, "closing running segment %" G_GINT64_FORMAT
675         " to %" G_GINT64_FORMAT, qtdemux->segment.start,
676         qtdemux->segment.last_stop);
677
678     gst_qtdemux_push_event (qtdemux,
679         gst_event_new_new_segment (TRUE,
680             qtdemux->segment.rate, qtdemux->segment.format,
681             qtdemux->segment.start, qtdemux->segment.last_stop,
682             qtdemux->segment.time));
683   }
684
685   /* commit the new segment */
686   memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
687
688   if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
689     gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
690         gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
691             qtdemux->segment.format, qtdemux->segment.last_stop));
692   }
693
694   /* send the newsegment */
695   GST_DEBUG_OBJECT (qtdemux, "Sending newsegment from %" GST_TIME_FORMAT
696       " to %" GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.start),
697       GST_TIME_ARGS (qtdemux->segment.stop));
698
699   newsegment =
700       gst_event_new_new_segment (FALSE, qtdemux->segment.rate,
701       qtdemux->segment.format, qtdemux->segment.last_stop,
702       qtdemux->segment.stop, qtdemux->segment.time);
703
704   gst_qtdemux_push_event (qtdemux, newsegment);
705
706   /* restart streaming */
707   qtdemux->segment_running = TRUE;
708   gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
709       qtdemux->sinkpad);
710
711   GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
712
713   return TRUE;
714
715   /* ERRORS */
716 no_format:
717   {
718     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
719     return FALSE;
720   }
721 }
722
723 static gboolean
724 gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
725 {
726   gboolean res = TRUE;
727   GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
728
729   switch (GST_EVENT_TYPE (event)) {
730     case GST_EVENT_SEEK:
731       res = gst_qtdemux_do_seek (qtdemux, pad, event);
732       break;
733     default:
734       res = FALSE;
735       break;
736   }
737
738   gst_object_unref (qtdemux);
739
740   gst_event_unref (event);
741
742   return res;
743 }
744
745 GST_DEBUG_CATEGORY (qtdemux_debug);
746
747 static gboolean
748 plugin_init (GstPlugin * plugin)
749 {
750   GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
751
752   return gst_element_register (plugin, "qtdemux",
753       GST_RANK_PRIMARY, GST_TYPE_QTDEMUX);
754 }
755
756 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
757     GST_VERSION_MINOR,
758     "qtdemux",
759     "Quicktime stream demuxer",
760     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
761
762 static gboolean
763 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
764 {
765   GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
766   gboolean res = FALSE;
767
768   switch (GST_EVENT_TYPE (event)) {
769     case GST_EVENT_NEWSEGMENT:
770       /* We need to convert it to a GST_FORMAT_TIME new segment */
771     default:
772       gst_pad_event_default (demux->sinkpad, event);
773       return TRUE;
774   }
775
776   gst_event_unref (event);
777   return res;
778 }
779
780 static GstStateChangeReturn
781 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
782 {
783   GstQTDemux *qtdemux = GST_QTDEMUX (element);
784   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
785
786   switch (transition) {
787     case GST_STATE_CHANGE_PAUSED_TO_READY:
788       break;
789     default:
790       break;
791   }
792
793   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
794
795   switch (transition) {
796     case GST_STATE_CHANGE_PAUSED_TO_READY:{
797       gint n;
798
799       qtdemux->state = QTDEMUX_STATE_INITIAL;
800       qtdemux->last_ts = GST_CLOCK_TIME_NONE;
801       qtdemux->neededbytes = 16;
802       qtdemux->todrop = 0;
803       qtdemux->pullbased = FALSE;
804       qtdemux->offset = 0;
805       qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
806       if (qtdemux->mdatbuffer)
807         gst_buffer_unref (qtdemux->mdatbuffer);
808       qtdemux->mdatbuffer = NULL;
809       gst_adapter_clear (qtdemux->adapter);
810       for (n = 0; n < qtdemux->n_streams; n++) {
811         gst_element_remove_pad (element, qtdemux->streams[n]->pad);
812         g_free (qtdemux->streams[n]->samples);
813         if (qtdemux->streams[n]->caps)
814           gst_caps_unref (qtdemux->streams[n]->caps);
815         g_free (qtdemux->streams[n]);
816       }
817       qtdemux->n_streams = 0;
818       gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
819       break;
820     }
821     default:
822       break;
823   }
824
825   return result;
826 }
827
828 static void
829 extract_initial_length_and_fourcc (guint8 * data, guint32 * plength,
830     guint32 * pfourcc)
831 {
832   guint32 length;
833   guint32 fourcc;
834
835   length = GST_READ_UINT32_BE (data);
836   GST_DEBUG ("length %08x", length);
837   fourcc = GST_READ_UINT32_LE (data + 4);
838   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
839
840   if (length == 0) {
841     length = G_MAXUINT32;
842   }
843   if (length == 1) {
844     /* this means we have an extended size, which is the 64 bit value of
845      * the next 8 bytes */
846     guint32 length1, length2;
847
848     length1 = GST_READ_UINT32_BE (data + 8);
849     GST_DEBUG ("length1 %08x", length1);
850     length2 = GST_READ_UINT32_BE (data + 12);
851     GST_DEBUG ("length2 %08x", length2);
852
853     /* FIXME: I guess someone didn't want to make 64 bit size work :) */
854     length = length2;
855   }
856
857   if (plength)
858     *plength = length;
859   if (pfourcc)
860     *pfourcc = fourcc;
861 }
862
863 static GstFlowReturn
864 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
865 {
866   guint32 length;
867   guint32 fourcc;
868   GstBuffer *buf = NULL;
869   GstFlowReturn ret = GST_FLOW_OK;
870   guint64 cur_offset = qtdemux->offset;
871
872   ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
873   if (ret != GST_FLOW_OK)
874     goto beach;
875   extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf), &length, &fourcc);
876   gst_buffer_unref (buf);
877
878
879   switch (fourcc) {
880     case GST_MAKE_FOURCC ('m', 'd', 'a', 't'):
881     case GST_MAKE_FOURCC ('f', 'r', 'e', 'e'):
882     case GST_MAKE_FOURCC ('w', 'i', 'd', 'e'):
883     case GST_MAKE_FOURCC ('P', 'I', 'C', 'T'):
884     case GST_MAKE_FOURCC ('p', 'n', 'o', 't'):
885       goto ed_edd_and_eddy;
886     case GST_MAKE_FOURCC ('m', 'o', 'o', 'v'):{
887       GstBuffer *moov;
888
889       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
890       if (ret != GST_FLOW_OK)
891         goto beach;
892       if (length != GST_BUFFER_SIZE (moov)) {
893         GST_WARNING_OBJECT (qtdemux,
894             "We got less than expected (received %d, wanted %d)",
895             GST_BUFFER_SIZE (moov), length);
896         ret = GST_FLOW_ERROR;
897         goto beach;
898       }
899       cur_offset += length;
900       qtdemux->offset += length;
901
902       qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
903       if (1) {
904         qtdemux_node_dump (qtdemux, qtdemux->moov_node);
905       }
906       qtdemux_parse_tree (qtdemux);
907       g_node_destroy (qtdemux->moov_node);
908       gst_buffer_unref (moov);
909       qtdemux->moov_node = NULL;
910       qtdemux->state = QTDEMUX_STATE_MOVIE;
911       GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
912           qtdemux->state);
913     }
914       break;
915     ed_edd_and_eddy:
916     default:{
917       GST_LOG ("unknown %08x '%" GST_FOURCC_FORMAT "' at %d",
918           fourcc, GST_FOURCC_ARGS (fourcc), cur_offset);
919       cur_offset += length;
920       qtdemux->offset += length;
921       break;
922     }
923   }
924
925 beach:
926   return ret;
927 }
928
929 static GstFlowReturn
930 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
931 {
932   GstFlowReturn ret = GST_FLOW_OK;
933   GstBuffer *buf = NULL;
934   QtDemuxStream *stream;
935   guint64 min_time;
936   guint64 offset;
937   guint64 timestamp;
938   gint size;
939   gint index = -1;
940   gint i;
941
942   /* Figure out the next stream sample to output */
943   min_time = G_MAXUINT64;
944
945   for (i = 0; i < qtdemux->n_streams; i++) {
946     stream = qtdemux->streams[i];
947     if (stream->sample_index < stream->n_samples) {
948
949       timestamp = stream->samples[stream->sample_index].timestamp;
950
951       GST_LOG_OBJECT (qtdemux,
952           "stream %d: sample_index %d, timestamp %" GST_TIME_FORMAT, i,
953           stream->sample_index, GST_TIME_ARGS (timestamp));
954
955       if (timestamp < min_time) {
956         min_time = timestamp;
957         index = i;
958       }
959     }
960   }
961   if (index == -1)
962     goto eos;
963
964   /* check for segment end */
965   if (qtdemux->segment.stop != -1 && qtdemux->segment.stop < min_time)
966     goto eos;
967
968   stream = qtdemux->streams[index];
969
970   offset = stream->samples[stream->sample_index].offset;
971   size = stream->samples[stream->sample_index].size;
972   timestamp = stream->samples[stream->sample_index].timestamp;
973
974   GST_LOG_OBJECT (qtdemux,
975       "pushing from stream %d, sample_index=%d offset=%" G_GUINT64_FORMAT
976       ",size=%d timestamp=%" GST_TIME_FORMAT,
977       index, stream->sample_index, offset, size, GST_TIME_ARGS (timestamp));
978
979   if (G_UNLIKELY (size <= 0))
980     goto beach;
981
982   GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
983       offset);
984
985   ret = gst_pad_pull_range (qtdemux->sinkpad, offset, size, &buf);
986   if (ret != GST_FLOW_OK)
987     goto beach;
988
989   buf = gst_buffer_make_metadata_writable (buf);
990
991 #if 0
992   /* hum... FIXME changing framerate breaks horribly, better set
993    * an average framerate, or get rid of the framerate property. */
994   if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e')) {
995     float fps =
996         1. * GST_SECOND / stream->samples[stream->sample_index].duration;
997     if (fps != stream->fps) {
998       gst_caps_set_simple (stream->caps, "framerate", G_TYPE_DOUBLE, fps, NULL);
999       stream->fps = fps;
1000       gst_pad_set_explicit_caps (stream->pad, stream->caps);
1001     }
1002   }
1003 #endif
1004
1005   /* first buffer? */
1006   if (qtdemux->last_ts == GST_CLOCK_TIME_NONE) {
1007     gst_qtdemux_push_event (qtdemux,
1008         gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
1009             0, GST_CLOCK_TIME_NONE, 0));
1010   }
1011
1012   if (stream->discont) {
1013     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
1014     stream->discont = FALSE;
1015   }
1016
1017   /* timestamps of AMR aren't known... */
1018   if (stream->fourcc == GST_MAKE_FOURCC ('s', 'a', 'm', 'r')) {
1019     if (stream->sample_index == 0)
1020       GST_BUFFER_TIMESTAMP (buf) = 0;
1021   } else {
1022     GST_BUFFER_TIMESTAMP (buf) = timestamp;
1023     qtdemux->last_ts = GST_BUFFER_TIMESTAMP (buf);
1024     GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int
1025         (stream->samples[stream->sample_index].duration, GST_SECOND,
1026         stream->timescale);
1027   }
1028   gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME,
1029       qtdemux->last_ts);
1030
1031   if (!(stream->all_keyframe || stream->samples[stream->sample_index].keyframe))
1032     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
1033
1034   GST_LOG_OBJECT (qtdemux,
1035       "Pushing buffer with time %" GST_TIME_FORMAT " on pad %p",
1036       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), stream->pad);
1037   gst_buffer_set_caps (buf, stream->caps);
1038
1039   ret = gst_pad_push (stream->pad, buf);
1040
1041   stream->sample_index++;
1042
1043 beach:
1044   return ret;
1045
1046   /* special cases */
1047 eos:
1048   {
1049     GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
1050     ret = GST_FLOW_UNEXPECTED;
1051     goto beach;
1052   }
1053 }
1054
1055 static void
1056 gst_qtdemux_loop (GstPad * pad)
1057 {
1058   GstQTDemux *qtdemux;
1059   guint64 cur_offset;
1060   GstFlowReturn ret;
1061
1062   qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
1063
1064   cur_offset = qtdemux->offset;
1065   GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
1066       cur_offset, qtdemux->state);
1067
1068   switch (qtdemux->state) {
1069     case QTDEMUX_STATE_INITIAL:
1070     case QTDEMUX_STATE_HEADER:
1071       ret = gst_qtdemux_loop_state_header (qtdemux);
1072       break;
1073     case QTDEMUX_STATE_MOVIE:
1074       ret = gst_qtdemux_loop_state_movie (qtdemux);
1075       break;
1076     default:
1077       /* ouch */
1078       goto invalid_state;
1079   }
1080
1081   /* if all is fine, continue */
1082   if (G_LIKELY (ret == GST_FLOW_OK))
1083     goto done;
1084
1085   /* we don't care about unlinked pads */
1086   if (ret == GST_FLOW_NOT_LINKED)
1087     goto done;
1088
1089   /* other errors make us stop */
1090   GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", gst_flow_get_name (ret));
1091
1092   qtdemux->segment_running = FALSE;
1093   gst_pad_pause_task (pad);
1094
1095   /* fatal errors need special actions */
1096   if (GST_FLOW_IS_FATAL (ret)) {
1097     /* check EOS */
1098     if (ret == GST_FLOW_UNEXPECTED) {
1099       if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1100         GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
1101         gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1102             gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
1103                 GST_FORMAT_TIME, qtdemux->last_ts));
1104       } else {
1105         GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
1106         gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
1107       }
1108     } else {
1109       gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
1110       GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
1111           (NULL), ("streaming stopped, reason %s", gst_flow_get_name (ret)));
1112     }
1113   }
1114
1115 done:
1116   gst_object_unref (qtdemux);
1117   return;
1118
1119   /* ERRORS */
1120 invalid_state:
1121   {
1122     GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
1123         (NULL), ("streaming stopped, invalid state"));
1124     qtdemux->segment_running = FALSE;
1125     gst_pad_pause_task (pad);
1126     gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
1127     goto done;
1128   }
1129 }
1130
1131 /*
1132   next_entry_size
1133   
1134   Returns the size of the first entry at the current offset.
1135   If -1, there are none (which means EOS or empty file).
1136 */
1137
1138 static guint64
1139 next_entry_size (GstQTDemux * demux)
1140 {
1141   QtDemuxStream *stream;
1142   int i;
1143   int smallidx = -1;
1144   guint64 smalloffs = -1;
1145
1146   GST_LOG_OBJECT (demux, "Finding entry at offset %lld", demux->offset);
1147
1148   for (i = 0; i < demux->n_streams; i++) {
1149     stream = demux->streams[i];
1150
1151     GST_LOG_OBJECT (demux,
1152         "Checking Stream %d (sample_index:%d / offset:%lld / size:%d / chunk:%d)",
1153         i, stream->sample_index, stream->samples[stream->sample_index].offset,
1154         stream->samples[stream->sample_index].size,
1155         stream->samples[stream->sample_index].chunk);
1156
1157     if (((smalloffs == -1)
1158             || (stream->samples[stream->sample_index].offset < smalloffs))
1159         && (stream->samples[stream->sample_index].size)) {
1160       smallidx = i;
1161       smalloffs = stream->samples[stream->sample_index].offset;
1162     }
1163   }
1164
1165   GST_LOG_OBJECT (demux, "stream %d offset %lld demux->offset :%lld",
1166       smallidx, smalloffs, demux->offset);
1167
1168   if (smallidx == -1)
1169     return -1;
1170   stream = demux->streams[smallidx];
1171
1172   if (stream->samples[stream->sample_index].offset >= demux->offset) {
1173     demux->todrop =
1174         stream->samples[stream->sample_index].offset - demux->offset;
1175     return stream->samples[stream->sample_index].size + demux->todrop;
1176   }
1177
1178   GST_DEBUG_OBJECT (demux, "There wasn't any entry at offset %lld",
1179       demux->offset);
1180   return -1;
1181 }
1182
1183 static void
1184 gst_qtdemux_post_buffering (GstQTDemux * demux, gint num, gint denom)
1185 {
1186   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
1187
1188   gst_element_post_message (GST_ELEMENT (demux),
1189       gst_message_new_custom (GST_MESSAGE_BUFFERING,
1190           GST_OBJECT (demux),
1191           gst_structure_new ("GstMessageBuffering",
1192               "buffer-percent", G_TYPE_INT, perc, NULL)));
1193 }
1194
1195 static GstFlowReturn
1196 gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
1197 {
1198   GstQTDemux *demux;
1199   GstFlowReturn ret = GST_FLOW_OK;
1200
1201   demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad));
1202
1203   gst_adapter_push (demux->adapter, inbuf);
1204
1205   GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
1206       inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
1207
1208   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
1209       (ret == GST_FLOW_OK)) {
1210
1211     GST_DEBUG_OBJECT (demux,
1212         "state:%d , demux->neededbytes:%d, demux->offset:%lld", demux->state,
1213         demux->neededbytes, demux->offset);
1214
1215     switch (demux->state) {
1216       case QTDEMUX_STATE_INITIAL:{
1217         const guint8 *data;
1218         guint32 fourcc;
1219         guint32 size;
1220
1221         data = gst_adapter_peek (demux->adapter, demux->neededbytes);
1222
1223         /* get fourcc/length, set neededbytes */
1224         extract_initial_length_and_fourcc ((guint8 *) data, &size, &fourcc);
1225         GST_DEBUG_OBJECT (demux,
1226             "Peeking found [%" GST_FOURCC_FORMAT "] size:%ld",
1227             GST_FOURCC_ARGS (fourcc), size);
1228         if ((fourcc == GST_MAKE_FOURCC ('m', 'd', 'a', 't'))) {
1229           if (demux->n_streams > 0) {
1230             demux->state = QTDEMUX_STATE_MOVIE;
1231             demux->neededbytes = next_entry_size (demux);
1232           } else {
1233             demux->state = QTDEMUX_STATE_BUFFER_MDAT;
1234             demux->neededbytes = size;
1235             demux->mdatoffset = demux->offset;
1236           }
1237         } else {
1238           demux->neededbytes = size;
1239           demux->state = QTDEMUX_STATE_HEADER;
1240         }
1241         break;
1242       }
1243       case QTDEMUX_STATE_HEADER:{
1244         guint8 *data;
1245         guint32 fourcc;
1246
1247         GST_DEBUG_OBJECT (demux, "In header");
1248
1249         data = gst_adapter_take (demux->adapter, demux->neededbytes);
1250
1251         /* parse the header */
1252         extract_initial_length_and_fourcc (data, NULL, &fourcc);
1253         if (fourcc == GST_MAKE_FOURCC ('m', 'o', 'o', 'v')) {
1254           GST_DEBUG_OBJECT (demux, "Parsing [moov]");
1255
1256           qtdemux_parse_moov (demux, data, demux->neededbytes);
1257           qtdemux_node_dump (demux, demux->moov_node);
1258           qtdemux_parse_tree (demux);
1259
1260           g_node_destroy (demux->moov_node);
1261           g_free (data);
1262           demux->moov_node = NULL;
1263         } else {
1264           GST_WARNING_OBJECT (demux,
1265               "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
1266               GST_FOURCC_ARGS (fourcc));
1267           /* Let's jump that one and go back to initial state */
1268         }
1269
1270         GST_DEBUG_OBJECT (demux, "Finished parsing the header");
1271         if (demux->mdatbuffer && demux->n_streams) {
1272           /* the mdat was before the header */
1273           GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
1274               demux->n_streams, demux->mdatbuffer);
1275           gst_adapter_clear (demux->adapter);
1276           GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
1277               GST_FOURCC_ARGS (GST_READ_UINT32_BE (demux->mdatbuffer)));
1278           gst_adapter_push (demux->adapter, demux->mdatbuffer);
1279           demux->mdatbuffer = NULL;
1280           demux->offset = demux->mdatoffset;
1281           demux->neededbytes = next_entry_size (demux);
1282           demux->state = QTDEMUX_STATE_MOVIE;
1283         } else {
1284           GST_DEBUG_OBJECT (demux, "Carrying on normally");
1285           demux->offset += demux->neededbytes;
1286           demux->neededbytes = 16;
1287           demux->state = QTDEMUX_STATE_INITIAL;
1288         }
1289
1290         break;
1291       }
1292       case QTDEMUX_STATE_BUFFER_MDAT:{
1293         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %lld",
1294             demux->mdatoffset);
1295         if (demux->mdatbuffer)
1296           gst_buffer_unref (demux->mdatbuffer);
1297         demux->mdatbuffer = gst_buffer_new ();
1298         gst_buffer_set_data (demux->mdatbuffer,
1299             gst_adapter_take (demux->adapter, demux->neededbytes),
1300             demux->neededbytes);
1301         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
1302             GST_FOURCC_ARGS (GST_READ_UINT32_BE (demux->mdatbuffer)));
1303         demux->offset += demux->neededbytes;
1304         demux->neededbytes = 16;
1305         demux->state = QTDEMUX_STATE_INITIAL;
1306         gst_qtdemux_post_buffering (demux, 1, 1);
1307
1308         break;
1309       }
1310       case QTDEMUX_STATE_MOVIE:{
1311         guint8 *data;
1312         GstBuffer *outbuf;
1313         QtDemuxStream *stream = NULL;
1314         int i = -1;
1315
1316         GST_DEBUG_OBJECT (demux, "BEGIN // in MOVIE for offset %lld",
1317             demux->offset);
1318
1319         if (demux->todrop) {
1320           gst_adapter_flush (demux->adapter, demux->todrop);
1321           demux->neededbytes -= demux->todrop;
1322           demux->offset += demux->todrop;
1323         }
1324
1325         /* Figure out which stream this is packet belongs to */
1326         for (i = 0; i < demux->n_streams; i++) {
1327           stream = demux->streams[i];
1328           GST_LOG_OBJECT (demux,
1329               "Checking stream %d (sample_index:%d / offset:%lld / size:%d / chunk:%d)",
1330               i, stream->sample_index,
1331               stream->samples[stream->sample_index].offset,
1332               stream->samples[stream->sample_index].size,
1333               stream->samples[stream->sample_index].chunk);
1334
1335           if (stream->samples[stream->sample_index].offset == demux->offset)
1336             break;
1337         }
1338
1339         if (stream == NULL)
1340           goto unknown_stream;
1341
1342         /* first buffer? */
1343         /* FIXME : this should be handled in sink_event */
1344         if (demux->last_ts == GST_CLOCK_TIME_NONE) {
1345           gst_qtdemux_push_event (demux,
1346               gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
1347                   0, GST_CLOCK_TIME_NONE, 0));
1348         }
1349
1350         /* get data */
1351         data = gst_adapter_take (demux->adapter, demux->neededbytes);
1352
1353         /* Put data in a buffer, set timestamps, caps, ... */
1354         outbuf = gst_buffer_new ();
1355         gst_buffer_set_data (outbuf, data, demux->neededbytes);
1356         GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
1357             GST_FOURCC_ARGS (stream->fourcc));
1358
1359         if (stream->fourcc != GST_MAKE_FOURCC ('s', 'a', 'm', 'r')) {
1360           GST_BUFFER_TIMESTAMP (outbuf) =
1361               stream->samples[stream->sample_index].timestamp;
1362           demux->last_ts = GST_BUFFER_TIMESTAMP (outbuf);
1363           GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int
1364               (stream->samples[stream->sample_index].duration, GST_SECOND,
1365               stream->timescale);
1366
1367         } else {
1368           if (stream->sample_index == 0)
1369             GST_BUFFER_TIMESTAMP (outbuf) = 0;
1370         }
1371
1372         /* send buffer */
1373         GST_LOG_OBJECT (demux,
1374             "Pushing buffer with time %" GST_TIME_FORMAT " on pad %p",
1375             GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), stream->pad);
1376         gst_buffer_set_caps (outbuf, stream->caps);
1377         ret = gst_pad_push (stream->pad, outbuf);
1378
1379         stream->sample_index++;
1380
1381         /* update current offset and figure out size of next buffer */
1382         GST_LOG_OBJECT (demux, "bumping offset:%lld up by %lld",
1383             demux->offset, demux->neededbytes);
1384         demux->offset += demux->neededbytes;
1385         GST_LOG_OBJECT (demux, "offset is now %lld", demux->offset);
1386
1387         if ((demux->neededbytes = next_entry_size (demux)) == -1)
1388           goto eos;
1389         break;
1390       }
1391       default:
1392         goto invalid_state;
1393     }
1394   }
1395
1396   /* when buffering movie data, at least show user something is happening */
1397   if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
1398       gst_adapter_available (demux->adapter) <= demux->neededbytes) {
1399     gst_qtdemux_post_buffering (demux, gst_adapter_available (demux->adapter),
1400         demux->neededbytes);
1401   }
1402
1403 done:
1404   gst_object_unref (demux);
1405
1406   return ret;
1407
1408   /* ERRORS */
1409 unknown_stream:
1410   {
1411     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
1412     ret = GST_FLOW_ERROR;
1413     goto done;
1414   }
1415 eos:
1416   {
1417     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
1418     ret = GST_FLOW_UNEXPECTED;
1419     goto done;
1420   }
1421 invalid_state:
1422   {
1423     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1424         (NULL), ("qtdemuxer invalid state %d", demux->state));
1425     ret = GST_FLOW_ERROR;
1426     goto done;
1427   }
1428 }
1429
1430 static gboolean
1431 qtdemux_sink_activate (GstPad * sinkpad)
1432 {
1433   if (gst_pad_check_pull_range (sinkpad))
1434     return gst_pad_activate_pull (sinkpad, TRUE);
1435   else
1436     return gst_pad_activate_push (sinkpad, TRUE);
1437 }
1438
1439 static gboolean
1440 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
1441 {
1442   GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1443
1444   if (active) {
1445     /* if we have a scheduler we can start the task */
1446     demux->pullbased = TRUE;
1447     demux->segment_running = TRUE;
1448     gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop, sinkpad);
1449   } else {
1450     demux->segment_running = FALSE;
1451     gst_pad_stop_task (sinkpad);
1452   }
1453
1454   return TRUE;
1455 }
1456
1457 static gboolean
1458 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
1459 {
1460   GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1461
1462   demux->pullbased = FALSE;
1463
1464   return TRUE;
1465 }
1466
1467 static void
1468 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
1469     QtDemuxStream * stream, GstTagList * list)
1470 {
1471   if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e')) {
1472     gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
1473
1474     stream->pad =
1475         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
1476     g_free (name);
1477     if ((stream->n_samples == 1) && (stream->samples[0].duration == 0)) {
1478       stream->fps_n = 0;
1479       stream->fps_d = 1;
1480     } else {
1481       stream->fps_n = stream->timescale;
1482       if (stream->samples[0].duration == 0)
1483         stream->fps_d = 1;
1484       else
1485         stream->fps_d = stream->samples[0].duration;
1486     }
1487
1488     if (stream->caps) {
1489       gst_caps_set_simple (stream->caps,
1490           "width", G_TYPE_INT, stream->width,
1491           "height", G_TYPE_INT, stream->height,
1492           "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
1493       if ((stream->bits_per_sample & 0x1F) == 8) {
1494         const guint32 *palette_data = NULL;
1495
1496         if ((stream->bits_per_sample & 0x20) != 0)
1497           palette_data = ff_qt_grayscale_palette_256;
1498         if ((stream->color_table_id & 0x08) != 0)
1499           palette_data = ff_qt_default_palette_256;
1500
1501         if (palette_data) {
1502           GstBuffer *palette = gst_buffer_new ();
1503
1504           GST_BUFFER_DATA (palette) = (guint8 *) palette_data;
1505           GST_BUFFER_SIZE (palette) = sizeof (guint32) * 256;
1506           gst_caps_set_simple (stream->caps, "palette_data",
1507               GST_TYPE_BUFFER, palette, NULL);
1508           gst_buffer_unref (palette);
1509         }
1510       }
1511     }
1512     qtdemux->n_video_streams++;
1513   } else {
1514     gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
1515
1516     stream->pad =
1517         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
1518     g_free (name);
1519     if (stream->caps) {
1520       gst_caps_set_simple (stream->caps,
1521           "rate", G_TYPE_INT, (int) stream->rate,
1522           "channels", G_TYPE_INT, stream->n_channels, NULL);
1523     }
1524     qtdemux->n_audio_streams++;
1525   }
1526
1527   gst_pad_use_fixed_caps (stream->pad);
1528
1529   GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
1530   qtdemux->streams[qtdemux->n_streams] = stream;
1531   qtdemux->n_streams++;
1532   GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
1533
1534   gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
1535   gst_pad_set_query_type_function (stream->pad,
1536       gst_qtdemux_get_src_query_types);
1537   gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
1538
1539   GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
1540   gst_pad_set_caps (stream->pad, stream->caps);
1541
1542   GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
1543       GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
1544   gst_element_add_pad (GST_ELEMENT (qtdemux), stream->pad);
1545   if (list) {
1546     gst_element_found_tags_for_pad (GST_ELEMENT (qtdemux), stream->pad, list);
1547   }
1548 }
1549
1550
1551 #define QT_CONTAINER 1
1552
1553 #define FOURCC_moov     GST_MAKE_FOURCC('m','o','o','v')
1554 #define FOURCC_mvhd     GST_MAKE_FOURCC('m','v','h','d')
1555 #define FOURCC_clip     GST_MAKE_FOURCC('c','l','i','p')
1556 #define FOURCC_trak     GST_MAKE_FOURCC('t','r','a','k')
1557 #define FOURCC_udta     GST_MAKE_FOURCC('u','d','t','a')
1558 #define FOURCC_ctab     GST_MAKE_FOURCC('c','t','a','b')
1559 #define FOURCC_tkhd     GST_MAKE_FOURCC('t','k','h','d')
1560 #define FOURCC_crgn     GST_MAKE_FOURCC('c','r','g','n')
1561 #define FOURCC_matt     GST_MAKE_FOURCC('m','a','t','t')
1562 #define FOURCC_kmat     GST_MAKE_FOURCC('k','m','a','t')
1563 #define FOURCC_edts     GST_MAKE_FOURCC('e','d','t','s')
1564 #define FOURCC_elst     GST_MAKE_FOURCC('e','l','s','t')
1565 #define FOURCC_load     GST_MAKE_FOURCC('l','o','a','d')
1566 #define FOURCC_tref     GST_MAKE_FOURCC('t','r','e','f')
1567 #define FOURCC_imap     GST_MAKE_FOURCC('i','m','a','p')
1568 #define FOURCC___in     GST_MAKE_FOURCC(' ',' ','i','n')
1569 #define FOURCC___ty     GST_MAKE_FOURCC(' ',' ','t','y')
1570 #define FOURCC_mdia     GST_MAKE_FOURCC('m','d','i','a')
1571 #define FOURCC_mdhd     GST_MAKE_FOURCC('m','d','h','d')
1572 #define FOURCC_hdlr     GST_MAKE_FOURCC('h','d','l','r')
1573 #define FOURCC_minf     GST_MAKE_FOURCC('m','i','n','f')
1574 #define FOURCC_vmhd     GST_MAKE_FOURCC('v','m','h','d')
1575 #define FOURCC_smhd     GST_MAKE_FOURCC('s','m','h','d')
1576 #define FOURCC_gmhd     GST_MAKE_FOURCC('g','m','h','d')
1577 #define FOURCC_gmin     GST_MAKE_FOURCC('g','m','i','n')
1578 #define FOURCC_dinf     GST_MAKE_FOURCC('d','i','n','f')
1579 #define FOURCC_dref     GST_MAKE_FOURCC('d','r','e','f')
1580 #define FOURCC_stbl     GST_MAKE_FOURCC('s','t','b','l')
1581 #define FOURCC_stsd     GST_MAKE_FOURCC('s','t','s','d')
1582 #define FOURCC_stts     GST_MAKE_FOURCC('s','t','t','s')
1583 #define FOURCC_stss     GST_MAKE_FOURCC('s','t','s','s')
1584 #define FOURCC_stsc     GST_MAKE_FOURCC('s','t','s','c')
1585 #define FOURCC_stsz     GST_MAKE_FOURCC('s','t','s','z')
1586 #define FOURCC_stco     GST_MAKE_FOURCC('s','t','c','o')
1587 #define FOURCC_vide     GST_MAKE_FOURCC('v','i','d','e')
1588 #define FOURCC_soun     GST_MAKE_FOURCC('s','o','u','n')
1589 #define FOURCC_co64     GST_MAKE_FOURCC('c','o','6','4')
1590 #define FOURCC_cmov     GST_MAKE_FOURCC('c','m','o','v')
1591 #define FOURCC_dcom     GST_MAKE_FOURCC('d','c','o','m')
1592 #define FOURCC_cmvd     GST_MAKE_FOURCC('c','m','v','d')
1593 #define FOURCC_hint     GST_MAKE_FOURCC('h','i','n','t')
1594 #define FOURCC_mp4a     GST_MAKE_FOURCC('m','p','4','a')
1595 #define FOURCC_mp4v     GST_MAKE_FOURCC('m','p','4','v')
1596 #define FOURCC_wave     GST_MAKE_FOURCC('w','a','v','e')
1597 #define FOURCC_appl     GST_MAKE_FOURCC('a','p','p','l')
1598 #define FOURCC_esds     GST_MAKE_FOURCC('e','s','d','s')
1599 #define FOURCC_hnti     GST_MAKE_FOURCC('h','n','t','i')
1600 #define FOURCC_rtp_     GST_MAKE_FOURCC('r','t','p',' ')
1601 #define FOURCC_sdp_     GST_MAKE_FOURCC('s','d','p',' ')
1602 #define FOURCC_meta     GST_MAKE_FOURCC('m','e','t','a')
1603 #define FOURCC_ilst     GST_MAKE_FOURCC('i','l','s','t')
1604 #define FOURCC__nam     GST_MAKE_FOURCC(0xa9,'n','a','m')
1605 #define FOURCC__ART     GST_MAKE_FOURCC(0xa9,'A','R','T')
1606 #define FOURCC__wrt     GST_MAKE_FOURCC(0xa9,'w','r','t')
1607 #define FOURCC__grp     GST_MAKE_FOURCC(0xa9,'g','r','p')
1608 #define FOURCC__alb     GST_MAKE_FOURCC(0xa9,'a','l','b')
1609 #define FOURCC_gnre     GST_MAKE_FOURCC('g','n','r','e')
1610 #define FOURCC_disc     GST_MAKE_FOURCC('d','i','s','c')
1611 #define FOURCC_disk     GST_MAKE_FOURCC('d','i','s','k')
1612 #define FOURCC_trkn     GST_MAKE_FOURCC('t','r','k','n')
1613 #define FOURCC_cpil     GST_MAKE_FOURCC('c','p','i','l')
1614 #define FOURCC_tmpo     GST_MAKE_FOURCC('t','m','p','o')
1615 #define FOURCC__too     GST_MAKE_FOURCC(0xa9,'t','o','o')
1616 #define FOURCC_____     GST_MAKE_FOURCC('-','-','-','-')
1617 #define FOURCC_free     GST_MAKE_FOURCC('f','r','e','e')
1618 #define FOURCC_data     GST_MAKE_FOURCC('d','a','t','a')
1619 #define FOURCC_SVQ3     GST_MAKE_FOURCC('S','V','Q','3')
1620 #define FOURCC_rmra     GST_MAKE_FOURCC('r','m','r','a')
1621 #define FOURCC_rmda     GST_MAKE_FOURCC('r','m','d','a')
1622 #define FOURCC_rdrf     GST_MAKE_FOURCC('r','d','r','f')
1623 #define FOURCC__gen     GST_MAKE_FOURCC(0xa9, 'g', 'e', 'n')
1624
1625 static void qtdemux_dump_mvhd (GstQTDemux * qtdemux, void *buffer, int depth);
1626 static void qtdemux_dump_tkhd (GstQTDemux * qtdemux, void *buffer, int depth);
1627 static void qtdemux_dump_elst (GstQTDemux * qtdemux, void *buffer, int depth);
1628 static void qtdemux_dump_mdhd (GstQTDemux * qtdemux, void *buffer, int depth);
1629 static void qtdemux_dump_hdlr (GstQTDemux * qtdemux, void *buffer, int depth);
1630 static void qtdemux_dump_vmhd (GstQTDemux * qtdemux, void *buffer, int depth);
1631 static void qtdemux_dump_dref (GstQTDemux * qtdemux, void *buffer, int depth);
1632 static void qtdemux_dump_stsd (GstQTDemux * qtdemux, void *buffer, int depth);
1633 static void qtdemux_dump_stts (GstQTDemux * qtdemux, void *buffer, int depth);
1634 static void qtdemux_dump_stss (GstQTDemux * qtdemux, void *buffer, int depth);
1635 static void qtdemux_dump_stsc (GstQTDemux * qtdemux, void *buffer, int depth);
1636 static void qtdemux_dump_stsz (GstQTDemux * qtdemux, void *buffer, int depth);
1637 static void qtdemux_dump_stco (GstQTDemux * qtdemux, void *buffer, int depth);
1638 static void qtdemux_dump_co64 (GstQTDemux * qtdemux, void *buffer, int depth);
1639 static void qtdemux_dump_dcom (GstQTDemux * qtdemux, void *buffer, int depth);
1640 static void qtdemux_dump_cmvd (GstQTDemux * qtdemux, void *buffer, int depth);
1641 static void qtdemux_dump_unknown (GstQTDemux * qtdemux, void *buffer,
1642     int depth);
1643
1644 QtNodeType qt_node_types[] = {
1645   {FOURCC_moov, "movie", QT_CONTAINER,},
1646   {FOURCC_mvhd, "movie header", 0,
1647       qtdemux_dump_mvhd},
1648   {FOURCC_clip, "clipping", QT_CONTAINER,},
1649   {FOURCC_trak, "track", QT_CONTAINER,},
1650   {FOURCC_udta, "user data", QT_CONTAINER,},    /* special container */
1651   {FOURCC_ctab, "color table", 0,},
1652   {FOURCC_tkhd, "track header", 0,
1653       qtdemux_dump_tkhd},
1654   {FOURCC_crgn, "clipping region", 0,},
1655   {FOURCC_matt, "track matte", QT_CONTAINER,},
1656   {FOURCC_kmat, "compressed matte", 0,},
1657   {FOURCC_edts, "edit", QT_CONTAINER,},
1658   {FOURCC_elst, "edit list", 0,
1659       qtdemux_dump_elst},
1660   {FOURCC_load, "track load settings", 0,},
1661   {FOURCC_tref, "track reference", QT_CONTAINER,},
1662   {FOURCC_imap, "track input map", QT_CONTAINER,},
1663   {FOURCC___in, "track input", 0,},     /* special container */
1664   {FOURCC___ty, "input type", 0,},
1665   {FOURCC_mdia, "media", QT_CONTAINER},
1666   {FOURCC_mdhd, "media header", 0,
1667       qtdemux_dump_mdhd},
1668   {FOURCC_hdlr, "handler reference", 0,
1669       qtdemux_dump_hdlr},
1670   {FOURCC_minf, "media information", QT_CONTAINER},
1671   {FOURCC_vmhd, "video media information", 0,
1672       qtdemux_dump_vmhd},
1673   {FOURCC_smhd, "sound media information", 0},
1674   {FOURCC_gmhd, "base media information header", 0},
1675   {FOURCC_gmin, "base media info", 0},
1676   {FOURCC_dinf, "data information", QT_CONTAINER},
1677   {FOURCC_dref, "data reference", 0,
1678       qtdemux_dump_dref},
1679   {FOURCC_stbl, "sample table", QT_CONTAINER},
1680   {FOURCC_stsd, "sample description", 0,
1681       qtdemux_dump_stsd},
1682   {FOURCC_stts, "time-to-sample", 0,
1683       qtdemux_dump_stts},
1684   {FOURCC_stss, "sync sample", 0,
1685       qtdemux_dump_stss},
1686   {FOURCC_stsc, "sample-to-chunk", 0,
1687       qtdemux_dump_stsc},
1688   {FOURCC_stsz, "sample size", 0,
1689       qtdemux_dump_stsz},
1690   {FOURCC_stco, "chunk offset", 0,
1691       qtdemux_dump_stco},
1692   {FOURCC_co64, "64-bit chunk offset", 0,
1693       qtdemux_dump_co64},
1694   {FOURCC_vide, "video media", 0},
1695   {FOURCC_cmov, "compressed movie", QT_CONTAINER},
1696   {FOURCC_dcom, "compressed data", 0, qtdemux_dump_dcom},
1697   {FOURCC_cmvd, "compressed movie data", 0, qtdemux_dump_cmvd},
1698   {FOURCC_hint, "hint", 0,},
1699   {FOURCC_mp4a, "mp4a", 0,},
1700   {FOURCC_mp4v, "mp4v", 0,},
1701   {FOURCC_wave, "wave", QT_CONTAINER},
1702   {FOURCC_appl, "appl", QT_CONTAINER},
1703   {FOURCC_esds, "esds", 0},
1704   {FOURCC_hnti, "hnti", QT_CONTAINER},
1705   {FOURCC_rtp_, "rtp ", 0, qtdemux_dump_unknown},
1706   {FOURCC_sdp_, "sdp ", 0, qtdemux_dump_unknown},
1707   {FOURCC_meta, "meta", 0, qtdemux_dump_unknown},
1708   {FOURCC_ilst, "ilst", QT_CONTAINER,},
1709   {FOURCC__nam, "Name", QT_CONTAINER,},
1710   {FOURCC__ART, "Artist", QT_CONTAINER,},
1711   {FOURCC__wrt, "Writer", QT_CONTAINER,},
1712   {FOURCC__grp, "Group", QT_CONTAINER,},
1713   {FOURCC__alb, "Album", QT_CONTAINER,},
1714   {FOURCC_gnre, "Genre", QT_CONTAINER,},
1715   {FOURCC_trkn, "Track Number", QT_CONTAINER,},
1716   {FOURCC_disc, "Disc Number", QT_CONTAINER,},
1717   {FOURCC_disk, "Disc Number", QT_CONTAINER,},
1718   {FOURCC_cpil, "cpil", QT_CONTAINER,},
1719   {FOURCC_tmpo, "Tempo", QT_CONTAINER,},
1720   {FOURCC__too, "too", QT_CONTAINER,},
1721   {FOURCC_____, "----", QT_CONTAINER,},
1722   {FOURCC_data, "data", 0, qtdemux_dump_unknown},
1723   {FOURCC_free, "free", 0,},
1724   {FOURCC_SVQ3, "SVQ3", 0,},
1725   {FOURCC_rmra, "rmra", QT_CONTAINER,},
1726   {FOURCC_rmda, "rmda", QT_CONTAINER,},
1727   {FOURCC_rdrf, "rdrf", 0,},
1728   {FOURCC__gen, "Custom Genre", QT_CONTAINER,},
1729   {0, "unknown", 0},
1730 };
1731 static int n_qt_node_types = sizeof (qt_node_types) / sizeof (qt_node_types[0]);
1732
1733
1734 static void *
1735 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
1736 {
1737   return g_malloc (items * size);
1738 }
1739
1740 static void
1741 qtdemux_zfree (void *opaque, void *addr)
1742 {
1743   g_free (addr);
1744 }
1745
1746 static void *
1747 qtdemux_inflate (void *z_buffer, int z_length, int length)
1748 {
1749   void *buffer;
1750   z_stream *z;
1751   int ret;
1752
1753   z = g_new0 (z_stream, 1);
1754   z->zalloc = qtdemux_zalloc;
1755   z->zfree = qtdemux_zfree;
1756   z->opaque = NULL;
1757
1758   z->next_in = z_buffer;
1759   z->avail_in = z_length;
1760
1761   buffer = g_malloc (length);
1762   ret = inflateInit (z);
1763   while (z->avail_in > 0) {
1764     if (z->avail_out == 0) {
1765       length += 1024;
1766       buffer = realloc (buffer, length);
1767       z->next_out = buffer + z->total_out;
1768       z->avail_out = 1024;
1769     }
1770     ret = inflate (z, Z_SYNC_FLUSH);
1771     if (ret != Z_OK)
1772       break;
1773   }
1774   if (ret != Z_STREAM_END) {
1775     g_warning ("inflate() returned %d", ret);
1776   }
1777
1778   g_free (z);
1779   return buffer;
1780 }
1781
1782 static void
1783 qtdemux_parse_moov (GstQTDemux * qtdemux, void *buffer, int length)
1784 {
1785   GNode *cmov;
1786
1787   qtdemux->moov_node = g_node_new (buffer);
1788
1789   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
1790   qtdemux_parse (qtdemux, qtdemux->moov_node, buffer, length);
1791
1792   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
1793   if (cmov) {
1794     GNode *dcom;
1795     GNode *cmvd;
1796
1797     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
1798     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
1799
1800     if (QTDEMUX_FOURCC_GET (dcom->data + 8) == GST_MAKE_FOURCC ('z', 'l', 'i',
1801             'b')) {
1802       int uncompressed_length;
1803       int compressed_length;
1804       void *buf;
1805
1806       uncompressed_length = QTDEMUX_GUINT32_GET (cmvd->data + 8);
1807       compressed_length = QTDEMUX_GUINT32_GET (cmvd->data + 4) - 12;
1808       GST_LOG ("length = %d", uncompressed_length);
1809
1810       buf = qtdemux_inflate (cmvd->data + 12, compressed_length,
1811           uncompressed_length);
1812
1813       qtdemux->moov_node_compressed = qtdemux->moov_node;
1814       qtdemux->moov_node = g_node_new (buf);
1815
1816       qtdemux_parse (qtdemux, qtdemux->moov_node, buf, uncompressed_length);
1817     } else {
1818       GST_LOG ("unknown header compression type");
1819     }
1820   }
1821 }
1822
1823 static void
1824 qtdemux_parse (GstQTDemux * qtdemux, GNode * node, void *buffer, int length)
1825 {
1826   guint32 fourcc;
1827   guint32 node_length;
1828   QtNodeType *type;
1829   void *end;
1830
1831   GST_LOG ("qtdemux_parse buffer %p length %d", buffer, length);
1832
1833   node_length = QTDEMUX_GUINT32_GET (buffer);
1834   fourcc = QTDEMUX_FOURCC_GET (buffer + 4);
1835
1836   type = qtdemux_type_get (fourcc);
1837
1838   if (fourcc == 0 || node_length == 8)
1839     return;
1840
1841   GST_LOG ("parsing '%" GST_FOURCC_FORMAT "', length=%d",
1842       GST_FOURCC_ARGS (fourcc), node_length);
1843
1844   if (type->flags & QT_CONTAINER) {
1845     void *buf;
1846     guint32 len;
1847
1848     buf = buffer + 8;
1849     end = buffer + length;
1850     while (buf < end) {
1851       GNode *child;
1852
1853       if (buf + 8 >= end) {
1854         /* FIXME: get annoyed */
1855         GST_LOG ("buffer overrun");
1856       }
1857       len = QTDEMUX_GUINT32_GET (buf);
1858       if (len < 8) {
1859         GST_WARNING ("atom length too short (%d < 8)", len);
1860         break;
1861       }
1862       if (len > (end - buf)) {
1863         GST_WARNING ("atom length too long (%d > %d)", len, end - buf);
1864         break;
1865       }
1866
1867       child = g_node_new (buf);
1868       g_node_append (node, child);
1869       qtdemux_parse (qtdemux, child, buf, len);
1870
1871       buf += len;
1872     }
1873   } else {
1874     if (fourcc == FOURCC_stsd) {
1875       void *buf;
1876       guint32 len;
1877
1878       GST_DEBUG_OBJECT (qtdemux,
1879           "parsing stsd (sample table, sample description) atom");
1880       buf = buffer + 16;
1881       end = buffer + length;
1882       while (buf < end) {
1883         GNode *child;
1884
1885         if (buf + 8 >= end) {
1886           /* FIXME: get annoyed */
1887           GST_LOG ("buffer overrun");
1888         }
1889         len = QTDEMUX_GUINT32_GET (buf);
1890         if (len < 8) {
1891           GST_WARNING ("length too short (%d < 8)");
1892           break;
1893         }
1894         if (len > (end - buf)) {
1895           GST_WARNING ("length too long (%d > %d)", len, end - buf);
1896           break;
1897         }
1898
1899         child = g_node_new (buf);
1900         g_node_append (node, child);
1901         qtdemux_parse (qtdemux, child, buf, len);
1902
1903         buf += len;
1904       }
1905     } else if (fourcc == FOURCC_mp4a) {
1906       void *buf;
1907       guint32 len;
1908       guint32 version;
1909
1910       version = QTDEMUX_GUINT32_GET (buffer + 16);
1911       if (version == 0x00010000 || 1) {
1912         buf = buffer + 0x24;
1913         end = buffer + length;
1914
1915         while (buf < end) {
1916           GNode *child;
1917
1918           if (buf + 8 >= end) {
1919             /* FIXME: get annoyed */
1920             GST_LOG ("buffer overrun");
1921           }
1922           len = QTDEMUX_GUINT32_GET (buf);
1923           if (len < 8) {
1924             GST_WARNING ("length too short (%d < 8)");
1925             break;
1926           }
1927           if (len > (end - buf)) {
1928             GST_WARNING ("length too long (%d > %d)", len, end - buf);
1929             break;
1930           }
1931
1932           child = g_node_new (buf);
1933           g_node_append (node, child);
1934           qtdemux_parse (qtdemux, child, buf, len);
1935
1936           buf += len;
1937         }
1938       }
1939     } else if (fourcc == FOURCC_mp4v) {
1940       void *buf;
1941       guint32 len;
1942       guint32 version;
1943       int tlen;
1944
1945       GST_DEBUG_OBJECT (qtdemux, "parsing in mp4v");
1946       version = QTDEMUX_GUINT32_GET (buffer + 16);
1947       GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
1948       if (1 || version == 0x00000000) {
1949
1950         buf = buffer + 0x32;
1951         end = buffer + length;
1952
1953         /* FIXME Quicktime uses PASCAL string while
1954          * the iso format uses C strings. Check the file
1955          * type before attempting to parse the string here. */
1956         tlen = QTDEMUX_GUINT8_GET (buf);
1957         GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
1958         buf++;
1959         GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
1960         /* the string has a reserved space of 32 bytes so skip
1961          * the remaining 31 */
1962         buf += 31;
1963         buf += 4;               /* and 4 bytes reserved */
1964
1965         gst_util_dump_mem (buf, end - buf);
1966         while (buf < end) {
1967           GNode *child;
1968
1969           if (buf + 8 >= end) {
1970             /* FIXME: get annoyed */
1971             GST_LOG ("buffer overrun");
1972           }
1973           len = QTDEMUX_GUINT32_GET (buf);
1974           if (len == 0)
1975             break;
1976           if (len < 8) {
1977             GST_WARNING ("length too short (%d < 8)");
1978             break;
1979           }
1980           if (len > (end - buf)) {
1981             GST_WARNING ("length too long (%d > %d)", len, end - buf);
1982             break;
1983           }
1984
1985           child = g_node_new (buf);
1986           g_node_append (node, child);
1987           qtdemux_parse (qtdemux, child, buf, len);
1988
1989           buf += len;
1990         }
1991       }
1992     } else if (fourcc == FOURCC_meta) {
1993       void *buf;
1994       guint32 len;
1995
1996       buf = buffer + 12;
1997       end = buffer + length;
1998       while (buf < end) {
1999         GNode *child;
2000
2001         if (buf + 8 >= end) {
2002           /* FIXME: get annoyed */
2003           GST_LOG ("buffer overrun");
2004         }
2005         len = QTDEMUX_GUINT32_GET (buf);
2006         if (len < 8) {
2007           GST_WARNING ("length too short (%d < 8)");
2008           break;
2009         }
2010         if (len > (end - buf)) {
2011           GST_WARNING ("length too long (%d > %d)", len, end - buf);
2012           break;
2013         }
2014
2015         child = g_node_new (buf);
2016         g_node_append (node, child);
2017         qtdemux_parse (qtdemux, child, buf, len);
2018
2019         buf += len;
2020       }
2021     } else if (fourcc == FOURCC_SVQ3) {
2022       void *buf;
2023       guint32 len;
2024       guint32 version;
2025       int tlen;
2026
2027       GST_LOG ("parsing in SVQ3");
2028       buf = buffer + 12;
2029       end = buffer + length;
2030       version = QTDEMUX_GUINT32_GET (buffer + 16);
2031       GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
2032       if (1 || version == 0x00000000) {
2033
2034         buf = buffer + 0x32;
2035         end = buffer + length;
2036
2037         tlen = QTDEMUX_GUINT8_GET (buf);
2038         GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
2039         buf++;
2040         GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
2041         buf += tlen;
2042         buf += 23;
2043
2044         gst_util_dump_mem (buf, end - buf);
2045         while (buf < end) {
2046           GNode *child;
2047
2048           if (buf + 8 >= end) {
2049             /* FIXME: get annoyed */
2050             GST_LOG ("buffer overrun");
2051           }
2052           len = QTDEMUX_GUINT32_GET (buf);
2053           if (len == 0)
2054             break;
2055           if (len < 8) {
2056             GST_WARNING ("length too short (%d < 8)");
2057             break;
2058           }
2059           if (len > (end - buf)) {
2060             GST_WARNING ("length too long (%d > %d)", len, end - buf);
2061             break;
2062           }
2063
2064           child = g_node_new (buf);
2065           g_node_append (node, child);
2066           qtdemux_parse (qtdemux, child, buf, len);
2067
2068           buf += len;
2069         }
2070       }
2071     }
2072 #if 0
2073     if (fourcc == FOURCC_cmvd) {
2074       int uncompressed_length;
2075       void *buf;
2076
2077       uncompressed_length = QTDEMUX_GUINT32_GET (buffer + 8);
2078       GST_LOG ("length = %d", uncompressed_length);
2079
2080       buf =
2081           qtdemux_inflate (buffer + 12, node_length - 12, uncompressed_length);
2082
2083       end = buf + uncompressed_length;
2084       while (buf < end) {
2085         GNode *child;
2086         guint32 len;
2087
2088         if (buf + 8 >= end) {
2089           /* FIXME: get annoyed */
2090           GST_LOG ("buffer overrun");
2091         }
2092         len = QTDEMUX_GUINT32_GET (buf);
2093
2094         child = g_node_new (buf);
2095         g_node_append (node, child);
2096         qtdemux_parse (qtdemux, child, buf, len);
2097
2098         buf += len;
2099       }
2100     }
2101 #endif
2102   }
2103 }
2104
2105 static QtNodeType *
2106 qtdemux_type_get (guint32 fourcc)
2107 {
2108   int i;
2109
2110   for (i = 0; i < n_qt_node_types; i++) {
2111     if (qt_node_types[i].fourcc == fourcc)
2112       return qt_node_types + i;
2113   }
2114
2115   GST_WARNING ("unknown QuickTime node type %" GST_FOURCC_FORMAT,
2116       GST_FOURCC_ARGS (fourcc));
2117   return qt_node_types + n_qt_node_types - 1;
2118 }
2119
2120 static gboolean
2121 qtdemux_node_dump_foreach (GNode * node, gpointer data)
2122 {
2123   void *buffer = node->data;
2124   guint32 node_length;
2125   guint32 fourcc;
2126   QtNodeType *type;
2127   int depth;
2128
2129   node_length = GST_READ_UINT32_BE (buffer);
2130   fourcc = GST_READ_UINT32_LE (buffer + 4);
2131
2132   type = qtdemux_type_get (fourcc);
2133
2134   depth = (g_node_depth (node) - 1) * 2;
2135   GST_LOG ("%*s'%" GST_FOURCC_FORMAT "', [%d], %s",
2136       depth, "", GST_FOURCC_ARGS (fourcc), node_length, type->name);
2137
2138   if (type->dump)
2139     type->dump (data, buffer, depth);
2140
2141   return FALSE;
2142 }
2143
2144 static void
2145 qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node)
2146 {
2147   g_node_traverse (qtdemux->moov_node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
2148       qtdemux_node_dump_foreach, qtdemux);
2149 }
2150
2151 static void
2152 qtdemux_dump_mvhd (GstQTDemux * qtdemux, void *buffer, int depth)
2153 {
2154   GST_LOG ("%*s  version/flags: %08x", depth, "",
2155       QTDEMUX_GUINT32_GET (buffer + 8));
2156   GST_LOG ("%*s  creation time: %u", depth, "",
2157       QTDEMUX_GUINT32_GET (buffer + 12));
2158   GST_LOG ("%*s  modify time:   %u", depth, "",
2159       QTDEMUX_GUINT32_GET (buffer + 16));
2160   qtdemux->duration = QTDEMUX_GUINT32_GET (buffer + 24);
2161   qtdemux->timescale = QTDEMUX_GUINT32_GET (buffer + 20);
2162   GST_LOG ("%*s  time scale:    1/%u sec", depth, "", qtdemux->timescale);
2163   GST_LOG ("%*s  duration:      %u", depth, "", qtdemux->duration);
2164   GST_LOG ("%*s  pref. rate:    %g", depth, "", QTDEMUX_FP32_GET (buffer + 28));
2165   GST_LOG ("%*s  pref. volume:  %g", depth, "", QTDEMUX_FP16_GET (buffer + 32));
2166   GST_LOG ("%*s  preview time:  %u", depth, "",
2167       QTDEMUX_GUINT32_GET (buffer + 80));
2168   GST_LOG ("%*s  preview dur.:  %u", depth, "",
2169       QTDEMUX_GUINT32_GET (buffer + 84));
2170   GST_LOG ("%*s  poster time:   %u", depth, "",
2171       QTDEMUX_GUINT32_GET (buffer + 88));
2172   GST_LOG ("%*s  select time:   %u", depth, "",
2173       QTDEMUX_GUINT32_GET (buffer + 92));
2174   GST_LOG ("%*s  select dur.:   %u", depth, "",
2175       QTDEMUX_GUINT32_GET (buffer + 96));
2176   GST_LOG ("%*s  current time:  %u", depth, "",
2177       QTDEMUX_GUINT32_GET (buffer + 100));
2178   GST_LOG ("%*s  next track ID: %d", depth, "",
2179       QTDEMUX_GUINT32_GET (buffer + 104));
2180 }
2181
2182 static void
2183 qtdemux_dump_tkhd (GstQTDemux * qtdemux, void *buffer, int depth)
2184 {
2185   GST_LOG ("%*s  version/flags: %08x", depth, "",
2186       QTDEMUX_GUINT32_GET (buffer + 8));
2187   GST_LOG ("%*s  creation time: %u", depth, "",
2188       QTDEMUX_GUINT32_GET (buffer + 12));
2189   GST_LOG ("%*s  modify time:   %u", depth, "",
2190       QTDEMUX_GUINT32_GET (buffer + 16));
2191   GST_LOG ("%*s  track ID:      %u", depth, "",
2192       QTDEMUX_GUINT32_GET (buffer + 20));
2193   GST_LOG ("%*s  duration:      %u", depth, "",
2194       QTDEMUX_GUINT32_GET (buffer + 28));
2195   GST_LOG ("%*s  layer:         %u", depth, "",
2196       QTDEMUX_GUINT16_GET (buffer + 36));
2197   GST_LOG ("%*s  alt group:     %u", depth, "",
2198       QTDEMUX_GUINT16_GET (buffer + 38));
2199   GST_LOG ("%*s  volume:        %g", depth, "", QTDEMUX_FP16_GET (buffer + 44));
2200   GST_LOG ("%*s  track width:   %g", depth, "", QTDEMUX_FP32_GET (buffer + 84));
2201   GST_LOG ("%*s  track height:  %g", depth, "", QTDEMUX_FP32_GET (buffer + 88));
2202
2203 }
2204
2205 static void
2206 qtdemux_dump_elst (GstQTDemux * qtdemux, void *buffer, int depth)
2207 {
2208   int i;
2209   int n;
2210
2211   GST_LOG ("%*s  version/flags: %08x", depth, "",
2212       QTDEMUX_GUINT32_GET (buffer + 8));
2213   GST_LOG ("%*s  n entries:     %u", depth, "",
2214       QTDEMUX_GUINT32_GET (buffer + 12));
2215   n = QTDEMUX_GUINT32_GET (buffer + 12);
2216   for (i = 0; i < n; i++) {
2217     GST_LOG ("%*s    track dur:     %u", depth, "",
2218         QTDEMUX_GUINT32_GET (buffer + 16 + i * 12));
2219     GST_LOG ("%*s    media time:    %u", depth, "",
2220         QTDEMUX_GUINT32_GET (buffer + 20 + i * 12));
2221     GST_LOG ("%*s    media rate:    %g", depth, "",
2222         QTDEMUX_FP32_GET (buffer + 24 + i * 12));
2223   }
2224 }
2225
2226 static void
2227 qtdemux_dump_mdhd (GstQTDemux * qtdemux, void *buffer, int depth)
2228 {
2229   GST_LOG ("%*s  version/flags: %08x", depth, "",
2230       QTDEMUX_GUINT32_GET (buffer + 8));
2231   GST_LOG ("%*s  creation time: %u", depth, "",
2232       QTDEMUX_GUINT32_GET (buffer + 12));
2233   GST_LOG ("%*s  modify time:   %u", depth, "",
2234       QTDEMUX_GUINT32_GET (buffer + 16));
2235   GST_LOG ("%*s  time scale:    1/%u sec", depth, "",
2236       QTDEMUX_GUINT32_GET (buffer + 20));
2237   GST_LOG ("%*s  duration:      %u", depth, "",
2238       QTDEMUX_GUINT32_GET (buffer + 24));
2239   GST_LOG ("%*s  language:      %u", depth, "",
2240       QTDEMUX_GUINT16_GET (buffer + 28));
2241   GST_LOG ("%*s  quality:       %u", depth, "",
2242       QTDEMUX_GUINT16_GET (buffer + 30));
2243
2244 }
2245
2246 static void
2247 qtdemux_dump_hdlr (GstQTDemux * qtdemux, void *buffer, int depth)
2248 {
2249   GST_LOG ("%*s  version/flags: %08x", depth, "",
2250       QTDEMUX_GUINT32_GET (buffer + 8));
2251   GST_LOG ("%*s  type:          %" GST_FOURCC_FORMAT, depth, "",
2252       GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 12)));
2253   GST_LOG ("%*s  subtype:       %" GST_FOURCC_FORMAT, depth, "",
2254       GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 16)));
2255   GST_LOG ("%*s  manufacturer:  %" GST_FOURCC_FORMAT, depth, "",
2256       GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 20)));
2257   GST_LOG ("%*s  flags:         %08x", depth, "",
2258       QTDEMUX_GUINT32_GET (buffer + 24));
2259   GST_LOG ("%*s  flags mask:    %08x", depth, "",
2260       QTDEMUX_GUINT32_GET (buffer + 28));
2261   GST_LOG ("%*s  name:          %*s", depth, "",
2262       QTDEMUX_GUINT8_GET (buffer + 32), (char *) (buffer + 33));
2263
2264 }
2265
2266 static void
2267 qtdemux_dump_vmhd (GstQTDemux * qtdemux, void *buffer, int depth)
2268 {
2269   GST_LOG ("%*s  version/flags: %08x", depth, "",
2270       QTDEMUX_GUINT32_GET (buffer + 8));
2271   GST_LOG ("%*s  mode/color:    %08x", depth, "",
2272       QTDEMUX_GUINT32_GET (buffer + 16));
2273 }
2274
2275 static void
2276 qtdemux_dump_dref (GstQTDemux * qtdemux, void *buffer, int depth)
2277 {
2278   int n;
2279   int i;
2280   int offset;
2281
2282   GST_LOG ("%*s  version/flags: %08x", depth, "",
2283       QTDEMUX_GUINT32_GET (buffer + 8));
2284   GST_LOG ("%*s  n entries:     %u", depth, "",
2285       QTDEMUX_GUINT32_GET (buffer + 12));
2286   n = QTDEMUX_GUINT32_GET (buffer + 12);
2287   offset = 16;
2288   for (i = 0; i < n; i++) {
2289     GST_LOG ("%*s    size:          %u", depth, "",
2290         QTDEMUX_GUINT32_GET (buffer + offset));
2291     GST_LOG ("%*s    type:          %" GST_FOURCC_FORMAT, depth, "",
2292         GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + offset + 4)));
2293     offset += QTDEMUX_GUINT32_GET (buffer + offset);
2294   }
2295 }
2296
2297 static void
2298 qtdemux_dump_stsd (GstQTDemux * qtdemux, void *buffer, int depth)
2299 {
2300   int i;
2301   int n;
2302   int offset;
2303
2304   GST_LOG ("%*s  version/flags: %08x", depth, "",
2305       QTDEMUX_GUINT32_GET (buffer + 8));
2306   GST_LOG ("%*s  n entries:     %d", depth, "",
2307       QTDEMUX_GUINT32_GET (buffer + 12));
2308   n = QTDEMUX_GUINT32_GET (buffer + 12);
2309   offset = 16;
2310   for (i = 0; i < n; i++) {
2311     GST_LOG ("%*s    size:          %u", depth, "",
2312         QTDEMUX_GUINT32_GET (buffer + offset));
2313     GST_LOG ("%*s    type:          %" GST_FOURCC_FORMAT, depth, "",
2314         GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + offset + 4)));
2315     GST_LOG ("%*s    data reference:%d", depth, "",
2316         QTDEMUX_GUINT16_GET (buffer + offset + 14));
2317
2318     GST_LOG ("%*s    version/rev.:  %08x", depth, "",
2319         QTDEMUX_GUINT32_GET (buffer + offset + 16));
2320     GST_LOG ("%*s    vendor:        %" GST_FOURCC_FORMAT, depth, "",
2321         GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + offset + 20)));
2322     GST_LOG ("%*s    temporal qual: %u", depth, "",
2323         QTDEMUX_GUINT32_GET (buffer + offset + 24));
2324     GST_LOG ("%*s    spatial qual:  %u", depth, "",
2325         QTDEMUX_GUINT32_GET (buffer + offset + 28));
2326     GST_LOG ("%*s    width:         %u", depth, "",
2327         QTDEMUX_GUINT16_GET (buffer + offset + 32));
2328     GST_LOG ("%*s    height:        %u", depth, "",
2329         QTDEMUX_GUINT16_GET (buffer + offset + 34));
2330     GST_LOG ("%*s    horiz. resol:  %g", depth, "",
2331         QTDEMUX_FP32_GET (buffer + offset + 36));
2332     GST_LOG ("%*s    vert. resol.:  %g", depth, "",
2333         QTDEMUX_FP32_GET (buffer + offset + 40));
2334     GST_LOG ("%*s    data size:     %u", depth, "",
2335         QTDEMUX_GUINT32_GET (buffer + offset + 44));
2336     GST_LOG ("%*s    frame count:   %u", depth, "",
2337         QTDEMUX_GUINT16_GET (buffer + offset + 48));
2338     GST_LOG ("%*s    compressor:    %d %d %d", depth, "",
2339         QTDEMUX_GUINT8_GET (buffer + offset + 49),
2340         QTDEMUX_GUINT8_GET (buffer + offset + 50),
2341         QTDEMUX_GUINT8_GET (buffer + offset + 51));
2342     //(char *) (buffer + offset + 51));
2343     GST_LOG ("%*s    depth:         %u", depth, "",
2344         QTDEMUX_GUINT16_GET (buffer + offset + 82));
2345     GST_LOG ("%*s    color table ID:%u", depth, "",
2346         QTDEMUX_GUINT16_GET (buffer + offset + 84));
2347
2348     offset += QTDEMUX_GUINT32_GET (buffer + offset);
2349   }
2350 }
2351
2352 static void
2353 qtdemux_dump_stts (GstQTDemux * qtdemux, void *buffer, int depth)
2354 {
2355   int i;
2356   int n;
2357   int offset;
2358
2359   GST_LOG ("%*s  version/flags: %08x", depth, "",
2360       QTDEMUX_GUINT32_GET (buffer + 8));
2361   GST_LOG ("%*s  n entries:     %d", depth, "",
2362       QTDEMUX_GUINT32_GET (buffer + 12));
2363   n = QTDEMUX_GUINT32_GET (buffer + 12);
2364   offset = 16;
2365   for (i = 0; i < n; i++) {
2366     GST_LOG ("%*s    count:         %u", depth, "",
2367         QTDEMUX_GUINT32_GET (buffer + offset));
2368     GST_LOG ("%*s    duration:      %u", depth, "",
2369         QTDEMUX_GUINT32_GET (buffer + offset + 4));
2370
2371     offset += 8;
2372   }
2373 }
2374
2375 static void
2376 qtdemux_dump_stss (GstQTDemux * qtdemux, void *buffer, int depth)
2377 {
2378   int i;
2379   int n;
2380   int offset;
2381
2382   GST_LOG ("%*s  version/flags: %08x", depth, "",
2383       QTDEMUX_GUINT32_GET (buffer + 8));
2384   GST_LOG ("%*s  n entries:     %d", depth, "",
2385       QTDEMUX_GUINT32_GET (buffer + 12));
2386   n = QTDEMUX_GUINT32_GET (buffer + 12);
2387   offset = 16;
2388   for (i = 0; i < n; i++) {
2389     GST_LOG ("%*s    sample:        %u", depth, "",
2390         QTDEMUX_GUINT32_GET (buffer + offset));
2391
2392     offset += 4;
2393   }
2394 }
2395
2396 static void
2397 qtdemux_dump_stsc (GstQTDemux * qtdemux, void *buffer, int depth)
2398 {
2399   int i;
2400   int n;
2401   int offset;
2402
2403   GST_LOG ("%*s  version/flags: %08x", depth, "",
2404       QTDEMUX_GUINT32_GET (buffer + 8));
2405   GST_LOG ("%*s  n entries:     %d", depth, "",
2406       QTDEMUX_GUINT32_GET (buffer + 12));
2407   n = QTDEMUX_GUINT32_GET (buffer + 12);
2408   offset = 16;
2409   for (i = 0; i < n; i++) {
2410     GST_LOG ("%*s    first chunk:   %u", depth, "",
2411         QTDEMUX_GUINT32_GET (buffer + offset));
2412     GST_LOG ("%*s    sample per ch: %u", depth, "",
2413         QTDEMUX_GUINT32_GET (buffer + offset + 4));
2414     GST_LOG ("%*s    sample desc id:%08x", depth, "",
2415         QTDEMUX_GUINT32_GET (buffer + offset + 8));
2416
2417     offset += 12;
2418   }
2419 }
2420
2421 static void
2422 qtdemux_dump_stsz (GstQTDemux * qtdemux, void *buffer, int depth)
2423 {
2424   //int i;
2425   int n;
2426   int offset;
2427   int sample_size;
2428
2429   GST_LOG ("%*s  version/flags: %08x", depth, "",
2430       QTDEMUX_GUINT32_GET (buffer + 8));
2431   GST_LOG ("%*s  sample size:   %d", depth, "",
2432       QTDEMUX_GUINT32_GET (buffer + 12));
2433   sample_size = QTDEMUX_GUINT32_GET (buffer + 12);
2434   if (sample_size == 0) {
2435     GST_LOG ("%*s  n entries:     %d", depth, "",
2436         QTDEMUX_GUINT32_GET (buffer + 16));
2437     n = QTDEMUX_GUINT32_GET (buffer + 16);
2438     offset = 20;
2439 #if 0
2440     for (i = 0; i < n; i++) {
2441       GST_LOG ("%*s    sample size:   %u", depth, "",
2442           QTDEMUX_GUINT32_GET (buffer + offset));
2443
2444       offset += 4;
2445     }
2446 #endif
2447   }
2448 }
2449
2450 static void
2451 qtdemux_dump_stco (GstQTDemux * qtdemux, void *buffer, int depth)
2452 {
2453   //int i;
2454   int n;
2455   int offset;
2456
2457   GST_LOG ("%*s  version/flags: %08x", depth, "",
2458       QTDEMUX_GUINT32_GET (buffer + 8));
2459   GST_LOG ("%*s  n entries:     %d", depth, "",
2460       QTDEMUX_GUINT32_GET (buffer + 12));
2461   n = QTDEMUX_GUINT32_GET (buffer + 12);
2462   offset = 16;
2463 #if 0
2464   for (i = 0; i < n; i++) {
2465     GST_LOG ("%*s    chunk offset:  %08x", depth, "",
2466         QTDEMUX_GUINT32_GET (buffer + offset));
2467
2468     offset += 4;
2469   }
2470 #endif
2471 }
2472
2473 static void
2474 qtdemux_dump_co64 (GstQTDemux * qtdemux, void *buffer, int depth)
2475 {
2476   //int i;
2477   int n;
2478   int offset;
2479
2480   GST_LOG ("%*s  version/flags: %08x", depth, "",
2481       QTDEMUX_GUINT32_GET (buffer + 8));
2482   GST_LOG ("%*s  n entries:     %d", depth, "",
2483       QTDEMUX_GUINT32_GET (buffer + 12));
2484   n = QTDEMUX_GUINT32_GET (buffer + 12);
2485   offset = 16;
2486 #if 0
2487   for (i = 0; i < n; i++) {
2488     GST_LOG ("%*s    chunk offset:  %" G_GUINT64_FORMAT, depth, "",
2489         QTDEMUX_GUINT64_GET (buffer + offset));
2490
2491     offset += 8;
2492   }
2493 #endif
2494 }
2495
2496 static void
2497 qtdemux_dump_dcom (GstQTDemux * qtdemux, void *buffer, int depth)
2498 {
2499   GST_LOG ("%*s  compression type: %" GST_FOURCC_FORMAT, depth, "",
2500       GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 8)));
2501 }
2502
2503 static void
2504 qtdemux_dump_cmvd (GstQTDemux * qtdemux, void *buffer, int depth)
2505 {
2506   GST_LOG ("%*s  length: %d", depth, "", QTDEMUX_GUINT32_GET (buffer + 8));
2507 }
2508
2509 static void
2510 qtdemux_dump_unknown (GstQTDemux * qtdemux, void *buffer, int depth)
2511 {
2512   int len;
2513
2514   GST_LOG ("%*s  length: %d", depth, "", QTDEMUX_GUINT32_GET (buffer + 0));
2515
2516   len = QTDEMUX_GUINT32_GET (buffer + 0);
2517   gst_util_dump_mem (buffer, len);
2518
2519 }
2520
2521
2522 static GNode *
2523 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
2524 {
2525   GNode *child;
2526   void *buffer;
2527   guint32 child_fourcc;
2528
2529   for (child = g_node_first_child (node); child;
2530       child = g_node_next_sibling (child)) {
2531     buffer = child->data;
2532
2533     child_fourcc = GST_READ_UINT32_LE (buffer);
2534     GST_LOG ("First chunk of buffer %p is [%" GST_FOURCC_FORMAT "]",
2535         buffer, GST_FOURCC_ARGS (child_fourcc));
2536
2537     child_fourcc = GST_READ_UINT32_LE (buffer + 4);
2538     GST_LOG ("buffer %p has fourcc [%" GST_FOURCC_FORMAT "]",
2539         buffer, GST_FOURCC_ARGS (child_fourcc));
2540
2541     if (child_fourcc == fourcc) {
2542       return child;
2543     }
2544   }
2545   return NULL;
2546 }
2547
2548 static GNode *
2549 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
2550 {
2551   GNode *child;
2552   void *buffer;
2553   guint32 child_fourcc;
2554
2555   for (child = g_node_next_sibling (node); child;
2556       child = g_node_next_sibling (child)) {
2557     buffer = child->data;
2558
2559     child_fourcc = GST_READ_UINT32_LE (buffer + 4);
2560
2561     if (child_fourcc == fourcc) {
2562       return child;
2563     }
2564   }
2565   return NULL;
2566 }
2567
2568 static void qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak);
2569
2570 static void
2571 qtdemux_parse_tree (GstQTDemux * qtdemux)
2572 {
2573   GNode *mvhd;
2574   GNode *trak;
2575   GNode *udta;
2576
2577   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
2578   if (mvhd == NULL) {
2579     GNode *rmra, *rmda, *rdrf;
2580
2581     rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
2582     if (rmra) {
2583       rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
2584       if (rmra) {
2585         rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
2586         if (rdrf) {
2587           GstStructure *s;
2588           GstMessage *msg;
2589
2590           GST_LOG ("New location: %s", (char *) rdrf->data + 20);
2591           s = gst_structure_new ("redirect", "new-location", G_TYPE_STRING,
2592               (char *) rdrf->data + 20, NULL);
2593           msg = gst_message_new_element (GST_OBJECT (qtdemux), s);
2594           gst_element_post_message (GST_ELEMENT (qtdemux), msg);
2595           return;
2596         }
2597       }
2598     }
2599
2600     GST_LOG ("No mvhd node found.");
2601     return;
2602   }
2603
2604   qtdemux->timescale = QTDEMUX_GUINT32_GET (mvhd->data + 20);
2605   qtdemux->duration = QTDEMUX_GUINT32_GET (mvhd->data + 24);
2606
2607   GST_INFO_OBJECT (qtdemux, "timescale: %d", qtdemux->timescale);
2608   GST_INFO_OBJECT (qtdemux, "duration: %d", qtdemux->duration);
2609
2610   if (qtdemux->timescale != 0 && qtdemux->duration != 0) {
2611     gint64 duration;
2612
2613     duration = gst_util_uint64_scale_int (qtdemux->duration,
2614         GST_SECOND, qtdemux->timescale);
2615
2616     gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
2617   }
2618
2619   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
2620   qtdemux_parse_trak (qtdemux, trak);
2621
2622 /*  trak = qtdemux_tree_get_sibling_by_type(trak, FOURCC_trak);
2623   if(trak)qtdemux_parse_trak(qtdemux, trak);*/
2624
2625   /* kid pads */
2626   while ((trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak)) != NULL)
2627     qtdemux_parse_trak (qtdemux, trak);
2628   gst_element_no_more_pads (GST_ELEMENT (qtdemux));
2629
2630   /* tags */
2631   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
2632   if (udta) {
2633     qtdemux_parse_udta (qtdemux, udta);
2634
2635     if (qtdemux->tag_list) {
2636       GST_DEBUG_OBJECT (qtdemux,
2637           "calling gst_element_found_tags with %" GST_PTR_FORMAT,
2638           qtdemux->tag_list);
2639       gst_element_found_tags (GST_ELEMENT (qtdemux), qtdemux->tag_list);
2640       qtdemux->tag_list = NULL;
2641     }
2642   } else {
2643     GST_LOG ("No udta node found.");
2644   }
2645 }
2646
2647 static void
2648 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
2649 {
2650   int offset;
2651   GNode *tkhd;
2652   GNode *mdia;
2653   GNode *mdhd;
2654   GNode *hdlr;
2655   GNode *minf;
2656   GNode *stbl;
2657   GNode *stsd;
2658   GNode *stsc;
2659   GNode *stss;
2660   GNode *stsz;
2661   GNode *stco;
2662   GNode *co64;
2663   GNode *stts;
2664   GNode *mp4a;
2665   GNode *mp4v;
2666   GNode *wave;
2667   GNode *esds;
2668   int n_samples;
2669   QtDemuxSample *samples;
2670   int n_samples_per_chunk;
2671   int index;
2672   int i, j, k;
2673   QtDemuxStream *stream;
2674   int n_sample_times;
2675   guint64 timestamp;
2676   int sample_size;
2677   int sample_index;
2678   GstTagList *list = NULL;
2679   const gchar *codec = NULL;
2680
2681   tkhd = qtdemux_tree_get_child_by_type (trak, FOURCC_tkhd);
2682   g_return_if_fail (tkhd);
2683
2684   GST_LOG ("track[tkhd] version/flags: 0x%08x",
2685       QTDEMUX_GUINT32_GET (tkhd->data + 8));
2686
2687   /* track duration? */
2688
2689   mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia);
2690   g_assert (mdia);
2691
2692   mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd);
2693   g_assert (mdhd);
2694
2695   /* new streams always need a discont */
2696   stream = g_new0 (QtDemuxStream, 1);
2697   stream->discont = TRUE;
2698
2699   stream->timescale = QTDEMUX_GUINT32_GET (mdhd->data + 20);
2700   GST_LOG ("track timescale: %d", stream->timescale);
2701   GST_LOG ("track duration: %d", QTDEMUX_GUINT32_GET (mdhd->data + 24));
2702
2703   /* HACK:
2704    * some of those trailers, nowadays, have prologue images that are
2705    * themselves vide tracks as well. I haven't really found a way to
2706    * identify those yet, except for just looking at their duration. */
2707   if (stream->timescale * qtdemux->duration != 0 &&
2708       (guint64) QTDEMUX_GUINT32_GET (mdhd->data + 24) *
2709       qtdemux->timescale * 10 / (stream->timescale * qtdemux->duration) < 2) {
2710     GST_WARNING ("Track shorter than 20%% (%d/%d vs. %d/%d) of the stream "
2711         "found, assuming preview image or something; skipping track",
2712         QTDEMUX_GUINT32_GET (mdhd->data + 24), stream->timescale,
2713         qtdemux->duration, qtdemux->timescale);
2714     g_free (stream);
2715     return;
2716   }
2717
2718   hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr);
2719   g_assert (hdlr);
2720
2721   GST_LOG ("track type: %" GST_FOURCC_FORMAT,
2722       GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (hdlr->data + 12)));
2723   GST_LOG ("track subtype: %" GST_FOURCC_FORMAT,
2724       GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (hdlr->data + 16)));
2725
2726   stream->subtype = QTDEMUX_FOURCC_GET (hdlr->data + 16);
2727
2728   minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf);
2729   g_assert (minf);
2730
2731   stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl);
2732   g_assert (stbl);
2733
2734   stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd);
2735   g_assert (stsd);
2736
2737   if (stream->subtype == FOURCC_vide) {
2738     guint32 fourcc;
2739
2740     offset = 16;
2741     GST_LOG ("st type:          %" GST_FOURCC_FORMAT,
2742         GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd->data + offset + 4)));
2743
2744     stream->width = QTDEMUX_GUINT16_GET (stsd->data + offset + 32);
2745     stream->height = QTDEMUX_GUINT16_GET (stsd->data + offset + 34);
2746     stream->fps_n = 0;          /* this is filled in later */
2747     stream->fps_d = 0;          /* this is filled in later */
2748     stream->bits_per_sample = QTDEMUX_GUINT16_GET (stsd->data + offset + 82);
2749     stream->color_table_id = QTDEMUX_GUINT16_GET (stsd->data + offset + 84);
2750
2751     GST_LOG ("frame count:   %u",
2752         QTDEMUX_GUINT16_GET (stsd->data + offset + 48));
2753
2754     stream->fourcc = fourcc = QTDEMUX_FOURCC_GET (stsd->data + offset + 4);
2755     stream->caps = qtdemux_video_caps (qtdemux, fourcc, stsd->data, &codec);
2756     if (codec) {
2757       list = gst_tag_list_new ();
2758       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
2759           GST_TAG_VIDEO_CODEC, codec, NULL);
2760     }
2761
2762     esds = NULL;
2763     mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4v);
2764     if (mp4v)
2765       esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
2766
2767     if (esds) {
2768       gst_qtdemux_handle_esds (qtdemux, stream, esds);
2769     } else {
2770       if (QTDEMUX_FOURCC_GET ((char *) stsd->data + 16 + 4) ==
2771           GST_MAKE_FOURCC ('a', 'v', 'c', '1')) {
2772         gint len = QTDEMUX_GUINT32_GET (stsd->data) - 0x66;
2773         guint8 *stsddata = stsd->data + 0x66;
2774
2775         /* find avcC */
2776         while (len >= 0x8 &&
2777             QTDEMUX_FOURCC_GET (stsddata + 0x4) !=
2778             GST_MAKE_FOURCC ('a', 'v', 'c', 'C') &&
2779             QTDEMUX_GUINT32_GET (stsddata) < len) {
2780           len -= QTDEMUX_GUINT32_GET (stsddata);
2781           stsddata += QTDEMUX_GUINT32_GET (stsddata);
2782         }
2783
2784         /* parse, if found */
2785         if (len > 0x8 &&
2786             QTDEMUX_FOURCC_GET (stsddata + 0x4) ==
2787             GST_MAKE_FOURCC ('a', 'v', 'c', 'C')) {
2788           GstBuffer *buf;
2789           gint size;
2790
2791           if (QTDEMUX_GUINT32_GET (stsddata) < len)
2792             size = QTDEMUX_GUINT32_GET (stsddata) - 0x8;
2793           else
2794             size = len - 0x8;
2795
2796           buf = gst_buffer_new_and_alloc (size);
2797           memcpy (GST_BUFFER_DATA (buf), stsddata + 0x8, size);
2798           gst_caps_set_simple (stream->caps,
2799               "codec_data", GST_TYPE_BUFFER, buf, NULL);
2800           gst_buffer_unref (buf);
2801         }
2802       } else if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2803           GST_MAKE_FOURCC ('S', 'V', 'Q', '3')) {
2804         GstBuffer *buf;
2805         gint len = QTDEMUX_GUINT32_GET (stsd->data);
2806
2807         buf = gst_buffer_new_and_alloc (len);
2808         memcpy (GST_BUFFER_DATA (buf), stsd->data, len);
2809         gst_caps_set_simple (stream->caps,
2810             "codec_data", GST_TYPE_BUFFER, buf, NULL);
2811         gst_buffer_unref (buf);
2812       } else if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2813           GST_MAKE_FOURCC ('V', 'P', '3', '1')) {
2814         GstBuffer *buf;
2815         gint len = QTDEMUX_GUINT32_GET (stsd->data);
2816
2817         buf = gst_buffer_new_and_alloc (len);
2818         memcpy (GST_BUFFER_DATA (buf), stsd->data, len);
2819         gst_caps_set_simple (stream->caps,
2820             "codec_data", GST_TYPE_BUFFER, buf, NULL);
2821         gst_buffer_unref (buf);
2822       } else if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2823           GST_MAKE_FOURCC ('r', 'l', 'e', ' ')) {
2824         gst_caps_set_simple (stream->caps,
2825             "depth", G_TYPE_INT, QTDEMUX_GUINT16_GET (stsd->data + offset + 82),
2826             NULL);
2827       }
2828     }
2829
2830     GST_INFO_OBJECT (qtdemux,
2831         "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
2832         GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd->data + offset + 4)),
2833         stream->caps);
2834   } else if (stream->subtype == FOURCC_soun) {
2835     int version, samplesize;
2836     guint32 fourcc;
2837     int len;
2838
2839     len = QTDEMUX_GUINT32_GET (stsd->data + 16);
2840     GST_LOG ("st type:          %" GST_FOURCC_FORMAT,
2841         GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4)));
2842
2843     stream->fourcc = fourcc = QTDEMUX_FOURCC_GET (stsd->data + 16 + 4);
2844     offset = 32;
2845
2846     GST_LOG ("version/rev:      %08x",
2847         QTDEMUX_GUINT32_GET (stsd->data + offset));
2848     version = QTDEMUX_GUINT32_GET (stsd->data + offset);
2849     GST_LOG ("vendor:           %08x",
2850         QTDEMUX_GUINT32_GET (stsd->data + offset + 4));
2851     GST_LOG ("n_channels:       %d",
2852         QTDEMUX_GUINT16_GET (stsd->data + offset + 8));
2853     stream->n_channels = QTDEMUX_GUINT16_GET (stsd->data + offset + 8);
2854     GST_LOG ("sample_size:      %d",
2855         QTDEMUX_GUINT16_GET (stsd->data + offset + 10));
2856     samplesize = QTDEMUX_GUINT16_GET (stsd->data + offset + 10);
2857     GST_LOG ("compression_id:   %d",
2858         QTDEMUX_GUINT16_GET (stsd->data + offset + 12));
2859     GST_LOG ("packet size:      %d",
2860         QTDEMUX_GUINT16_GET (stsd->data + offset + 14));
2861     GST_LOG ("sample rate:      %g",
2862         QTDEMUX_FP32_GET (stsd->data + offset + 16));
2863     stream->rate = QTDEMUX_FP32_GET (stsd->data + offset + 16);
2864
2865     offset = 52;
2866     if (version == 0x00010000) {
2867       GST_LOG ("samples/packet:   %d",
2868           QTDEMUX_GUINT32_GET (stsd->data + offset));
2869       stream->samples_per_packet = QTDEMUX_GUINT32_GET (stsd->data + offset);
2870       GST_LOG ("bytes/packet:     %d",
2871           QTDEMUX_GUINT32_GET (stsd->data + offset + 4));
2872       GST_LOG ("bytes/frame:      %d",
2873           QTDEMUX_GUINT32_GET (stsd->data + offset + 8));
2874       stream->bytes_per_frame = QTDEMUX_GUINT32_GET (stsd->data + offset + 8);
2875       GST_LOG ("bytes/sample:     %d",
2876           QTDEMUX_GUINT32_GET (stsd->data + offset + 12));
2877       stream->compression = 1;
2878       offset = 68;
2879     } else if (version == 0x00000000) {
2880       stream->bytes_per_frame = stream->n_channels * samplesize / 8;
2881       stream->samples_per_packet = 1;
2882       stream->compression = 1;
2883
2884       /* Yes, these have to be hard-coded */
2885       if (fourcc == GST_MAKE_FOURCC ('M', 'A', 'C', '6'))
2886         stream->compression = 6;
2887       if (fourcc == GST_MAKE_FOURCC ('M', 'A', 'C', '3'))
2888         stream->compression = 3;
2889       if (fourcc == GST_MAKE_FOURCC ('i', 'm', 'a', '4'))
2890         stream->compression = 4;
2891       if (fourcc == GST_MAKE_FOURCC ('s', 'a', 'm', 'r')) {
2892         stream->n_channels = 1;
2893         stream->rate = 8000;
2894         stream->bytes_per_frame <<= 3;
2895       }
2896       if (fourcc == GST_MAKE_FOURCC ('u', 'l', 'a', 'w'))
2897         stream->compression = 2;
2898       if (fourcc == GST_MAKE_FOURCC ('a', 'g', 's', 'm')) {
2899         stream->bytes_per_frame *= 33;
2900         stream->compression = 320;
2901       }
2902     } else {
2903       GST_WARNING ("unknown version %08x", version);
2904     }
2905
2906     stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
2907         &codec);
2908
2909     if (codec) {
2910       list = gst_tag_list_new ();
2911       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
2912           GST_TAG_AUDIO_CODEC, codec, NULL);
2913     }
2914
2915     mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
2916     wave = NULL;
2917     if (mp4a)
2918       wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
2919
2920     esds = NULL;
2921     if (wave)
2922       esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
2923     else if (mp4a)
2924       esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
2925
2926     if (esds) {
2927       gst_qtdemux_handle_esds (qtdemux, stream, esds);
2928 #if 0
2929       GstBuffer *buffer;
2930       int len = QTDEMUX_GUINT32_GET (esds->data);
2931
2932       buffer = gst_buffer_new_and_alloc (len - 8);
2933       memcpy (GST_BUFFER_DATA (buffer), esds->data + 8, len - 8);
2934
2935       gst_caps_set_simple (stream->caps, "codec_data",
2936           GST_TYPE_BUFFER, buffer, NULL);
2937 #endif
2938     } else {
2939       if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2940           GST_MAKE_FOURCC ('Q', 'D', 'M', '2')) {
2941         gint len = QTDEMUX_GUINT32_GET (stsd->data);
2942
2943         if (len > 0x4C) {
2944           GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
2945
2946           memcpy (GST_BUFFER_DATA (buf),
2947               (guint8 *) stsd->data + 0x4C, len - 0x4C);
2948           gst_caps_set_simple (stream->caps,
2949               "codec_data", GST_TYPE_BUFFER, buf, NULL);
2950           gst_buffer_unref (buf);
2951         }
2952         gst_caps_set_simple (stream->caps,
2953             "samplesize", G_TYPE_INT, samplesize, NULL);
2954       } else if (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4) ==
2955           GST_MAKE_FOURCC ('a', 'l', 'a', 'c')) {
2956         gint len = QTDEMUX_GUINT32_GET (stsd->data);
2957
2958         if (len > 0x34) {
2959           GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
2960
2961           memcpy (GST_BUFFER_DATA (buf),
2962               (guint8 *) stsd->data + 0x34, len - 0x34);
2963           gst_caps_set_simple (stream->caps,
2964               "codec_data", GST_TYPE_BUFFER, buf, NULL);
2965           gst_buffer_unref (buf);
2966         }
2967         gst_caps_set_simple (stream->caps,
2968             "samplesize", G_TYPE_INT, samplesize, NULL);
2969       }
2970     }
2971     GST_INFO_OBJECT (qtdemux,
2972         "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
2973         GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd->data + 16 + 4)),
2974         stream->caps);
2975   } else {
2976     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
2977         GST_FOURCC_ARGS (stream->subtype));
2978     g_free (stream);
2979     return;
2980   }
2981
2982   /* sample to chunk */
2983   stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc);
2984   g_assert (stsc);
2985   /* sample size */
2986   stsz = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsz);
2987   g_assert (stsz);
2988   /* chunk offsets */
2989   stco = qtdemux_tree_get_child_by_type (stbl, FOURCC_stco);
2990   co64 = qtdemux_tree_get_child_by_type (stbl, FOURCC_co64);
2991   g_assert (stco || co64);
2992   /* sample time */
2993   stts = qtdemux_tree_get_child_by_type (stbl, FOURCC_stts);
2994   g_assert (stts);
2995   /* sample sync, can be NULL */
2996   stss = qtdemux_tree_get_child_by_type (stbl, FOURCC_stss);
2997
2998   sample_size = QTDEMUX_GUINT32_GET (stsz->data + 12);
2999   if (sample_size == 0) {
3000     n_samples = QTDEMUX_GUINT32_GET (stsz->data + 16);
3001     GST_DEBUG_OBJECT (qtdemux, "stsz sample_size 0, allocating n_samples %d",
3002         n_samples);
3003     stream->n_samples = n_samples;
3004     samples = g_malloc (sizeof (QtDemuxSample) * n_samples);
3005     stream->samples = samples;
3006
3007     for (i = 0; i < n_samples; i++) {
3008       samples[i].size = QTDEMUX_GUINT32_GET (stsz->data + i * 4 + 20);
3009       GST_LOG_OBJECT (qtdemux, "sample %d has size %d", i, samples[i].size);
3010       /* init other fields to defaults for this sample */
3011       samples[i].keyframe = FALSE;
3012     }
3013     n_samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 12);
3014     index = 0;
3015     offset = 16;
3016     for (i = 0; i < n_samples_per_chunk; i++) {
3017       int first_chunk, last_chunk;
3018       int samples_per_chunk;
3019
3020       first_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 0) - 1;
3021       if (i == n_samples_per_chunk - 1) {
3022         last_chunk = INT_MAX;
3023       } else {
3024         last_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 12) - 1;
3025       }
3026       samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 4);
3027
3028       for (j = first_chunk; j < last_chunk; j++) {
3029         guint64 chunk_offset;
3030
3031         if (stco) {
3032           chunk_offset = QTDEMUX_GUINT32_GET (stco->data + 16 + j * 4);
3033         } else {
3034           chunk_offset = QTDEMUX_GUINT64_GET (co64->data + 16 + j * 8);
3035         }
3036         for (k = 0; k < samples_per_chunk; k++) {
3037           GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld",
3038               index, chunk_offset);
3039           samples[index].chunk = j;
3040           samples[index].offset = chunk_offset;
3041           chunk_offset += samples[index].size;
3042           index++;
3043           if (index >= n_samples)
3044             goto done;
3045         }
3046       }
3047     }
3048   done:
3049
3050     n_sample_times = QTDEMUX_GUINT32_GET (stts->data + 12);
3051     timestamp = 0;
3052     index = 0;
3053     for (i = 0; i < n_sample_times; i++) {
3054       int n;
3055       int duration;
3056       guint64 time;
3057
3058       n = QTDEMUX_GUINT32_GET (stts->data + 16 + 8 * i);
3059       duration = QTDEMUX_GUINT32_GET (stts->data + 16 + 8 * i + 4);
3060       time =
3061           gst_util_uint64_scale_int (duration, GST_SECOND, stream->timescale);
3062       for (j = 0; j < n; j++) {
3063         //GST_INFO("moo %lld", timestamp);
3064         samples[index].timestamp = timestamp;
3065         samples[index].duration = duration;
3066         timestamp += time;
3067         index++;
3068       }
3069     }
3070     if (stss) {
3071       /* mark keyframes */
3072       guint32 n_sample_syncs;
3073
3074       n_sample_syncs = QTDEMUX_GUINT32_GET (stss->data + 12);
3075       if (n_sample_syncs == 0) {
3076         stream->all_keyframe = TRUE;
3077       } else {
3078         offset = 16;
3079         for (i = 0; i < n_sample_syncs; i++) {
3080           /* not that the first sample is index 1, not 0 */
3081           index = QTDEMUX_GUINT32_GET (stss->data + offset);
3082           samples[index - 1].keyframe = TRUE;
3083           offset += 4;
3084         }
3085       }
3086     } else {
3087       /* no stss, all samples are keyframes */
3088       stream->all_keyframe = TRUE;
3089     }
3090   } else {
3091     guint64 timestamp = 0;
3092
3093     GST_DEBUG_OBJECT (qtdemux,
3094         "stsz sample_size %d != 0, treating chunks as samples", sample_size);
3095
3096     /* treat chunks as samples */
3097     if (stco) {
3098       n_samples = QTDEMUX_GUINT32_GET (stco->data + 12);
3099     } else {
3100       n_samples = QTDEMUX_GUINT32_GET (co64->data + 12);
3101     }
3102     stream->n_samples = n_samples;
3103     GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %d", n_samples);
3104     samples = g_malloc (sizeof (QtDemuxSample) * n_samples);
3105     stream->samples = samples;
3106
3107     n_samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 12);
3108     GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %d", n_samples_per_chunk);
3109     offset = 16;
3110     sample_index = 0;
3111     for (i = 0; i < n_samples_per_chunk; i++) {
3112       int first_chunk, last_chunk;
3113       int samples_per_chunk;
3114
3115       first_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 0) - 1;
3116       /* the last chunk of each entry is calculated by taking the first chunk
3117        * of the next entry; except if there is no next, where we fake it with
3118        * INT_MAX */
3119       if (i == n_samples_per_chunk - 1) {
3120         last_chunk = INT_MAX;
3121       } else {
3122         last_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 12) - 1;
3123       }
3124       samples_per_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 4);
3125
3126       GST_LOG_OBJECT (qtdemux,
3127           "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
3128           first_chunk, last_chunk, samples_per_chunk);
3129
3130       for (j = first_chunk; j < last_chunk; j++) {
3131         guint64 chunk_offset;
3132
3133         if (j >= n_samples)
3134           goto done2;
3135         if (stco) {
3136           chunk_offset = QTDEMUX_GUINT32_GET (stco->data + 16 + j * 4);
3137           GST_LOG_OBJECT (qtdemux, "stco chunk %d offset %x", j, chunk_offset);
3138         } else {
3139           chunk_offset = QTDEMUX_GUINT64_GET (co64->data + 16 + j * 8);
3140           GST_LOG_OBJECT (qtdemux, "co64 chunk %d offset %" G_GUINT64_FORMAT, j,
3141               chunk_offset);
3142         }
3143         GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld",
3144             j, chunk_offset);
3145         samples[j].chunk = j;
3146         samples[j].offset = chunk_offset;
3147         if (stream->samples_per_packet * stream->compression != 0)
3148           samples[j].size =
3149               samples_per_chunk * stream->bytes_per_frame /
3150               stream->samples_per_packet / stream->compression;
3151         else if (stream->bytes_per_frame)
3152           samples[j].size = stream->bytes_per_frame;
3153         else
3154           samples[j].size = sample_size;
3155         samples[j].duration =
3156             samples_per_chunk * stream->timescale / (stream->rate / 2);
3157         samples[j].timestamp = timestamp;
3158         samples[j].keyframe = TRUE;
3159
3160         if (stream->rate > 0) {
3161           timestamp += gst_util_uint64_scale_int (samples_per_chunk,
3162               GST_SECOND, stream->rate);
3163         }
3164 #if 0
3165         GST_INFO_OBJECT (qtdemux,
3166             "moo samples_per_chunk=%d rate=%d dur=%lld %lld",
3167             (int) samples_per_chunk, (int) stream->rate,
3168             (long long) ((samples_per_chunk * GST_SECOND) / stream->rate),
3169             (long long) timestamp);
3170 #endif
3171         samples[j].sample_index = sample_index;
3172         sample_index += samples_per_chunk;
3173       }
3174     }
3175   }
3176 done2:
3177 #if 0
3178   for (i = 0; i < n_samples; i++) {
3179     GST_LOG ("%d: %d %d %d %d %" G_GUINT64_FORMAT, i,
3180         samples[i].sample_index, samples[i].chunk,
3181         samples[i].offset, samples[i].size, samples[i].timestamp);
3182     if (i > 10)
3183       break;
3184   }
3185 #endif
3186   gst_qtdemux_add_stream (qtdemux, stream, list);
3187 }
3188
3189 static void
3190 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
3191 {
3192   GNode *meta;
3193   GNode *ilst;
3194   GNode *node;
3195
3196   meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
3197   if (meta == NULL) {
3198     GST_LOG ("no meta");
3199     return;
3200   }
3201
3202   ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
3203   if (ilst == NULL) {
3204     GST_LOG ("no ilst");
3205     return;
3206   }
3207
3208   GST_DEBUG_OBJECT (qtdemux, "new tag list");
3209   qtdemux->tag_list = gst_tag_list_new ();
3210
3211   node = qtdemux_tree_get_child_by_type (ilst, FOURCC__nam);
3212   if (node) {
3213     qtdemux_tag_add_str (qtdemux, GST_TAG_TITLE, node);
3214   }
3215
3216   node = qtdemux_tree_get_child_by_type (ilst, FOURCC__ART);
3217   if (node) {
3218     qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
3219   } else {
3220     node = qtdemux_tree_get_child_by_type (ilst, FOURCC__wrt);
3221     if (node) {
3222       qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
3223     } else {
3224       node = qtdemux_tree_get_child_by_type (ilst, FOURCC__grp);
3225       if (node) {
3226         qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
3227       }
3228     }
3229   }
3230
3231   node = qtdemux_tree_get_child_by_type (ilst, FOURCC__alb);
3232   if (node) {
3233     qtdemux_tag_add_str (qtdemux, GST_TAG_ALBUM, node);
3234   }
3235
3236   node = qtdemux_tree_get_child_by_type (ilst, FOURCC_trkn);
3237   if (node) {
3238     qtdemux_tag_add_num (qtdemux, GST_TAG_TRACK_NUMBER,
3239         GST_TAG_TRACK_COUNT, node);
3240   }
3241
3242   node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disc);
3243   if (node) {
3244     qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER,
3245         GST_TAG_ALBUM_VOLUME_COUNT, node);
3246   } else {
3247     node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disk);
3248     if (node) {
3249       qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER,
3250           GST_TAG_ALBUM_VOLUME_COUNT, node);
3251     }
3252   }
3253
3254   node = qtdemux_tree_get_child_by_type (ilst, FOURCC_gnre);
3255   if (node) {
3256     qtdemux_tag_add_gnre (qtdemux, GST_TAG_GENRE, node);
3257   } else {
3258     node = qtdemux_tree_get_child_by_type (ilst, FOURCC__gen);
3259     if (node) {
3260       qtdemux_tag_add_str (qtdemux, GST_TAG_GENRE, node);
3261     }
3262   }
3263 }
3264
3265 static void
3266 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag, GNode * node)
3267 {
3268   GNode *data;
3269   char *s;
3270   int len;
3271   int type;
3272
3273   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3274   if (data) {
3275     len = QTDEMUX_GUINT32_GET (data->data);
3276     type = QTDEMUX_GUINT32_GET (data->data + 8);
3277     if (type == 0x00000001) {
3278       s = g_strndup ((char *) data->data + 16, len - 16);
3279       GST_DEBUG_OBJECT (qtdemux, "adding tag %s", s);
3280       gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
3281       g_free (s);
3282     }
3283   }
3284 }
3285
3286 static void
3287 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
3288     const char *tag2, GNode * node)
3289 {
3290   GNode *data;
3291   int len;
3292   int type;
3293   int n1, n2;
3294
3295   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3296   if (data) {
3297     len = QTDEMUX_GUINT32_GET (data->data);
3298     type = QTDEMUX_GUINT32_GET (data->data + 8);
3299     if (type == 0x00000000 && len >= 22) {
3300       n1 = GST_READ_UINT16_BE (data->data + 18);
3301       n2 = GST_READ_UINT16_BE (data->data + 20);
3302       GST_DEBUG_OBJECT (qtdemux, "adding tag %d/%d", n1, n2);
3303       gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
3304           tag1, n1, tag2, n2, NULL);
3305     }
3306   }
3307 }
3308
3309 static void
3310 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, GNode * node)
3311 {
3312   const gchar *genres[] = {
3313     "N/A", "Blues", "Classic Rock", "Country", "Dance", "Disco",
3314     "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
3315     "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno",
3316     "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
3317     "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
3318     "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
3319     "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
3320     "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative",
3321     "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
3322     "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk",
3323     "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
3324     "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American",
3325     "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes",
3326     "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka",
3327     "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
3328     "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob",
3329     "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde",
3330     "Gothic Rock", "Progressive Rock", "Psychedelic Rock",
3331     "Symphonic Rock", "Slow Rock", "Big Band", "Chorus",
3332     "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
3333     "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
3334     "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango",
3335     "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul",
3336     "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella",
3337     "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club House",
3338     "Hardcore", "Terror", "Indie", "BritPop", "NegerPunk",
3339     "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal",
3340     "Black Metal", "Crossover", "Contemporary C", "Christian Rock",
3341     "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop"
3342   };
3343   GNode *data;
3344   int len;
3345   int type;
3346   int n;
3347
3348   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3349   if (data) {
3350     len = QTDEMUX_GUINT32_GET (data->data);
3351     type = QTDEMUX_GUINT32_GET (data->data + 8);
3352     if (type == 0x00000000 && len >= 18) {
3353       n = GST_READ_UINT16_BE (data->data + 16);
3354       if (n > 0 && n < sizeof (genres) / sizeof (char *)) {
3355         GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genres[n]);
3356         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
3357             tag, genres[n], NULL);
3358       }
3359     }
3360   }
3361 }
3362
3363 /* taken from ffmpeg */
3364 static unsigned int
3365 get_size (guint8 * ptr, guint8 ** end)
3366 {
3367   int count = 4;
3368   int len = 0;
3369
3370   while (count--) {
3371     int c = *ptr;
3372
3373     ptr++;
3374     len = (len << 7) | (c & 0x7f);
3375     if (!(c & 0x80))
3376       break;
3377   }
3378   if (end)
3379     *end = ptr;
3380   return len;
3381 }
3382
3383 static void
3384 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
3385     GNode * esds)
3386 {
3387   int len = QTDEMUX_GUINT32_GET (esds->data);
3388   guint8 *ptr = esds->data;
3389   guint8 *end = ptr + len;
3390   int tag;
3391   guint8 *data_ptr = NULL;
3392   int data_len = 0;
3393
3394   gst_util_dump_mem (ptr, len);
3395   ptr += 8;
3396   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QTDEMUX_GUINT32_GET (ptr));
3397   ptr += 4;
3398   while (ptr < end) {
3399     tag = QTDEMUX_GUINT8_GET (ptr);
3400     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
3401     ptr++;
3402     len = get_size (ptr, &ptr);
3403     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
3404
3405     switch (tag) {
3406       case 0x03:
3407         GST_DEBUG_OBJECT (qtdemux, "ID %04x", QTDEMUX_GUINT16_GET (ptr));
3408         GST_DEBUG_OBJECT (qtdemux, "priority %04x",
3409             QTDEMUX_GUINT8_GET (ptr + 2));
3410         ptr += 3;
3411         break;
3412       case 0x04:
3413         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x",
3414             QTDEMUX_GUINT8_GET (ptr));
3415         GST_DEBUG_OBJECT (qtdemux, "stream_type %02x",
3416             QTDEMUX_GUINT8_GET (ptr + 1));
3417         GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x",
3418             QTDEMUX_GUINT24_GET (ptr + 2));
3419         GST_DEBUG_OBJECT (qtdemux, "max bitrate %d",
3420             QTDEMUX_GUINT32_GET (ptr + 5));
3421         GST_DEBUG_OBJECT (qtdemux, "avg bitrate %d",
3422             QTDEMUX_GUINT32_GET (ptr + 9));
3423         ptr += 13;
3424         break;
3425       case 0x05:
3426         GST_DEBUG_OBJECT (qtdemux, "data:");
3427         gst_util_dump_mem (ptr, len);
3428         data_ptr = ptr;
3429         data_len = len;
3430         ptr += len;
3431         break;
3432       case 0x06:
3433         GST_DEBUG_OBJECT (qtdemux, "data %02x", QTDEMUX_GUINT8_GET (ptr));
3434         ptr += 1;
3435         break;
3436       default:
3437         GST_ERROR ("parse error");
3438     }
3439   }
3440
3441   if (data_ptr) {
3442     GstBuffer *buffer;
3443
3444     buffer = gst_buffer_new_and_alloc (data_len);
3445     memcpy (GST_BUFFER_DATA (buffer), data_ptr, data_len);
3446     gst_util_dump_mem (GST_BUFFER_DATA (buffer), data_len);
3447
3448     gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
3449         buffer, NULL);
3450     gst_buffer_unref (buffer);
3451   }
3452 }
3453
3454 #define _codec(name) \
3455   do { \
3456     if (codec_name) { \
3457       *codec_name = name; \
3458     } \
3459   } while (0)
3460
3461 static GstCaps *
3462 qtdemux_video_caps (GstQTDemux * qtdemux, guint32 fourcc,
3463     const guint8 * stsd_data, const gchar ** codec_name)
3464 {
3465   switch (fourcc) {
3466     case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
3467       _codec ("PNG still images");
3468       return gst_caps_from_string ("image/png");
3469     case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
3470       _codec ("JPEG still images");
3471       return gst_caps_from_string ("image/jpeg");
3472     case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
3473     case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
3474       _codec ("Motion-JPEG");
3475       return gst_caps_from_string ("image/jpeg");
3476     case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
3477       _codec ("Motion-JPEG format B");
3478       return gst_caps_from_string ("video/x-mjpeg-b");
3479     case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
3480       _codec ("Sorensen video v.3");
3481       return gst_caps_from_string ("video/x-svq, " "svqversion = (int) 3");
3482     case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
3483     case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
3484       _codec ("Sorensen video v.1");
3485       return gst_caps_from_string ("video/x-svq, " "svqversion = (int) 1");
3486     case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
3487       _codec ("Raw RGB video");
3488       return gst_caps_from_string ("video/x-raw-rgb, "
3489           "endianness = (int) BIG_ENDIAN");
3490       /*"bpp", GST_PROPS_INT(x),
3491          "depth", GST_PROPS_INT(x),
3492          "red_mask", GST_PROPS_INT(x),
3493          "green_mask", GST_PROPS_INT(x),
3494          "blue_mask", GST_PROPS_INT(x), FIXME! */
3495     case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
3496       _codec ("Raw packed YUV 4:2:2");
3497       return gst_caps_from_string ("video/x-raw-yuv, "
3498           "format = (fourcc) YUY2");
3499     case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
3500       _codec ("MPEG-1 video");
3501       return gst_caps_from_string ("video/mpeg, "
3502           "systemstream = (boolean) false, " "mpegversion = (int) 1");
3503     case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
3504       _codec ("GIF still images");
3505       return gst_caps_from_string ("image/gif");
3506     case GST_MAKE_FOURCC ('h', '2', '6', '3'):
3507     case GST_MAKE_FOURCC ('s', '2', '6', '3'):
3508       _codec ("H.263");
3509       /* ffmpeg uses the height/width props, don't know why */
3510       return gst_caps_from_string ("video/x-h263");
3511     case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
3512       _codec ("MPEG-4 video");
3513       return gst_caps_from_string ("video/mpeg, "
3514           "mpegversion = (int) 4, " "systemstream = (boolean) false");
3515     case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
3516     case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
3517       _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
3518       return gst_caps_from_string ("video/x-msmpeg, msmpegversion = (int) 43");
3519     case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
3520     case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
3521       _codec ("3ivX video");
3522       return gst_caps_from_string ("video/x-3ivx");
3523     case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
3524       _codec ("DivX 3");
3525       return gst_caps_from_string ("video/x-divx," "divxversion= (int) 3");
3526     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
3527       _codec ("DivX 4");
3528       return gst_caps_from_string ("video/x-divx," "divxversion= (int) 4");
3529
3530     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
3531       _codec ("DivX 5");
3532       return gst_caps_from_string ("video/x-divx," "divxversion= (int) 5");
3533     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
3534       _codec ("Cinepak");
3535       return gst_caps_from_string ("video/x-cinepak");
3536     case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
3537       _codec ("Apple video");
3538       return gst_caps_from_string ("video/x-apple-video");
3539     case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
3540       _codec ("H.264 / AVC");
3541       return gst_caps_from_string ("video/x-h264");
3542     case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
3543       _codec ("Run-length encoding");
3544       return gst_caps_from_string ("video/x-rle, layout=(string)quicktime");
3545     case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
3546       _codec ("Indeo Video 3");
3547       return gst_caps_from_string ("video/x-indeo, indeoversion=(int)3");
3548     case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
3549     case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
3550     case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
3551     case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
3552       _codec ("DV Video");
3553       return gst_caps_from_string ("video/x-dv, systemstream=(boolean)false");
3554     case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
3555       _codec ("Apple Graphics (SMC)");
3556       return gst_caps_from_string ("video/x-smc");
3557     case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
3558       _codec ("VP3");
3559       return gst_caps_from_string ("video/x-vp3");
3560     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
3561     default:
3562 #if 0
3563       g_critical ("Don't know how to convert fourcc '%" GST_FOURCC_FORMAT
3564           "' to caps", GST_FOURCC_ARGS (fourcc));
3565       return NULL;
3566 #endif
3567       {
3568         char *s;
3569
3570         s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
3571             GST_FOURCC_ARGS (fourcc));
3572         return gst_caps_new_simple (s, NULL);
3573       }
3574   }
3575 }
3576
3577 static GstCaps *
3578 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
3579     guint32 fourcc, const guint8 * data, int len, const gchar ** codec_name)
3580 {
3581   switch (fourcc) {
3582 #if 0
3583     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
3584       return NULL;              /*gst_caps_from_string ("audio/raw"); */
3585 #endif
3586     case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
3587       _codec ("Raw 8-bit PCM audio");
3588       /* FIXME */
3589       return gst_caps_from_string ("audio/x-raw-int, "
3590           "width = (int) 8, " "depth = (int) 8, " "signed = (boolean) false");
3591     case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
3592       if (stream->bytes_per_frame == 1) {
3593         _codec ("Raw 8-bit PCM audio");
3594         return gst_caps_from_string ("audio/x-raw-int, "
3595             "width = (int) 8, " "depth = (int) 8, " "signed = (boolean) true");
3596       } else {
3597         _codec ("Raw 16-bit PCM audio");
3598         /* FIXME */
3599         return gst_caps_from_string ("audio/x-raw-int, "
3600             "width = (int) 16, "
3601             "depth = (int) 16, "
3602             "endianness = (int) BIG_ENDIAN, " "signed = (boolean) true");
3603       }
3604     case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
3605       if (stream->bytes_per_frame == 1) {
3606         _codec ("Raw 8-bit PCM audio");
3607         return gst_caps_from_string ("audio/x-raw-int, "
3608             "width = (int) 8, " "depth = (int) 8, " "signed = (boolean) true");
3609       } else {
3610         _codec ("Raw 16-bit PCM audio");
3611         /* FIXME */
3612         return gst_caps_from_string ("audio/x-raw-int, "
3613             "width = (int) 16, "
3614             "depth = (int) 16, "
3615             "endianness = (int) LITTLE_ENDIAN, " "signed = (boolean) true");
3616       }
3617     case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
3618       _codec ("Raw 64-bit floating-point audio");
3619       return gst_caps_from_string ("audio/x-raw-float, "
3620           "width = (int) 64, " "endianness = (int) BIG_ENDIAN");
3621     case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
3622       _codec ("Raw 32-bit floating-point audio");
3623       return gst_caps_from_string ("audio/x-raw-float, "
3624           "width = (int) 32, " "endianness = (int) BIG_ENDIAN");
3625     case GST_MAKE_FOURCC ('i', 'n', '2', '4'):
3626       _codec ("Raw 24-bit PCM audio");
3627       /* FIXME */
3628       return gst_caps_from_string ("audio/x-raw-int, "
3629           "width = (int) 24, "
3630           "depth = (int) 32, "
3631           "endianness = (int) BIG_ENDIAN, " "signed = (boolean) true");
3632     case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
3633       _codec ("Raw 32-bit PCM audio");
3634       /* FIXME */
3635       return gst_caps_from_string ("audio/x-raw-int, "
3636           "width = (int) 32, "
3637           "depth = (int) 32, "
3638           "endianness = (int) BIG_ENDIAN, " "signed = (boolean) true");
3639     case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
3640       _codec ("Mu-law audio");
3641       /* FIXME */
3642       return gst_caps_from_string ("audio/x-mulaw");
3643     case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
3644       _codec ("A-law audio");
3645       /* FIXME */
3646       return gst_caps_from_string ("audio/x-alaw");
3647     case 0x6d730002:
3648       _codec ("Microsoft ADPCM");
3649       /* Microsoft ADPCM-ACM code 2 */
3650       return gst_caps_from_string ("audio/x-adpcm, "
3651           "layout = (string) microsoft");
3652     case 0x6d730011:
3653     case 0x6d730017:
3654       _codec ("DVI/Intel IMA ADPCM");
3655       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
3656       return gst_caps_from_string ("audio/x-adpcm, "
3657           "layout = (string) quicktime");
3658     case 0x6d730055:
3659       /* MPEG layer 3, CBR only (pre QT4.1) */
3660     case 0x5500736d:
3661     case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
3662       _codec ("MPEG-1 layer 3");
3663       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
3664       return gst_caps_from_string ("audio/mpeg, "
3665           "layer = (int) 3, " "mpegversion = (int) 1");
3666     case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
3667       _codec ("MACE-3");
3668       return gst_caps_from_string ("audio/x-mace, " "maceversion = (int) 3");
3669     case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
3670       _codec ("MACE-6");
3671       return gst_caps_from_string ("audio/x-mace, " "maceversion = (int) 6");
3672     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
3673       /* ogg/vorbis */
3674       return gst_caps_from_string ("application/ogg");
3675     case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
3676       _codec ("DV audio");
3677       return gst_caps_from_string ("audio/x-dv");
3678     case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
3679       _codec ("MPEG-4 AAC audio");
3680       return gst_caps_new_simple ("audio/mpeg",
3681           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
3682     case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
3683       _codec ("QDesign Music v.2");
3684       /* FIXME: QDesign music version 2 (no constant) */
3685       if (data) {
3686         return gst_caps_new_simple ("audio/x-qdm2",
3687             "framesize", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 52),
3688             "bitrate", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 40),
3689             "blocksize", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 44), NULL);
3690       } else {
3691         return gst_caps_new_simple ("audio/x-qdm2", NULL);
3692       }
3693     case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
3694       _codec ("GSM audio");
3695       return gst_caps_new_simple ("audio/x-gsm", NULL);
3696     case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
3697       _codec ("AMR audio");
3698       return gst_caps_new_simple ("audio/AMR", NULL);
3699     case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
3700       _codec ("Quicktime IMA ADPCM");
3701       return gst_caps_new_simple ("audio/x-adpcm",
3702           "layout", G_TYPE_STRING, "quicktime", NULL);
3703     case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
3704       _codec ("Apple lossless audio");
3705       return gst_caps_new_simple ("audio/x-alac", NULL);
3706     case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
3707       /* ? */
3708     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
3709       /* QDesign music */
3710     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
3711       /* QUALCOMM PureVoice */
3712     default:
3713 #if 0
3714       g_critical ("Don't know how to convert fourcc '%" GST_FOURCC_FORMAT
3715           "' to caps", GST_FOURCC_ARGS (fourcc));
3716       return NULL;
3717 #endif
3718       {
3719         char *s;
3720
3721         s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
3722             GST_FOURCC_ARGS (fourcc));
3723         return gst_caps_new_simple (s, NULL);
3724       }
3725   }
3726 }