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