Sorry Dave... Add mpegversion=1 to mp3 caps everywhere so that the autoplugger uses...
[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  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include "qtdemux.h"
25
26 #include <string.h>
27 #include <zlib.h>
28
29 #define g_print(x...)
30
31 #define QTDEMUX_GUINT32_GET(a) GUINT32_FROM_BE(*(guint32 *)(a))
32 #define QTDEMUX_GUINT16_GET(a) GUINT16_FROM_BE(*(guint16 *)(a))
33 #define QTDEMUX_GUINT8_GET(a) (*(guint8 *)(a))
34 #define QTDEMUX_FP32_GET(a) (GUINT32_FROM_BE(*(guint16 *)(a))/65536.0)
35 #define QTDEMUX_FP16_GET(a) (GUINT16_FROM_BE(*(guint16 *)(a))/256.0)
36 #define QTDEMUX_FOURCC_GET(a) GUINT32_FROM_LE(*(guint32 *)(a))
37
38 #define QTDEMUX_GUINT64_GET(a) ((((guint64)QTDEMUX_GUINT32_GET(a))<<32)|QTDEMUX_GUINT32_GET(((void *)a)+4))
39
40 typedef struct _QtNode QtNode;
41 typedef struct _QtNodeType QtNodeType;
42 typedef struct _QtDemuxSample QtDemuxSample;
43 //typedef struct _QtDemuxStream QtDemuxStream;
44
45 struct _QtNode {
46   guint32 type;
47   gpointer data;
48   int len;
49 };
50
51 struct _QtNodeType {
52   guint32 fourcc;
53   char *name;
54   int flags;
55   void (*dump)(GstQTDemux *qtdemux, void *buffer, int depth);
56 };
57
58 struct _QtDemuxSample {
59   int sample_index;
60   int chunk;
61   int size;
62   guint32 offset;
63   guint64 timestamp;
64   guint64 duration;
65 };
66
67 struct _QtDemuxStream {
68   guint32 subtype;
69   GstCaps *caps;
70   GstPad *pad;
71   int n_samples;
72   QtDemuxSample *samples;
73   int timescale;
74
75   int sample_index;
76
77   int width;
78   int height;
79   float fps;
80   double rate;
81   int n_channels;
82 };
83
84 enum QtDemuxState {
85   QTDEMUX_STATE_NULL,
86   QTDEMUX_STATE_HEADER,
87   QTDEMUX_STATE_HEADER_SEEKING,
88   QTDEMUX_STATE_SEEKING,
89   QTDEMUX_STATE_MOVIE,
90   QTDEMUX_STATE_SEEKING_EOS,
91   QTDEMUX_STATE_EOS,
92 };
93
94 static GNode *qtdemux_tree_get_child_by_type(GNode *node, guint32 fourcc);
95 static GNode *qtdemux_tree_get_sibling_by_type(GNode *node, guint32 fourcc);
96
97 static GstElementDetails 
98 gst_qtdemux_details = 
99 {
100   "QuickTime Demuxer",
101   "Codec/Demuxer",
102   "Demultiplex a QuickTime file into audio and video streams",
103   "David Schleef <ds@schleef.org>"
104 };
105
106 enum {
107   LAST_SIGNAL
108 };
109
110 enum {
111   ARG_0
112 };
113
114 GST_PAD_TEMPLATE_FACTORY (sink_templ,
115   "sink",
116   GST_PAD_SINK,
117   GST_PAD_ALWAYS,
118   GST_CAPS_NEW (
119     "qtdemux_sink",
120     "video/quicktime",
121       NULL
122   ),
123   GST_CAPS_NEW (
124     "qtdemux_sink",
125     "audio/x-m4a",
126     NULL
127   )
128 )
129
130 static GstPadTemplate *videosrctempl, *audiosrctempl;
131 static GstElementClass *parent_class = NULL;
132
133 static void gst_qtdemux_class_init (GstQTDemuxClass *klass);
134 static void gst_qtdemux_base_init (GstQTDemuxClass *klass);
135 static void gst_qtdemux_init (GstQTDemux *quicktime_demux);
136 static GstElementStateReturn gst_qtdemux_change_state(GstElement *element);
137 static void gst_qtdemux_loop_header (GstElement *element);
138 static gboolean gst_qtdemux_handle_sink_event (GstQTDemux *qtdemux);
139
140 static void qtdemux_parse_moov(GstQTDemux *qtdemux, void *buffer, int length);
141 static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int length);
142 static QtNodeType *qtdemux_type_get(guint32 fourcc);
143 static void qtdemux_node_dump(GstQTDemux *qtdemux, GNode *node);
144 static void qtdemux_parse_tree(GstQTDemux *qtdemux);
145 static GstCaps *qtdemux_video_caps(GstQTDemux *qtdemux, guint32 fourcc);
146 static GstCaps *qtdemux_audio_caps(GstQTDemux *qtdemux, guint32 fourcc);
147
148 static GType gst_qtdemux_get_type (void) 
149 {
150   static GType qtdemux_type = 0;
151
152   if (!qtdemux_type) {
153     static const GTypeInfo qtdemux_info = {
154       sizeof(GstQTDemuxClass),
155       (GBaseInitFunc)gst_qtdemux_base_init, NULL,
156       (GClassInitFunc)gst_qtdemux_class_init,
157       NULL, NULL, sizeof(GstQTDemux), 0,
158       (GInstanceInitFunc)gst_qtdemux_init,
159     };
160     qtdemux_type = g_type_register_static (GST_TYPE_ELEMENT, "GstQTDemux", &qtdemux_info, 0);
161   }
162   return qtdemux_type;
163 }
164
165 static void gst_qtdemux_base_init (GstQTDemuxClass *klass)
166 {
167   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
168
169   gst_element_class_add_pad_template (element_class,
170                 GST_PAD_TEMPLATE_GET (sink_templ));
171   gst_element_class_add_pad_template (element_class, videosrctempl);
172   gst_element_class_add_pad_template (element_class, audiosrctempl);
173   gst_element_class_set_details (element_class, &gst_qtdemux_details);
174 }
175
176 static void gst_qtdemux_class_init (GstQTDemuxClass *klass) 
177 {
178   GObjectClass *gobject_class;
179   GstElementClass *gstelement_class;
180
181   gobject_class = (GObjectClass*)klass;
182   gstelement_class = (GstElementClass*)klass;
183
184   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
185
186   gstelement_class->change_state = gst_qtdemux_change_state;
187 }
188
189 static void 
190 gst_qtdemux_init (GstQTDemux *qtdemux) 
191 {
192   qtdemux->sinkpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (sink_templ), "sink");
193   gst_element_set_loop_function (GST_ELEMENT (qtdemux), gst_qtdemux_loop_header);
194   gst_element_add_pad (GST_ELEMENT (qtdemux), qtdemux->sinkpad);
195 }
196
197 static gboolean
198 plugin_init (GstPlugin *plugin)
199 {
200   GstCaps *audiocaps = NULL, *videocaps = NULL, *temp;
201   const guint32 audio_fcc[] = {
202     /* FILLME */
203     0,
204   }, video_fcc[] = {
205     /* FILLME */
206     0,
207   };
208   gint i;
209
210   if (!gst_library_load ("gstbytestream"))
211     return FALSE;
212
213   for (i = 0; audio_fcc[i] != 0; i++) {
214     temp = qtdemux_audio_caps (NULL, audio_fcc[i]);
215     audiocaps = gst_caps_append (audiocaps, temp);
216   }
217   audiosrctempl = gst_pad_template_new ("audio_%02d",
218                                         GST_PAD_SRC,
219                                         GST_PAD_SOMETIMES,
220                                         audiocaps, NULL);
221
222   for (i = 0; video_fcc[i] != 0; i++) {
223     temp = qtdemux_video_caps (NULL, video_fcc[i]);
224     videocaps = gst_caps_append (videocaps, temp);
225   }
226   videosrctempl = gst_pad_template_new ("video_%02d",
227                                         GST_PAD_SRC,
228                                         GST_PAD_SOMETIMES,
229                                         videocaps, NULL);
230
231   return gst_element_register (plugin, "qtdemux",
232                                GST_RANK_PRIMARY, GST_TYPE_QTDEMUX);
233 }
234
235 GST_PLUGIN_DEFINE (
236   GST_VERSION_MAJOR,
237   GST_VERSION_MINOR,
238   "qtdemux",
239   "Quicktime stream demuxer",
240   plugin_init,
241   VERSION,
242   "LGPL",
243   GST_PACKAGE,
244   GST_ORIGIN
245 )
246
247 static gboolean gst_qtdemux_handle_sink_event (GstQTDemux *qtdemux)
248 {
249   guint32 remaining;
250   GstEvent *event;
251   GstEventType type;
252
253   gst_bytestream_get_status(qtdemux->bs, &remaining, &event);
254
255   type = event ? GST_EVENT_TYPE(event) : GST_EVENT_UNKNOWN;
256   GST_DEBUG ("qtdemux: event %p %d", event, type);
257
258   switch(type){
259     case GST_EVENT_EOS:
260       gst_bytestream_flush(qtdemux->bs, remaining);
261       gst_pad_event_default(qtdemux->sinkpad, event);
262       return FALSE;
263     case GST_EVENT_FLUSH:
264       g_warning("flush event");
265       break;
266     case GST_EVENT_DISCONTINUOUS:
267       GST_DEBUG ("discontinuous event\n");
268       //gst_bytestream_flush_fast(qtdemux->bs, remaining);
269       break;
270     default:
271       g_warning("unhandled event %d",type);
272       break;
273   }
274
275   gst_event_unref(event);
276   return TRUE;
277 }
278
279 static GstElementStateReturn gst_qtdemux_change_state(GstElement *element)
280 {
281   GstQTDemux *qtdemux = GST_QTDEMUX(element);
282
283   switch(GST_STATE_TRANSITION(element)){
284     case GST_STATE_NULL_TO_READY:
285       break;
286     case GST_STATE_READY_TO_PAUSED:
287       qtdemux->bs = gst_bytestream_new(qtdemux->sinkpad);
288       qtdemux->state = QTDEMUX_STATE_HEADER;
289       /* FIXME */
290       break;
291     case GST_STATE_PAUSED_TO_PLAYING:
292       break;
293     case GST_STATE_PLAYING_TO_PAUSED:
294       break;
295     case GST_STATE_PAUSED_TO_READY:
296       gst_bytestream_destroy(qtdemux->bs);
297       break;
298     case GST_STATE_READY_TO_NULL:
299       break;
300     default:
301       break;
302   }
303
304   return GST_ELEMENT_CLASS(parent_class)->change_state(element);
305 }
306
307 static void gst_qtdemux_loop_header (GstElement *element)
308 {
309   GstQTDemux *qtdemux = GST_QTDEMUX(element);
310   guint8 *data;
311   guint32 length;
312   guint32 fourcc;
313   GstBuffer *buf;
314   int offset;
315   int cur_offset;
316   int size;
317   int ret;
318
319   /* FIXME _tell gets the offset wrong */
320   //cur_offset = gst_bytestream_tell(qtdemux->bs);
321   
322   cur_offset = qtdemux->offset;
323   GST_DEBUG ("loop at position %d",cur_offset);
324
325   switch(qtdemux->state){
326   case QTDEMUX_STATE_HEADER:
327   {
328     do{
329       ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 16);
330       if(ret<16){
331         if(!gst_qtdemux_handle_sink_event(qtdemux)){
332           return;
333         }
334       }else{
335         break;
336       }
337     }while(1);
338
339     length = GUINT32_FROM_BE(*(guint32 *)data);
340     GST_DEBUG ("length %08x",length);
341     fourcc = GUINT32_FROM_LE(*(guint32 *)(data+4));
342     GST_DEBUG ("fourcc " GST_FOURCC_FORMAT, GST_FOURCC_ARGS(fourcc));
343
344     if(length==0){
345       length = gst_bytestream_length(qtdemux->bs) - cur_offset;
346     }
347     if(length==1){
348       guint32 length1, length2;
349   
350       length1 = GUINT32_FROM_BE(*(guint32 *)(data+8));
351       GST_DEBUG ("length1 %08x",length1);
352       length2 = GUINT32_FROM_BE(*(guint32 *)(data+12));
353       GST_DEBUG ("length2 %08x",length2);
354   
355       length=length2;
356     }
357   
358     switch(fourcc){
359       case GST_MAKE_FOURCC('m','d','a','t'):
360       case GST_MAKE_FOURCC('f','r','e','e'):
361       case GST_MAKE_FOURCC('w','i','d','e'):
362       case GST_MAKE_FOURCC('P','I','C','T'):
363       case GST_MAKE_FOURCC('p','n','o','t'):
364         break;
365       case GST_MAKE_FOURCC('m','o','o','v'):
366       {
367         GstBuffer *moov;
368   
369         do{
370           ret = gst_bytestream_read(qtdemux->bs, &moov, length);
371           if(ret < length){
372             GST_DEBUG ("read failed (%d < %d)",ret,length);
373             if(!gst_qtdemux_handle_sink_event(qtdemux)){
374               return;
375             }
376           }else{
377             break;
378           }
379         }while(1);
380
381         qtdemux_parse_moov(qtdemux, GST_BUFFER_DATA(moov), length);
382         if(1)qtdemux_node_dump(qtdemux, qtdemux->moov_node);
383         qtdemux_parse_tree(qtdemux);
384         qtdemux->state = QTDEMUX_STATE_MOVIE;
385         break;
386       }
387       default:
388       {
389         g_print("unknown %08x '" GST_FOURCC_FORMAT "' at %d\n",
390             fourcc, GST_FOURCC_ARGS(fourcc), cur_offset);
391         break;
392       }
393     }
394     ret = gst_bytestream_seek(qtdemux->bs, cur_offset + length,
395         GST_SEEK_METHOD_SET);
396     qtdemux->offset = cur_offset + length;
397     GST_DEBUG ("seek returned %d\n",ret);
398     break;
399   }
400   case QTDEMUX_STATE_SEEKING_EOS:
401   {
402     guint8 *data;
403
404     do{
405       ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 1);
406       if(ret<1){
407         if(!gst_qtdemux_handle_sink_event(qtdemux)){
408           return;
409         }
410       }else{
411         break;
412       }
413     }while(TRUE);
414     gst_element_set_eos(element);
415
416     qtdemux->state = QTDEMUX_STATE_EOS;
417     return;
418   }
419   case QTDEMUX_STATE_EOS:
420     g_warning("spinning in EOS\n");
421     return;
422   case QTDEMUX_STATE_MOVIE:
423   {
424     QtDemuxStream *stream;
425     guint64 min_time;
426     int index = -1;
427     int i;
428
429     min_time = G_MAXUINT64;
430     for(i=0;i<qtdemux->n_streams;i++){
431       stream = qtdemux->streams[i];
432
433       if(stream->sample_index < stream->n_samples &&
434           stream->samples[stream->sample_index].timestamp < min_time){
435         min_time = stream->samples[stream->sample_index].timestamp;
436         index = i;
437       }
438     }
439
440     if(index==-1){
441       for(i=0;i<qtdemux->n_streams;i++){
442         gst_pad_push(qtdemux->streams[i]->pad,
443             GST_DATA(gst_event_new (GST_EVENT_EOS)));
444       }
445       ret = gst_bytestream_seek(qtdemux->bs, 0, GST_SEEK_METHOD_END);
446       GST_DEBUG ("seek returned %d",ret);
447
448       qtdemux->state = QTDEMUX_STATE_SEEKING_EOS;
449       return;
450     }
451
452     stream = qtdemux->streams[index];
453
454     offset = stream->samples[stream->sample_index].offset;
455     size = stream->samples[stream->sample_index].size;
456
457     GST_DEBUG ("pushing from stream %d, sample_index=%d offset=%d size=%d",
458         index, stream->sample_index, offset, size);
459
460     cur_offset = gst_bytestream_tell(qtdemux->bs);
461     if(offset != cur_offset){
462       GST_DEBUG ("seeking to offset %d",offset);
463       ret = gst_bytestream_seek(qtdemux->bs, offset, GST_SEEK_METHOD_SET);
464       GST_DEBUG ("seek returned %d",ret);
465       return;
466     }
467
468     GST_DEBUG ("reading %d bytes\n",size);
469     buf = NULL;
470     do{
471       ret = gst_bytestream_read(qtdemux->bs, &buf, size);
472       if(ret < size){
473         GST_DEBUG ("read failed (%d < %d)",ret,size);
474         if(!gst_qtdemux_handle_sink_event(qtdemux)){
475           return;
476         }
477       }else{
478         break;
479       }
480     }while(TRUE);
481
482     if(buf){
483       /* hum... */
484       if(stream->subtype == GST_MAKE_FOURCC('v','i','d','e')){
485         float fps = 1. * GST_SECOND / stream->samples[stream->sample_index].duration;
486         if (fps != stream->fps) {
487           gst_props_remove_entry_by_name(stream->caps->properties, "framerate");
488           gst_props_add_entry(stream->caps->properties,
489                               gst_props_entry_new("framerate", GST_PROPS_FLOAT(fps)));
490           stream->fps = fps;
491           gst_pad_try_set_caps(stream->pad, stream->caps);
492         }
493       }
494
495       GST_BUFFER_TIMESTAMP(buf) = stream->samples[stream->sample_index].timestamp;
496       GST_BUFFER_DURATION(buf) = stream->samples[stream->sample_index].duration;
497       gst_pad_push(stream->pad, GST_DATA (buf));
498     }
499     stream->sample_index++;
500     break;
501   }
502   default:
503     /* unreached */
504     g_assert(0);
505   }
506
507 }
508
509 static GstCaps *gst_qtdemux_src_getcaps(GstPad *pad, GstCaps *caps)
510 {
511   GstQTDemux *qtdemux;
512   QtDemuxStream *stream;
513   int i;
514
515   GST_DEBUG ("gst_qtdemux_src_getcaps");
516
517   qtdemux = GST_QTDEMUX(gst_pad_get_parent(pad));
518
519   g_return_val_if_fail(GST_IS_QTDEMUX(qtdemux), NULL);
520
521   GST_DEBUG ("looking for pad %p in qtdemux %p", pad, qtdemux);
522   GST_DEBUG ("n_streams is %d", qtdemux->n_streams);
523   for(i=0;i<qtdemux->n_streams;i++){
524     stream = qtdemux->streams[i];
525     if(stream->pad == pad){
526       return stream->caps;
527     }
528   }
529
530   GST_DEBUG ("Couldn't find stream cooresponding to pad\n");
531
532   return NULL;
533 }
534
535 static GstPadLinkReturn
536 gst_qtdemux_src_link(GstPad *pad, GstCaps *caps)
537 {
538   GstQTDemux *qtdemux;
539   QtDemuxStream *stream;
540   int i;
541
542   GST_DEBUG ("gst_qtdemux_src_link");
543
544   qtdemux = GST_QTDEMUX(gst_pad_get_parent(pad));
545
546   GST_DEBUG ("looking for pad %p in qtdemux %p", pad, qtdemux);
547   g_return_val_if_fail(GST_IS_QTDEMUX(qtdemux), GST_PAD_LINK_REFUSED);
548
549   GST_DEBUG ("n_streams is %d", qtdemux->n_streams);
550   for(i=0;i<qtdemux->n_streams;i++){
551     stream = qtdemux->streams[i];
552     GST_DEBUG ("pad[%d] is %p", i, stream->pad);
553     if(stream->pad == pad){
554       return GST_PAD_LINK_OK;
555     }
556   }
557
558   GST_DEBUG ("Couldn't find stream cooresponding to pad\n");
559
560   return GST_PAD_LINK_REFUSED;
561 }
562
563 void gst_qtdemux_add_stream(GstQTDemux *qtdemux, QtDemuxStream *stream)
564 {
565   if(stream->subtype == GST_MAKE_FOURCC('v','i','d','e')){
566     stream->pad = gst_pad_new_from_template (videosrctempl,
567         g_strdup_printf ("video_%02d", qtdemux->n_video_streams));
568     stream->fps = 1. * GST_SECOND / stream->samples[0].duration;
569     if(stream->caps){
570       GstProps *properties = gst_props_intersect(
571           stream->caps->properties,
572           gst_props_new("width",GST_PROPS_INT(stream->width),
573               "height",GST_PROPS_INT(stream->height),
574               "framerate", GST_PROPS_FLOAT(stream->fps), NULL));
575       if (stream->caps->properties != NULL)
576         gst_props_unref (stream->caps->properties);
577       stream->caps->properties = properties;
578     }
579     qtdemux->n_video_streams++;
580   }else{
581     stream->pad = gst_pad_new_from_template (audiosrctempl,
582         g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams));
583     if(stream->caps){
584       GstProps *properties = gst_props_intersect(
585           stream->caps->properties,
586           gst_props_new("rate",GST_PROPS_INT((int)stream->rate),
587               "channels",GST_PROPS_INT(stream->n_channels), NULL));
588       if (stream->caps->properties != NULL)
589         gst_props_unref (stream->caps->properties);
590       stream->caps->properties = properties;
591     }
592     qtdemux->n_audio_streams++;
593   }
594
595   gst_pad_set_getcaps_function(stream->pad, gst_qtdemux_src_getcaps);
596   gst_pad_set_link_function(stream->pad, gst_qtdemux_src_link);
597
598   qtdemux->streams[qtdemux->n_streams] = stream;
599   qtdemux->n_streams++;
600   GST_DEBUG ("n_streams is now %d", qtdemux->n_streams);
601
602   GST_DEBUG ("adding pad %p to qtdemux %p", stream->pad, qtdemux);
603   gst_element_add_pad(GST_ELEMENT (qtdemux), stream->pad);
604
605   /* Note: we need to have everything set up before calling try_set_caps */
606   if(stream->caps){
607     g_print("setting caps to %s\n",gst_caps_to_string(stream->caps));
608
609     gst_pad_try_set_caps(stream->pad, stream->caps);
610   }
611 }
612
613
614 #define QT_CONTAINER 1
615
616 #define FOURCC_moov     GST_MAKE_FOURCC('m','o','o','v')
617 #define FOURCC_mvhd     GST_MAKE_FOURCC('m','v','h','d')
618 #define FOURCC_clip     GST_MAKE_FOURCC('c','l','i','p')
619 #define FOURCC_trak     GST_MAKE_FOURCC('t','r','a','k')
620 #define FOURCC_udta     GST_MAKE_FOURCC('u','d','t','a')
621 #define FOURCC_ctab     GST_MAKE_FOURCC('c','t','a','b')
622 #define FOURCC_tkhd     GST_MAKE_FOURCC('t','k','h','d')
623 #define FOURCC_crgn     GST_MAKE_FOURCC('c','r','g','n')
624 #define FOURCC_matt     GST_MAKE_FOURCC('m','a','t','t')
625 #define FOURCC_kmat     GST_MAKE_FOURCC('k','m','a','t')
626 #define FOURCC_edts     GST_MAKE_FOURCC('e','d','t','s')
627 #define FOURCC_elst     GST_MAKE_FOURCC('e','l','s','t')
628 #define FOURCC_load     GST_MAKE_FOURCC('l','o','a','d')
629 #define FOURCC_tref     GST_MAKE_FOURCC('t','r','e','f')
630 #define FOURCC_imap     GST_MAKE_FOURCC('i','m','a','p')
631 #define FOURCC___in     GST_MAKE_FOURCC(' ',' ','i','n')
632 #define FOURCC___ty     GST_MAKE_FOURCC(' ',' ','t','y')
633 #define FOURCC_mdia     GST_MAKE_FOURCC('m','d','i','a')
634 #define FOURCC_mdhd     GST_MAKE_FOURCC('m','d','h','d')
635 #define FOURCC_hdlr     GST_MAKE_FOURCC('h','d','l','r')
636 #define FOURCC_minf     GST_MAKE_FOURCC('m','i','n','f')
637 #define FOURCC_vmhd     GST_MAKE_FOURCC('v','m','h','d')
638 #define FOURCC_smhd     GST_MAKE_FOURCC('s','m','h','d')
639 #define FOURCC_gmhd     GST_MAKE_FOURCC('g','m','h','d')
640 #define FOURCC_gmin     GST_MAKE_FOURCC('g','m','i','n')
641 #define FOURCC_dinf     GST_MAKE_FOURCC('d','i','n','f')
642 #define FOURCC_dref     GST_MAKE_FOURCC('d','r','e','f')
643 #define FOURCC_stbl     GST_MAKE_FOURCC('s','t','b','l')
644 #define FOURCC_stsd     GST_MAKE_FOURCC('s','t','s','d')
645 #define FOURCC_stts     GST_MAKE_FOURCC('s','t','t','s')
646 #define FOURCC_stss     GST_MAKE_FOURCC('s','t','s','s')
647 #define FOURCC_stsc     GST_MAKE_FOURCC('s','t','s','c')
648 #define FOURCC_stsz     GST_MAKE_FOURCC('s','t','s','z')
649 #define FOURCC_stco     GST_MAKE_FOURCC('s','t','c','o')
650 #define FOURCC_vide     GST_MAKE_FOURCC('v','i','d','e')
651 #define FOURCC_soun     GST_MAKE_FOURCC('s','o','u','n')
652 #define FOURCC_co64     GST_MAKE_FOURCC('c','o','6','4')
653 #define FOURCC_cmov     GST_MAKE_FOURCC('c','m','o','v')
654 #define FOURCC_dcom     GST_MAKE_FOURCC('d','c','o','m')
655 #define FOURCC_cmvd     GST_MAKE_FOURCC('c','m','v','d')
656
657
658 static void qtdemux_dump_mvhd(GstQTDemux *qtdemux, void *buffer, int depth);
659 static void qtdemux_dump_tkhd(GstQTDemux *qtdemux, void *buffer, int depth);
660 static void qtdemux_dump_elst(GstQTDemux *qtdemux, void *buffer, int depth);
661 static void qtdemux_dump_mdhd(GstQTDemux *qtdemux, void *buffer, int depth);
662 static void qtdemux_dump_hdlr(GstQTDemux *qtdemux, void *buffer, int depth);
663 static void qtdemux_dump_vmhd(GstQTDemux *qtdemux, void *buffer, int depth);
664 static void qtdemux_dump_dref(GstQTDemux *qtdemux, void *buffer, int depth);
665 static void qtdemux_dump_stsd(GstQTDemux *qtdemux, void *buffer, int depth);
666 static void qtdemux_dump_stts(GstQTDemux *qtdemux, void *buffer, int depth);
667 static void qtdemux_dump_stss(GstQTDemux *qtdemux, void *buffer, int depth);
668 static void qtdemux_dump_stsc(GstQTDemux *qtdemux, void *buffer, int depth);
669 static void qtdemux_dump_stsz(GstQTDemux *qtdemux, void *buffer, int depth);
670 static void qtdemux_dump_stco(GstQTDemux *qtdemux, void *buffer, int depth);
671 static void qtdemux_dump_co64(GstQTDemux *qtdemux, void *buffer, int depth);
672 static void qtdemux_dump_dcom(GstQTDemux *qtdemux, void *buffer, int depth);
673 static void qtdemux_dump_cmvd(GstQTDemux *qtdemux, void *buffer, int depth);
674
675 QtNodeType qt_node_types[] = {
676   { FOURCC_moov, "movie",               QT_CONTAINER, },
677   { FOURCC_mvhd, "movie header",        0,
678         qtdemux_dump_mvhd },
679   { FOURCC_clip, "clipping",            QT_CONTAINER, },
680   { FOURCC_trak, "track",               QT_CONTAINER, },
681   { FOURCC_udta, "user data",           0, }, /* special container */
682   { FOURCC_ctab, "color table",         0, },
683   { FOURCC_tkhd, "track header",        0,
684         qtdemux_dump_tkhd },
685   { FOURCC_crgn, "clipping region",     0, },
686   { FOURCC_matt, "track matte",         QT_CONTAINER, },
687   { FOURCC_kmat, "compressed matte",    0, },
688   { FOURCC_edts, "edit",                QT_CONTAINER, },
689   { FOURCC_elst, "edit list",           0,
690         qtdemux_dump_elst },
691   { FOURCC_load, "track load settings", 0, },
692   { FOURCC_tref, "track reference",     QT_CONTAINER, },
693   { FOURCC_imap, "track input map",     QT_CONTAINER, },
694   { FOURCC___in, "track input",         0, }, /* special container */
695   { FOURCC___ty, "input type",          0, },
696   { FOURCC_mdia, "media",               QT_CONTAINER },
697   { FOURCC_mdhd, "media header",        0,
698         qtdemux_dump_mdhd },
699   { FOURCC_hdlr, "handler reference",   0,
700         qtdemux_dump_hdlr },
701   { FOURCC_minf, "media information",   QT_CONTAINER },
702   { FOURCC_vmhd, "video media information", 0,
703         qtdemux_dump_vmhd },
704   { FOURCC_smhd, "sound media information", 0 },
705   { FOURCC_gmhd, "base media information header", 0 },
706   { FOURCC_gmin, "base media info",     0 },
707   { FOURCC_dinf, "data information",    QT_CONTAINER },
708   { FOURCC_dref, "data reference",      0,
709         qtdemux_dump_dref },
710   { FOURCC_stbl, "sample table",        QT_CONTAINER },
711   { FOURCC_stsd, "sample description",  0,
712         qtdemux_dump_stsd },
713   { FOURCC_stts, "time-to-sample",      0,
714         qtdemux_dump_stts },
715   { FOURCC_stss, "sync sample",         0,
716         qtdemux_dump_stss },
717   { FOURCC_stsc, "sample-to-chunk",     0,
718         qtdemux_dump_stsc },
719   { FOURCC_stsz, "sample size",         0,
720         qtdemux_dump_stsz },
721   { FOURCC_stco, "chunk offset",        0,
722         qtdemux_dump_stco },
723   { FOURCC_co64, "64-bit chunk offset", 0,
724         qtdemux_dump_co64 },
725   { FOURCC_vide, "video media",         0 },
726   { FOURCC_cmov, "compressed movie",    QT_CONTAINER },
727   { FOURCC_dcom, "compressed data",     0,
728         qtdemux_dump_dcom },
729   { FOURCC_cmvd, "compressed movie data", 0,
730         qtdemux_dump_cmvd },
731   { 0, "unknown", 0 },
732 };
733 static int n_qt_node_types = sizeof(qt_node_types)/sizeof(qt_node_types[0]);
734
735
736 static void *qtdemux_zalloc(void *opaque, unsigned int items, unsigned int size)
737 {
738   return g_malloc(items*size);
739 }
740
741 static void qtdemux_zfree(void *opaque, void *addr)
742 {
743   g_free(addr);
744 }
745
746 static void *qtdemux_inflate(void *z_buffer, int z_length, int length)
747 {
748   void *buffer;
749   z_stream *z;
750   int ret;
751
752   z = g_new0(z_stream, 1);
753   z->zalloc = qtdemux_zalloc;
754   z->zfree = qtdemux_zfree;
755   z->opaque = NULL;
756
757   z->next_in = z_buffer;
758   z->avail_in = z_length;
759
760   buffer = g_malloc(length);
761   ret = inflateInit(z);
762   while(z->avail_in > 0){
763     if(z->avail_out == 0){
764       length += 1024;
765       buffer = realloc(buffer, length);
766       z->next_out = buffer + z->total_out;
767       z->avail_out = 1024;
768     }
769     ret = inflate(z,Z_SYNC_FLUSH);
770     if(ret != Z_OK)break;
771   }
772   if(ret != Z_STREAM_END){
773     g_warning("inflate() returned %d\n",ret);
774   }
775
776   g_free(z);
777   return buffer;
778 }
779
780 static void qtdemux_parse_moov(GstQTDemux *qtdemux, void *buffer, int length)
781 {
782   GNode *cmov;
783
784   qtdemux->moov_node = g_node_new(buffer);
785
786   qtdemux_parse(qtdemux, qtdemux->moov_node, buffer, length);
787
788   cmov = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_cmov);
789   if(cmov){
790     GNode *dcom;
791     GNode *cmvd;
792
793     dcom = qtdemux_tree_get_child_by_type(cmov, FOURCC_dcom);
794     cmvd = qtdemux_tree_get_child_by_type(cmov, FOURCC_cmvd);
795
796     if(QTDEMUX_FOURCC_GET(dcom->data+8) == GST_MAKE_FOURCC('z','l','i','b')){
797       int uncompressed_length;
798       int compressed_length;
799       void *buf;
800       
801       uncompressed_length = QTDEMUX_GUINT32_GET(cmvd->data+8);
802       compressed_length = QTDEMUX_GUINT32_GET(cmvd->data+4) - 12;
803       g_print("length = %d\n",uncompressed_length);
804
805       buf = qtdemux_inflate(cmvd->data + 12, compressed_length,
806           uncompressed_length);
807
808       qtdemux->moov_node_compressed = qtdemux->moov_node;
809       qtdemux->moov_node = g_node_new(buf);
810
811       qtdemux_parse(qtdemux, qtdemux->moov_node, buf, uncompressed_length);
812     }else{
813       g_print("unknown header compression type\n");
814     }
815   }
816 }
817
818 static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int length)
819 {
820   guint32 fourcc;
821   guint32 node_length;
822   QtNodeType *type;
823   void *end;
824
825   //g_print("qtdemux_parse %p %d\n",buffer, length);
826
827   node_length = QTDEMUX_GUINT32_GET(buffer);
828   fourcc = QTDEMUX_FOURCC_GET(buffer+4);
829
830   type = qtdemux_type_get(fourcc);
831   
832   /*g_print("parsing '" GST_FOURCC_FORMAT "', length=%d\n",
833       GST_FOURCC_ARGS(fourcc), node_length);*/
834
835   if(type->flags & QT_CONTAINER){
836     void *buf;
837     guint32 len;
838
839     buf = buffer + 8;
840     end = buffer + length;
841     while(buf < end){
842       GNode *child;
843
844       if(buf + 8 >= end){
845         /* FIXME: get annoyed */
846         g_print("buffer overrun\n");
847       }
848       len = QTDEMUX_GUINT32_GET(buf);
849
850       child = g_node_new(buf);
851       g_node_append(node, child);
852       qtdemux_parse(qtdemux, child, buf, len);
853
854       buf += len;
855     }
856   }else{
857 #if 0
858     if(fourcc == FOURCC_cmvd){
859       int uncompressed_length;
860       void *buf;
861       
862       uncompressed_length = QTDEMUX_GUINT32_GET(buffer+8);
863       g_print("length = %d\n",uncompressed_length);
864
865       buf = qtdemux_inflate(buffer + 12, node_length-12, uncompressed_length);
866
867       end = buf + uncompressed_length;
868       while(buf < end){
869         GNode *child;
870         guint32 len;
871
872         if(buf + 8 >= end){
873           /* FIXME: get annoyed */
874           g_print("buffer overrun\n");
875         }
876         len = QTDEMUX_GUINT32_GET(buf);
877
878         child = g_node_new(buf);
879         g_node_append(node, child);
880         qtdemux_parse(qtdemux, child, buf, len);
881
882         buf += len;
883       }
884     }
885 #endif
886   }
887 }
888
889 static QtNodeType *qtdemux_type_get(guint32 fourcc)
890 {
891   int i;
892
893   for(i=0;i<n_qt_node_types;i++){
894     if(qt_node_types[i].fourcc == fourcc)
895       return qt_node_types+i;
896   }
897   return qt_node_types+n_qt_node_types-1;
898 }
899
900 static gboolean qtdemux_node_dump_foreach(GNode *node, gpointer data)
901 {
902   void *buffer = node->data;
903   guint32 node_length;
904   guint32 fourcc;
905   QtNodeType *type;
906   int depth;
907
908   node_length = GUINT32_FROM_BE(*(guint32 *)buffer);
909   fourcc = GUINT32_FROM_LE(*(guint32 *)(buffer+4));
910
911   type = qtdemux_type_get(fourcc);
912
913   depth = (g_node_depth(node)-1)*2;
914   g_print("%*s'" GST_FOURCC_FORMAT "', [%d], %s\n",
915       depth, "",
916       GST_FOURCC_ARGS(fourcc),
917       node_length,
918       type->name);
919
920   if(type->dump)type->dump(data, buffer, depth);
921
922   return FALSE;
923 }
924
925 static void qtdemux_node_dump(GstQTDemux *qtdemux, GNode *node)
926 {
927   g_node_traverse(qtdemux->moov_node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
928       qtdemux_node_dump_foreach, qtdemux);
929 }
930
931 static void qtdemux_dump_mvhd(GstQTDemux *qtdemux, void *buffer, int depth)
932 {
933   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
934   g_print("%*s  creation time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
935   g_print("%*s  modify time:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
936   g_print("%*s  time scale:    1/%u sec\n", depth, "", QTDEMUX_GUINT32_GET(buffer+20));
937   g_print("%*s  duration:      %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+24));
938   g_print("%*s  pref. rate:    %g\n", depth, "", QTDEMUX_FP32_GET(buffer+28));
939   g_print("%*s  pref. volume:  %g\n", depth, "", QTDEMUX_FP16_GET(buffer+32));
940   g_print("%*s  preview time:  %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+80));
941   g_print("%*s  preview dur.:  %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+84));
942   g_print("%*s  poster time:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+88));
943   g_print("%*s  select time:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+92));
944   g_print("%*s  select dur.:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+96));
945   g_print("%*s  current time:  %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+100));
946   g_print("%*s  next track ID: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+104));
947 }
948
949 static void qtdemux_dump_tkhd(GstQTDemux *qtdemux, void *buffer, int depth)
950 {
951   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
952   g_print("%*s  creation time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
953   g_print("%*s  modify time:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
954   g_print("%*s  track ID:      %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+20));
955   g_print("%*s  duration:      %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+28));
956   g_print("%*s  layer:         %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+36));
957   g_print("%*s  alt group:     %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+38));
958   g_print("%*s  volume:        %g\n", depth, "", QTDEMUX_FP16_GET(buffer+44));
959   g_print("%*s  track width:   %g\n", depth, "", QTDEMUX_FP32_GET(buffer+84));
960   g_print("%*s  track height:  %g\n", depth, "", QTDEMUX_FP32_GET(buffer+88));
961
962 }
963
964 static void qtdemux_dump_elst(GstQTDemux *qtdemux, void *buffer, int depth)
965 {
966   int i;
967   int n;
968
969   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
970   g_print("%*s  n entries:     %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
971   n = QTDEMUX_GUINT32_GET(buffer+12);
972   for(i=0;i<n;i++){
973     g_print("%*s    track dur:     %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16+i*12));
974     g_print("%*s    media time:    %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+20+i*12));
975     g_print("%*s    media rate:    %g\n", depth, "", QTDEMUX_FP32_GET(buffer+24+i*12));
976   }
977 }
978
979 static void qtdemux_dump_mdhd(GstQTDemux *qtdemux, void *buffer, int depth)
980 {
981   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
982   g_print("%*s  creation time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
983   g_print("%*s  modify time:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
984   g_print("%*s  time scale:    1/%u sec\n", depth, "", QTDEMUX_GUINT32_GET(buffer+20));
985   g_print("%*s  duration:      %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+24));
986   g_print("%*s  language:      %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+28));
987   g_print("%*s  quality:       %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+30));
988
989 }
990
991 static void qtdemux_dump_hdlr(GstQTDemux *qtdemux, void *buffer, int depth)
992 {
993   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
994   g_print("%*s  type:          " GST_FOURCC_FORMAT "\n", depth, "",
995       GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+12)));
996   g_print("%*s  subtype:       " GST_FOURCC_FORMAT "\n", depth, "",
997       GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+16)));
998   g_print("%*s  manufacturer:  " GST_FOURCC_FORMAT "\n", depth, "",
999       GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+20)));
1000   g_print("%*s  flags:         %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+24));
1001   g_print("%*s  flags mask:    %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+28));
1002   g_print("%*s  name:          %*s\n", depth, "",
1003       QTDEMUX_GUINT8_GET(buffer+32), (char *)(buffer+33));
1004
1005 }
1006
1007 static void qtdemux_dump_vmhd(GstQTDemux *qtdemux, void *buffer, int depth)
1008 {
1009   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1010   g_print("%*s  mode/color:    %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
1011 }
1012
1013 static void qtdemux_dump_dref(GstQTDemux *qtdemux, void *buffer, int depth)
1014 {
1015   int n;
1016   int i;
1017   int offset;
1018
1019   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1020   g_print("%*s  n entries:     %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1021   n = QTDEMUX_GUINT32_GET(buffer+12);
1022   offset = 16;
1023   for(i=0;i<n;i++){
1024     g_print("%*s    size:          %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1025     g_print("%*s    type:          " GST_FOURCC_FORMAT "\n", depth, "",
1026         GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+offset+4)));
1027     offset += QTDEMUX_GUINT32_GET(buffer+offset);
1028   }
1029 }
1030
1031 static void qtdemux_dump_stsd(GstQTDemux *qtdemux, void *buffer, int depth)
1032 {
1033   int i;
1034   int n;
1035   int offset;
1036
1037   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1038   g_print("%*s  n entries:     %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1039   n = QTDEMUX_GUINT32_GET(buffer+12);
1040   offset = 16;
1041   for(i=0;i<n;i++){
1042     g_print("%*s    size:          %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1043     g_print("%*s    type:          " GST_FOURCC_FORMAT "\n", depth, "",
1044         GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+offset+4)));
1045     g_print("%*s    data reference:%d\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+14));
1046
1047     g_print("%*s    version/rev.:  %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+16));
1048     g_print("%*s    vendor:        " GST_FOURCC_FORMAT "\n", depth, "",
1049         GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+offset+20)));
1050     g_print("%*s    temporal qual: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+24));
1051     g_print("%*s    spatial qual:  %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+28));
1052     g_print("%*s    width:         %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+32));
1053     g_print("%*s    height:        %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+34));
1054     g_print("%*s    horiz. resol:  %g\n", depth, "", QTDEMUX_FP32_GET(buffer+offset+36));
1055     g_print("%*s    vert. resol.:  %g\n", depth, "", QTDEMUX_FP32_GET(buffer+offset+40));
1056     g_print("%*s    data size:     %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+44));
1057     g_print("%*s    frame count:   %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+48));
1058     g_print("%*s    compressor:    %*s\n", depth, "",
1059         QTDEMUX_GUINT8_GET(buffer+offset+49), (char *)(buffer+offset+51));
1060     g_print("%*s    depth:         %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+82));
1061     g_print("%*s    color table ID:%u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+84));
1062
1063     offset += QTDEMUX_GUINT32_GET(buffer+offset);
1064   }
1065 }
1066
1067 static void qtdemux_dump_stts(GstQTDemux *qtdemux, void *buffer, int depth)
1068 {
1069   int i;
1070   int n;
1071   int offset;
1072
1073   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1074   g_print("%*s  n entries:     %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1075   n = QTDEMUX_GUINT32_GET(buffer+12);
1076   offset = 16;
1077   for(i=0;i<n;i++){
1078     g_print("%*s    count:         %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1079     g_print("%*s    duration:      %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset + 4));
1080
1081     offset += 8;
1082   }
1083 }
1084
1085 static void qtdemux_dump_stss(GstQTDemux *qtdemux, void *buffer, int depth)
1086 {
1087   int i;
1088   int n;
1089   int offset;
1090
1091   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1092   g_print("%*s  n entries:     %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1093   n = QTDEMUX_GUINT32_GET(buffer+12);
1094   offset = 16;
1095   for(i=0;i<n;i++){
1096     g_print("%*s    sample:        %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1097
1098     offset += 4;
1099   }
1100 }
1101
1102 static void qtdemux_dump_stsc(GstQTDemux *qtdemux, void *buffer, int depth)
1103 {
1104   int i;
1105   int n;
1106   int offset;
1107
1108   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1109   g_print("%*s  n entries:     %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1110   n = QTDEMUX_GUINT32_GET(buffer+12);
1111   offset = 16;
1112   for(i=0;i<n;i++){
1113     g_print("%*s    first chunk:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1114     g_print("%*s    sample per ch: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+4));
1115     g_print("%*s    sample desc id:%08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+8));
1116
1117     offset += 12;
1118   }
1119 }
1120
1121 static void qtdemux_dump_stsz(GstQTDemux *qtdemux, void *buffer, int depth)
1122 {
1123   int i;
1124   int n;
1125   int offset;
1126   int sample_size;
1127
1128   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1129   g_print("%*s  sample size:   %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1130   sample_size = QTDEMUX_GUINT32_GET(buffer+12);
1131   if(sample_size == 0){
1132     g_print("%*s  n entries:     %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
1133     n = QTDEMUX_GUINT32_GET(buffer+16);
1134     offset = 20;
1135     for(i=0;i<n;i++){
1136       g_print("%*s    sample size:   %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1137
1138       offset += 4;
1139     }
1140   }
1141 }
1142
1143 static void qtdemux_dump_stco(GstQTDemux *qtdemux, void *buffer, int depth)
1144 {
1145   int i;
1146   int n;
1147   int offset;
1148
1149   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1150   g_print("%*s  n entries:     %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1151   n = QTDEMUX_GUINT32_GET(buffer+12);
1152   offset = 16;
1153   for(i=0;i<n;i++){
1154     g_print("%*s    chunk offset:  %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1155
1156     offset += 4;
1157   }
1158 }
1159
1160 static void qtdemux_dump_co64(GstQTDemux *qtdemux, void *buffer, int depth)
1161 {
1162   int i;
1163   int n;
1164   int offset;
1165
1166   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1167   g_print("%*s  n entries:     %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1168   n = QTDEMUX_GUINT32_GET(buffer+12);
1169   offset = 16;
1170   for(i=0;i<n;i++){
1171     g_print("%*s    chunk offset:  %" G_GUINT64_FORMAT "\n", depth, "", QTDEMUX_GUINT64_GET(buffer+offset));
1172
1173     offset += 8;
1174   }
1175 }
1176
1177 static void qtdemux_dump_dcom(GstQTDemux *qtdemux, void *buffer, int depth)
1178 {
1179   g_print("%*s  compression type: " GST_FOURCC_FORMAT "\n", depth, "",
1180       GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+8)));
1181 }
1182
1183 static void qtdemux_dump_cmvd(GstQTDemux *qtdemux, void *buffer, int depth)
1184 {
1185   g_print("%*s  length: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1186 }
1187
1188
1189 static GNode *qtdemux_tree_get_child_by_type(GNode *node, guint32 fourcc)
1190 {
1191   GNode *child;
1192   void *buffer;
1193   guint32 child_fourcc;
1194
1195   for(child = g_node_first_child(node); child; child = g_node_next_sibling(child)){
1196     buffer = child->data;
1197
1198     child_fourcc = GUINT32_FROM_LE(*(guint32 *)(buffer+4));
1199
1200     if(child_fourcc == fourcc){
1201       return child;
1202     }
1203   }
1204   return NULL;
1205 }
1206
1207 static GNode *qtdemux_tree_get_sibling_by_type(GNode *node, guint32 fourcc)
1208 {
1209   GNode *child;
1210   void *buffer;
1211   guint32 child_fourcc;
1212
1213   for(child = g_node_next_sibling(node); child; child = g_node_next_sibling(child)){
1214     buffer = child->data;
1215
1216     child_fourcc = GUINT32_FROM_LE(*(guint32 *)(buffer+4));
1217
1218     if(child_fourcc == fourcc){
1219       return child;
1220     }
1221   }
1222   return NULL;
1223 }
1224
1225 static void qtdemux_parse_trak(GstQTDemux *qtdemux, GNode *trak);
1226
1227 static void qtdemux_parse_tree(GstQTDemux *qtdemux)
1228 {
1229   GNode *mvhd;
1230   GNode *trak;
1231
1232   mvhd = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_mvhd);
1233   if(mvhd==NULL){
1234     g_print("No mvhd node found.\n");
1235     return;
1236   }
1237
1238   qtdemux->timescale = QTDEMUX_GUINT32_GET(mvhd->data + 20);
1239   qtdemux->duration = QTDEMUX_GUINT32_GET(mvhd->data + 24);
1240
1241   g_print("timescale: %d\n", qtdemux->timescale);
1242   g_print("duration: %d\n", qtdemux->duration);
1243
1244   trak = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_trak);
1245   qtdemux_parse_trak(qtdemux, trak);
1246
1247 /*  trak = qtdemux_tree_get_sibling_by_type(trak, FOURCC_trak);
1248   if(trak)qtdemux_parse_trak(qtdemux, trak);*/
1249
1250   while ((trak = qtdemux_tree_get_sibling_by_type(trak, FOURCC_trak)) != NULL)
1251     qtdemux_parse_trak(qtdemux, trak);
1252 }
1253
1254 static void qtdemux_parse_trak(GstQTDemux *qtdemux, GNode *trak)
1255 {
1256   int offset;
1257   GNode *tkhd;
1258   GNode *mdia;
1259   GNode *mdhd;
1260   GNode *hdlr;
1261   GNode *minf;
1262   GNode *stbl;
1263   GNode *stsd;
1264   GNode *stsc;
1265   GNode *stsz;
1266   GNode *stco;
1267   GNode *co64;
1268   GNode *stts;
1269   int n_samples;
1270   QtDemuxSample *samples;
1271   int n_samples_per_chunk;
1272   int index;
1273   int i,j,k;
1274   QtDemuxStream *stream;
1275   int n_sample_times;
1276   guint64 timestamp;
1277   int sample_size;
1278   int sample_index;
1279
1280   stream = g_new0(QtDemuxStream,1);
1281
1282   tkhd = qtdemux_tree_get_child_by_type(trak, FOURCC_tkhd);
1283   g_assert(tkhd);
1284
1285   /* track duration? */
1286
1287   mdia = qtdemux_tree_get_child_by_type(trak, FOURCC_mdia);
1288   g_assert(mdia);
1289
1290   mdhd = qtdemux_tree_get_child_by_type(mdia, FOURCC_mdhd);
1291   g_assert(mdhd);
1292
1293   stream->timescale = QTDEMUX_GUINT32_GET(mdhd->data+20);
1294   
1295   hdlr = qtdemux_tree_get_child_by_type(mdia, FOURCC_hdlr);
1296   g_assert(hdlr);
1297   
1298   g_print("track type: " GST_FOURCC_FORMAT "\n",
1299       GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(hdlr->data+12)));
1300   g_print("track subtype: " GST_FOURCC_FORMAT "\n",
1301       GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(hdlr->data+16)));
1302
1303   stream->subtype = QTDEMUX_FOURCC_GET(hdlr->data+16);
1304
1305   minf = qtdemux_tree_get_child_by_type(mdia, FOURCC_minf);
1306   g_assert(minf);
1307
1308   stbl = qtdemux_tree_get_child_by_type(minf, FOURCC_stbl);
1309   g_assert(stbl);
1310
1311   stsd = qtdemux_tree_get_child_by_type(stbl, FOURCC_stsd);
1312   g_assert(stsd);
1313
1314   if(stream->subtype == FOURCC_vide){
1315     offset = 16;
1316     g_print("st type:          " GST_FOURCC_FORMAT "\n",
1317           GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(stsd->data+offset+4)));
1318
1319     stream->width = QTDEMUX_GUINT16_GET(stsd->data+offset+32);
1320     stream->height = QTDEMUX_GUINT16_GET(stsd->data+offset+34);
1321     stream->fps = 0.; /* this is filled in later */
1322
1323     g_print("frame count:   %u\n", QTDEMUX_GUINT16_GET(stsd->data+offset+48));
1324     
1325     stream->caps = qtdemux_video_caps(qtdemux,
1326         QTDEMUX_FOURCC_GET(stsd->data+offset+4));
1327     g_print("caps %s\n",gst_caps_to_string(stream->caps));
1328   }else if(stream->subtype == FOURCC_soun){
1329     int version;
1330
1331     g_print("st type:          " GST_FOURCC_FORMAT "\n",
1332           GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(stsd->data+16+4)));
1333
1334     offset = 32;
1335     g_print("version/rev:      %08x\n", QTDEMUX_GUINT32_GET(stsd->data+offset));
1336     version = QTDEMUX_GUINT32_GET(stsd->data+offset);
1337     g_print("vendor:           %08x\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 4));
1338     g_print("n_channels:       %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 8));
1339     stream->n_channels = QTDEMUX_GUINT16_GET(stsd->data+offset + 8);
1340     g_print("sample_size:      %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 10));
1341     g_print("compression_id:   %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 12));
1342     g_print("packet size:      %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 14));
1343     g_print("sample rate:      %g\n", QTDEMUX_FP32_GET(stsd->data+offset + 16));
1344     stream->rate = QTDEMUX_FP32_GET(stsd->data+offset + 16);
1345
1346     if(version == 0x00010000){
1347       g_print("samples/packet:   %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 20));
1348       g_print("bytes/packet:     %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 24));
1349       g_print("bytes/frame:      %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 28));
1350       g_print("bytes/sample:     %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 32));
1351     }
1352
1353     stream->caps = qtdemux_audio_caps(qtdemux,
1354         QTDEMUX_FOURCC_GET(stsd->data+16+4));
1355     g_print("caps %s\n",gst_caps_to_string(stream->caps));
1356   }else{
1357     g_print("unknown subtype\n");
1358     return;
1359   }
1360
1361   if(stream->caps){
1362     gst_caps_ref(stream->caps);
1363     gst_caps_sink(stream->caps);
1364   }
1365
1366   /* sample to chunk */
1367   stsc = qtdemux_tree_get_child_by_type(stbl, FOURCC_stsc);
1368   g_assert(stsc);
1369   /* sample size */
1370   stsz = qtdemux_tree_get_child_by_type(stbl, FOURCC_stsz);
1371   g_assert(stsz);
1372   /* chunk offsets */
1373   stco = qtdemux_tree_get_child_by_type(stbl, FOURCC_stco);
1374   co64 = qtdemux_tree_get_child_by_type(stbl, FOURCC_co64);
1375   g_assert(stco || co64);
1376   /* sample time */
1377   stts = qtdemux_tree_get_child_by_type(stbl, FOURCC_stts);
1378   g_assert(stts);
1379
1380   sample_size = QTDEMUX_GUINT32_GET(stsz->data+12);
1381   if(sample_size == 0){
1382     n_samples = QTDEMUX_GUINT32_GET(stsz->data+16);
1383     stream->n_samples = n_samples;
1384     samples = g_malloc(sizeof(QtDemuxSample)*n_samples);
1385     stream->samples = samples;
1386
1387     for(i=0;i<n_samples;i++){
1388       samples[i].size = QTDEMUX_GUINT32_GET(stsz->data + i*4 + 20);
1389     }
1390     n_samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data+12);
1391     index = 0;
1392     offset = 16;
1393     for(i=0;i<n_samples_per_chunk;i++){
1394       int first_chunk, last_chunk;
1395       int samples_per_chunk;
1396   
1397       first_chunk = QTDEMUX_GUINT32_GET(stsc->data + 16 + i*12 + 0) - 1;
1398       if(i==n_samples_per_chunk-1){
1399         last_chunk = INT_MAX;
1400       }else{
1401         last_chunk = QTDEMUX_GUINT32_GET(stsc->data +16 + i*12 + 12) - 1;
1402       }
1403       samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data + 16 + i*12 + 4);
1404
1405       for(j=first_chunk;j<last_chunk;j++){
1406         int chunk_offset;
1407         if(stco){
1408           chunk_offset = QTDEMUX_GUINT32_GET(stco->data + 16 + j*4);
1409         }else{
1410           chunk_offset = QTDEMUX_GUINT64_GET(co64->data + 16 + j*8);
1411         }
1412         for(k=0;k<samples_per_chunk;k++){
1413           samples[index].chunk = j;
1414           samples[index].offset = chunk_offset;
1415           chunk_offset += samples[index].size;
1416           index++;
1417           if(index>=n_samples)goto done;
1418         }
1419       }
1420     }
1421 done:
1422     
1423     n_sample_times = QTDEMUX_GUINT32_GET(stts->data + 12);
1424     timestamp = 0;
1425     index = 0;
1426     for(i=0;i<n_sample_times;i++){
1427       int n;
1428       int duration;
1429       guint64 time;
1430   
1431       n = QTDEMUX_GUINT32_GET(stts->data + 16 + 8*i);
1432       duration = QTDEMUX_GUINT32_GET(stts->data + 16 + 8*i + 4);
1433       time = (GST_SECOND * duration)/stream->timescale;
1434       for(j=0;j<n;j++){
1435         samples[index].timestamp = timestamp;
1436         samples[index].duration = time;
1437         timestamp += time;
1438         index++;
1439       }
1440     }
1441   }else{
1442     int sample_width;
1443
1444     g_print("treating chunks as samples\n");
1445
1446     /* treat chunks as samples */
1447     if(stco){
1448       n_samples = QTDEMUX_GUINT32_GET(stco->data+12);
1449     }else{
1450       n_samples = QTDEMUX_GUINT32_GET(co64->data+12);
1451     }
1452     stream->n_samples = n_samples;
1453     samples = g_malloc(sizeof(QtDemuxSample)*n_samples);
1454     stream->samples = samples;
1455
1456     sample_width = QTDEMUX_GUINT16_GET(stsd->data+offset + 10) / 8;
1457
1458     n_samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data+12);
1459     offset = 16;
1460     sample_index = 0;
1461     for(i=0;i<n_samples_per_chunk;i++){
1462       int first_chunk, last_chunk;
1463       int samples_per_chunk;
1464   
1465       first_chunk = QTDEMUX_GUINT32_GET(stsc->data + 16 + i*12 + 0) - 1;
1466       if(i==n_samples-1){
1467         last_chunk = INT_MAX;
1468       }else{
1469         last_chunk = QTDEMUX_GUINT32_GET(stsc->data +16 + i*12 + 12) - 1;
1470       }
1471       samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data + 16 + i*12 + 4);
1472
1473       for(j=first_chunk;j<last_chunk;j++){
1474         int chunk_offset;
1475         if(stco){
1476           chunk_offset = QTDEMUX_GUINT32_GET(stco->data + 16 + j*4);
1477         }else{
1478           chunk_offset = QTDEMUX_GUINT64_GET(co64->data + 16 + j*8);
1479         }
1480         samples[j].chunk = j;
1481         samples[j].offset = chunk_offset;
1482         samples[j].size = samples_per_chunk * stream->n_channels * sample_width;
1483         samples[j].sample_index = sample_index;
1484         sample_index += samples_per_chunk;
1485         if(j>=n_samples)goto done2;
1486       }
1487     }
1488 done2:
1489
1490     n_sample_times = QTDEMUX_GUINT32_GET(stts->data + 12);
1491     g_print("n_sample_times = %d\n",n_sample_times);
1492     timestamp = 0;
1493     index = 0;
1494     sample_index = 0;
1495     for(i=0;i<n_sample_times;i++){
1496       int duration;
1497       guint64 time;
1498   
1499       sample_index += QTDEMUX_GUINT32_GET(stts->data + 16 + 8*i);
1500       duration = QTDEMUX_GUINT32_GET(stts->data + 16 + 8*i + 4);
1501       for(;index < n_samples && samples[index].sample_index < sample_index;index++){
1502         int size;
1503
1504         samples[index].timestamp = timestamp;
1505         size = samples[index+1].sample_index - samples[index].sample_index;
1506         time = (GST_SECOND * duration * samples[index].size)/stream->timescale ;
1507         timestamp += time;
1508         samples[index].duration = time;
1509       }
1510     }
1511   }
1512
1513 #if 0
1514   for(i=0;i<n_samples;i++){
1515     g_print("%d: %d %d %d %d %" G_GUINT64_FORMAT "\n",i,
1516         samples[i].sample_index,samples[i].chunk,
1517         samples[i].offset, samples[i].size, samples[i].timestamp);
1518     if(i>10)break;
1519   }
1520 #endif
1521
1522   gst_qtdemux_add_stream(qtdemux,stream);
1523 }
1524
1525
1526 static GstCaps *qtdemux_video_caps(GstQTDemux *qtdemux, guint32 fourcc)
1527 {
1528   switch(fourcc){
1529     case GST_MAKE_FOURCC('j','p','e','g'):
1530       /* JPEG */
1531       return GST_CAPS_NEW("jpeg_caps","image/jpeg",
1532           "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT),
1533           "width", GST_PROPS_INT_RANGE (16, 4096),
1534           "height", GST_PROPS_INT_RANGE (16, 4096));
1535     case GST_MAKE_FOURCC('m','j','p','a'):
1536       /* Motion-JPEG (format A) */
1537       return GST_CAPS_NEW("mjpa_caps","image/jpeg",
1538           "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT),
1539           "width", GST_PROPS_INT_RANGE (16, 4096),
1540           "height", GST_PROPS_INT_RANGE (16, 4096));
1541     case GST_MAKE_FOURCC('m','j','p','b'):
1542       /* Motion-JPEG (format B) */
1543       return GST_CAPS_NEW("mjpb_caps","image/jpeg",
1544           "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT),
1545           "width", GST_PROPS_INT_RANGE (16, 4096),
1546           "height", GST_PROPS_INT_RANGE (16, 4096));
1547     case GST_MAKE_FOURCC('S','V','Q','3'):
1548       return GST_CAPS_NEW("SVQ3_caps","video/x-svq",
1549           "svqversion", GST_PROPS_INT(3),
1550           "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT),
1551           "width", GST_PROPS_INT_RANGE (16, 4096),
1552           "height", GST_PROPS_INT_RANGE (16, 4096));
1553     case GST_MAKE_FOURCC('s','v','q','i'):
1554     case GST_MAKE_FOURCC('S','V','Q','1'):
1555       return GST_CAPS_NEW("SVQ1_caps","video/x-svq",
1556           "svqversion", GST_PROPS_INT(1),
1557           "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT),
1558           "width", GST_PROPS_INT_RANGE (16, 4096),
1559           "height", GST_PROPS_INT_RANGE (16, 4096));
1560     case GST_MAKE_FOURCC('r','a','w',' '):
1561       /* uncompressed RGB */
1562       return GST_CAPS_NEW("raw__caps","video/x-raw-rgb",
1563           "endianness",GST_PROPS_INT(G_BIG_ENDIAN),
1564           /*"bpp", GST_PROPS_INT(x),
1565           "depth", GST_PROPS_INT(x),
1566           "red_mask", GST_PROPS_INT(x),
1567           "green_mask", GST_PROPS_INT(x),
1568           "blue_mask", GST_PROPS_INT(x), FIXME! */
1569           "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT),
1570           "width", GST_PROPS_INT_RANGE (16, 4096),
1571           "height", GST_PROPS_INT_RANGE (16, 4096));
1572     case GST_MAKE_FOURCC('Y','u','v','2'):
1573       /* uncompressed YUV2 */
1574       return GST_CAPS_NEW("Yuv2_caps","video/x-raw-yuv",
1575           "format",GST_PROPS_FOURCC(GST_MAKE_FOURCC('Y','U','V','2')),
1576           "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT),
1577           "width", GST_PROPS_INT_RANGE (16, 4096),
1578           "height", GST_PROPS_INT_RANGE (16, 4096));
1579     case GST_MAKE_FOURCC('m','p','e','g'):
1580       /* MPEG */
1581       return GST_CAPS_NEW("mpeg_caps","video/mpeg",
1582           "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT),
1583           "width", GST_PROPS_INT_RANGE (16, 4096),
1584           "height", GST_PROPS_INT_RANGE (16, 4096),
1585           "systemstream", GST_PROPS_BOOLEAN(FALSE),
1586           "mpegversion", GST_PROPS_INT(1));
1587     case GST_MAKE_FOURCC('g','i','f',' '):
1588       return GST_CAPS_NEW("gif__caps","image/gif",
1589           "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT),
1590           "width", GST_PROPS_INT_RANGE (16, 4096),
1591           "height", GST_PROPS_INT_RANGE (16, 4096));
1592     case GST_MAKE_FOURCC('h','2','6','3'):
1593       /* H.263 */
1594       /* ffmpeg uses the height/width props, don't know why */
1595       return GST_CAPS_NEW("h263_caps","video/x-h263",
1596           "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT),
1597           "width", GST_PROPS_INT_RANGE (16, 4096),
1598           "height", GST_PROPS_INT_RANGE (16, 4096));
1599     case GST_MAKE_FOURCC('m','p','4','v'):
1600       /* MPEG-4 */
1601       return GST_CAPS_NEW("mp4v_caps", "video/mpeg",
1602           "mpegversion",GST_PROPS_INT(4),
1603           "systemstream", GST_PROPS_BOOLEAN(FALSE),
1604           "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT),
1605           "width", GST_PROPS_INT_RANGE (16, 4096),
1606           "height", GST_PROPS_INT_RANGE (16, 4096));
1607     case GST_MAKE_FOURCC('3','I','V','1'):
1608       return GST_CAPS_NEW("3IV1_caps", "video/x-3ivx",
1609           "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT),
1610           "width", GST_PROPS_INT_RANGE (16, 4096),
1611           "height", GST_PROPS_INT_RANGE (16, 4096));
1612     case GST_MAKE_FOURCC('r','p','z','a'):
1613     case GST_MAKE_FOURCC('c','v','i','d'):
1614       /* Cinepak */
1615     case GST_MAKE_FOURCC('r','l','e',' '):
1616       /* Run-length encoding */
1617     case GST_MAKE_FOURCC('s','m','c',' '):
1618     case GST_MAKE_FOURCC('k','p','c','d'):
1619     default:
1620       g_print("Don't know how to convert fourcc '" GST_FOURCC_FORMAT
1621           "' to caps\n", GST_FOURCC_ARGS(fourcc));
1622       return NULL;
1623   }
1624 }
1625
1626 static GstCaps *qtdemux_audio_caps(GstQTDemux *qtdemux, guint32 fourcc)
1627 {
1628   switch(fourcc){
1629     case GST_MAKE_FOURCC('N','O','N','E'):
1630       return NULL; /*GST_CAPS_NEW("NONE_caps","audio/raw",NULL);*/
1631     case GST_MAKE_FOURCC('r','a','w',' '):
1632       /* FIXME */
1633       return GST_CAPS_NEW("raw__caps","audio/x-raw-int",
1634           "width",GST_PROPS_INT(8),
1635           "depth",GST_PROPS_INT(8),
1636           "signed",GST_PROPS_BOOLEAN(FALSE),
1637           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1638           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT));
1639     case GST_MAKE_FOURCC('t','w','o','s'):
1640       /* FIXME */
1641       return GST_CAPS_NEW("twos_caps","audio/x-raw-int",
1642           "width",GST_PROPS_INT(16),
1643           "depth",GST_PROPS_INT(16),
1644           "endianness",GST_PROPS_INT(G_BIG_ENDIAN),
1645           "signed",GST_PROPS_BOOLEAN(TRUE),
1646           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1647           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT));
1648     case GST_MAKE_FOURCC('s','o','w','t'):
1649       /* FIXME */
1650       return GST_CAPS_NEW("sowt_caps","audio/x-raw-int",
1651           "width",GST_PROPS_INT(16),
1652           "depth",GST_PROPS_INT(16),
1653           "endianness",GST_PROPS_INT(G_LITTLE_ENDIAN),
1654           "signed",GST_PROPS_BOOLEAN(TRUE),
1655           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1656           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT));
1657     case GST_MAKE_FOURCC('f','l','6','4'):
1658       return GST_CAPS_NEW("fl64_caps","audio/x-raw-float",
1659           "width",GST_PROPS_INT (64),
1660           "endianness",GST_PROPS_INT (G_BIG_ENDIAN),
1661           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1662           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT));
1663     case GST_MAKE_FOURCC('f','l','3','2'):
1664       return GST_CAPS_NEW("fl32_caps","audio/x-raw-float",
1665           "width",GST_PROPS_INT (32),
1666           "endianness",GST_PROPS_INT (G_BIG_ENDIAN),
1667           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1668           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT));
1669     case GST_MAKE_FOURCC('i','n','2','4'):
1670       /* FIXME */
1671       return GST_CAPS_NEW("in24_caps","audio/x-raw-int",
1672           "width",GST_PROPS_INT(24),
1673           "depth",GST_PROPS_INT(32),
1674           "endianness",GST_PROPS_INT(G_BIG_ENDIAN),
1675           "signed",GST_PROPS_BOOLEAN(TRUE),
1676           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1677           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT));
1678     case GST_MAKE_FOURCC('i','n','3','2'):
1679       /* FIXME */
1680       return GST_CAPS_NEW("in32_caps","audio/x-raw-int",
1681           "width",GST_PROPS_INT(24),
1682           "depth",GST_PROPS_INT(32),
1683           "endianness",GST_PROPS_INT(G_BIG_ENDIAN),
1684           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1685           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT));
1686     case GST_MAKE_FOURCC('u','l','a','w'):
1687       /* FIXME */
1688       return GST_CAPS_NEW("ulaw_caps","audio/x-mulaw",
1689           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1690           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT));
1691     case GST_MAKE_FOURCC('a','l','a','w'):
1692       /* FIXME */
1693       return GST_CAPS_NEW("alaw_caps","audio/x-alaw",
1694           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1695           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT));
1696     case 0x6d730002:
1697       /* Microsoft ADPCM-ACM code 2 */
1698       return GST_CAPS_NEW("msxx_caps","audio/x-adpcm",
1699           "layout", GST_PROPS_STRING("microsoft"),
1700           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1701           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT),
1702           NULL);
1703     case 0x6d730011:
1704       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
1705       return GST_CAPS_NEW("msxx_caps","audio/x-adpcm",
1706           "layout", GST_PROPS_STRING("quicktime"),
1707           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1708           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT),
1709           NULL);
1710     case 0x6d730055:
1711       /* MPEG layer 3, CBR only (pre QT4.1) */
1712     case 0x5500736d:
1713     case GST_MAKE_FOURCC('.','m','p','3'):
1714       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
1715       return GST_CAPS_NEW("_mp3_caps","audio/mpeg",
1716           "mpegversion", GST_PROPS_INT(1),
1717           "layer", GST_PROPS_INT(3),
1718           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1719           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT),
1720           NULL);
1721     case GST_MAKE_FOURCC('M','A','C','3'):
1722       /* MACE 3:1 */
1723       return GST_CAPS_NEW("MAC3_caps","audio/x-mace",
1724           "maceversion",GST_PROPS_INT(3),
1725           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1726           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT),
1727           NULL);
1728     case GST_MAKE_FOURCC('M','A','C','6'):
1729       /* MACE 6:1 */
1730       return GST_CAPS_NEW("MAC3_caps","audio/x-mace",
1731           "maceversion",GST_PROPS_INT(6),
1732           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1733           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT),
1734           NULL);
1735     case GST_MAKE_FOURCC('O','g','g','V'):
1736       /* Ogg Vorbis */
1737       return GST_CAPS_NEW("OggV_caps","application/ogg",
1738           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1739           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT),
1740           NULL);
1741     case GST_MAKE_FOURCC('d','v','c','a'):
1742       /* DV audio */
1743       return GST_CAPS_NEW("dvca_caps","audio/x-dv",
1744           "rate",GST_PROPS_INT_RANGE(1,G_MAXINT),
1745           "channels",GST_PROPS_INT_RANGE(1,G_MAXINT),
1746           NULL);
1747     case GST_MAKE_FOURCC('m','p','4','a'):
1748       /* MPEG-4 AAC */
1749       return GST_CAPS_NEW("mp4a_caps", "audio/mpeg",
1750            "mpegversion", GST_PROPS_INT(4),
1751            "rate", GST_PROPS_INT_RANGE(1, G_MAXINT),
1752            "channels", GST_PROPS_INT_RANGE(1, G_MAXINT),
1753            "systemstream", GST_PROPS_BOOLEAN(FALSE), NULL);
1754     case GST_MAKE_FOURCC('q','t','v','r'):
1755       /* ? */
1756     case GST_MAKE_FOURCC('Q','D','M','2'):
1757       /* QDesign music version 2 (no constant) */
1758     case GST_MAKE_FOURCC('Q','D','M','C'):
1759       /* QDesign music */
1760     case GST_MAKE_FOURCC('i','m','a','4'):
1761       /* IMA 4:1 */
1762     case GST_MAKE_FOURCC('Q','c','l','p'):
1763       /* QUALCOMM PureVoice */
1764     case GST_MAKE_FOURCC('a','g','s','m'):
1765       /* ? */
1766     default:
1767       g_print("Don't know how to convert fourcc '" GST_FOURCC_FORMAT
1768           "' to caps\n", GST_FOURCC_ARGS(fourcc));
1769       return NULL;
1770   }
1771 }
1772