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.
29 GST_DEBUG_CATEGORY_EXTERN (qtdemux_debug);
30 #define GST_CAT_DEFAULT qtdemux_debug
32 #define QTDEMUX_GUINT32_GET(a) GUINT32_FROM_BE(*(guint32 *)(a))
33 #define QTDEMUX_GUINT16_GET(a) GUINT16_FROM_BE(*(guint16 *)(a))
34 #define QTDEMUX_GUINT8_GET(a) (*(guint8 *)(a))
35 #define QTDEMUX_FP32_GET(a) (GUINT32_FROM_BE(*(guint16 *)(a))/65536.0)
36 #define QTDEMUX_FP16_GET(a) (GUINT16_FROM_BE(*(guint16 *)(a))/256.0)
37 #define QTDEMUX_FOURCC_GET(a) GUINT32_FROM_LE(*(guint32 *)(a))
39 #define QTDEMUX_GUINT64_GET(a) ((((guint64)QTDEMUX_GUINT32_GET(a))<<32)|QTDEMUX_GUINT32_GET(((void *)a)+4))
41 typedef struct _QtNode QtNode;
42 typedef struct _QtNodeType QtNodeType;
43 typedef struct _QtDemuxSample QtDemuxSample;
44 //typedef struct _QtDemuxStream QtDemuxStream;
56 void (*dump)(GstQTDemux *qtdemux, void *buffer, int depth);
59 struct _QtDemuxSample {
68 struct _QtDemuxStream {
73 QtDemuxSample *samples;
84 guint bytes_per_frame;
85 guint samples_per_packet;
91 QTDEMUX_STATE_HEADER_SEEKING,
92 QTDEMUX_STATE_SEEKING,
94 QTDEMUX_STATE_SEEKING_EOS,
98 static GNode *qtdemux_tree_get_child_by_type(GNode *node, guint32 fourcc);
99 static GNode *qtdemux_tree_get_sibling_by_type(GNode *node, guint32 fourcc);
101 static GstElementDetails
102 gst_qtdemux_details =
106 "Demultiplex a QuickTime file into audio and video streams",
107 "David Schleef <ds@schleef.org>"
118 static GstStaticPadTemplate gst_qtdemux_sink_template =
119 GST_STATIC_PAD_TEMPLATE (
123 GST_STATIC_CAPS ("video/quicktime")
126 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
127 GST_STATIC_PAD_TEMPLATE (
134 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
135 GST_STATIC_PAD_TEMPLATE (
142 static GstElementClass *parent_class = NULL;
144 static void gst_qtdemux_class_init (GstQTDemuxClass *klass);
145 static void gst_qtdemux_base_init (GstQTDemuxClass *klass);
146 static void gst_qtdemux_init (GstQTDemux *quicktime_demux);
147 static GstElementStateReturn gst_qtdemux_change_state(GstElement *element);
148 static void gst_qtdemux_loop_header (GstElement *element);
149 static gboolean gst_qtdemux_handle_sink_event (GstQTDemux *qtdemux);
151 static void qtdemux_parse_moov(GstQTDemux *qtdemux, void *buffer, int length);
152 static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int length);
153 static QtNodeType *qtdemux_type_get(guint32 fourcc);
154 static void qtdemux_node_dump(GstQTDemux *qtdemux, GNode *node);
155 static void qtdemux_parse_tree(GstQTDemux *qtdemux);
156 static GstCaps *qtdemux_video_caps(GstQTDemux *qtdemux, guint32 fourcc, const guint8 *stsd_data);
157 static GstCaps *qtdemux_audio_caps(GstQTDemux *qtdemux, guint32 fourcc, const guint8 *data);
159 static GType gst_qtdemux_get_type (void)
161 static GType qtdemux_type = 0;
164 static const GTypeInfo qtdemux_info = {
165 sizeof(GstQTDemuxClass),
166 (GBaseInitFunc)gst_qtdemux_base_init, NULL,
167 (GClassInitFunc)gst_qtdemux_class_init,
168 NULL, NULL, sizeof(GstQTDemux), 0,
169 (GInstanceInitFunc)gst_qtdemux_init,
171 qtdemux_type = g_type_register_static (GST_TYPE_ELEMENT, "GstQTDemux", &qtdemux_info, 0);
176 static void gst_qtdemux_base_init (GstQTDemuxClass *klass)
178 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
180 gst_element_class_add_pad_template (element_class,
181 gst_static_pad_template_get (&gst_qtdemux_sink_template));
182 gst_element_class_add_pad_template (element_class,
183 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
184 gst_element_class_add_pad_template (element_class,
185 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
186 gst_element_class_set_details (element_class, &gst_qtdemux_details);
190 static void gst_qtdemux_class_init (GstQTDemuxClass *klass)
192 GObjectClass *gobject_class;
193 GstElementClass *gstelement_class;
195 gobject_class = (GObjectClass*)klass;
196 gstelement_class = (GstElementClass*)klass;
198 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
200 gstelement_class->change_state = gst_qtdemux_change_state;
204 gst_qtdemux_init (GstQTDemux *qtdemux)
206 qtdemux->sinkpad = gst_pad_new_from_template (
207 gst_static_pad_template_get (&gst_qtdemux_sink_template), "sink");
208 gst_element_set_loop_function (GST_ELEMENT (qtdemux),
209 gst_qtdemux_loop_header);
210 gst_element_add_pad (GST_ELEMENT (qtdemux), qtdemux->sinkpad);
213 static const GstFormat *
214 gst_qtdemux_get_src_formats (GstPad *pad)
216 static const GstFormat src_a_formats[] = {
222 static const GstFormat src_v_formats[] = {
227 QtDemuxStream *stream = gst_pad_get_element_private(pad);
229 return (stream->subtype == GST_MAKE_FOURCC('v','i','d','e')) ?
230 src_v_formats : src_a_formats;
234 gst_qtdemux_src_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
235 GstFormat *dest_format, gint64 *dest_value)
238 QtDemuxStream *stream = gst_pad_get_element_private(pad);
240 if (stream->subtype == GST_MAKE_FOURCC('v','i','d','e') &&
241 (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
244 switch (src_format) {
245 case GST_FORMAT_TIME:
246 switch (*dest_format) {
247 case GST_FORMAT_BYTES:
248 *dest_value = src_value * 1; /* FIXME */
250 case GST_FORMAT_DEFAULT:
251 *dest_value = src_value * 1; /* FIXME */
258 case GST_FORMAT_BYTES:
259 switch (*dest_format) {
260 case GST_FORMAT_TIME:
261 *dest_value = src_value * 1; /* FIXME */
268 case GST_FORMAT_DEFAULT:
269 switch (*dest_format) {
270 case GST_FORMAT_TIME:
271 *dest_value = src_value * 1; /* FIXME */
285 static const GstQueryType *
286 gst_qtdemux_get_src_query_types (GstPad *pad)
288 static const GstQueryType src_types[] = {
297 static const GstEventMask *
298 gst_qtdemux_get_event_mask (GstPad *pad)
300 static const GstEventMask masks[] = {
301 { GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT },
309 gst_qtdemux_handle_src_query (GstPad *pad, GstQueryType type,
310 GstFormat *format, gint64 *value)
313 //QtDemuxStream *stream = gst_pad_get_element_private(pad);
316 case GST_QUERY_TOTAL:
318 case GST_FORMAT_TIME:
319 *value = 0; /* FIXME */
321 case GST_FORMAT_BYTES:
322 *value = 0; /* FIXME */
324 case GST_FORMAT_DEFAULT:
325 *value = 0; /* FIXME */
332 case GST_QUERY_POSITION:
334 case GST_FORMAT_TIME:
335 *value = 0; /* FIXME */
337 case GST_FORMAT_BYTES:
338 *value = 0; /* FIXME */
340 case GST_FORMAT_DEFAULT:
341 *value = 0; /* FIXME */
357 gst_qtdemux_handle_src_event (GstPad *pad, GstEvent *event)
360 //QtDemuxStream *stream = gst_pad_get_element_private(pad);
362 switch (GST_EVENT_TYPE (event)) {
364 GST_DEBUG ("seek format %d", GST_EVENT_SEEK_FORMAT (event));
366 switch (GST_EVENT_SEEK_FORMAT (event)) {
367 case GST_FORMAT_BYTES:
368 case GST_FORMAT_DEFAULT:
369 case GST_FORMAT_TIME:
371 gint64 desired_offset = GST_EVENT_SEEK_OFFSET (event);
373 GST_DEBUG ("seeking to %" G_GINT64_FORMAT, desired_offset);
386 gst_event_unref (event);
393 GST_DEBUG_CATEGORY (qtdemux_debug);
396 plugin_init (GstPlugin *plugin)
398 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
400 if (!gst_library_load ("gstbytestream"))
403 if (!gst_library_load ("gstgetbits"))
406 return gst_element_register (plugin, "qtdemux",
407 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX);
414 "Quicktime stream demuxer",
422 static gboolean gst_qtdemux_handle_sink_event (GstQTDemux *qtdemux)
428 gst_bytestream_get_status(qtdemux->bs, &remaining, &event);
430 type = event ? GST_EVENT_TYPE(event) : GST_EVENT_UNKNOWN;
431 GST_DEBUG ("qtdemux: event %p %d", event, type);
435 gst_bytestream_flush(qtdemux->bs, remaining);
436 gst_pad_event_default(qtdemux->sinkpad, event);
438 case GST_EVENT_FLUSH:
439 //g_warning("flush event");
441 case GST_EVENT_DISCONTINUOUS:
442 GST_DEBUG ("discontinuous event\n");
443 //gst_bytestream_flush_fast(qtdemux->bs, remaining);
446 g_warning("unhandled event %d",type);
450 gst_event_unref(event);
454 static GstElementStateReturn gst_qtdemux_change_state(GstElement *element)
456 GstQTDemux *qtdemux = GST_QTDEMUX(element);
458 switch(GST_STATE_TRANSITION(element)){
459 case GST_STATE_NULL_TO_READY:
461 case GST_STATE_READY_TO_PAUSED:
462 qtdemux->bs = gst_bytestream_new(qtdemux->sinkpad);
463 qtdemux->state = QTDEMUX_STATE_HEADER;
466 case GST_STATE_PAUSED_TO_PLAYING:
468 case GST_STATE_PLAYING_TO_PAUSED:
470 case GST_STATE_PAUSED_TO_READY:
471 gst_bytestream_destroy(qtdemux->bs);
473 case GST_STATE_READY_TO_NULL:
479 return GST_ELEMENT_CLASS(parent_class)->change_state(element);
482 static void gst_qtdemux_loop_header (GstElement *element)
484 GstQTDemux *qtdemux = GST_QTDEMUX(element);
494 /* FIXME _tell gets the offset wrong */
495 //cur_offset = gst_bytestream_tell(qtdemux->bs);
497 cur_offset = qtdemux->offset;
498 GST_DEBUG ("loop at position %d",cur_offset);
500 switch(qtdemux->state){
501 case QTDEMUX_STATE_HEADER:
504 ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 16);
506 if(!gst_qtdemux_handle_sink_event(qtdemux)){
514 length = GUINT32_FROM_BE(*(guint32 *)data);
515 GST_DEBUG ("length %08x",length);
516 fourcc = GUINT32_FROM_LE(*(guint32 *)(data+4));
517 GST_DEBUG ("fourcc " GST_FOURCC_FORMAT, GST_FOURCC_ARGS(fourcc));
520 length = gst_bytestream_length(qtdemux->bs) - cur_offset;
523 guint32 length1, length2;
525 length1 = GUINT32_FROM_BE(*(guint32 *)(data+8));
526 GST_DEBUG ("length1 %08x",length1);
527 length2 = GUINT32_FROM_BE(*(guint32 *)(data+12));
528 GST_DEBUG ("length2 %08x",length2);
534 case GST_MAKE_FOURCC('m','d','a','t'):
535 case GST_MAKE_FOURCC('f','r','e','e'):
536 case GST_MAKE_FOURCC('w','i','d','e'):
537 case GST_MAKE_FOURCC('P','I','C','T'):
538 case GST_MAKE_FOURCC('p','n','o','t'):
540 case GST_MAKE_FOURCC('m','o','o','v'):
545 ret = gst_bytestream_read(qtdemux->bs, &moov, length);
547 GST_DEBUG ("read failed (%d < %d)",ret,length);
548 if(!gst_qtdemux_handle_sink_event(qtdemux)){
556 qtdemux_parse_moov(qtdemux, GST_BUFFER_DATA(moov), length);
557 if(1)qtdemux_node_dump(qtdemux, qtdemux->moov_node);
558 qtdemux_parse_tree(qtdemux);
559 qtdemux->state = QTDEMUX_STATE_MOVIE;
564 GST_LOG("unknown %08x '" GST_FOURCC_FORMAT "' at %d\n",
565 fourcc, GST_FOURCC_ARGS(fourcc), cur_offset);
569 ret = gst_bytestream_seek(qtdemux->bs, cur_offset + length,
570 GST_SEEK_METHOD_SET);
571 qtdemux->offset = cur_offset + length;
572 GST_DEBUG ("seek returned %d\n",ret);
575 case QTDEMUX_STATE_SEEKING_EOS:
580 ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 1);
582 if(!gst_qtdemux_handle_sink_event(qtdemux)){
589 gst_element_set_eos(element);
591 qtdemux->state = QTDEMUX_STATE_EOS;
594 case QTDEMUX_STATE_EOS:
595 g_warning("spinning in EOS\n");
597 case QTDEMUX_STATE_MOVIE:
599 QtDemuxStream *stream;
604 min_time = G_MAXUINT64;
605 for(i=0;i<qtdemux->n_streams;i++){
606 stream = qtdemux->streams[i];
608 if(stream->sample_index < stream->n_samples &&
609 stream->samples[stream->sample_index].timestamp < min_time){
610 min_time = stream->samples[stream->sample_index].timestamp;
616 for(i=0;i<qtdemux->n_streams;i++){
617 gst_pad_push(qtdemux->streams[i]->pad,
618 GST_DATA(gst_event_new (GST_EVENT_EOS)));
620 ret = gst_bytestream_seek(qtdemux->bs, 0, GST_SEEK_METHOD_END);
621 GST_DEBUG ("seek returned %d",ret);
623 qtdemux->state = QTDEMUX_STATE_SEEKING_EOS;
627 stream = qtdemux->streams[index];
629 offset = stream->samples[stream->sample_index].offset;
630 size = stream->samples[stream->sample_index].size;
632 GST_INFO ("pushing from stream %d, sample_index=%d offset=%d size=%d timestamp=%lld",
633 index, stream->sample_index, offset, size,
634 stream->samples[stream->sample_index].timestamp);
636 cur_offset = gst_bytestream_tell(qtdemux->bs);
637 if(offset != cur_offset){
638 GST_DEBUG ("seeking to offset %d",offset);
639 GST_LOG ("seeking to offset %d\n",offset);
640 ret = gst_bytestream_seek(qtdemux->bs, offset, GST_SEEK_METHOD_SET);
641 GST_DEBUG ("seek returned %d",ret);
645 GST_DEBUG ("reading %d bytes\n",size);
648 ret = gst_bytestream_read(qtdemux->bs, &buf, size);
650 GST_DEBUG ("read failed (%d < %d)",ret,size);
651 if(!gst_qtdemux_handle_sink_event(qtdemux)){
661 if(stream->subtype == GST_MAKE_FOURCC('v','i','d','e')){
662 float fps = 1. * GST_SECOND / stream->samples[stream->sample_index].duration;
663 if (fps != stream->fps) {
664 gst_caps_set_simple (stream->caps, "framerate", G_TYPE_DOUBLE, fps,
667 gst_pad_set_explicit_caps(stream->pad, stream->caps);
671 GST_BUFFER_TIMESTAMP(buf) = stream->samples[stream->sample_index].timestamp;
672 GST_BUFFER_DURATION(buf) = stream->samples[stream->sample_index].duration;
673 gst_pad_push(stream->pad, GST_DATA (buf));
675 GST_DEBUG ("pushing buffer on %" GST_PTR_FORMAT, stream->pad);
677 stream->sample_index++;
687 void gst_qtdemux_add_stream(GstQTDemux *qtdemux, QtDemuxStream *stream)
689 if(stream->subtype == GST_MAKE_FOURCC('v','i','d','e')){
690 gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
691 stream->pad = gst_pad_new_from_template (
692 gst_static_pad_template_get(&gst_qtdemux_videosrc_template), name);
694 stream->fps = 1. * GST_SECOND / stream->samples[0].duration;
696 gst_caps_set_simple(stream->caps,
697 "width", G_TYPE_INT, stream->width,
698 "height", G_TYPE_INT, stream->height,
699 "framerate", G_TYPE_DOUBLE, stream->fps, NULL);
701 qtdemux->n_video_streams++;
703 gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
704 stream->pad = gst_pad_new_from_template (
705 gst_static_pad_template_get(&gst_qtdemux_audiosrc_template), name);
708 gst_caps_set_simple(stream->caps,
709 "rate", G_TYPE_INT, (int)stream->rate,
710 "channels", G_TYPE_INT, stream->n_channels, NULL);
712 qtdemux->n_audio_streams++;
715 gst_pad_use_explicit_caps (stream->pad);
717 GST_PAD_ELEMENT_PRIVATE(stream->pad) = stream;
718 qtdemux->streams[qtdemux->n_streams] = stream;
719 qtdemux->n_streams++;
720 GST_DEBUG ("n_streams is now %d", qtdemux->n_streams);
722 gst_pad_set_event_mask_function (stream->pad, gst_qtdemux_get_event_mask);
723 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
724 gst_pad_set_query_type_function (stream->pad, gst_qtdemux_get_src_query_types);
725 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
726 gst_pad_set_formats_function (stream->pad, gst_qtdemux_get_src_formats);
727 gst_pad_set_convert_function (stream->pad, gst_qtdemux_src_convert);
729 gst_pad_set_explicit_caps(stream->pad, stream->caps);
731 GST_DEBUG ("adding pad %p to qtdemux %p", stream->pad, qtdemux);
732 gst_element_add_pad(GST_ELEMENT (qtdemux), stream->pad);
736 #define QT_CONTAINER 1
738 #define FOURCC_moov GST_MAKE_FOURCC('m','o','o','v')
739 #define FOURCC_mvhd GST_MAKE_FOURCC('m','v','h','d')
740 #define FOURCC_clip GST_MAKE_FOURCC('c','l','i','p')
741 #define FOURCC_trak GST_MAKE_FOURCC('t','r','a','k')
742 #define FOURCC_udta GST_MAKE_FOURCC('u','d','t','a')
743 #define FOURCC_ctab GST_MAKE_FOURCC('c','t','a','b')
744 #define FOURCC_tkhd GST_MAKE_FOURCC('t','k','h','d')
745 #define FOURCC_crgn GST_MAKE_FOURCC('c','r','g','n')
746 #define FOURCC_matt GST_MAKE_FOURCC('m','a','t','t')
747 #define FOURCC_kmat GST_MAKE_FOURCC('k','m','a','t')
748 #define FOURCC_edts GST_MAKE_FOURCC('e','d','t','s')
749 #define FOURCC_elst GST_MAKE_FOURCC('e','l','s','t')
750 #define FOURCC_load GST_MAKE_FOURCC('l','o','a','d')
751 #define FOURCC_tref GST_MAKE_FOURCC('t','r','e','f')
752 #define FOURCC_imap GST_MAKE_FOURCC('i','m','a','p')
753 #define FOURCC___in GST_MAKE_FOURCC(' ',' ','i','n')
754 #define FOURCC___ty GST_MAKE_FOURCC(' ',' ','t','y')
755 #define FOURCC_mdia GST_MAKE_FOURCC('m','d','i','a')
756 #define FOURCC_mdhd GST_MAKE_FOURCC('m','d','h','d')
757 #define FOURCC_hdlr GST_MAKE_FOURCC('h','d','l','r')
758 #define FOURCC_minf GST_MAKE_FOURCC('m','i','n','f')
759 #define FOURCC_vmhd GST_MAKE_FOURCC('v','m','h','d')
760 #define FOURCC_smhd GST_MAKE_FOURCC('s','m','h','d')
761 #define FOURCC_gmhd GST_MAKE_FOURCC('g','m','h','d')
762 #define FOURCC_gmin GST_MAKE_FOURCC('g','m','i','n')
763 #define FOURCC_dinf GST_MAKE_FOURCC('d','i','n','f')
764 #define FOURCC_dref GST_MAKE_FOURCC('d','r','e','f')
765 #define FOURCC_stbl GST_MAKE_FOURCC('s','t','b','l')
766 #define FOURCC_stsd GST_MAKE_FOURCC('s','t','s','d')
767 #define FOURCC_stts GST_MAKE_FOURCC('s','t','t','s')
768 #define FOURCC_stss GST_MAKE_FOURCC('s','t','s','s')
769 #define FOURCC_stsc GST_MAKE_FOURCC('s','t','s','c')
770 #define FOURCC_stsz GST_MAKE_FOURCC('s','t','s','z')
771 #define FOURCC_stco GST_MAKE_FOURCC('s','t','c','o')
772 #define FOURCC_vide GST_MAKE_FOURCC('v','i','d','e')
773 #define FOURCC_soun GST_MAKE_FOURCC('s','o','u','n')
774 #define FOURCC_co64 GST_MAKE_FOURCC('c','o','6','4')
775 #define FOURCC_cmov GST_MAKE_FOURCC('c','m','o','v')
776 #define FOURCC_dcom GST_MAKE_FOURCC('d','c','o','m')
777 #define FOURCC_cmvd GST_MAKE_FOURCC('c','m','v','d')
780 static void qtdemux_dump_mvhd(GstQTDemux *qtdemux, void *buffer, int depth);
781 static void qtdemux_dump_tkhd(GstQTDemux *qtdemux, void *buffer, int depth);
782 static void qtdemux_dump_elst(GstQTDemux *qtdemux, void *buffer, int depth);
783 static void qtdemux_dump_mdhd(GstQTDemux *qtdemux, void *buffer, int depth);
784 static void qtdemux_dump_hdlr(GstQTDemux *qtdemux, void *buffer, int depth);
785 static void qtdemux_dump_vmhd(GstQTDemux *qtdemux, void *buffer, int depth);
786 static void qtdemux_dump_dref(GstQTDemux *qtdemux, void *buffer, int depth);
787 static void qtdemux_dump_stsd(GstQTDemux *qtdemux, void *buffer, int depth);
788 static void qtdemux_dump_stts(GstQTDemux *qtdemux, void *buffer, int depth);
789 static void qtdemux_dump_stss(GstQTDemux *qtdemux, void *buffer, int depth);
790 static void qtdemux_dump_stsc(GstQTDemux *qtdemux, void *buffer, int depth);
791 static void qtdemux_dump_stsz(GstQTDemux *qtdemux, void *buffer, int depth);
792 static void qtdemux_dump_stco(GstQTDemux *qtdemux, void *buffer, int depth);
793 static void qtdemux_dump_co64(GstQTDemux *qtdemux, void *buffer, int depth);
794 static void qtdemux_dump_dcom(GstQTDemux *qtdemux, void *buffer, int depth);
795 static void qtdemux_dump_cmvd(GstQTDemux *qtdemux, void *buffer, int depth);
797 QtNodeType qt_node_types[] = {
798 { FOURCC_moov, "movie", QT_CONTAINER, },
799 { FOURCC_mvhd, "movie header", 0,
801 { FOURCC_clip, "clipping", QT_CONTAINER, },
802 { FOURCC_trak, "track", QT_CONTAINER, },
803 { FOURCC_udta, "user data", 0, }, /* special container */
804 { FOURCC_ctab, "color table", 0, },
805 { FOURCC_tkhd, "track header", 0,
807 { FOURCC_crgn, "clipping region", 0, },
808 { FOURCC_matt, "track matte", QT_CONTAINER, },
809 { FOURCC_kmat, "compressed matte", 0, },
810 { FOURCC_edts, "edit", QT_CONTAINER, },
811 { FOURCC_elst, "edit list", 0,
813 { FOURCC_load, "track load settings", 0, },
814 { FOURCC_tref, "track reference", QT_CONTAINER, },
815 { FOURCC_imap, "track input map", QT_CONTAINER, },
816 { FOURCC___in, "track input", 0, }, /* special container */
817 { FOURCC___ty, "input type", 0, },
818 { FOURCC_mdia, "media", QT_CONTAINER },
819 { FOURCC_mdhd, "media header", 0,
821 { FOURCC_hdlr, "handler reference", 0,
823 { FOURCC_minf, "media information", QT_CONTAINER },
824 { FOURCC_vmhd, "video media information", 0,
826 { FOURCC_smhd, "sound media information", 0 },
827 { FOURCC_gmhd, "base media information header", 0 },
828 { FOURCC_gmin, "base media info", 0 },
829 { FOURCC_dinf, "data information", QT_CONTAINER },
830 { FOURCC_dref, "data reference", 0,
832 { FOURCC_stbl, "sample table", QT_CONTAINER },
833 { FOURCC_stsd, "sample description", 0,
835 { FOURCC_stts, "time-to-sample", 0,
837 { FOURCC_stss, "sync sample", 0,
839 { FOURCC_stsc, "sample-to-chunk", 0,
841 { FOURCC_stsz, "sample size", 0,
843 { FOURCC_stco, "chunk offset", 0,
845 { FOURCC_co64, "64-bit chunk offset", 0,
847 { FOURCC_vide, "video media", 0 },
848 { FOURCC_cmov, "compressed movie", QT_CONTAINER },
849 { FOURCC_dcom, "compressed data", 0,
851 { FOURCC_cmvd, "compressed movie data", 0,
855 static int n_qt_node_types = sizeof(qt_node_types)/sizeof(qt_node_types[0]);
858 static void *qtdemux_zalloc(void *opaque, unsigned int items, unsigned int size)
860 return g_malloc(items*size);
863 static void qtdemux_zfree(void *opaque, void *addr)
868 static void *qtdemux_inflate(void *z_buffer, int z_length, int length)
874 z = g_new0(z_stream, 1);
875 z->zalloc = qtdemux_zalloc;
876 z->zfree = qtdemux_zfree;
879 z->next_in = z_buffer;
880 z->avail_in = z_length;
882 buffer = g_malloc(length);
883 ret = inflateInit(z);
884 while(z->avail_in > 0){
885 if(z->avail_out == 0){
887 buffer = realloc(buffer, length);
888 z->next_out = buffer + z->total_out;
891 ret = inflate(z,Z_SYNC_FLUSH);
892 if(ret != Z_OK)break;
894 if(ret != Z_STREAM_END){
895 g_warning("inflate() returned %d\n",ret);
902 static void qtdemux_parse_moov(GstQTDemux *qtdemux, void *buffer, int length)
906 qtdemux->moov_node = g_node_new(buffer);
908 qtdemux_parse(qtdemux, qtdemux->moov_node, buffer, length);
910 cmov = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_cmov);
915 dcom = qtdemux_tree_get_child_by_type(cmov, FOURCC_dcom);
916 cmvd = qtdemux_tree_get_child_by_type(cmov, FOURCC_cmvd);
918 if(QTDEMUX_FOURCC_GET(dcom->data+8) == GST_MAKE_FOURCC('z','l','i','b')){
919 int uncompressed_length;
920 int compressed_length;
923 uncompressed_length = QTDEMUX_GUINT32_GET(cmvd->data+8);
924 compressed_length = QTDEMUX_GUINT32_GET(cmvd->data+4) - 12;
925 GST_LOG("length = %d\n",uncompressed_length);
927 buf = qtdemux_inflate(cmvd->data + 12, compressed_length,
928 uncompressed_length);
930 qtdemux->moov_node_compressed = qtdemux->moov_node;
931 qtdemux->moov_node = g_node_new(buf);
933 qtdemux_parse(qtdemux, qtdemux->moov_node, buf, uncompressed_length);
935 GST_LOG("unknown header compression type\n");
940 static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int length)
947 GST_LOG("qtdemux_parse %p %d\n",buffer, length);
949 node_length = QTDEMUX_GUINT32_GET(buffer);
950 fourcc = QTDEMUX_FOURCC_GET(buffer+4);
952 type = qtdemux_type_get(fourcc);
954 GST_LOG("parsing '" GST_FOURCC_FORMAT "', length=%d\n",
955 GST_FOURCC_ARGS(fourcc), node_length);
957 if(type->flags & QT_CONTAINER){
962 end = buffer + length;
967 /* FIXME: get annoyed */
968 GST_LOG("buffer overrun\n");
970 len = QTDEMUX_GUINT32_GET(buf);
972 child = g_node_new(buf);
973 g_node_append(node, child);
974 qtdemux_parse(qtdemux, child, buf, len);
980 if(fourcc == FOURCC_cmvd){
981 int uncompressed_length;
984 uncompressed_length = QTDEMUX_GUINT32_GET(buffer+8);
985 GST_LOG("length = %d\n",uncompressed_length);
987 buf = qtdemux_inflate(buffer + 12, node_length-12, uncompressed_length);
989 end = buf + uncompressed_length;
995 /* FIXME: get annoyed */
996 GST_LOG("buffer overrun\n");
998 len = QTDEMUX_GUINT32_GET(buf);
1000 child = g_node_new(buf);
1001 g_node_append(node, child);
1002 qtdemux_parse(qtdemux, child, buf, len);
1011 static QtNodeType *qtdemux_type_get(guint32 fourcc)
1015 for(i=0;i<n_qt_node_types;i++){
1016 if(qt_node_types[i].fourcc == fourcc)
1017 return qt_node_types+i;
1019 return qt_node_types+n_qt_node_types-1;
1022 static gboolean qtdemux_node_dump_foreach(GNode *node, gpointer data)
1024 void *buffer = node->data;
1025 guint32 node_length;
1030 node_length = GUINT32_FROM_BE(*(guint32 *)buffer);
1031 fourcc = GUINT32_FROM_LE(*(guint32 *)(buffer+4));
1033 type = qtdemux_type_get(fourcc);
1035 depth = (g_node_depth(node)-1)*2;
1036 GST_LOG("%*s'" GST_FOURCC_FORMAT "', [%d], %s\n",
1038 GST_FOURCC_ARGS(fourcc),
1042 if(type->dump)type->dump(data, buffer, depth);
1047 static void qtdemux_node_dump(GstQTDemux *qtdemux, GNode *node)
1049 g_node_traverse(qtdemux->moov_node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1050 qtdemux_node_dump_foreach, qtdemux);
1053 static void qtdemux_dump_mvhd(GstQTDemux *qtdemux, void *buffer, int depth)
1055 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1056 GST_LOG("%*s creation time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1057 GST_LOG("%*s modify time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
1058 GST_LOG("%*s time scale: 1/%u sec\n", depth, "", QTDEMUX_GUINT32_GET(buffer+20));
1059 GST_LOG("%*s duration: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+24));
1060 GST_LOG("%*s pref. rate: %g\n", depth, "", QTDEMUX_FP32_GET(buffer+28));
1061 GST_LOG("%*s pref. volume: %g\n", depth, "", QTDEMUX_FP16_GET(buffer+32));
1062 GST_LOG("%*s preview time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+80));
1063 GST_LOG("%*s preview dur.: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+84));
1064 GST_LOG("%*s poster time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+88));
1065 GST_LOG("%*s select time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+92));
1066 GST_LOG("%*s select dur.: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+96));
1067 GST_LOG("%*s current time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+100));
1068 GST_LOG("%*s next track ID: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+104));
1071 static void qtdemux_dump_tkhd(GstQTDemux *qtdemux, void *buffer, int depth)
1073 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1074 GST_LOG("%*s creation time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1075 GST_LOG("%*s modify time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
1076 GST_LOG("%*s track ID: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+20));
1077 GST_LOG("%*s duration: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+28));
1078 GST_LOG("%*s layer: %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+36));
1079 GST_LOG("%*s alt group: %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+38));
1080 GST_LOG("%*s volume: %g\n", depth, "", QTDEMUX_FP16_GET(buffer+44));
1081 GST_LOG("%*s track width: %g\n", depth, "", QTDEMUX_FP32_GET(buffer+84));
1082 GST_LOG("%*s track height: %g\n", depth, "", QTDEMUX_FP32_GET(buffer+88));
1086 static void qtdemux_dump_elst(GstQTDemux *qtdemux, void *buffer, int depth)
1091 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1092 GST_LOG("%*s n entries: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1093 n = QTDEMUX_GUINT32_GET(buffer+12);
1095 GST_LOG("%*s track dur: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16+i*12));
1096 GST_LOG("%*s media time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+20+i*12));
1097 GST_LOG("%*s media rate: %g\n", depth, "", QTDEMUX_FP32_GET(buffer+24+i*12));
1101 static void qtdemux_dump_mdhd(GstQTDemux *qtdemux, void *buffer, int depth)
1103 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1104 GST_LOG("%*s creation time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1105 GST_LOG("%*s modify time: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
1106 GST_LOG("%*s time scale: 1/%u sec\n", depth, "", QTDEMUX_GUINT32_GET(buffer+20));
1107 GST_LOG("%*s duration: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+24));
1108 GST_LOG("%*s language: %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+28));
1109 GST_LOG("%*s quality: %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+30));
1113 static void qtdemux_dump_hdlr(GstQTDemux *qtdemux, void *buffer, int depth)
1115 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1116 GST_LOG("%*s type: " GST_FOURCC_FORMAT "\n", depth, "",
1117 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+12)));
1118 GST_LOG("%*s subtype: " GST_FOURCC_FORMAT "\n", depth, "",
1119 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+16)));
1120 GST_LOG("%*s manufacturer: " GST_FOURCC_FORMAT "\n", depth, "",
1121 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+20)));
1122 GST_LOG("%*s flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+24));
1123 GST_LOG("%*s flags mask: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+28));
1124 GST_LOG("%*s name: %*s\n", depth, "",
1125 QTDEMUX_GUINT8_GET(buffer+32), (char *)(buffer+33));
1129 static void qtdemux_dump_vmhd(GstQTDemux *qtdemux, void *buffer, int depth)
1131 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1132 GST_LOG("%*s mode/color: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
1135 static void qtdemux_dump_dref(GstQTDemux *qtdemux, void *buffer, int depth)
1141 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1142 GST_LOG("%*s n entries: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1143 n = QTDEMUX_GUINT32_GET(buffer+12);
1146 GST_LOG("%*s size: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1147 GST_LOG("%*s type: " GST_FOURCC_FORMAT "\n", depth, "",
1148 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+offset+4)));
1149 offset += QTDEMUX_GUINT32_GET(buffer+offset);
1153 static void qtdemux_dump_stsd(GstQTDemux *qtdemux, void *buffer, int depth)
1159 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1160 GST_LOG("%*s n entries: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1161 n = QTDEMUX_GUINT32_GET(buffer+12);
1164 GST_LOG("%*s size: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1165 GST_LOG("%*s type: " GST_FOURCC_FORMAT "\n", depth, "",
1166 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+offset+4)));
1167 GST_LOG("%*s data reference:%d\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+14));
1169 GST_LOG("%*s version/rev.: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+16));
1170 GST_LOG("%*s vendor: " GST_FOURCC_FORMAT "\n", depth, "",
1171 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+offset+20)));
1172 GST_LOG("%*s temporal qual: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+24));
1173 GST_LOG("%*s spatial qual: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+28));
1174 GST_LOG("%*s width: %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+32));
1175 GST_LOG("%*s height: %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+34));
1176 GST_LOG("%*s horiz. resol: %g\n", depth, "", QTDEMUX_FP32_GET(buffer+offset+36));
1177 GST_LOG("%*s vert. resol.: %g\n", depth, "", QTDEMUX_FP32_GET(buffer+offset+40));
1178 GST_LOG("%*s data size: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+44));
1179 GST_LOG("%*s frame count: %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+48));
1180 GST_LOG("%*s compressor: %*s\n", depth, "",
1181 QTDEMUX_GUINT8_GET(buffer+offset+49), (char *)(buffer+offset+51));
1182 GST_LOG("%*s depth: %u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+82));
1183 GST_LOG("%*s color table ID:%u\n", depth, "", QTDEMUX_GUINT16_GET(buffer+offset+84));
1185 offset += QTDEMUX_GUINT32_GET(buffer+offset);
1189 static void qtdemux_dump_stts(GstQTDemux *qtdemux, void *buffer, int depth)
1195 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1196 GST_LOG("%*s n entries: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1197 n = QTDEMUX_GUINT32_GET(buffer+12);
1200 GST_LOG("%*s count: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1201 GST_LOG("%*s duration: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset + 4));
1207 static void qtdemux_dump_stss(GstQTDemux *qtdemux, void *buffer, int depth)
1213 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1214 GST_LOG("%*s n entries: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1215 n = QTDEMUX_GUINT32_GET(buffer+12);
1218 GST_LOG("%*s sample: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1224 static void qtdemux_dump_stsc(GstQTDemux *qtdemux, void *buffer, int depth)
1230 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1231 GST_LOG("%*s n entries: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1232 n = QTDEMUX_GUINT32_GET(buffer+12);
1235 GST_LOG("%*s first chunk: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1236 GST_LOG("%*s sample per ch: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+4));
1237 GST_LOG("%*s sample desc id:%08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset+8));
1243 static void qtdemux_dump_stsz(GstQTDemux *qtdemux, void *buffer, int depth)
1250 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1251 GST_LOG("%*s sample size: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1252 sample_size = QTDEMUX_GUINT32_GET(buffer+12);
1253 if(sample_size == 0){
1254 GST_LOG("%*s n entries: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+16));
1255 n = QTDEMUX_GUINT32_GET(buffer+16);
1258 GST_LOG("%*s sample size: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1265 static void qtdemux_dump_stco(GstQTDemux *qtdemux, void *buffer, int depth)
1271 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1272 GST_LOG("%*s n entries: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1273 n = QTDEMUX_GUINT32_GET(buffer+12);
1276 GST_LOG("%*s chunk offset: %u\n", depth, "", QTDEMUX_GUINT32_GET(buffer+offset));
1282 static void qtdemux_dump_co64(GstQTDemux *qtdemux, void *buffer, int depth)
1288 GST_LOG("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1289 GST_LOG("%*s n entries: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+12));
1290 n = QTDEMUX_GUINT32_GET(buffer+12);
1293 GST_LOG("%*s chunk offset: %" G_GUINT64_FORMAT "\n", depth, "", QTDEMUX_GUINT64_GET(buffer+offset));
1299 static void qtdemux_dump_dcom(GstQTDemux *qtdemux, void *buffer, int depth)
1301 GST_LOG("%*s compression type: " GST_FOURCC_FORMAT "\n", depth, "",
1302 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+8)));
1305 static void qtdemux_dump_cmvd(GstQTDemux *qtdemux, void *buffer, int depth)
1307 GST_LOG("%*s length: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
1311 static GNode *qtdemux_tree_get_child_by_type(GNode *node, guint32 fourcc)
1315 guint32 child_fourcc;
1317 for(child = g_node_first_child(node); child; child = g_node_next_sibling(child)){
1318 buffer = child->data;
1320 child_fourcc = GUINT32_FROM_LE(*(guint32 *)(buffer+4));
1322 if(child_fourcc == fourcc){
1329 static GNode *qtdemux_tree_get_sibling_by_type(GNode *node, guint32 fourcc)
1333 guint32 child_fourcc;
1335 for(child = g_node_next_sibling(node); child; child = g_node_next_sibling(child)){
1336 buffer = child->data;
1338 child_fourcc = GUINT32_FROM_LE(*(guint32 *)(buffer+4));
1340 if(child_fourcc == fourcc){
1347 static void qtdemux_parse_trak(GstQTDemux *qtdemux, GNode *trak);
1349 static void qtdemux_parse_tree(GstQTDemux *qtdemux)
1354 mvhd = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_mvhd);
1356 GST_LOG("No mvhd node found.\n");
1360 qtdemux->timescale = QTDEMUX_GUINT32_GET(mvhd->data + 20);
1361 qtdemux->duration = QTDEMUX_GUINT32_GET(mvhd->data + 24);
1363 GST_INFO("timescale: %d\n", qtdemux->timescale);
1364 GST_INFO("duration: %d\n", qtdemux->duration);
1366 trak = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_trak);
1367 qtdemux_parse_trak(qtdemux, trak);
1369 /* trak = qtdemux_tree_get_sibling_by_type(trak, FOURCC_trak);
1370 if(trak)qtdemux_parse_trak(qtdemux, trak);*/
1372 while ((trak = qtdemux_tree_get_sibling_by_type(trak, FOURCC_trak)) != NULL)
1373 qtdemux_parse_trak(qtdemux, trak);
1376 static void qtdemux_parse_trak(GstQTDemux *qtdemux, GNode *trak)
1392 QtDemuxSample *samples;
1393 int n_samples_per_chunk;
1396 QtDemuxStream *stream;
1402 stream = g_new0(QtDemuxStream,1);
1404 tkhd = qtdemux_tree_get_child_by_type(trak, FOURCC_tkhd);
1407 /* track duration? */
1409 mdia = qtdemux_tree_get_child_by_type(trak, FOURCC_mdia);
1412 mdhd = qtdemux_tree_get_child_by_type(mdia, FOURCC_mdhd);
1415 stream->timescale = QTDEMUX_GUINT32_GET(mdhd->data+20);
1416 GST_INFO("track timescale: %d", stream->timescale);
1418 hdlr = qtdemux_tree_get_child_by_type(mdia, FOURCC_hdlr);
1421 GST_LOG("track type: " GST_FOURCC_FORMAT "\n",
1422 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(hdlr->data+12)));
1423 GST_LOG("track subtype: " GST_FOURCC_FORMAT "\n",
1424 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(hdlr->data+16)));
1426 stream->subtype = QTDEMUX_FOURCC_GET(hdlr->data+16);
1428 minf = qtdemux_tree_get_child_by_type(mdia, FOURCC_minf);
1431 stbl = qtdemux_tree_get_child_by_type(minf, FOURCC_stbl);
1434 stsd = qtdemux_tree_get_child_by_type(stbl, FOURCC_stsd);
1437 if(stream->subtype == FOURCC_vide){
1439 GST_LOG("st type: " GST_FOURCC_FORMAT "\n",
1440 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(stsd->data+offset+4)));
1442 stream->width = QTDEMUX_GUINT16_GET(stsd->data+offset+32);
1443 stream->height = QTDEMUX_GUINT16_GET(stsd->data+offset+34);
1444 stream->fps = 0.; /* this is filled in later */
1446 GST_LOG("frame count: %u\n", QTDEMUX_GUINT16_GET(stsd->data+offset+48));
1448 stream->caps = qtdemux_video_caps(qtdemux,
1449 QTDEMUX_FOURCC_GET(stsd->data+offset+4), stsd->data);
1450 GST_INFO("type " GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT "\n",
1451 GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET(stsd->data+offset+4)),
1453 }else if(stream->subtype == FOURCC_soun){
1454 int version, samplesize;
1456 GST_LOG("st type: " GST_FOURCC_FORMAT "\n",
1457 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(stsd->data+16+4)));
1460 GST_LOG("version/rev: %08x\n", QTDEMUX_GUINT32_GET(stsd->data+offset));
1461 version = QTDEMUX_GUINT32_GET(stsd->data+offset);
1462 GST_LOG("vendor: %08x\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 4));
1463 GST_LOG("n_channels: %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 8));
1464 stream->n_channels = QTDEMUX_GUINT16_GET(stsd->data+offset + 8);
1465 GST_LOG("sample_size: %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 10));
1466 samplesize = QTDEMUX_GUINT16_GET(stsd->data+offset + 10);
1467 GST_LOG("compression_id: %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 12));
1468 GST_LOG("packet size: %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 14));
1469 GST_LOG("sample rate: %g\n", QTDEMUX_FP32_GET(stsd->data+offset + 16));
1470 stream->rate = QTDEMUX_FP32_GET(stsd->data+offset + 16);
1473 if(version == 0x00010000){
1474 GST_LOG("samples/packet: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset));
1475 stream->samples_per_packet = QTDEMUX_GUINT32_GET(stsd->data+offset);
1476 GST_LOG("bytes/packet: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 4));
1477 GST_LOG("bytes/frame: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 8));
1478 stream->bytes_per_frame = QTDEMUX_GUINT32_GET(stsd->data+offset + 8);
1479 GST_LOG("bytes/sample: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 12));
1482 stream->bytes_per_frame = stream->n_channels * samplesize / 8;
1483 stream->samples_per_packet = 1;
1486 stream->caps = qtdemux_audio_caps(qtdemux,
1487 QTDEMUX_FOURCC_GET(stsd->data+16+4), (QTDEMUX_GUINT32_GET(stsd->data) > offset) ? stsd->data + offset : NULL);
1488 GST_INFO("type " GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT "\n",
1489 GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(stsd->data+16+4)), stream->caps);
1491 GST_LOG("unknown subtype\n");
1495 /* sample to chunk */
1496 stsc = qtdemux_tree_get_child_by_type(stbl, FOURCC_stsc);
1499 stsz = qtdemux_tree_get_child_by_type(stbl, FOURCC_stsz);
1502 stco = qtdemux_tree_get_child_by_type(stbl, FOURCC_stco);
1503 co64 = qtdemux_tree_get_child_by_type(stbl, FOURCC_co64);
1504 g_assert(stco || co64);
1506 stts = qtdemux_tree_get_child_by_type(stbl, FOURCC_stts);
1509 sample_size = QTDEMUX_GUINT32_GET(stsz->data+12);
1510 if(sample_size == 0){
1511 n_samples = QTDEMUX_GUINT32_GET(stsz->data+16);
1512 stream->n_samples = n_samples;
1513 samples = g_malloc(sizeof(QtDemuxSample)*n_samples);
1514 stream->samples = samples;
1516 for(i=0;i<n_samples;i++){
1517 samples[i].size = QTDEMUX_GUINT32_GET(stsz->data + i*4 + 20);
1519 n_samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data+12);
1522 for(i=0;i<n_samples_per_chunk;i++){
1523 int first_chunk, last_chunk;
1524 int samples_per_chunk;
1526 first_chunk = QTDEMUX_GUINT32_GET(stsc->data + 16 + i*12 + 0) - 1;
1527 if(i==n_samples_per_chunk-1){
1528 last_chunk = INT_MAX;
1530 last_chunk = QTDEMUX_GUINT32_GET(stsc->data +16 + i*12 + 12) - 1;
1532 samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data + 16 + i*12 + 4);
1534 for(j=first_chunk;j<last_chunk;j++){
1537 chunk_offset = QTDEMUX_GUINT32_GET(stco->data + 16 + j*4);
1539 chunk_offset = QTDEMUX_GUINT64_GET(co64->data + 16 + j*8);
1541 for(k=0;k<samples_per_chunk;k++){
1542 samples[index].chunk = j;
1543 samples[index].offset = chunk_offset;
1544 chunk_offset += samples[index].size;
1546 if(index>=n_samples)goto done;
1552 n_sample_times = QTDEMUX_GUINT32_GET(stts->data + 12);
1555 for(i=0;i<n_sample_times;i++){
1560 n = QTDEMUX_GUINT32_GET(stts->data + 16 + 8*i);
1561 duration = QTDEMUX_GUINT32_GET(stts->data + 16 + 8*i + 4);
1562 time = (GST_SECOND * duration)/stream->timescale;
1564 //GST_INFO("moo %lld", timestamp);
1565 samples[index].timestamp = timestamp;
1566 samples[index].duration = time;
1573 guint64 timestamp = 0;
1575 GST_LOG("treating chunks as samples\n");
1577 /* treat chunks as samples */
1579 n_samples = QTDEMUX_GUINT32_GET(stco->data+12);
1581 n_samples = QTDEMUX_GUINT32_GET(co64->data+12);
1583 stream->n_samples = n_samples;
1584 samples = g_malloc(sizeof(QtDemuxSample)*n_samples);
1585 stream->samples = samples;
1587 sample_width = QTDEMUX_GUINT16_GET(stsd->data+offset + 10) / 8;
1589 n_samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data+12);
1592 for(i=0;i<n_samples_per_chunk;i++){
1593 int first_chunk, last_chunk;
1594 int samples_per_chunk;
1596 first_chunk = QTDEMUX_GUINT32_GET(stsc->data + 16 + i*12 + 0) - 1;
1598 last_chunk = INT_MAX;
1600 last_chunk = QTDEMUX_GUINT32_GET(stsc->data +16 + i*12 + 12) - 1;
1602 samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data + 16 + i*12 + 4);
1604 for(j=first_chunk;j<last_chunk;j++){
1606 if(j>=n_samples)goto done2;
1608 chunk_offset = QTDEMUX_GUINT32_GET(stco->data + 16 + j*4);
1610 chunk_offset = QTDEMUX_GUINT64_GET(co64->data + 16 + j*8);
1612 samples[j].chunk = j;
1613 samples[j].offset = chunk_offset;
1614 samples[j].size = samples_per_chunk * stream->bytes_per_frame / stream->samples_per_packet;
1615 samples[j].duration = samples_per_chunk * GST_SECOND / (stream->rate/2);
1616 samples[j].timestamp = timestamp;
1617 timestamp += (samples_per_chunk * GST_SECOND) / stream->rate;
1619 GST_INFO("moo samples_per_chunk=%d rate=%d dur=%lld %lld",
1620 (int)samples_per_chunk,
1622 (long long)((samples_per_chunk * GST_SECOND) / stream->rate),
1623 (long long)timestamp);
1625 samples[j].sample_index = sample_index;
1626 sample_index += samples_per_chunk;
1631 n_sample_times = QTDEMUX_GUINT32_GET(stts->data + 12);
1632 GST_LOG("n_sample_times = %d\n",n_sample_times);
1636 for(i=0;i<n_sample_times;i++){
1640 sample_index += QTDEMUX_GUINT32_GET(stts->data + 16 + 8*i);
1641 duration = QTDEMUX_GUINT32_GET(stts->data + 16 + 8*i + 4);
1642 for(;index < n_samples && samples[index].sample_index < sample_index;index++){
1645 samples[index].timestamp = timestamp;
1646 size = samples[index+1].sample_index - samples[index].sample_index;
1647 time = GST_SECOND / stream->rate; //(GST_SECOND * duration * samples[index].size)/stream->timescale ;
1649 samples[index].duration = time;
1656 for(i=0;i<n_samples;i++){
1657 GST_LOG("%d: %d %d %d %d %" G_GUINT64_FORMAT "\n",i,
1658 samples[i].sample_index,samples[i].chunk,
1659 samples[i].offset, samples[i].size, samples[i].timestamp);
1664 gst_qtdemux_add_stream(qtdemux,stream);
1668 static GstCaps *qtdemux_video_caps(GstQTDemux *qtdemux, guint32 fourcc, const guint8 *stsd_data)
1671 case GST_MAKE_FOURCC('j','p','e','g'):
1673 return gst_caps_from_string ("image/jpeg");
1674 case GST_MAKE_FOURCC('m','j','p','a'):
1675 /* Motion-JPEG (format A) */
1676 return gst_caps_from_string ("image/jpeg");
1677 case GST_MAKE_FOURCC('m','j','p','b'):
1678 /* Motion-JPEG (format B) */
1679 return gst_caps_from_string ("image/jpeg");
1680 case GST_MAKE_FOURCC('S','V','Q','3'):
1681 if (stsd_data != NULL) {
1685 gint unknown_svq3_flag;
1689 size = QTDEMUX_GUINT32_GET(stsd_data + 16);
1691 gst_getbits_init (&gb, NULL, NULL);
1692 gst_getbits_newbuf (&gb, (unsigned char *)stsd_data + 98 + 16 + 4 , (size - 102 + 16));
1694 /* Infos ripped from ffmpeg see libavcodec/svq3.c */
1696 /* 'frame size code' and optional 'width, height' */
1697 if (gst_getbitsn (&gb, 3) == 7) {
1698 gst_getbitsn (&gb, 12);
1699 gst_getbitsn (&gb, 12);
1702 halfpel_flag = gst_get1bit (&gb);
1703 thirdpel_flag = gst_get1bit (&gb);
1705 /* unknown fields */
1711 low_delay = gst_get1bit (&gb);
1716 while (gst_get1bit (&gb)) {
1717 gst_getbitsn (&gb, 8);
1720 unknown_svq3_flag = gst_get1bit (&gb);
1722 return gst_caps_new_simple ("video/x-svq",
1723 "svqversion", G_TYPE_INT, 3,
1724 "halfpel_flag", G_TYPE_INT, halfpel_flag,
1725 "thirdpel_flag", G_TYPE_INT, thirdpel_flag,
1726 "low_delay", G_TYPE_INT, low_delay,
1727 "unknown_svq3_flag", G_TYPE_INT, unknown_svq3_flag,
1730 return gst_caps_from_string ("video/x-svq, "
1731 "svqversion = (int) 3");
1732 case GST_MAKE_FOURCC('s','v','q','i'):
1733 case GST_MAKE_FOURCC('S','V','Q','1'):
1734 return gst_caps_from_string ("video/x-svq, "
1735 "svqversion = (int) 1");
1736 case GST_MAKE_FOURCC('r','a','w',' '):
1737 /* uncompressed RGB */
1738 return gst_caps_from_string ("video/x-raw-rgb, "
1739 "endianness = (int) BIG_ENDIAN");
1740 /*"bpp", GST_PROPS_INT(x),
1741 "depth", GST_PROPS_INT(x),
1742 "red_mask", GST_PROPS_INT(x),
1743 "green_mask", GST_PROPS_INT(x),
1744 "blue_mask", GST_PROPS_INT(x), FIXME! */
1745 case GST_MAKE_FOURCC('Y','u','v','2'):
1746 /* uncompressed YUV2 */
1747 return gst_caps_from_string ("video/x-raw-yuv, "
1748 "format = (fourcc) YUY2");
1749 case GST_MAKE_FOURCC('m','p','e','g'):
1751 return gst_caps_from_string ("video/mpeg, "
1752 "systemstream = (boolean) false, "
1753 "mpegversion = (int) 1");
1754 case GST_MAKE_FOURCC('g','i','f',' '):
1755 return gst_caps_from_string ("image/gif");
1756 case GST_MAKE_FOURCC('h','2','6','3'):
1758 /* ffmpeg uses the height/width props, don't know why */
1759 return gst_caps_from_string ("video/x-h263");
1760 case GST_MAKE_FOURCC('m','p','4','v'):
1762 return gst_caps_from_string ("video/mpeg, "
1763 "mpegversion = (int) 4, "
1764 "systemstream = (boolean) false");
1765 case GST_MAKE_FOURCC('3','I','V','1'):
1766 return gst_caps_from_string ("video/x-3ivx");
1767 case GST_MAKE_FOURCC('c','v','i','d'):
1769 return gst_caps_from_string ("video/x-cinepak");
1770 case GST_MAKE_FOURCC('r','p','z','a'):
1771 case GST_MAKE_FOURCC('r','l','e',' '):
1772 /* Run-length encoding */
1773 case GST_MAKE_FOURCC('s','m','c',' '):
1774 case GST_MAKE_FOURCC('k','p','c','d'):
1776 g_critical ("Don't know how to convert fourcc '" GST_FOURCC_FORMAT
1777 "' to caps\n", GST_FOURCC_ARGS(fourcc));
1782 static GstCaps *qtdemux_audio_caps(GstQTDemux *qtdemux, guint32 fourcc, const guint8 *data)
1785 case GST_MAKE_FOURCC('N','O','N','E'):
1786 return NULL; /*gst_caps_from_string ("audio/raw");*/
1787 case GST_MAKE_FOURCC('r','a','w',' '):
1789 return gst_caps_from_string ("audio/x-raw-int, "
1792 "signed = (boolean) true");
1793 case GST_MAKE_FOURCC('t','w','o','s'):
1795 return gst_caps_from_string ("audio/x-raw-int, "
1796 "width = (int) 16, "
1797 "depth = (int) 16, "
1798 "endianness = (int) G_BIG_ENDIAN, "
1799 "signed = (boolean) true");
1800 case GST_MAKE_FOURCC('s','o','w','t'):
1802 return gst_caps_from_string ("audio/x-raw-int, "
1803 "width = (int) 16, "
1804 "depth = (int) 16, "
1805 "endianness = (int) G_LITTLE_ENDIAN, "
1806 "signed = (boolean) true");
1807 case GST_MAKE_FOURCC('f','l','6','4'):
1808 return gst_caps_from_string ("audio/x-raw-float, "
1809 "width = (int) 64, "
1810 "endianness = (int) G_BIG_ENDIAN");
1811 case GST_MAKE_FOURCC('f','l','3','2'):
1812 return gst_caps_from_string ("audio/x-raw-float, "
1813 "width = (int) 32, "
1814 "endianness = (int) G_BIG_ENDIAN");
1815 case GST_MAKE_FOURCC('i','n','2','4'):
1817 return gst_caps_from_string ("audio/x-raw-int, "
1818 "width = (int) 24, "
1819 "depth = (int) 32, "
1820 "endianness = (int) G_BIG_ENDIAN, "
1821 "signed = (boolean) true");
1822 case GST_MAKE_FOURCC('i','n','3','2'):
1824 return gst_caps_from_string ("audio/x-raw-int, "
1825 "width = (int) 32, "
1826 "depth = (int) 32, "
1827 "endianness = (int) G_BIG_ENDIAN, "
1828 "signed = (boolean) true");
1829 case GST_MAKE_FOURCC('u','l','a','w'):
1831 return gst_caps_from_string ("audio/x-mulaw");
1832 case GST_MAKE_FOURCC('a','l','a','w'):
1834 return gst_caps_from_string ("audio/x-alaw");
1836 /* Microsoft ADPCM-ACM code 2 */
1837 return gst_caps_from_string ("audio/x-adpcm, "
1838 "layout = (string) microsoft");
1840 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
1841 return gst_caps_from_string ("audio/x-adpcm, "
1842 "layout = (string) quicktime");
1844 /* MPEG layer 3, CBR only (pre QT4.1) */
1846 case GST_MAKE_FOURCC('.','m','p','3'):
1847 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
1848 return gst_caps_from_string ("audio/mpeg, "
1850 "mpegversion = (int) 1");
1851 case GST_MAKE_FOURCC('M','A','C','3'):
1853 return gst_caps_from_string ("audio/x-mace, "
1854 "maceversion = (int) 3");
1855 case GST_MAKE_FOURCC('M','A','C','6'):
1857 return gst_caps_from_string ("audio/x-mace, "
1858 "maceversion = (int) 6");
1859 case GST_MAKE_FOURCC('O','g','g','V'):
1861 return gst_caps_from_string ("application/ogg");
1862 case GST_MAKE_FOURCC('d','v','c','a'):
1864 return gst_caps_from_string ("audio/x-dv");
1865 case GST_MAKE_FOURCC('m','p','4','a'):
1867 return gst_caps_from_string ("audio/mpeg, "
1868 "mpegversion = (int) 4");
1869 case GST_MAKE_FOURCC('Q','D','M','2'):
1870 /* FIXME: QDesign music version 2 (no constant) */
1871 if (QTDEMUX_GUINT32_GET (data) <= 100) {
1872 gst_util_dump_mem ((guint8*)data, 100);
1873 return gst_caps_new_simple ("audio/x-qdm2",
1874 "framesize", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 52),
1875 "bitrate", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 40),
1876 "blocksize", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 44),
1879 case GST_MAKE_FOURCC('q','t','v','r'):
1881 case GST_MAKE_FOURCC('Q','D','M','C'):
1883 case GST_MAKE_FOURCC('i','m','a','4'):
1885 case GST_MAKE_FOURCC('Q','c','l','p'):
1886 /* QUALCOMM PureVoice */
1887 case GST_MAKE_FOURCC('a','g','s','m'):
1890 g_critical ("Don't know how to convert fourcc '" GST_FOURCC_FORMAT
1891 "' to caps\n", GST_FOURCC_ARGS(fourcc));