2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
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.
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.
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.
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))
38 #define QTDEMUX_GUINT64_GET(a) ((((guint64)QTDEMUX_GUINT32_GET(a))<<32)|QTDEMUX_GUINT32_GET(((void *)a)+4))
40 typedef struct _QtNode QtNode;
41 typedef struct _QtNodeType QtNodeType;
42 typedef struct _QtDemuxSample QtDemuxSample;
43 //typedef struct _QtDemuxStream QtDemuxStream;
55 void (*dump)(GstQTDemux *qtdemux, void *buffer, int depth);
58 struct _QtDemuxSample {
67 struct _QtDemuxStream {
72 QtDemuxSample *samples;
87 QTDEMUX_STATE_HEADER_SEEKING,
88 QTDEMUX_STATE_SEEKING,
90 QTDEMUX_STATE_SEEKING_EOS,
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);
97 static GstElementDetails
102 "Demultiplex a QuickTime file into audio and video streams",
103 "David Schleef <ds@schleef.org>"
114 GST_PAD_TEMPLATE_FACTORY (sink_templ,
130 static GstPadTemplate *videosrctempl, *audiosrctempl;
131 static GstElementClass *parent_class = NULL;
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);
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);
148 static GType gst_qtdemux_get_type (void)
150 static GType qtdemux_type = 0;
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,
160 qtdemux_type = g_type_register_static (GST_TYPE_ELEMENT, "GstQTDemux", &qtdemux_info, 0);
165 static void gst_qtdemux_base_init (GstQTDemuxClass *klass)
167 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
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);
176 static void gst_qtdemux_class_init (GstQTDemuxClass *klass)
178 GObjectClass *gobject_class;
179 GstElementClass *gstelement_class;
181 gobject_class = (GObjectClass*)klass;
182 gstelement_class = (GstElementClass*)klass;
184 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
186 gstelement_class->change_state = gst_qtdemux_change_state;
190 gst_qtdemux_init (GstQTDemux *qtdemux)
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);
198 plugin_init (GstPlugin *plugin)
200 GstCaps *audiocaps = NULL, *videocaps = NULL, *temp;
201 const guint32 audio_fcc[] = {
210 if (!gst_library_load ("gstbytestream"))
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);
217 audiosrctempl = gst_pad_template_new ("audio_%02d",
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);
226 videosrctempl = gst_pad_template_new ("video_%02d",
231 return gst_element_register (plugin, "qtdemux",
232 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX);
239 "Quicktime stream demuxer",
247 static gboolean gst_qtdemux_handle_sink_event (GstQTDemux *qtdemux)
253 gst_bytestream_get_status(qtdemux->bs, &remaining, &event);
255 type = event ? GST_EVENT_TYPE(event) : GST_EVENT_UNKNOWN;
256 GST_DEBUG ("qtdemux: event %p %d", event, type);
260 gst_bytestream_flush(qtdemux->bs, remaining);
261 gst_pad_event_default(qtdemux->sinkpad, event);
263 case GST_EVENT_FLUSH:
264 g_warning("flush event");
266 case GST_EVENT_DISCONTINUOUS:
267 GST_DEBUG ("discontinuous event\n");
268 //gst_bytestream_flush_fast(qtdemux->bs, remaining);
271 g_warning("unhandled event %d",type);
275 gst_event_unref(event);
279 static GstElementStateReturn gst_qtdemux_change_state(GstElement *element)
281 GstQTDemux *qtdemux = GST_QTDEMUX(element);
283 switch(GST_STATE_TRANSITION(element)){
284 case GST_STATE_NULL_TO_READY:
286 case GST_STATE_READY_TO_PAUSED:
287 qtdemux->bs = gst_bytestream_new(qtdemux->sinkpad);
288 qtdemux->state = QTDEMUX_STATE_HEADER;
291 case GST_STATE_PAUSED_TO_PLAYING:
293 case GST_STATE_PLAYING_TO_PAUSED:
295 case GST_STATE_PAUSED_TO_READY:
296 gst_bytestream_destroy(qtdemux->bs);
298 case GST_STATE_READY_TO_NULL:
304 return GST_ELEMENT_CLASS(parent_class)->change_state(element);
307 static void gst_qtdemux_loop_header (GstElement *element)
309 GstQTDemux *qtdemux = GST_QTDEMUX(element);
319 /* FIXME _tell gets the offset wrong */
320 //cur_offset = gst_bytestream_tell(qtdemux->bs);
322 cur_offset = qtdemux->offset;
323 GST_DEBUG ("loop at position %d",cur_offset);
325 switch(qtdemux->state){
326 case QTDEMUX_STATE_HEADER:
329 ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 16);
331 if(!gst_qtdemux_handle_sink_event(qtdemux)){
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));
345 length = gst_bytestream_length(qtdemux->bs) - cur_offset;
348 guint32 length1, length2;
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);
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'):
365 case GST_MAKE_FOURCC('m','o','o','v'):
370 ret = gst_bytestream_read(qtdemux->bs, &moov, length);
372 GST_DEBUG ("read failed (%d < %d)",ret,length);
373 if(!gst_qtdemux_handle_sink_event(qtdemux)){
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;
389 g_print("unknown %08x '" GST_FOURCC_FORMAT "' at %d\n",
390 fourcc, GST_FOURCC_ARGS(fourcc), cur_offset);
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);
400 case QTDEMUX_STATE_SEEKING_EOS:
405 ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 1);
407 if(!gst_qtdemux_handle_sink_event(qtdemux)){
414 gst_element_set_eos(element);
416 qtdemux->state = QTDEMUX_STATE_EOS;
419 case QTDEMUX_STATE_EOS:
420 g_warning("spinning in EOS\n");
422 case QTDEMUX_STATE_MOVIE:
424 QtDemuxStream *stream;
429 min_time = G_MAXUINT64;
430 for(i=0;i<qtdemux->n_streams;i++){
431 stream = qtdemux->streams[i];
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;
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)));
445 ret = gst_bytestream_seek(qtdemux->bs, 0, GST_SEEK_METHOD_END);
446 GST_DEBUG ("seek returned %d",ret);
448 qtdemux->state = QTDEMUX_STATE_SEEKING_EOS;
452 stream = qtdemux->streams[index];
454 offset = stream->samples[stream->sample_index].offset;
455 size = stream->samples[stream->sample_index].size;
457 GST_DEBUG ("pushing from stream %d, sample_index=%d offset=%d size=%d",
458 index, stream->sample_index, offset, size);
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);
468 GST_DEBUG ("reading %d bytes\n",size);
471 ret = gst_bytestream_read(qtdemux->bs, &buf, size);
473 GST_DEBUG ("read failed (%d < %d)",ret,size);
474 if(!gst_qtdemux_handle_sink_event(qtdemux)){
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)));
491 gst_pad_try_set_caps(stream->pad, stream->caps);
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));
499 stream->sample_index++;
509 static GstCaps *gst_qtdemux_src_getcaps(GstPad *pad, GstCaps *caps)
512 QtDemuxStream *stream;
515 GST_DEBUG ("gst_qtdemux_src_getcaps");
517 qtdemux = GST_QTDEMUX(gst_pad_get_parent(pad));
519 g_return_val_if_fail(GST_IS_QTDEMUX(qtdemux), NULL);
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){
530 GST_DEBUG ("Couldn't find stream cooresponding to pad\n");
535 static GstPadLinkReturn
536 gst_qtdemux_src_link(GstPad *pad, GstCaps *caps)
539 QtDemuxStream *stream;
542 GST_DEBUG ("gst_qtdemux_src_link");
544 qtdemux = GST_QTDEMUX(gst_pad_get_parent(pad));
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);
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;
558 GST_DEBUG ("Couldn't find stream cooresponding to pad\n");
560 return GST_PAD_LINK_REFUSED;
563 void gst_qtdemux_add_stream(GstQTDemux *qtdemux, QtDemuxStream *stream)
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;
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;
579 qtdemux->n_video_streams++;
581 stream->pad = gst_pad_new_from_template (audiosrctempl,
582 g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams));
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;
592 qtdemux->n_audio_streams++;
595 gst_pad_set_getcaps_function(stream->pad, gst_qtdemux_src_getcaps);
596 gst_pad_set_link_function(stream->pad, gst_qtdemux_src_link);
598 qtdemux->streams[qtdemux->n_streams] = stream;
599 qtdemux->n_streams++;
600 GST_DEBUG ("n_streams is now %d", qtdemux->n_streams);
602 GST_DEBUG ("adding pad %p to qtdemux %p", stream->pad, qtdemux);
603 gst_element_add_pad(GST_ELEMENT (qtdemux), stream->pad);
605 /* Note: we need to have everything set up before calling try_set_caps */
607 g_print("setting caps to %s\n",gst_caps_to_string(stream->caps));
609 gst_pad_try_set_caps(stream->pad, stream->caps);
614 #define QT_CONTAINER 1
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')
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);
675 QtNodeType qt_node_types[] = {
676 { FOURCC_moov, "movie", QT_CONTAINER, },
677 { FOURCC_mvhd, "movie header", 0,
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,
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,
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,
699 { FOURCC_hdlr, "handler reference", 0,
701 { FOURCC_minf, "media information", QT_CONTAINER },
702 { FOURCC_vmhd, "video media information", 0,
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,
710 { FOURCC_stbl, "sample table", QT_CONTAINER },
711 { FOURCC_stsd, "sample description", 0,
713 { FOURCC_stts, "time-to-sample", 0,
715 { FOURCC_stss, "sync sample", 0,
717 { FOURCC_stsc, "sample-to-chunk", 0,
719 { FOURCC_stsz, "sample size", 0,
721 { FOURCC_stco, "chunk offset", 0,
723 { FOURCC_co64, "64-bit chunk offset", 0,
725 { FOURCC_vide, "video media", 0 },
726 { FOURCC_cmov, "compressed movie", QT_CONTAINER },
727 { FOURCC_dcom, "compressed data", 0,
729 { FOURCC_cmvd, "compressed movie data", 0,
733 static int n_qt_node_types = sizeof(qt_node_types)/sizeof(qt_node_types[0]);
736 static void *qtdemux_zalloc(void *opaque, unsigned int items, unsigned int size)
738 return g_malloc(items*size);
741 static void qtdemux_zfree(void *opaque, void *addr)
746 static void *qtdemux_inflate(void *z_buffer, int z_length, int length)
752 z = g_new0(z_stream, 1);
753 z->zalloc = qtdemux_zalloc;
754 z->zfree = qtdemux_zfree;
757 z->next_in = z_buffer;
758 z->avail_in = z_length;
760 buffer = g_malloc(length);
761 ret = inflateInit(z);
762 while(z->avail_in > 0){
763 if(z->avail_out == 0){
765 buffer = realloc(buffer, length);
766 z->next_out = buffer + z->total_out;
769 ret = inflate(z,Z_SYNC_FLUSH);
770 if(ret != Z_OK)break;
772 if(ret != Z_STREAM_END){
773 g_warning("inflate() returned %d\n",ret);
780 static void qtdemux_parse_moov(GstQTDemux *qtdemux, void *buffer, int length)
784 qtdemux->moov_node = g_node_new(buffer);
786 qtdemux_parse(qtdemux, qtdemux->moov_node, buffer, length);
788 cmov = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_cmov);
793 dcom = qtdemux_tree_get_child_by_type(cmov, FOURCC_dcom);
794 cmvd = qtdemux_tree_get_child_by_type(cmov, FOURCC_cmvd);
796 if(QTDEMUX_FOURCC_GET(dcom->data+8) == GST_MAKE_FOURCC('z','l','i','b')){
797 int uncompressed_length;
798 int compressed_length;
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);
805 buf = qtdemux_inflate(cmvd->data + 12, compressed_length,
806 uncompressed_length);
808 qtdemux->moov_node_compressed = qtdemux->moov_node;
809 qtdemux->moov_node = g_node_new(buf);
811 qtdemux_parse(qtdemux, qtdemux->moov_node, buf, uncompressed_length);
813 g_print("unknown header compression type\n");
818 static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int length)
825 //g_print("qtdemux_parse %p %d\n",buffer, length);
827 node_length = QTDEMUX_GUINT32_GET(buffer);
828 fourcc = QTDEMUX_FOURCC_GET(buffer+4);
830 type = qtdemux_type_get(fourcc);
832 /*g_print("parsing '" GST_FOURCC_FORMAT "', length=%d\n",
833 GST_FOURCC_ARGS(fourcc), node_length);*/
835 if(type->flags & QT_CONTAINER){
840 end = buffer + length;
845 /* FIXME: get annoyed */
846 g_print("buffer overrun\n");
848 len = QTDEMUX_GUINT32_GET(buf);
850 child = g_node_new(buf);
851 g_node_append(node, child);
852 qtdemux_parse(qtdemux, child, buf, len);
858 if(fourcc == FOURCC_cmvd){
859 int uncompressed_length;
862 uncompressed_length = QTDEMUX_GUINT32_GET(buffer+8);
863 g_print("length = %d\n",uncompressed_length);
865 buf = qtdemux_inflate(buffer + 12, node_length-12, uncompressed_length);
867 end = buf + uncompressed_length;
873 /* FIXME: get annoyed */
874 g_print("buffer overrun\n");
876 len = QTDEMUX_GUINT32_GET(buf);
878 child = g_node_new(buf);
879 g_node_append(node, child);
880 qtdemux_parse(qtdemux, child, buf, len);
889 static QtNodeType *qtdemux_type_get(guint32 fourcc)
893 for(i=0;i<n_qt_node_types;i++){
894 if(qt_node_types[i].fourcc == fourcc)
895 return qt_node_types+i;
897 return qt_node_types+n_qt_node_types-1;
900 static gboolean qtdemux_node_dump_foreach(GNode *node, gpointer data)
902 void *buffer = node->data;
908 node_length = GUINT32_FROM_BE(*(guint32 *)buffer);
909 fourcc = GUINT32_FROM_LE(*(guint32 *)(buffer+4));
911 type = qtdemux_type_get(fourcc);
913 depth = (g_node_depth(node)-1)*2;
914 g_print("%*s'" GST_FOURCC_FORMAT "', [%d], %s\n",
916 GST_FOURCC_ARGS(fourcc),
920 if(type->dump)type->dump(data, buffer, depth);
925 static void qtdemux_node_dump(GstQTDemux *qtdemux, GNode *node)
927 g_node_traverse(qtdemux->moov_node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
928 qtdemux_node_dump_foreach, qtdemux);
931 static void qtdemux_dump_mvhd(GstQTDemux *qtdemux, void *buffer, int depth)
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));
949 static void qtdemux_dump_tkhd(GstQTDemux *qtdemux, void *buffer, int depth)
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));
964 static void qtdemux_dump_elst(GstQTDemux *qtdemux, void *buffer, int depth)
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);
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));
979 static void qtdemux_dump_mdhd(GstQTDemux *qtdemux, void *buffer, int depth)
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));
991 static void qtdemux_dump_hdlr(GstQTDemux *qtdemux, void *buffer, int depth)
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));
1007 static void qtdemux_dump_vmhd(GstQTDemux *qtdemux, void *buffer, int depth)
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));
1013 static void qtdemux_dump_dref(GstQTDemux *qtdemux, void *buffer, int depth)
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);
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);
1031 static void qtdemux_dump_stsd(GstQTDemux *qtdemux, void *buffer, int depth)
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);
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));
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));
1063 offset += QTDEMUX_GUINT32_GET(buffer+offset);
1067 static void qtdemux_dump_stts(GstQTDemux *qtdemux, void *buffer, int depth)
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);
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));
1085 static void qtdemux_dump_stss(GstQTDemux *qtdemux, void *buffer, int depth)
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);
1096 g_print("%*s sample: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1102 static void qtdemux_dump_stsc(GstQTDemux *qtdemux, void *buffer, int depth)
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);
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));
1121 static void qtdemux_dump_stsz(GstQTDemux *qtdemux, void *buffer, int depth)
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);
1136 g_print("%*s sample size: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1143 static void qtdemux_dump_stco(GstQTDemux *qtdemux, void *buffer, int depth)
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);
1154 g_print("%*s chunk offset: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1160 static void qtdemux_dump_co64(GstQTDemux *qtdemux, void *buffer, int depth)
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);
1171 g_print("%*s chunk offset: %" G_GUINT64_FORMAT "\n", depth, "", QTDEMUX_GUINT64_GET(buffer+offset));
1177 static void qtdemux_dump_dcom(GstQTDemux *qtdemux, void *buffer, int depth)
1179 g_print("%*s compression type: " GST_FOURCC_FORMAT "\n", depth, "",
1180 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+8)));
1183 static void qtdemux_dump_cmvd(GstQTDemux *qtdemux, void *buffer, int depth)
1185 g_print("%*s length: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1189 static GNode *qtdemux_tree_get_child_by_type(GNode *node, guint32 fourcc)
1193 guint32 child_fourcc;
1195 for(child = g_node_first_child(node); child; child = g_node_next_sibling(child)){
1196 buffer = child->data;
1198 child_fourcc = GUINT32_FROM_LE(*(guint32 *)(buffer+4));
1200 if(child_fourcc == fourcc){
1207 static GNode *qtdemux_tree_get_sibling_by_type(GNode *node, guint32 fourcc)
1211 guint32 child_fourcc;
1213 for(child = g_node_next_sibling(node); child; child = g_node_next_sibling(child)){
1214 buffer = child->data;
1216 child_fourcc = GUINT32_FROM_LE(*(guint32 *)(buffer+4));
1218 if(child_fourcc == fourcc){
1225 static void qtdemux_parse_trak(GstQTDemux *qtdemux, GNode *trak);
1227 static void qtdemux_parse_tree(GstQTDemux *qtdemux)
1232 mvhd = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_mvhd);
1234 g_print("No mvhd node found.\n");
1238 qtdemux->timescale = QTDEMUX_GUINT32_GET(mvhd->data + 20);
1239 qtdemux->duration = QTDEMUX_GUINT32_GET(mvhd->data + 24);
1241 g_print("timescale: %d\n", qtdemux->timescale);
1242 g_print("duration: %d\n", qtdemux->duration);
1244 trak = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_trak);
1245 qtdemux_parse_trak(qtdemux, trak);
1247 /* trak = qtdemux_tree_get_sibling_by_type(trak, FOURCC_trak);
1248 if(trak)qtdemux_parse_trak(qtdemux, trak);*/
1250 while ((trak = qtdemux_tree_get_sibling_by_type(trak, FOURCC_trak)) != NULL)
1251 qtdemux_parse_trak(qtdemux, trak);
1254 static void qtdemux_parse_trak(GstQTDemux *qtdemux, GNode *trak)
1270 QtDemuxSample *samples;
1271 int n_samples_per_chunk;
1274 QtDemuxStream *stream;
1280 stream = g_new0(QtDemuxStream,1);
1282 tkhd = qtdemux_tree_get_child_by_type(trak, FOURCC_tkhd);
1285 /* track duration? */
1287 mdia = qtdemux_tree_get_child_by_type(trak, FOURCC_mdia);
1290 mdhd = qtdemux_tree_get_child_by_type(mdia, FOURCC_mdhd);
1293 stream->timescale = QTDEMUX_GUINT32_GET(mdhd->data+20);
1295 hdlr = qtdemux_tree_get_child_by_type(mdia, FOURCC_hdlr);
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)));
1303 stream->subtype = QTDEMUX_FOURCC_GET(hdlr->data+16);
1305 minf = qtdemux_tree_get_child_by_type(mdia, FOURCC_minf);
1308 stbl = qtdemux_tree_get_child_by_type(minf, FOURCC_stbl);
1311 stsd = qtdemux_tree_get_child_by_type(stbl, FOURCC_stsd);
1314 if(stream->subtype == FOURCC_vide){
1316 g_print("st type: " GST_FOURCC_FORMAT "\n",
1317 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(stsd->data+offset+4)));
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 */
1323 g_print("frame count: %u\n", QTDEMUX_GUINT16_GET(stsd->data+offset+48));
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){
1331 g_print("st type: " GST_FOURCC_FORMAT "\n",
1332 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(stsd->data+16+4)));
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);
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));
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));
1357 g_print("unknown subtype\n");
1362 gst_caps_ref(stream->caps);
1363 gst_caps_sink(stream->caps);
1366 /* sample to chunk */
1367 stsc = qtdemux_tree_get_child_by_type(stbl, FOURCC_stsc);
1370 stsz = qtdemux_tree_get_child_by_type(stbl, FOURCC_stsz);
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);
1377 stts = qtdemux_tree_get_child_by_type(stbl, FOURCC_stts);
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;
1387 for(i=0;i<n_samples;i++){
1388 samples[i].size = QTDEMUX_GUINT32_GET(stsz->data + i*4 + 20);
1390 n_samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data+12);
1393 for(i=0;i<n_samples_per_chunk;i++){
1394 int first_chunk, last_chunk;
1395 int samples_per_chunk;
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;
1401 last_chunk = QTDEMUX_GUINT32_GET(stsc->data +16 + i*12 + 12) - 1;
1403 samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data + 16 + i*12 + 4);
1405 for(j=first_chunk;j<last_chunk;j++){
1408 chunk_offset = QTDEMUX_GUINT32_GET(stco->data + 16 + j*4);
1410 chunk_offset = QTDEMUX_GUINT64_GET(co64->data + 16 + j*8);
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;
1417 if(index>=n_samples)goto done;
1423 n_sample_times = QTDEMUX_GUINT32_GET(stts->data + 12);
1426 for(i=0;i<n_sample_times;i++){
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;
1435 samples[index].timestamp = timestamp;
1436 samples[index].duration = time;
1444 g_print("treating chunks as samples\n");
1446 /* treat chunks as samples */
1448 n_samples = QTDEMUX_GUINT32_GET(stco->data+12);
1450 n_samples = QTDEMUX_GUINT32_GET(co64->data+12);
1452 stream->n_samples = n_samples;
1453 samples = g_malloc(sizeof(QtDemuxSample)*n_samples);
1454 stream->samples = samples;
1456 sample_width = QTDEMUX_GUINT16_GET(stsd->data+offset + 10) / 8;
1458 n_samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data+12);
1461 for(i=0;i<n_samples_per_chunk;i++){
1462 int first_chunk, last_chunk;
1463 int samples_per_chunk;
1465 first_chunk = QTDEMUX_GUINT32_GET(stsc->data + 16 + i*12 + 0) - 1;
1467 last_chunk = INT_MAX;
1469 last_chunk = QTDEMUX_GUINT32_GET(stsc->data +16 + i*12 + 12) - 1;
1471 samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data + 16 + i*12 + 4);
1473 for(j=first_chunk;j<last_chunk;j++){
1476 chunk_offset = QTDEMUX_GUINT32_GET(stco->data + 16 + j*4);
1478 chunk_offset = QTDEMUX_GUINT64_GET(co64->data + 16 + j*8);
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;
1490 n_sample_times = QTDEMUX_GUINT32_GET(stts->data + 12);
1491 g_print("n_sample_times = %d\n",n_sample_times);
1495 for(i=0;i<n_sample_times;i++){
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++){
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 ;
1508 samples[index].duration = time;
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);
1522 gst_qtdemux_add_stream(qtdemux,stream);
1526 static GstCaps *qtdemux_video_caps(GstQTDemux *qtdemux, guint32 fourcc)
1529 case GST_MAKE_FOURCC('j','p','e','g'):
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'):
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'):
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'):
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'):
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'):
1620 g_print("Don't know how to convert fourcc '" GST_FOURCC_FORMAT
1621 "' to caps\n", GST_FOURCC_ARGS(fourcc));
1626 static GstCaps *qtdemux_audio_caps(GstQTDemux *qtdemux, guint32 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',' '):
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'):
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'):
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'):
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'):
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'):
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'):
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));
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),
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),
1711 /* MPEG layer 3, CBR only (pre QT4.1) */
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),
1721 case GST_MAKE_FOURCC('M','A','C','3'):
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),
1728 case GST_MAKE_FOURCC('M','A','C','6'):
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),
1735 case GST_MAKE_FOURCC('O','g','g','V'):
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),
1741 case GST_MAKE_FOURCC('d','v','c','a'):
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),
1747 case GST_MAKE_FOURCC('m','p','4','a'):
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'):
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'):
1760 case GST_MAKE_FOURCC('i','m','a','4'):
1762 case GST_MAKE_FOURCC('Q','c','l','p'):
1763 /* QUALCOMM PureVoice */
1764 case GST_MAKE_FOURCC('a','g','s','m'):
1767 g_print("Don't know how to convert fourcc '" GST_FOURCC_FORMAT
1768 "' to caps\n", GST_FOURCC_ARGS(fourcc));