2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 * SECTION:element-qtdemux
28 * Demuxes a .mov file into raw or compressed audio and/or video streams.
30 * This element supports both push and pull-based scheduling, depending on the
31 * capabilities of the upstream elements.
34 * <title>Example launch line</title>
36 * gst-launch filesrc location=test.mov ! qtdemux name=demux demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
37 * ]| Play (parse and decode) a .mov file and try to output it to
38 * an automatically detected soundcard and videosink. If the MOV file contains
39 * compressed audio or video data, this will only work if you have the
40 * right decoder elements/plugins installed.
43 * Last reviewed on 2006-12-29 (0.10.5)
50 #include "gst/gst-i18n-plugin.h"
52 #include <glib/gprintf.h>
53 #include <gst/tag/tag.h>
55 #include "qtatomparser.h"
56 #include "qtdemux_types.h"
57 #include "qtdemux_dump.h"
58 #include "qtdemux_fourcc.h"
59 #include "qtdemux_lang.h"
61 #include "qtpalette.h"
63 #include "gst/riff/riff-media.h"
64 #include "gst/riff/riff-read.h"
66 #include <gst/pbutils/pbutils.h>
76 /* max. size considered 'sane' for non-mdat atoms */
77 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
79 /* if the sample index is larger than this, something is likely wrong */
80 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
82 /* For converting qt creation times to unix epoch times */
83 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
84 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
85 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
86 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
88 GST_DEBUG_CATEGORY (qtdemux_debug);
90 /*typedef struct _QtNode QtNode; */
91 typedef struct _QtDemuxSegment QtDemuxSegment;
92 typedef struct _QtDemuxSample QtDemuxSample;
101 struct _QtDemuxSample
104 gint32 pts_offset; /* Add this value to timestamp to get the pts */
106 guint64 timestamp; /* DTS In mov time */
107 guint32 duration; /* In mov time */
108 gboolean keyframe; /* TRUE when this packet is a keyframe */
111 /* timestamp is the DTS */
112 #define QTSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
113 GST_SECOND, (stream)->timescale)
114 /* timestamp + offset is the PTS */
115 #define QTSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
116 (sample)->pts_offset, GST_SECOND, (stream)->timescale)
117 /* timestamp + duration - dts is the duration */
118 #define QTSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
119 (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
120 /* timestamp + offset + duration - pts is the duration */
121 #define QTSAMPLE_DUR_PTS(stream,sample,pts) (gst_util_uint64_scale ((sample)->timestamp + \
122 (sample)->pts_offset + (sample)->duration, GST_SECOND, (stream)->timescale) - (pts));
124 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
127 * Quicktime has tracks and segments. A track is a continuous piece of
128 * multimedia content. The track is not always played from start to finish but
129 * instead, pieces of the track are 'cut out' and played in sequence. This is
130 * what the segments do.
132 * Inside the track we have keyframes (K) and delta frames. The track has its
133 * own timing, which starts from 0 and extends to end. The position in the track
134 * is called the media_time.
136 * The segments now describe the pieces that should be played from this track
137 * and are basically tupples of media_time/duration/rate entries. We can have
138 * multiple segments and they are all played after one another. An example:
140 * segment 1: media_time: 1 second, duration: 1 second, rate 1
141 * segment 2: media_time: 3 second, duration: 2 second, rate 2
143 * To correctly play back this track, one must play: 1 second of media starting
144 * from media_time 1 followed by 2 seconds of media starting from media_time 3
147 * Each of the segments will be played at a specific time, the first segment at
148 * time 0, the second one after the duration of the first one, etc.. Note that
149 * the time in resulting playback is not identical to the media_time of the
152 * Visually, assuming the track has 4 second of media_time:
155 * .-----------------------------------------------------------.
156 * track: | K.....K.........K........K.......K.......K...........K... |
157 * '-----------------------------------------------------------'
159 * .------------^ ^ .----------^ ^
160 * / .-------------' / .------------------'
162 * .--------------. .--------------.
163 * | segment 1 | | segment 2 |
164 * '--------------' '--------------'
166 * The challenge here is to cut out the right pieces of the track for each of
167 * the playback segments. This fortunatly can easily be done with the SEGMENT
168 * events of gstreamer.
170 * For playback of segment 1, we need to provide the decoder with the keyframe
171 * (a), in the above figure, but we must instruct it only to output the decoded
172 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
173 * position set to the time of the segment: 0.
175 * We then proceed to push data from keyframe (a) to frame (b). The decoder
176 * decodes but clips all before media_time 1.
178 * After finishing a segment, we push out a new SEGMENT event with the clipping
179 * boundaries of the new data.
181 * This is a good usecase for the GStreamer accumulated SEGMENT events.
184 struct _QtDemuxSegment
186 /* global time and duration, all gst time */
190 /* media time of trak, all gst time */
196 struct _QtDemuxStream
205 /* if the stream has a redirect URI in its headers, we store it here */
212 guint64 duration; /* in timescale */
216 gchar lang_id[4]; /* ISO 639-2T language code */
220 QtDemuxSample *samples;
221 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
222 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
223 the framerate, in timescale units */
225 /* if we use chunks or samples */
237 /* Numerator/denominator framerate */
240 guint16 bits_per_sample;
241 guint16 color_table_id;
246 guint samples_per_packet;
247 guint samples_per_frame;
248 guint bytes_per_packet;
249 guint bytes_per_sample;
250 guint bytes_per_frame;
253 /* when a discontinuity is pending */
256 /* list of buffers to push first */
259 /* if we need to clip this buffer. This is only needed for uncompressed
263 /* buffer needs some custom processing, e.g. subtitles */
264 gboolean need_process;
266 /* current position */
267 guint32 segment_index;
268 guint32 sample_index;
269 guint64 time_position; /* in gst time */
271 /* the Gst segment we are processing out, used for clipping */
274 /* last GstFlowReturn */
275 GstFlowReturn last_ret;
277 /* quicktime segments */
279 QtDemuxSegment *segments;
284 GstTagList *pending_tags;
285 gboolean send_global_tags;
287 GstEvent *pending_event;
297 gboolean chunks_are_chunks;
301 GstByteReader co_chunk;
303 guint32 current_chunk;
305 guint32 samples_per_chunk;
306 guint32 stco_sample_index;
308 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
311 guint32 n_samples_per_chunk;
312 guint32 stsc_chunk_index;
313 guint32 stsc_sample_index;
314 guint64 chunk_offset;
317 guint32 stts_samples;
318 guint32 n_sample_times;
319 guint32 stts_sample_index;
321 guint32 stts_duration;
323 gboolean stss_present;
324 guint32 n_sample_syncs;
327 gboolean stps_present;
328 guint32 n_sample_partial_syncs;
331 gboolean ctts_present;
332 guint32 n_composition_times;
334 guint32 ctts_sample_index;
339 gboolean parsed_trex;
340 guint32 def_sample_duration;
341 guint32 def_sample_size;
342 guint32 def_sample_flags;
347 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
348 QTDEMUX_STATE_HEADER, /* Parsing the header */
349 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
350 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
353 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
354 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
355 guint32 fourcc, GstByteReader * parser);
356 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
357 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
358 guint32 fourcc, GstByteReader * parser);
360 static GstStaticPadTemplate gst_qtdemux_sink_template =
361 GST_STATIC_PAD_TEMPLATE ("sink",
364 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
368 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
369 GST_STATIC_PAD_TEMPLATE ("video_%02d",
372 GST_STATIC_CAPS_ANY);
374 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
375 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
378 GST_STATIC_CAPS_ANY);
380 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
381 GST_STATIC_PAD_TEMPLATE ("subtitle_%02d",
384 GST_STATIC_CAPS_ANY);
386 GST_BOILERPLATE (GstQTDemux, gst_qtdemux, GstQTDemux, GST_TYPE_ELEMENT);
388 static void gst_qtdemux_dispose (GObject * object);
391 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
394 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
395 QtDemuxStream * str, gint64 media_offset);
397 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
398 static GstIndex *gst_qtdemux_get_index (GstElement * element);
399 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
400 GstStateChange transition);
401 static gboolean qtdemux_sink_activate (GstPad * sinkpad);
402 static gboolean qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active);
403 static gboolean qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active);
405 static void gst_qtdemux_loop (GstPad * pad);
406 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf);
407 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstEvent * event);
409 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
410 const guint8 * buffer, guint length);
411 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
412 const guint8 * buffer, guint length);
413 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
415 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
416 QtDemuxStream * stream, GNode * esds, GstTagList * list);
417 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
418 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
419 gchar ** codec_name);
420 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
421 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
422 gchar ** codec_name);
423 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
424 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
425 gchar ** codec_name);
426 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
427 QtDemuxStream * stream, guint32 n);
428 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
431 gst_qtdemux_base_init (gpointer klass)
433 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
435 gst_element_class_add_pad_template (element_class,
436 gst_static_pad_template_get (&gst_qtdemux_sink_template));
437 gst_element_class_add_pad_template (element_class,
438 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
439 gst_element_class_add_pad_template (element_class,
440 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
441 gst_element_class_add_pad_template (element_class,
442 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
443 gst_element_class_set_details_simple (element_class, "QuickTime demuxer",
445 "Demultiplex a QuickTime file into audio and video streams",
446 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
448 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
452 gst_qtdemux_class_init (GstQTDemuxClass * klass)
454 GObjectClass *gobject_class;
455 GstElementClass *gstelement_class;
457 gobject_class = (GObjectClass *) klass;
458 gstelement_class = (GstElementClass *) klass;
460 parent_class = g_type_class_peek_parent (klass);
462 gobject_class->dispose = gst_qtdemux_dispose;
464 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
466 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
467 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
469 gst_tag_register_musicbrainz_tags ();
473 gst_qtdemux_init (GstQTDemux * qtdemux, GstQTDemuxClass * klass)
476 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
477 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
478 gst_pad_set_activatepull_function (qtdemux->sinkpad,
479 qtdemux_sink_activate_pull);
480 gst_pad_set_activatepush_function (qtdemux->sinkpad,
481 qtdemux_sink_activate_push);
482 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
483 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
484 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
486 qtdemux->state = QTDEMUX_STATE_INITIAL;
487 qtdemux->pullbased = FALSE;
488 qtdemux->posted_redirect = FALSE;
489 qtdemux->neededbytes = 16;
491 qtdemux->adapter = gst_adapter_new ();
493 qtdemux->first_mdat = -1;
494 qtdemux->got_moov = FALSE;
495 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
496 qtdemux->mdatbuffer = NULL;
497 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
501 gst_qtdemux_dispose (GObject * object)
503 GstQTDemux *qtdemux = GST_QTDEMUX (object);
505 if (qtdemux->adapter) {
506 g_object_unref (G_OBJECT (qtdemux->adapter));
507 qtdemux->adapter = NULL;
510 G_OBJECT_CLASS (parent_class)->dispose (object);
514 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
516 if (qtdemux->posted_redirect) {
517 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
518 (_("This file contains no playable streams.")),
519 ("no known streams found, a redirect message has been posted"));
521 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
522 (_("This file contains no playable streams.")),
523 ("no known streams found"));
528 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
533 if (G_UNLIKELY (size == 0)) {
535 GstBuffer *tmp = NULL;
537 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
538 if (ret != GST_FLOW_OK)
541 size = QT_UINT32 (GST_BUFFER_DATA (tmp));
542 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
544 gst_buffer_unref (tmp);
547 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
548 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
549 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
550 /* we're pulling header but already got most interesting bits,
551 * so never mind the rest (e.g. tags) (that much) */
552 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
554 return GST_FLOW_UNEXPECTED;
556 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
557 (_("This file is invalid and cannot be played.")),
558 ("atom has bogus size %" G_GUINT64_FORMAT, size));
559 return GST_FLOW_ERROR;
563 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
565 if (G_UNLIKELY (flow != GST_FLOW_OK))
568 /* Catch short reads - we don't want any partial atoms */
569 if (G_UNLIKELY (GST_BUFFER_SIZE (*buf) < size)) {
570 GST_WARNING_OBJECT (qtdemux, "short read: %u < %" G_GUINT64_FORMAT,
571 GST_BUFFER_SIZE (*buf), size);
572 gst_buffer_unref (*buf);
574 return GST_FLOW_UNEXPECTED;
582 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
583 GstFormat dest_format, gint64 * dest_value)
586 QtDemuxStream *stream = gst_pad_get_element_private (pad);
587 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
590 if (stream->subtype != FOURCC_vide) {
595 switch (src_format) {
596 case GST_FORMAT_TIME:
597 switch (dest_format) {
598 case GST_FORMAT_BYTES:{
599 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
603 *dest_value = stream->samples[index].offset;
605 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
606 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
607 GST_TIME_ARGS (src_value), *dest_value);
615 case GST_FORMAT_BYTES:
616 switch (dest_format) {
617 case GST_FORMAT_TIME:{
619 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
626 gst_util_uint64_scale (stream->samples[index].timestamp,
627 GST_SECOND, stream->timescale);
628 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
629 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
630 src_value, GST_TIME_ARGS (*dest_value));
643 gst_object_unref (qtdemux);
649 static const GstQueryType *
650 gst_qtdemux_get_src_query_types (GstPad * pad)
652 static const GstQueryType src_types[] = {
665 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
669 *duration = GST_CLOCK_TIME_NONE;
671 if (qtdemux->duration != 0) {
672 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
673 *duration = gst_util_uint64_scale (qtdemux->duration,
674 GST_SECOND, qtdemux->timescale);
681 gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
683 gboolean res = FALSE;
684 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
686 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
688 switch (GST_QUERY_TYPE (query)) {
689 case GST_QUERY_POSITION:
690 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.last_stop)) {
691 gst_query_set_position (query, GST_FORMAT_TIME,
692 qtdemux->segment.last_stop);
696 case GST_QUERY_DURATION:{
699 gst_query_parse_duration (query, &fmt, NULL);
700 if (fmt == GST_FORMAT_TIME) {
701 gint64 duration = -1;
703 gst_qtdemux_get_duration (qtdemux, &duration);
705 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
711 case GST_QUERY_CONVERT:{
712 GstFormat src_fmt, dest_fmt;
713 gint64 src_value, dest_value = 0;
715 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
717 res = gst_qtdemux_src_convert (pad,
718 src_fmt, src_value, dest_fmt, &dest_value);
720 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
725 case GST_QUERY_FORMATS:
726 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
729 case GST_QUERY_SEEKING:{
733 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
734 if (fmt == GST_FORMAT_TIME) {
735 gint64 duration = -1;
737 gst_qtdemux_get_duration (qtdemux, &duration);
739 if (!qtdemux->pullbased) {
742 /* we might be able with help from upstream */
744 q = gst_query_new_seeking (GST_FORMAT_BYTES);
745 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
746 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
747 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
751 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
757 res = gst_pad_query_default (pad, query);
761 gst_object_unref (qtdemux);
767 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
769 if (G_LIKELY (stream->pad)) {
770 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
771 GST_DEBUG_PAD_NAME (stream->pad));
773 if (G_UNLIKELY (stream->pending_tags)) {
774 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
775 stream->pending_tags);
776 gst_pad_push_event (stream->pad,
777 gst_event_new_tag (stream->pending_tags));
778 stream->pending_tags = NULL;
781 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
782 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
784 gst_pad_push_event (stream->pad,
785 gst_event_new_tag (gst_tag_list_copy (qtdemux->tag_list)));
786 stream->send_global_tags = FALSE;
791 /* push event on all source pads; takes ownership of the event */
793 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
796 gboolean has_valid_stream = FALSE;
797 GstEventType etype = GST_EVENT_TYPE (event);
799 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
800 GST_EVENT_TYPE_NAME (event));
802 for (n = 0; n < qtdemux->n_streams; n++) {
804 QtDemuxStream *stream = qtdemux->streams[n];
806 if ((pad = stream->pad)) {
807 has_valid_stream = TRUE;
809 if (etype == GST_EVENT_EOS) {
810 /* let's not send twice */
811 if (stream->sent_eos)
813 stream->sent_eos = TRUE;
816 gst_pad_push_event (pad, gst_event_ref (event));
820 gst_event_unref (event);
822 /* if it is EOS and there are no pads, post an error */
823 if (!has_valid_stream && etype == GST_EVENT_EOS) {
824 gst_qtdemux_post_no_playable_stream_error (qtdemux);
828 /* push a pending newsegment event, if any from the streaming thread */
830 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
832 if (qtdemux->pending_newsegment) {
833 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
834 qtdemux->pending_newsegment = NULL;
844 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
846 if (s1->timestamp > *media_time)
852 /* find the index of the sample that includes the data for @media_time using a
853 * binary search. Only to be called in optimized cases of linear search below.
855 * Returns the index of the sample.
858 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
861 QtDemuxSample *result;
864 /* convert media_time to mov format */
866 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
868 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
869 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
870 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
872 if (G_LIKELY (result))
873 index = result - str->samples;
882 /* find the index of the sample that includes the data for @media_offset using a
885 * Returns the index of the sample.
888 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
889 QtDemuxStream * str, gint64 media_offset)
891 QtDemuxSample *result = str->samples;
894 if (result == NULL || str->n_samples == 0)
897 if (media_offset == result->offset)
901 while (index < str->n_samples - 1) {
902 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
905 if (media_offset < result->offset)
916 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
921 /* find the index of the sample that includes the data for @media_time using a
922 * linear search, and keeping in mind that not all samples may have been parsed
923 * yet. If possible, it will delegate to binary search.
925 * Returns the index of the sample.
928 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
934 /* convert media_time to mov format */
936 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
938 if (mov_time == str->samples[0].timestamp)
941 /* use faster search if requested time in already parsed range */
942 if (str->stbl_index >= 0 &&
943 mov_time <= str->samples[str->stbl_index].timestamp)
944 return gst_qtdemux_find_index (qtdemux, str, media_time);
946 while (index < str->n_samples - 1) {
947 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
950 if (mov_time < str->samples[index + 1].timestamp)
960 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
965 /* find the index of the keyframe needed to decode the sample at @index
968 * Returns the index of the keyframe.
971 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
974 guint32 new_index = index;
976 if (index >= str->n_samples) {
977 new_index = str->n_samples;
981 /* all keyframes, return index */
982 if (str->all_keyframe) {
987 /* else go back until we have a keyframe */
989 if (str->samples[new_index].keyframe)
999 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1000 "gave %u", index, new_index);
1005 /* find the segment for @time_position for @stream
1007 * Returns -1 if the segment cannot be found.
1010 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1011 guint64 time_position)
1016 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1017 GST_TIME_ARGS (time_position));
1019 /* find segment corresponding to time_position if we are looking
1022 for (i = 0; i < stream->n_segments; i++) {
1023 QtDemuxSegment *segment = &stream->segments[i];
1025 GST_LOG_OBJECT (qtdemux,
1026 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1027 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1029 /* For the last segment we include stop_time in the last segment */
1030 if (i < stream->n_segments - 1) {
1031 if (segment->time <= time_position && time_position < segment->stop_time) {
1032 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1037 if (segment->time <= time_position && time_position <= segment->stop_time) {
1038 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1047 /* move the stream @str to the sample position @index.
1049 * Updates @str->sample_index and marks discontinuity if needed.
1052 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1055 /* no change needed */
1056 if (index == str->sample_index)
1059 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1062 /* position changed, we have a discont */
1063 str->sample_index = index;
1064 /* Each time we move in the stream we store the position where we are
1066 str->from_sample = index;
1067 str->discont = TRUE;
1071 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1072 gint64 * key_time, gint64 * key_offset)
1075 gint64 min_byte_offset = -1;
1078 min_offset = desired_time;
1080 /* for each stream, find the index of the sample in the segment
1081 * and move back to the previous keyframe. */
1082 for (n = 0; n < qtdemux->n_streams; n++) {
1084 guint32 index, kindex;
1086 guint64 media_start;
1089 QtDemuxSegment *seg;
1091 str = qtdemux->streams[n];
1093 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1094 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1096 /* segment not found, continue with normal flow */
1100 /* get segment and time in the segment */
1101 seg = &str->segments[seg_idx];
1102 seg_time = desired_time - seg->time;
1104 /* get the media time in the segment */
1105 media_start = seg->media_start + seg_time;
1107 /* get the index of the sample with media time */
1108 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1109 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1110 " at offset %" G_GUINT64_FORMAT,
1111 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1113 /* find previous keyframe */
1114 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1116 /* if the keyframe is at a different position, we need to update the
1117 * requested seek time */
1118 if (index != kindex) {
1121 /* get timestamp of keyframe */
1123 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1125 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT
1126 " at offset %" G_GUINT64_FORMAT,
1127 kindex, GST_TIME_ARGS (media_time), str->samples[kindex].offset);
1129 /* keyframes in the segment get a chance to change the
1130 * desired_offset. keyframes out of the segment are
1132 if (media_time >= seg->media_start) {
1135 /* this keyframe is inside the segment, convert back to
1137 seg_time = (media_time - seg->media_start) + seg->time;
1138 if (seg_time < min_offset)
1139 min_offset = seg_time;
1143 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1144 min_byte_offset = str->samples[index].offset;
1148 *key_time = min_offset;
1150 *key_offset = min_byte_offset;
1154 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1155 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1160 g_return_val_if_fail (format != NULL, FALSE);
1161 g_return_val_if_fail (cur != NULL, FALSE);
1162 g_return_val_if_fail (stop != NULL, FALSE);
1164 if (*format == GST_FORMAT_TIME)
1167 fmt = GST_FORMAT_TIME;
1169 if (cur_type != GST_SEEK_TYPE_NONE)
1170 res = gst_pad_query_convert (pad, *format, *cur, &fmt, cur);
1171 if (res && stop_type != GST_SEEK_TYPE_NONE)
1172 res = gst_pad_query_convert (pad, *format, *stop, &fmt, stop);
1175 *format = GST_FORMAT_TIME;
1180 /* perform seek in push based mode:
1181 find BYTE position to move to based on time and delegate to upstream
1184 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1189 GstSeekType cur_type, stop_type;
1194 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1196 gst_event_parse_seek (event, &rate, &format, &flags,
1197 &cur_type, &cur, &stop_type, &stop);
1199 /* FIXME, always play to the end */
1202 /* only forward streaming and seeking is possible */
1204 goto unsupported_seek;
1206 /* convert to TIME if needed and possible */
1207 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1211 /* find reasonable corresponding BYTE position,
1212 * also try to mind about keyframes, since we can not go back a bit for them
1214 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1219 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1220 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1223 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1224 GST_DEBUG_OBJECT (qtdemux,
1225 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1226 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1227 GST_OBJECT_LOCK (qtdemux);
1228 qtdemux->requested_seek_time = cur;
1229 qtdemux->seek_offset = byte_cur;
1230 GST_OBJECT_UNLOCK (qtdemux);
1233 /* BYTE seek event */
1234 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1236 res = gst_pad_push_event (qtdemux->sinkpad, event);
1243 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1249 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1254 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1259 /* perform the seek.
1261 * We set all segment_indexes in the streams to unknown and
1262 * adjust the time_position to the desired position. this is enough
1263 * to trigger a segment switch in the streaming thread to start
1264 * streaming from the desired position.
1266 * Keyframe seeking is a little more complicated when dealing with
1267 * segments. Ideally we want to move to the previous keyframe in
1268 * the segment but there might not be a keyframe in the segment. In
1269 * fact, none of the segments could contain a keyframe. We take a
1270 * practical approach: seek to the previous keyframe in the segment,
1271 * if there is none, seek to the beginning of the segment.
1273 * Called with STREAM_LOCK
1276 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1278 gint64 desired_offset;
1281 desired_offset = segment->last_stop;
1283 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1284 GST_TIME_ARGS (desired_offset));
1286 /* may not have enough fragmented info to do this adjustment,
1287 * and we can't scan (and probably should not) at this time with
1288 * possibly flushing upstream */
1289 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1292 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1293 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1294 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1295 desired_offset = min_offset;
1298 /* and set all streams to the final position */
1299 for (n = 0; n < qtdemux->n_streams; n++) {
1300 QtDemuxStream *stream = qtdemux->streams[n];
1302 stream->time_position = desired_offset;
1303 stream->sample_index = -1;
1304 stream->segment_index = -1;
1305 stream->last_ret = GST_FLOW_OK;
1306 stream->sent_eos = FALSE;
1308 segment->last_stop = desired_offset;
1309 segment->time = desired_offset;
1311 /* we stop at the end */
1312 if (segment->stop == -1)
1313 segment->stop = segment->duration;
1318 /* do a seek in pull based mode */
1320 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1325 GstSeekType cur_type, stop_type;
1329 GstSegment seeksegment;
1333 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1335 gst_event_parse_seek (event, &rate, &format, &flags,
1336 &cur_type, &cur, &stop_type, &stop);
1338 /* we have to have a format as the segment format. Try to convert
1340 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1344 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1346 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1350 flush = flags & GST_SEEK_FLAG_FLUSH;
1352 /* stop streaming, either by flushing or by pausing the task */
1354 /* unlock upstream pull_range */
1355 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1356 /* make sure out loop function exits */
1357 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1359 /* non flushing seek, pause the task */
1360 gst_pad_pause_task (qtdemux->sinkpad);
1363 /* wait for streaming to finish */
1364 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1366 /* copy segment, we need this because we still need the old
1367 * segment when we close the current segment. */
1368 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1371 /* configure the segment with the seek variables */
1372 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1373 gst_segment_set_seek (&seeksegment, rate, format, flags,
1374 cur_type, cur, stop_type, stop, &update);
1377 /* now do the seek, this actually never returns FALSE */
1378 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1380 /* prepare for streaming again */
1382 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop ());
1383 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop ());
1384 } else if (qtdemux->segment_running) {
1385 /* we are running the current segment and doing a non-flushing seek,
1386 * close the segment first based on the last_stop. */
1387 GST_DEBUG_OBJECT (qtdemux, "closing running segment %" G_GINT64_FORMAT
1388 " to %" G_GINT64_FORMAT, qtdemux->segment.start,
1389 qtdemux->segment.last_stop);
1391 if (qtdemux->segment.rate >= 0) {
1392 /* FIXME, rate is the product of the global rate and the (quicktime)
1394 qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
1395 qtdemux->segment.rate, qtdemux->segment.format,
1396 qtdemux->segment.start, qtdemux->segment.last_stop,
1397 qtdemux->segment.time);
1398 } else { /* For Reverse Playback */
1401 if ((stop = qtdemux->segment.stop) == -1)
1402 stop = qtdemux->segment.duration;
1403 /* for reverse playback, we played from stop to last_stop. */
1404 qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
1405 qtdemux->segment.rate, qtdemux->segment.format,
1406 qtdemux->segment.last_stop, stop, qtdemux->segment.last_stop);
1410 /* commit the new segment */
1411 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1413 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1414 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1415 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1416 qtdemux->segment.format, qtdemux->segment.last_stop));
1419 /* restart streaming, NEWSEGMENT will be sent from the streaming
1421 qtdemux->segment_running = TRUE;
1422 for (i = 0; i < qtdemux->n_streams; i++)
1423 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1425 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1428 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1435 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1441 qtdemux_ensure_index (GstQTDemux * qtdemux)
1445 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1447 /* Build complete index */
1448 for (i = 0; i < qtdemux->n_streams; i++) {
1449 QtDemuxStream *stream = qtdemux->streams[i];
1451 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1459 GST_LOG_OBJECT (qtdemux,
1460 "Building complete index of stream %u for seeking failed!", i);
1466 gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
1468 gboolean res = TRUE;
1469 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
1471 switch (GST_EVENT_TYPE (event)) {
1472 case GST_EVENT_SEEK:
1474 #ifndef GST_DISABLE_GST_DEBUG
1475 GstClockTime ts = gst_util_get_timestamp ();
1477 /* Build complete index for seeking;
1478 * if not a fragmented file at least */
1479 if (!qtdemux->fragmented)
1480 if (!qtdemux_ensure_index (qtdemux))
1482 #ifndef GST_DISABLE_GST_DEBUG
1483 ts = gst_util_get_timestamp () - ts;
1484 GST_INFO_OBJECT (qtdemux,
1485 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1488 if (qtdemux->pullbased) {
1489 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1490 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams &&
1491 !qtdemux->fragmented) {
1492 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1494 GST_DEBUG_OBJECT (qtdemux,
1495 "ignoring seek in push mode in current state");
1498 gst_event_unref (event);
1501 case GST_EVENT_NAVIGATION:
1503 gst_event_unref (event);
1506 res = gst_pad_event_default (pad, event);
1510 gst_object_unref (qtdemux);
1518 GST_ERROR_OBJECT (qtdemux, "Index failed");
1519 gst_event_unref (event);
1525 /* stream/index return sample that is min/max w.r.t. byte position,
1526 * time is min/max w.r.t. time of samples,
1527 * the latter need not be time of the former sample */
1529 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1530 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1533 gint64 time, min_time;
1534 QtDemuxStream *stream;
1540 for (n = 0; n < qtdemux->n_streams; ++n) {
1543 gboolean set_sample;
1545 str = qtdemux->streams[n];
1552 i = str->n_samples - 1;
1555 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1556 if (str->samples[i].size &&
1557 ((fw && (str->samples[i].offset >= byte_pos)) ||
1559 (str->samples[i].offset + str->samples[i].size <=
1561 /* move stream to first available sample */
1563 gst_qtdemux_move_stream (qtdemux, str, i);
1566 /* determine min/max time */
1567 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1568 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1569 if (min_time == -1 || (!fw && time > min_time) ||
1570 (fw && time < min_time)) {
1573 /* determine stream with leading sample, to get its position */
1575 && (str->samples[i].offset < stream->samples[index].offset))
1577 && (str->samples[i].offset > stream->samples[index].offset))) {
1584 /* no sample for this stream, mark eos */
1586 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1598 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
1600 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1603 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1605 switch (GST_EVENT_TYPE (event)) {
1606 case GST_EVENT_NEWSEGMENT:
1609 gdouble rate, arate;
1610 gint64 start, stop, time, offset = 0;
1611 QtDemuxStream *stream;
1616 /* some debug output */
1617 gst_segment_init (&segment, GST_FORMAT_UNDEFINED);
1618 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
1619 &start, &stop, &time);
1620 gst_segment_set_newsegment_full (&segment, update, rate, arate, format,
1622 GST_DEBUG_OBJECT (demux,
1623 "received format %d newsegment %" GST_SEGMENT_FORMAT, format,
1626 /* chain will send initial newsegment after pads have been added */
1627 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1628 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1632 /* we only expect a BYTE segment, e.g. following a seek */
1633 if (format == GST_FORMAT_BYTES) {
1635 gint64 requested_seek_time;
1636 guint64 seek_offset;
1640 GST_OBJECT_LOCK (demux);
1641 requested_seek_time = demux->requested_seek_time;
1642 seek_offset = demux->seek_offset;
1643 demux->requested_seek_time = -1;
1644 demux->seek_offset = -1;
1645 GST_OBJECT_UNLOCK (demux);
1647 if (offset == seek_offset) {
1648 start = requested_seek_time;
1650 gst_qtdemux_find_sample (demux, start, TRUE, FALSE, NULL, NULL,
1652 start = MAX (start, 0);
1656 gst_qtdemux_find_sample (demux, stop, FALSE, FALSE, NULL, NULL,
1658 /* keyframe seeking should already arrange for start >= stop,
1659 * but make sure in other rare cases */
1660 stop = MAX (stop, start);
1663 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1667 /* accept upstream's notion of segment and distribute along */
1668 gst_segment_set_newsegment_full (&demux->segment, update, rate, arate,
1669 GST_FORMAT_TIME, start, stop, start);
1670 GST_DEBUG_OBJECT (demux, "Pushing newseg update %d, rate %g, "
1671 "applied rate %g, format %d, start %" GST_TIME_FORMAT ", "
1672 "stop %" GST_TIME_FORMAT, update, rate, arate, GST_FORMAT_TIME,
1673 GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1675 gst_qtdemux_push_event (demux,
1676 gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME,
1677 start, stop, start));
1679 /* clear leftover in current segment, if any */
1680 gst_adapter_clear (demux->adapter);
1681 /* set up streaming thread */
1682 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1683 demux->offset = offset;
1685 demux->todrop = stream->samples[idx].offset - offset;
1686 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1688 /* set up for EOS */
1689 demux->neededbytes = -1;
1693 gst_event_unref (event);
1698 case GST_EVENT_FLUSH_STOP:
1702 /* clean up, force EOS if no more info follows */
1703 gst_adapter_clear (demux->adapter);
1705 demux->neededbytes = -1;
1706 /* reset flow return, e.g. following seek */
1707 for (i = 0; i < demux->n_streams; i++) {
1708 demux->streams[i]->last_ret = GST_FLOW_OK;
1709 demux->streams[i]->sent_eos = FALSE;
1714 /* If we are in push mode, and get an EOS before we've seen any streams,
1715 * then error out - we have nowhere to send the EOS */
1716 if (!demux->pullbased) {
1718 gboolean has_valid_stream = FALSE;
1719 for (i = 0; i < demux->n_streams; i++) {
1720 if (demux->streams[i]->pad != NULL) {
1721 has_valid_stream = TRUE;
1725 if (!has_valid_stream)
1726 gst_qtdemux_post_no_playable_stream_error (demux);
1733 res = gst_pad_event_default (demux->sinkpad, event);
1740 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1742 GstQTDemux *demux = GST_QTDEMUX (element);
1744 GST_OBJECT_LOCK (demux);
1745 if (demux->element_index)
1746 gst_object_unref (demux->element_index);
1748 demux->element_index = gst_object_ref (index);
1750 demux->element_index = NULL;
1752 GST_OBJECT_UNLOCK (demux);
1753 /* object lock might be taken again */
1755 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1756 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
1757 demux->element_index, demux->index_id);
1761 gst_qtdemux_get_index (GstElement * element)
1763 GstIndex *result = NULL;
1764 GstQTDemux *demux = GST_QTDEMUX (element);
1766 GST_OBJECT_LOCK (demux);
1767 if (demux->element_index)
1768 result = gst_object_ref (demux->element_index);
1769 GST_OBJECT_UNLOCK (demux);
1771 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1777 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1779 g_free ((gpointer) stream->stco.data);
1780 stream->stco.data = NULL;
1781 g_free ((gpointer) stream->stsz.data);
1782 stream->stsz.data = NULL;
1783 g_free ((gpointer) stream->stsc.data);
1784 stream->stsc.data = NULL;
1785 g_free ((gpointer) stream->stts.data);
1786 stream->stts.data = NULL;
1787 g_free ((gpointer) stream->stss.data);
1788 stream->stss.data = NULL;
1789 g_free ((gpointer) stream->stps.data);
1790 stream->stps.data = NULL;
1791 g_free ((gpointer) stream->ctts.data);
1792 stream->ctts.data = NULL;
1796 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
1798 while (stream->buffers) {
1799 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1800 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1803 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
1804 g_free (stream->samples);
1806 gst_caps_unref (stream->caps);
1807 g_free (stream->segments);
1808 if (stream->pending_tags)
1809 gst_tag_list_free (stream->pending_tags);
1810 g_free (stream->redirect_uri);
1811 /* free stbl sub-atoms */
1812 gst_qtdemux_stbl_free (stream);
1816 static GstStateChangeReturn
1817 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1819 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1820 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1822 switch (transition) {
1823 case GST_STATE_CHANGE_PAUSED_TO_READY:
1829 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1831 switch (transition) {
1832 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1835 qtdemux->state = QTDEMUX_STATE_INITIAL;
1836 qtdemux->neededbytes = 16;
1837 qtdemux->todrop = 0;
1838 qtdemux->pullbased = FALSE;
1839 qtdemux->posted_redirect = FALSE;
1840 qtdemux->offset = 0;
1841 qtdemux->first_mdat = -1;
1842 qtdemux->header_size = 0;
1843 qtdemux->got_moov = FALSE;
1844 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1845 if (qtdemux->mdatbuffer)
1846 gst_buffer_unref (qtdemux->mdatbuffer);
1847 qtdemux->mdatbuffer = NULL;
1848 if (qtdemux->comp_brands)
1849 gst_buffer_unref (qtdemux->comp_brands);
1850 qtdemux->comp_brands = NULL;
1851 if (qtdemux->tag_list)
1852 gst_tag_list_free (qtdemux->tag_list);
1853 qtdemux->tag_list = NULL;
1854 if (qtdemux->element_index)
1855 gst_object_unref (qtdemux->element_index);
1856 qtdemux->element_index = NULL;
1857 gst_adapter_clear (qtdemux->adapter);
1858 for (n = 0; n < qtdemux->n_streams; n++) {
1859 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1860 qtdemux->streams[n] = NULL;
1862 qtdemux->major_brand = 0;
1863 qtdemux->n_streams = 0;
1864 qtdemux->n_video_streams = 0;
1865 qtdemux->n_audio_streams = 0;
1866 qtdemux->n_sub_streams = 0;
1867 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1868 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1869 qtdemux->seek_offset = 0;
1870 qtdemux->upstream_seekable = FALSE;
1871 qtdemux->upstream_size = 0;
1882 qtdemux_post_global_tags (GstQTDemux * qtdemux)
1884 if (qtdemux->tag_list) {
1885 /* all header tags ready and parsed, push them */
1886 GST_INFO_OBJECT (qtdemux, "posting global tags: %" GST_PTR_FORMAT,
1888 /* post now, send event on pads later */
1889 gst_element_post_message (GST_ELEMENT (qtdemux),
1890 gst_message_new_tag (GST_OBJECT (qtdemux),
1891 gst_tag_list_copy (qtdemux->tag_list)));
1896 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1898 /* counts as header data */
1899 qtdemux->header_size += length;
1901 /* only consider at least a sufficiently complete ftyp atom */
1905 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1906 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1907 GST_FOURCC_ARGS (qtdemux->major_brand));
1908 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1909 memcpy (GST_BUFFER_DATA (buf), buffer + 16, GST_BUFFER_SIZE (buf));
1914 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
1916 /* Strip out bogus fields */
1918 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
1920 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
1922 if (qtdemux->tag_list) {
1923 /* prioritize native tags using _KEEP mode */
1924 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
1925 gst_tag_list_free (taglist);
1927 qtdemux->tag_list = taglist;
1932 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1934 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
1935 0x97, 0xA9, 0x42, 0xE8,
1936 0x9C, 0x71, 0x99, 0x94,
1937 0x91, 0xE3, 0xAF, 0xAC
1941 /* counts as header data */
1942 qtdemux->header_size += length;
1944 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
1946 if (length <= offset + 16) {
1947 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
1951 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
1953 GstTagList *taglist;
1955 buf = gst_buffer_new ();
1956 GST_BUFFER_DATA (buf) = (guint8 *) buffer + offset + 16;
1957 GST_BUFFER_SIZE (buf) = length - offset - 16;
1959 taglist = gst_tag_list_from_xmp_buffer (buf);
1960 gst_buffer_unref (buf);
1962 qtdemux_handle_xmp_taglist (qtdemux, taglist);
1965 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
1969 /* caller verifies at least 8 bytes in buf */
1971 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1972 guint64 * plength, guint32 * pfourcc)
1977 length = QT_UINT32 (data);
1978 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1979 fourcc = QT_FOURCC (data + 4);
1980 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1983 length = G_MAXUINT32;
1984 } else if (length == 1 && size >= 16) {
1985 /* this means we have an extended size, which is the 64 bit value of
1986 * the next 8 bytes */
1987 length = QT_UINT64 (data + 8);
1988 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1998 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2000 guint32 version = 0;
2001 guint64 duration = 0;
2003 if (!gst_byte_reader_get_uint32_be (br, &version))
2008 if (!gst_byte_reader_get_uint64_be (br, &duration))
2013 if (!gst_byte_reader_get_uint32_be (br, &dur))
2018 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2019 qtdemux->duration = duration;
2025 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2031 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2032 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2034 if (!stream->parsed_trex && qtdemux->moov_node) {
2036 GstByteReader trex_data;
2038 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2040 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2043 guint32 id = 0, dur = 0, size = 0, flags = 0;
2045 /* skip version/flags */
2046 if (!gst_byte_reader_skip (&trex_data, 4))
2048 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2050 if (id != stream->track_id)
2052 /* sample description index; ignore */
2053 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2055 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2057 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2059 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2062 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2063 "duration %d, size %d, flags 0x%x", stream->track_id,
2066 stream->parsed_trex = TRUE;
2067 stream->def_sample_duration = dur;
2068 stream->def_sample_size = size;
2069 stream->def_sample_flags = flags;
2072 /* iterate all siblings */
2073 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2079 *ds_duration = stream->def_sample_duration;
2080 *ds_size = stream->def_sample_size;
2081 *ds_size = stream->def_sample_size;
2083 /* even then, above values are better than random ... */
2084 if (G_UNLIKELY (!stream->parsed_trex)) {
2085 GST_WARNING_OBJECT (qtdemux,
2086 "failed to find fragment defaults for stream %d", stream->track_id);
2094 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2095 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2096 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2097 gint64 * base_offset, gint64 * running_offset)
2100 gint32 data_offset = 0;
2101 guint32 flags = 0, first_flags = 0, samples_count = 0;
2104 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2105 QtDemuxSample *sample;
2106 gboolean ismv = FALSE;
2108 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2109 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2110 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2113 /* presence of stss or not can't really tell us much,
2114 * and flags and so on tend to be marginally reliable in these files */
2115 if (stream->subtype == FOURCC_soun) {
2116 GST_DEBUG_OBJECT (qtdemux,
2117 "sound track in fragmented file; marking all keyframes");
2118 stream->all_keyframe = TRUE;
2121 if (!gst_byte_reader_skip (trun, 1) ||
2122 !gst_byte_reader_get_uint24_be (trun, &flags))
2125 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2128 if (flags & TR_DATA_OFFSET) {
2129 /* note this is really signed */
2130 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2132 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2133 /* default base offset = first byte of moof */
2134 if (*base_offset == -1) {
2135 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2136 *base_offset = moof_offset;
2138 *running_offset = *base_offset + data_offset;
2140 /* if no offset at all, that would mean data starts at moof start,
2141 * which is a bit wrong and is ismv crappy way, so compensate
2142 * assuming data is in mdat following moof */
2143 if (*base_offset == -1) {
2144 *base_offset = moof_offset + moof_length + 8;
2145 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2148 if (*running_offset == -1)
2149 *running_offset = *base_offset;
2152 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2154 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2155 data_offset, flags, samples_count);
2157 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2158 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2159 GST_DEBUG_OBJECT (qtdemux,
2160 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2161 flags ^= TR_FIRST_SAMPLE_FLAGS;
2163 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2165 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2169 /* FIXME ? spec says other bits should also be checked to determine
2170 * entry size (and prefix size for that matter) */
2172 dur_offset = size_offset = 0;
2173 if (flags & TR_SAMPLE_DURATION) {
2174 GST_LOG_OBJECT (qtdemux, "entry duration present");
2175 dur_offset = entry_size;
2178 if (flags & TR_SAMPLE_SIZE) {
2179 GST_LOG_OBJECT (qtdemux, "entry size present");
2180 size_offset = entry_size;
2183 if (flags & TR_SAMPLE_FLAGS) {
2184 GST_LOG_OBJECT (qtdemux, "entry flags present");
2185 flags_offset = entry_size;
2188 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2189 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2190 ct_offset = entry_size;
2194 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2196 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2198 if (stream->n_samples >=
2199 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2202 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2203 stream->n_samples, (guint) sizeof (QtDemuxSample),
2204 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2206 /* create a new array of samples if it's the first sample parsed */
2207 if (stream->n_samples == 0)
2208 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2209 /* or try to reallocate it with space enough to insert the new samples */
2211 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2212 stream->n_samples + samples_count);
2213 if (stream->samples == NULL)
2216 if (G_UNLIKELY (stream->n_samples == 0)) {
2217 /* the timestamp of the first sample is also provided by the tfra entry
2218 * but we shouldn't rely on it as it is at the end of files */
2221 /* subsequent fragments extend stream */
2223 stream->samples[stream->n_samples - 1].timestamp +
2224 stream->samples[stream->n_samples - 1].duration;
2226 sample = stream->samples + stream->n_samples;
2227 for (i = 0; i < samples_count; i++) {
2228 guint32 dur, size, sflags, ct;
2230 /* first read sample data */
2231 if (flags & TR_SAMPLE_DURATION) {
2232 dur = QT_UINT32 (data + dur_offset);
2234 dur = d_sample_duration;
2236 if (flags & TR_SAMPLE_SIZE) {
2237 size = QT_UINT32 (data + size_offset);
2239 size = d_sample_size;
2241 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2243 sflags = first_flags;
2245 sflags = d_sample_flags;
2247 } else if (flags & TR_SAMPLE_FLAGS) {
2248 sflags = QT_UINT32 (data + flags_offset);
2250 sflags = d_sample_flags;
2252 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2253 ct = QT_UINT32 (data + ct_offset);
2259 /* fill the sample information */
2260 sample->offset = *running_offset;
2261 sample->pts_offset = ct;
2262 sample->size = size;
2263 sample->timestamp = timestamp;
2264 sample->duration = dur;
2265 /* sample-is-difference-sample */
2266 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2267 * now idea how it relates to bitfield other than massive LE/BE confusion */
2268 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2269 *running_offset += size;
2274 stream->n_samples += samples_count;
2280 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2285 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2291 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2292 "be larger than %uMB (broken file?)", stream->n_samples,
2293 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2298 /* find stream with @id */
2299 static inline QtDemuxStream *
2300 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2302 QtDemuxStream *stream;
2306 if (G_UNLIKELY (!id)) {
2307 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2311 /* try to get it fast and simple */
2312 if (G_LIKELY (id <= qtdemux->n_streams)) {
2313 stream = qtdemux->streams[id - 1];
2314 if (G_LIKELY (stream->track_id == id))
2318 /* linear search otherwise */
2319 for (i = 0; i < qtdemux->n_streams; i++) {
2320 stream = qtdemux->streams[i];
2321 if (stream->track_id == id)
2329 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2330 QtDemuxStream ** stream, guint32 * default_sample_duration,
2331 guint32 * default_sample_size, guint32 * default_sample_flags,
2332 gint64 * base_offset)
2335 guint32 track_id = 0;
2337 if (!gst_byte_reader_skip (tfhd, 1) ||
2338 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2341 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2344 *stream = qtdemux_find_stream (qtdemux, track_id);
2345 if (G_UNLIKELY (!*stream))
2346 goto unknown_stream;
2348 if (flags & TF_BASE_DATA_OFFSET)
2349 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2352 /* obtain stream defaults */
2353 qtdemux_parse_trex (qtdemux, *stream,
2354 default_sample_duration, default_sample_size, default_sample_flags);
2356 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2357 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2358 if (!gst_byte_reader_skip (tfhd, 4))
2361 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2362 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2365 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2366 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2369 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2370 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2377 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2382 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2388 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2389 guint64 moof_offset, QtDemuxStream * stream)
2391 GNode *moof_node, *traf_node, *tfhd_node, *trun_node;
2392 GstByteReader trun_data, tfhd_data;
2393 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2394 gint64 base_offset, running_offset;
2396 /* NOTE @stream ignored */
2398 moof_node = g_node_new ((guint8 *) buffer);
2399 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2400 qtdemux_node_dump (qtdemux, moof_node);
2402 /* unknown base_offset to start with */
2403 base_offset = running_offset = -1;
2404 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2406 /* Fragment Header node */
2408 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2412 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2413 &ds_size, &ds_flags, &base_offset))
2415 if (G_UNLIKELY (!stream)) {
2416 /* we lost track of offset, we'll need to regain it,
2417 * but can delay complaining until later or avoid doing so altogether */
2421 if (G_UNLIKELY (base_offset < -1))
2423 /* Track Run node */
2425 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2428 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2429 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2431 /* iterate all siblings */
2432 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2435 /* if no new base_offset provided for next traf,
2436 * base is end of current traf */
2437 base_offset = running_offset;
2438 running_offset = -1;
2440 /* iterate all siblings */
2441 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2443 g_node_destroy (moof_node);
2448 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2453 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2458 g_node_destroy (moof_node);
2459 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2460 (_("This file is corrupt and cannot be played.")), (NULL));
2465 /* might be used if some day we actually use mfra & co
2466 * for random access to fragments,
2467 * but that will require quite some modifications and much less relying
2468 * on a sample array */
2471 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2472 QtDemuxStream * stream)
2474 guint64 time = 0, moof_offset = 0;
2475 guint32 ver_flags, track_id, len, num_entries, i;
2476 guint value_size, traf_size, trun_size, sample_size;
2477 GstBuffer *buf = NULL;
2481 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2482 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2484 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2487 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2488 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2489 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2492 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2493 track_id, stream->track_id);
2494 if (track_id != stream->track_id) {
2498 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2499 sample_size = (len & 3) + 1;
2500 trun_size = ((len & 12) >> 2) + 1;
2501 traf_size = ((len & 48) >> 4) + 1;
2503 if (num_entries == 0)
2506 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2507 value_size + value_size + traf_size + trun_size + sample_size))
2510 for (i = 0; i < num_entries; i++) {
2511 qt_atom_parser_get_offset (&tfra, value_size, &time);
2512 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2513 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2514 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2515 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2517 GST_LOG_OBJECT (qtdemux,
2518 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2519 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2520 stream->timescale)), moof_offset);
2522 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2523 if (ret != GST_FLOW_OK)
2525 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2526 moof_offset, stream);
2527 gst_buffer_unref (buf);
2535 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2536 (_("This file is corrupt and cannot be played.")), (NULL));
2541 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2547 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2550 GNode *mfra_node, *tfra_node;
2553 if (!qtdemux->mfra_offset)
2556 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2557 if (ret != GST_FLOW_OK)
2560 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2561 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2562 GST_BUFFER_SIZE (buffer));
2564 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2567 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2568 /* iterate all siblings */
2569 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2571 g_node_destroy (mfra_node);
2572 gst_buffer_unref (buffer);
2578 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2579 (_("This file is corrupt and cannot be played.")), (NULL));
2584 static GstFlowReturn
2585 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2586 guint32 * mfro_size)
2588 GstFlowReturn ret = GST_FLOW_ERROR;
2589 GstBuffer *mfro = NULL;
2592 GstFormat fmt = GST_FORMAT_BYTES;
2594 if (!gst_pad_query_peer_duration (qtdemux->sinkpad, &fmt, &len)) {
2595 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2596 "can not locate mfro");
2600 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2601 if (ret != GST_FLOW_OK)
2604 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2605 if (fourcc != FOURCC_mfro)
2608 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2609 if (GST_BUFFER_SIZE (mfro) >= 16) {
2610 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
2611 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
2612 if (*mfro_size >= len) {
2613 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
2614 ret = GST_FLOW_ERROR;
2617 *mfra_offset = len - *mfro_size;
2622 gst_buffer_unref (mfro);
2628 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
2631 guint32 mfra_size = 0;
2632 guint64 mfra_offset = 0;
2635 qtdemux->fragmented = FALSE;
2637 /* We check here if it is a fragmented mp4 container */
2638 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
2639 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
2640 qtdemux->fragmented = TRUE;
2641 GST_DEBUG_OBJECT (qtdemux,
2642 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
2643 qtdemux->mfra_offset = mfra_offset;
2648 static GstFlowReturn
2649 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
2653 GstBuffer *buf = NULL;
2654 GstFlowReturn ret = GST_FLOW_OK;
2655 guint64 cur_offset = qtdemux->offset;
2657 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
2658 if (G_UNLIKELY (ret != GST_FLOW_OK))
2660 if (G_LIKELY (GST_BUFFER_SIZE (buf) >= 8))
2661 extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf),
2662 GST_BUFFER_SIZE (buf), &length, &fourcc);
2663 gst_buffer_unref (buf);
2665 /* maybe we already got most we needed, so only consider this eof */
2666 if (G_UNLIKELY (length == 0)) {
2667 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
2668 (_("Invalid atom size.")),
2669 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
2670 GST_FOURCC_ARGS (fourcc)));
2671 ret = GST_FLOW_UNEXPECTED;
2677 /* record for later parsing when needed */
2678 if (!qtdemux->moof_offset) {
2679 qtdemux->moof_offset = qtdemux->offset;
2688 GST_LOG_OBJECT (qtdemux,
2689 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
2690 GST_FOURCC_ARGS (fourcc), cur_offset);
2691 qtdemux->offset += length;
2698 if (qtdemux->got_moov) {
2699 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
2700 qtdemux->offset += length;
2704 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
2705 if (ret != GST_FLOW_OK)
2707 if (length != GST_BUFFER_SIZE (moov)) {
2708 /* Some files have a 'moov' atom at the end of the file which contains
2709 * a terminal 'free' atom where the body of the atom is missing.
2710 * Check for, and permit, this special case.
2712 if (GST_BUFFER_SIZE (moov) >= 8) {
2713 guint8 *final_data = GST_BUFFER_DATA (moov) +
2714 (GST_BUFFER_SIZE (moov) - 8);
2715 guint32 final_length = QT_UINT32 (final_data);
2716 guint32 final_fourcc = QT_FOURCC (final_data + 4);
2717 if (final_fourcc == FOURCC_free &&
2718 GST_BUFFER_SIZE (moov) + final_length - 8 == length) {
2719 /* Ok, we've found that special case. Allocate a new buffer with
2720 * that free atom actually present. */
2721 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
2722 gst_buffer_copy_metadata (newmoov, moov,
2723 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
2724 GST_BUFFER_COPY_CAPS);
2725 memcpy (GST_BUFFER_DATA (newmoov), GST_BUFFER_DATA (moov),
2726 GST_BUFFER_SIZE (moov));
2727 memset (GST_BUFFER_DATA (newmoov) + GST_BUFFER_SIZE (moov), 0,
2729 gst_buffer_unref (moov);
2735 if (length != GST_BUFFER_SIZE (moov)) {
2736 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2737 (_("This file is incomplete and cannot be played.")),
2738 ("We got less than expected (received %u, wanted %u, offset %"
2739 G_GUINT64_FORMAT ")",
2740 GST_BUFFER_SIZE (moov), (guint) length, cur_offset));
2741 gst_buffer_unref (moov);
2742 ret = GST_FLOW_ERROR;
2745 qtdemux->offset += length;
2747 qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
2748 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
2750 qtdemux_parse_tree (qtdemux);
2751 g_node_destroy (qtdemux->moov_node);
2752 gst_buffer_unref (moov);
2753 qtdemux->moov_node = NULL;
2754 qtdemux->got_moov = TRUE;
2762 /* extract major brand; might come in handy for ISO vs QT issues */
2763 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
2764 if (ret != GST_FLOW_OK)
2766 qtdemux->offset += length;
2767 qtdemux_parse_ftyp (qtdemux, GST_BUFFER_DATA (ftyp),
2768 GST_BUFFER_SIZE (ftyp));
2769 gst_buffer_unref (ftyp);
2776 /* uuid are extension atoms */
2777 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
2778 if (ret != GST_FLOW_OK)
2780 qtdemux->offset += length;
2781 qtdemux_parse_uuid (qtdemux, GST_BUFFER_DATA (uuid),
2782 GST_BUFFER_SIZE (uuid));
2783 gst_buffer_unref (uuid);
2790 GST_LOG_OBJECT (qtdemux,
2791 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
2792 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
2794 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
2795 if (ret != GST_FLOW_OK)
2797 GST_MEMDUMP ("Unknown tag", GST_BUFFER_DATA (unknown),
2798 GST_BUFFER_SIZE (unknown));
2799 gst_buffer_unref (unknown);
2800 qtdemux->offset += length;
2806 if (ret == GST_FLOW_UNEXPECTED && qtdemux->got_moov) {
2807 /* digested all data, show what we have */
2808 ret = qtdemux_expose_streams (qtdemux);
2810 /* Only post, event on pads is done after newsegment */
2811 qtdemux_post_global_tags (qtdemux);
2813 qtdemux->state = QTDEMUX_STATE_MOVIE;
2814 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
2821 /* Seeks to the previous keyframe of the indexed stream and
2822 * aligns other streams with respect to the keyframe timestamp
2823 * of indexed stream. Only called in case of Reverse Playback
2825 static GstFlowReturn
2826 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
2829 guint32 seg_idx = 0, k_index = 0;
2830 guint32 ref_seg_idx, ref_k_index;
2831 guint64 k_pos = 0, last_stop = 0;
2832 QtDemuxSegment *seg = NULL;
2833 QtDemuxStream *ref_str = NULL;
2834 guint64 seg_media_start_mov; /* segment media start time in mov format */
2836 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
2837 * and finally align all the other streams on that timestamp with their
2838 * respective keyframes */
2839 for (n = 0; n < qtdemux->n_streams; n++) {
2840 QtDemuxStream *str = qtdemux->streams[n];
2842 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
2843 qtdemux->segment.last_stop);
2845 /* segment not found, continue with normal flow */
2849 /* No candidate yet, take that one */
2855 /* So that stream has a segment, we prefer video streams */
2856 if (str->subtype == FOURCC_vide) {
2862 if (G_UNLIKELY (!ref_str)) {
2863 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
2867 if (G_UNLIKELY (!ref_str->from_sample)) {
2868 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
2872 /* So that stream has been playing from from_sample to to_sample. We will
2873 * get the timestamp of the previous sample and search for a keyframe before
2874 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
2875 if (ref_str->subtype == FOURCC_vide) {
2876 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
2877 ref_str->from_sample - 1);
2879 if (ref_str->from_sample >= 10)
2880 k_index = ref_str->from_sample - 10;
2885 /* get current segment for that stream */
2886 seg = &ref_str->segments[ref_str->segment_index];
2887 /* convert seg->media_start to mov format time for timestamp comparison */
2888 seg_media_start_mov =
2889 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
2890 /* Crawl back through segments to find the one containing this I frame */
2891 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
2892 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
2893 ref_str->segment_index);
2894 if (G_UNLIKELY (!ref_str->segment_index)) {
2895 /* Reached first segment, let's consider it's EOS */
2898 ref_str->segment_index--;
2899 seg = &ref_str->segments[ref_str->segment_index];
2900 /* convert seg->media_start to mov format time for timestamp comparison */
2901 seg_media_start_mov =
2902 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
2905 /* Calculate time position of the keyframe and where we should stop */
2907 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
2908 ref_str->timescale) - seg->media_start) + seg->time;
2910 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
2911 GST_SECOND, ref_str->timescale);
2912 last_stop = (last_stop - seg->media_start) + seg->time;
2914 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
2915 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
2916 k_index, GST_TIME_ARGS (k_pos));
2918 /* Set last_stop with the keyframe timestamp we pushed of that stream */
2919 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, last_stop);
2920 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
2921 GST_TIME_ARGS (last_stop));
2923 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
2924 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
2928 ref_seg_idx = ref_str->segment_index;
2929 ref_k_index = k_index;
2931 /* Align them all on this */
2932 for (n = 0; n < qtdemux->n_streams; n++) {
2934 guint64 media_start = 0, seg_time = 0;
2935 QtDemuxStream *str = qtdemux->streams[n];
2937 /* aligning reference stream again might lead to backing up to yet another
2938 * keyframe (due to timestamp rounding issues),
2939 * potentially putting more load on downstream; so let's try to avoid */
2940 if (str == ref_str) {
2941 seg_idx = ref_seg_idx;
2942 seg = &str->segments[seg_idx];
2943 k_index = ref_k_index;
2944 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
2945 "sample at index %d", ref_str->segment_index, k_index);
2947 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
2948 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
2950 /* segment not found, continue with normal flow */
2954 /* get segment and time in the segment */
2955 seg = &str->segments[seg_idx];
2956 seg_time = k_pos - seg->time;
2958 /* get the media time in the segment */
2959 media_start = seg->media_start + seg_time;
2961 /* get the index of the sample with media time */
2962 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
2963 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
2964 GST_TIME_ARGS (media_start), index);
2966 /* find previous keyframe */
2967 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
2970 /* Remember until where we want to go */
2971 str->to_sample = str->from_sample - 1;
2972 /* Define our time position */
2973 str->time_position =
2974 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
2975 str->timescale) - seg->media_start) + seg->time;
2976 /* Now seek back in time */
2977 gst_qtdemux_move_stream (qtdemux, str, k_index);
2978 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
2979 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
2980 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
2986 return GST_FLOW_UNEXPECTED;
2989 /* activate the given segment number @seg_idx of @stream at time @offset.
2990 * @offset is an absolute global position over all the segments.
2992 * This will push out a NEWSEGMENT event with the right values and
2993 * position the stream index to the first decodable sample before
2997 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
2998 guint32 seg_idx, guint64 offset)
3001 QtDemuxSegment *segment;
3002 guint32 index, kf_index;
3004 guint64 start, stop, time;
3007 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3010 /* update the current segment */
3011 stream->segment_index = seg_idx;
3013 /* get the segment */
3014 segment = &stream->segments[seg_idx];
3016 if (G_UNLIKELY (offset < segment->time)) {
3017 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3022 /* segment lies beyond total indicated duration */
3023 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3024 segment->time > qtdemux->segment.duration)) {
3025 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3026 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3031 /* get time in this segment */
3032 seg_time = offset - segment->time;
3034 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3035 GST_TIME_ARGS (seg_time));
3037 if (G_UNLIKELY (seg_time > segment->duration)) {
3038 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3039 GST_TIME_ARGS (segment->duration));
3043 /* qtdemux->segment.stop is in outside-time-realm, whereas
3044 * segment->media_stop is in track-time-realm.
3046 * In order to compare the two, we need to bring segment.stop
3047 * into the track-time-realm */
3049 stop = qtdemux->segment.stop;
3051 stop = qtdemux->segment.duration;
3053 stop = segment->media_stop;
3056 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3058 if (qtdemux->segment.rate >= 0) {
3059 start = MIN (segment->media_start + seg_time, stop);
3062 if (segment->media_start >= qtdemux->segment.start) {
3063 start = segment->media_start;
3064 time = segment->time;
3066 start = qtdemux->segment.start;
3067 time = segment->time + (qtdemux->segment.start - segment->media_start);
3070 start = MAX (segment->media_start, qtdemux->segment.start);
3071 stop = MIN (segment->media_start + seg_time, stop);
3074 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3075 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3076 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3078 /* combine global rate with that of the segment */
3079 rate = segment->rate * qtdemux->segment.rate;
3081 /* update the segment values used for clipping */
3082 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
3083 gst_segment_set_newsegment (&stream->segment, FALSE, rate, GST_FORMAT_TIME,
3086 /* now prepare and send the segment */
3088 event = gst_event_new_new_segment (FALSE, rate, GST_FORMAT_TIME,
3090 gst_pad_push_event (stream->pad, event);
3091 /* assume we can send more data now */
3092 stream->last_ret = GST_FLOW_OK;
3093 /* clear to send tags on this pad now */
3094 gst_qtdemux_push_tags (qtdemux, stream);
3097 /* and move to the keyframe before the indicated media time of the
3099 if (qtdemux->segment.rate >= 0) {
3100 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3101 stream->to_sample = G_MAXUINT32;
3102 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3103 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3104 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3105 GST_SECOND, stream->timescale)));
3107 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3108 stream->to_sample = index;
3109 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3110 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3111 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3112 GST_SECOND, stream->timescale)));
3115 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3116 * encountered an error and printed a message so we return appropriately */
3120 /* we're at the right spot */
3121 if (index == stream->sample_index) {
3122 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3126 /* find keyframe of the target index */
3127 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3130 /* indent does stupid stuff with stream->samples[].timestamp */
3132 /* if we move forwards, we don't have to go back to the previous
3133 * keyframe since we already sent that. We can also just jump to
3134 * the keyframe right before the target index if there is one. */
3135 if (index > stream->sample_index) {
3136 /* moving forwards check if we move past a keyframe */
3137 if (kf_index > stream->sample_index) {
3138 GST_DEBUG_OBJECT (qtdemux,
3139 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3140 GST_TIME_ARGS (gst_util_uint64_scale (
3141 stream->samples[kf_index].timestamp,
3142 GST_SECOND, stream->timescale)));
3143 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3145 GST_DEBUG_OBJECT (qtdemux,
3146 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3147 " already sent", kf_index,
3148 GST_TIME_ARGS (gst_util_uint64_scale (
3149 stream->samples[kf_index].timestamp,
3150 GST_SECOND, stream->timescale)));
3153 GST_DEBUG_OBJECT (qtdemux,
3154 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3155 GST_TIME_ARGS (gst_util_uint64_scale (
3156 stream->samples[kf_index].timestamp,
3157 GST_SECOND, stream->timescale)));
3158 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3166 /* prepare to get the current sample of @stream, getting essential values.
3168 * This function will also prepare and send the segment when needed.
3170 * Return FALSE if the stream is EOS.
3173 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3174 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp,
3175 guint64 * duration, gboolean * keyframe)
3177 QtDemuxSample *sample;
3178 guint64 time_position;
3181 g_return_val_if_fail (stream != NULL, FALSE);
3183 time_position = stream->time_position;
3184 if (G_UNLIKELY (time_position == -1))
3187 seg_idx = stream->segment_index;
3188 if (G_UNLIKELY (seg_idx == -1)) {
3189 /* find segment corresponding to time_position if we are looking
3191 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3193 /* nothing found, we're really eos */
3198 /* different segment, activate it, sample_index will be set. */
3199 if (G_UNLIKELY (stream->segment_index != seg_idx))
3200 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3202 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3203 stream->sample_index, stream->n_samples);
3205 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3208 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3209 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3210 stream->sample_index);
3214 /* now get the info for the sample we're at */
3215 sample = &stream->samples[stream->sample_index];
3217 *timestamp = QTSAMPLE_PTS (stream, sample);
3218 *offset = sample->offset;
3219 *size = sample->size;
3220 *duration = QTSAMPLE_DUR_PTS (stream, sample, *timestamp);
3221 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3228 stream->time_position = -1;
3233 /* move to the next sample in @stream.
3235 * Moves to the next segment when needed.
3238 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3240 QtDemuxSample *sample;
3241 QtDemuxSegment *segment;
3243 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3244 /* Mark the stream as EOS */
3245 GST_DEBUG_OBJECT (qtdemux,
3246 "reached max allowed sample %u, mark EOS", stream->to_sample);
3247 stream->time_position = -1;
3251 /* move to next sample */
3252 stream->sample_index++;
3254 /* get current segment */
3255 segment = &stream->segments[stream->segment_index];
3257 /* reached the last sample, we need the next segment */
3258 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3261 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3262 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3263 stream->sample_index);
3267 /* get next sample */
3268 sample = &stream->samples[stream->sample_index];
3270 /* see if we are past the segment */
3271 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3272 GST_SECOND, stream->timescale) >= segment->media_stop))
3275 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3276 stream->timescale) >= segment->media_start) {
3277 /* inside the segment, update time_position, looks very familiar to
3278 * GStreamer segments, doesn't it? */
3279 stream->time_position =
3280 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3281 stream->timescale) - segment->media_start) + segment->time;
3283 /* not yet in segment, time does not yet increment. This means
3284 * that we are still prerolling keyframes to the decoder so it can
3285 * decode the first sample of the segment. */
3286 stream->time_position = segment->time;
3290 /* move to the next segment */
3293 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3295 if (stream->segment_index == stream->n_segments - 1) {
3296 /* are we at the end of the last segment, we're EOS */
3297 stream->time_position = -1;
3299 /* else we're only at the end of the current segment */
3300 stream->time_position = segment->stop_time;
3302 /* make sure we select a new segment */
3303 stream->segment_index = -1;
3308 gst_qtdemux_sync_streams (GstQTDemux * demux)
3312 if (demux->n_streams <= 1)
3315 for (i = 0; i < demux->n_streams; i++) {
3316 QtDemuxStream *stream;
3317 GstClockTime end_time;
3319 stream = demux->streams[i];
3324 /* TODO advance time on subtitle streams here, if any some day */
3326 /* some clips/trailers may have unbalanced streams at the end,
3327 * so send EOS on shorter stream to prevent stalling others */
3329 /* do not mess with EOS if SEGMENT seeking */
3330 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3333 if (demux->pullbased) {
3334 /* loop mode is sample time based */
3335 if (stream->time_position != -1)
3338 /* push mode is byte position based */
3339 if (stream->n_samples &&
3340 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3344 if (stream->sent_eos)
3347 /* only act if some gap */
3348 end_time = stream->segments[stream->n_segments - 1].stop_time;
3349 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3350 ", stream end: %" GST_TIME_FORMAT,
3351 GST_TIME_ARGS (demux->segment.last_stop), GST_TIME_ARGS (end_time));
3352 if (end_time + 2 * GST_SECOND < demux->segment.last_stop) {
3353 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3354 GST_PAD_NAME (stream->pad));
3355 stream->sent_eos = TRUE;
3356 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3361 /* UNEXPECTED and NOT_LINKED need to be combined. This means that we return:
3363 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3364 * GST_FLOW_UNEXPECTED: when all pads UNEXPECTED or NOT_LINKED.
3366 static GstFlowReturn
3367 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3371 gboolean unexpected = FALSE, not_linked = TRUE;
3373 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3375 /* store the value */
3376 stream->last_ret = ret;
3378 /* any other error that is not-linked or eos can be returned right away */
3379 if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
3382 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3383 for (i = 0; i < demux->n_streams; i++) {
3384 QtDemuxStream *ostream = demux->streams[i];
3386 ret = ostream->last_ret;
3388 /* no unexpected or unlinked, return */
3389 if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
3392 /* we check to see if we have at least 1 unexpected or all unlinked */
3393 unexpected |= (ret == GST_FLOW_UNEXPECTED);
3394 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3397 /* when we get here, we all have unlinked or unexpected */
3399 ret = GST_FLOW_NOT_LINKED;
3400 else if (unexpected)
3401 ret = GST_FLOW_UNEXPECTED;
3403 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3407 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3408 * completely cliped */
3410 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3413 gint64 start, stop, cstart, cstop, diff;
3414 GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
3417 gint num_rate, denom_rate;
3421 data = GST_BUFFER_DATA (buf);
3422 size = GST_BUFFER_SIZE (buf);
3424 /* depending on the type, setup the clip parameters */
3425 if (stream->subtype == FOURCC_soun) {
3426 frame_size = stream->bytes_per_frame;
3427 num_rate = GST_SECOND;
3428 denom_rate = (gint) stream->rate;
3430 } else if (stream->subtype == FOURCC_vide) {
3432 num_rate = stream->fps_n;
3433 denom_rate = stream->fps_d;
3438 /* we can only clip if we have a valid timestamp */
3439 timestamp = GST_BUFFER_TIMESTAMP (buf);
3440 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
3443 if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf))) {
3444 duration = GST_BUFFER_DURATION (buf);
3447 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3451 stop = start + duration;
3453 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3454 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3457 /* see if some clipping happened */
3458 diff = cstart - start;
3464 /* bring clipped time to samples and to bytes */
3465 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3468 GST_DEBUG_OBJECT (qtdemux,
3469 "clipping start to %" GST_TIME_FORMAT " %"
3470 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3476 diff = stop - cstop;
3481 /* bring clipped time to samples and then to bytes */
3482 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3484 GST_DEBUG_OBJECT (qtdemux,
3485 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3486 " bytes", GST_TIME_ARGS (cstop), diff);
3491 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3492 GST_BUFFER_DURATION (buf) = duration;
3493 GST_BUFFER_SIZE (buf) = size;
3494 GST_BUFFER_DATA (buf) = data;
3498 /* dropped buffer */
3501 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3506 GST_DEBUG_OBJECT (qtdemux, "no timestamp on buffer");
3511 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3512 gst_buffer_unref (buf);
3517 /* the input buffer metadata must be writable,
3518 * but time/duration etc not yet set and need not be preserved */
3520 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3524 guint size, nsize = 0;
3527 data = GST_BUFFER_DATA (buf);
3528 size = GST_BUFFER_SIZE (buf);
3530 /* not many cases for now */
3531 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3532 /* send a one time dvd clut event */
3533 if (stream->pending_event && stream->pad)
3534 gst_pad_push_event (stream->pad, stream->pending_event);
3535 stream->pending_event = NULL;
3536 /* no further processing needed */
3537 stream->need_process = FALSE;
3540 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
3544 if (G_LIKELY (size >= 2)) {
3545 nsize = GST_READ_UINT16_BE (data);
3546 nsize = MIN (nsize, size - 2);
3549 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%d", nsize, size);
3551 /* takes care of UTF-8 validation or UTF-16 recognition,
3552 * no other encoding expected */
3553 str = gst_tag_freeform_string_to_utf8 ((gchar *) data + 2, nsize, NULL);
3555 gst_buffer_unref (buf);
3556 buf = gst_buffer_new ();
3557 GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = (guint8 *) str;
3558 GST_BUFFER_SIZE (buf) = strlen (str);
3560 /* may be 0-size subtitle, which is also sent to keep pipeline going */
3561 GST_BUFFER_DATA (buf) = data + 2;
3562 GST_BUFFER_SIZE (buf) = nsize;
3565 /* FIXME ? convert optional subsequent style info to markup */
3570 /* Sets a buffer's attributes properly and pushes it downstream.
3571 * Also checks for additional actions and custom processing that may
3572 * need to be done first.
3575 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3576 QtDemuxStream * stream, GstBuffer * buf,
3577 guint64 timestamp, guint64 duration, gboolean keyframe, guint64 position,
3578 guint64 byte_position)
3580 GstFlowReturn ret = GST_FLOW_OK;
3582 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
3585 url = g_strndup ((gchar *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
3586 if (url != NULL && strlen (url) != 0) {
3587 /* we have RTSP redirect now */
3588 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3589 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
3590 gst_structure_new ("redirect",
3591 "new-location", G_TYPE_STRING, url, NULL)));
3592 qtdemux->posted_redirect = TRUE;
3594 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
3600 /* position reporting */
3601 if (qtdemux->segment.rate >= 0) {
3602 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, position);
3603 gst_qtdemux_sync_streams (qtdemux);
3606 if (G_UNLIKELY (!stream->pad)) {
3607 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
3608 gst_buffer_unref (buf);
3612 /* send out pending buffers */
3613 while (stream->buffers) {
3614 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
3616 if (G_UNLIKELY (stream->discont)) {
3617 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3618 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
3619 stream->discont = FALSE;
3621 gst_buffer_set_caps (buffer, stream->caps);
3623 gst_pad_push (stream->pad, buffer);
3625 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
3628 /* we're going to modify the metadata */
3629 buf = gst_buffer_make_metadata_writable (buf);
3631 if (G_UNLIKELY (stream->need_process))
3632 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
3634 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3635 GST_BUFFER_DURATION (buf) = duration;
3636 GST_BUFFER_OFFSET (buf) = -1;
3637 GST_BUFFER_OFFSET_END (buf) = -1;
3639 if (G_UNLIKELY (stream->padding)) {
3640 GST_BUFFER_DATA (buf) += stream->padding;
3641 GST_BUFFER_SIZE (buf) -= stream->padding;
3644 if (G_UNLIKELY (qtdemux->element_index)) {
3645 GstClockTime stream_time;
3648 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
3650 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
3651 GST_LOG_OBJECT (qtdemux,
3652 "adding association %" GST_TIME_FORMAT "-> %"
3653 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
3654 gst_index_add_association (qtdemux->element_index,
3656 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
3657 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
3658 GST_FORMAT_BYTES, byte_position, NULL);
3662 if (stream->need_clip)
3663 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
3665 if (G_UNLIKELY (buf == NULL))
3668 if (G_UNLIKELY (stream->discont)) {
3669 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3670 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3671 stream->discont = FALSE;
3675 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3677 gst_buffer_set_caps (buf, stream->caps);
3679 GST_LOG_OBJECT (qtdemux,
3680 "Pushing buffer with time %" GST_TIME_FORMAT ", duration %"
3681 GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
3682 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
3684 ret = gst_pad_push (stream->pad, buf);
3690 static GstFlowReturn
3691 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
3693 GstFlowReturn ret = GST_FLOW_OK;
3694 GstBuffer *buf = NULL;
3695 QtDemuxStream *stream;
3698 guint64 timestamp = GST_CLOCK_TIME_NONE;
3699 guint64 duration = 0;
3700 gboolean keyframe = FALSE;
3705 gst_qtdemux_push_pending_newsegment (qtdemux);
3707 /* Figure out the next stream sample to output, min_time is expressed in
3708 * global time and runs over the edit list segments. */
3709 min_time = G_MAXUINT64;
3711 for (i = 0; i < qtdemux->n_streams; i++) {
3714 stream = qtdemux->streams[i];
3715 position = stream->time_position;
3717 /* position of -1 is EOS */
3718 if (position != -1 && position < min_time) {
3719 min_time = position;
3724 if (G_UNLIKELY (index == -1)) {
3725 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
3729 /* check for segment end */
3730 if (G_UNLIKELY (qtdemux->segment.stop != -1
3731 && qtdemux->segment.stop < min_time)) {
3732 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
3736 stream = qtdemux->streams[index];
3738 /* fetch info for the current sample of this stream */
3739 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
3740 &size, ×tamp, &duration, &keyframe)))
3743 GST_LOG_OBJECT (qtdemux,
3744 "pushing from stream %d, offset %" G_GUINT64_FORMAT
3745 ", size %d, timestamp=%" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
3746 index, offset, size, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
3748 /* hmm, empty sample, skip and move to next sample */
3749 if (G_UNLIKELY (size <= 0))
3752 /* last pushed sample was out of boundary, goto next sample */
3753 if (G_UNLIKELY (stream->last_ret == GST_FLOW_UNEXPECTED))
3756 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
3759 ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
3760 if (G_UNLIKELY (ret != GST_FLOW_OK))
3763 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
3764 timestamp, duration, keyframe, min_time, offset);
3767 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
3768 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
3769 * we have no more data for the pad to push */
3770 if (ret == GST_FLOW_UNEXPECTED)
3774 gst_qtdemux_advance_sample (qtdemux, stream);
3782 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
3783 ret = GST_FLOW_UNEXPECTED;
3788 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
3789 /* EOS will be raised if all are EOS */
3796 gst_qtdemux_loop (GstPad * pad)
3798 GstQTDemux *qtdemux;
3802 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
3804 cur_offset = qtdemux->offset;
3805 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
3806 cur_offset, qtdemux->state);
3808 switch (qtdemux->state) {
3809 case QTDEMUX_STATE_INITIAL:
3810 case QTDEMUX_STATE_HEADER:
3811 ret = gst_qtdemux_loop_state_header (qtdemux);
3813 case QTDEMUX_STATE_MOVIE:
3814 ret = gst_qtdemux_loop_state_movie (qtdemux);
3815 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_UNEXPECTED) {
3816 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
3824 /* if something went wrong, pause */
3825 if (ret != GST_FLOW_OK)
3829 gst_object_unref (qtdemux);
3835 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3836 (NULL), ("streaming stopped, invalid state"));
3837 qtdemux->segment_running = FALSE;
3838 gst_pad_pause_task (pad);
3839 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3844 const gchar *reason = gst_flow_get_name (ret);
3846 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
3848 qtdemux->segment_running = FALSE;
3849 gst_pad_pause_task (pad);
3851 /* fatal errors need special actions */
3853 if (ret == GST_FLOW_UNEXPECTED) {
3854 if (qtdemux->n_streams == 0) {
3855 /* we have no streams, post an error */
3856 gst_qtdemux_post_no_playable_stream_error (qtdemux);
3858 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3861 /* FIXME: I am not sure this is the right fix. If the sinks are
3862 * supposed to detect the segment is complete and accumulate
3863 * automatically, it does not seem to work here. Need more work */
3864 qtdemux->segment_running = TRUE;
3866 if ((stop = qtdemux->segment.stop) == -1)
3867 stop = qtdemux->segment.duration;
3869 if (qtdemux->segment.rate >= 0) {
3870 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
3871 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3872 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3873 GST_FORMAT_TIME, stop));
3875 /* For Reverse Playback */
3876 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
3877 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3878 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3879 GST_FORMAT_TIME, qtdemux->segment.start));
3882 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
3883 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3885 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
3886 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3887 (NULL), ("streaming stopped, reason %s", reason));
3888 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3897 * Returns the size of the first entry at the current offset.
3898 * If -1, there are none (which means EOS or empty file).
3901 next_entry_size (GstQTDemux * demux)
3903 QtDemuxStream *stream;
3906 guint64 smalloffs = (guint64) - 1;
3907 QtDemuxSample *sample;
3909 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
3912 for (i = 0; i < demux->n_streams; i++) {
3913 stream = demux->streams[i];
3915 if (stream->sample_index == -1)
3916 stream->sample_index = 0;
3918 if (stream->sample_index >= stream->n_samples) {
3919 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
3923 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
3924 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
3925 stream->sample_index);
3929 sample = &stream->samples[stream->sample_index];
3931 GST_LOG_OBJECT (demux,
3932 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3933 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
3934 sample->offset, sample->size);
3936 if (((smalloffs == -1)
3937 || (sample->offset < smalloffs)) && (sample->size)) {
3939 smalloffs = sample->offset;
3943 GST_LOG_OBJECT (demux,
3944 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
3945 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
3950 stream = demux->streams[smallidx];
3951 sample = &stream->samples[stream->sample_index];
3953 if (sample->offset >= demux->offset) {
3954 demux->todrop = sample->offset - demux->offset;
3955 return sample->size + demux->todrop;
3958 GST_DEBUG_OBJECT (demux,
3959 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
3964 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
3966 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
3968 gst_element_post_message (GST_ELEMENT_CAST (demux),
3969 gst_message_new_element (GST_OBJECT_CAST (demux),
3970 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
3974 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
3979 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
3982 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
3983 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
3984 GST_SEEK_TYPE_NONE, -1);
3986 res = gst_pad_push_event (demux->sinkpad, event);
3991 /* check for seekable upstream, above and beyond a mere query */
3993 gst_qtdemux_check_seekability (GstQTDemux * demux)
3996 gboolean seekable = FALSE;
3997 gint64 start = -1, stop = -1;
3999 if (demux->upstream_size)
4002 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4003 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4004 GST_DEBUG_OBJECT (demux, "seeking query failed");
4008 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4010 /* try harder to query upstream size if we didn't get it the first time */
4011 if (seekable && stop == -1) {
4012 GstFormat fmt = GST_FORMAT_BYTES;
4014 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4015 gst_pad_query_peer_duration (demux->sinkpad, &fmt, &stop);
4018 /* if upstream doesn't know the size, it's likely that it's not seekable in
4019 * practice even if it technically may be seekable */
4020 if (seekable && (start != 0 || stop <= start)) {
4021 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4026 gst_query_unref (query);
4028 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4029 G_GUINT64_FORMAT ")", seekable, start, stop);
4030 demux->upstream_seekable = seekable;
4031 demux->upstream_size = seekable ? stop : -1;
4034 /* FIXME, unverified after edit list updates */
4035 static GstFlowReturn
4036 gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
4039 GstFlowReturn ret = GST_FLOW_OK;
4041 demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad));
4043 gst_adapter_push (demux->adapter, inbuf);
4045 /* we never really mean to buffer that much */
4046 if (demux->neededbytes == -1)
4049 GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
4050 inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
4052 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4053 (ret == GST_FLOW_OK)) {
4055 GST_DEBUG_OBJECT (demux,
4056 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4057 demux->state, demux->neededbytes, demux->offset);
4059 switch (demux->state) {
4060 case QTDEMUX_STATE_INITIAL:{
4065 gst_qtdemux_check_seekability (demux);
4067 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
4069 /* get fourcc/length, set neededbytes */
4070 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4072 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4073 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4075 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4076 (_("This file is invalid and cannot be played.")),
4077 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4078 GST_FOURCC_ARGS (fourcc)));
4079 ret = GST_FLOW_ERROR;
4082 if (fourcc == FOURCC_mdat) {
4083 if (demux->n_streams > 0) {
4084 /* we have the headers, start playback */
4085 demux->state = QTDEMUX_STATE_MOVIE;
4086 demux->neededbytes = next_entry_size (demux);
4087 demux->mdatleft = size;
4089 /* Only post, event on pads is done after newsegment */
4090 qtdemux_post_global_tags (demux);
4093 /* no headers yet, try to get them */
4096 guint64 old, target;
4099 old = demux->offset;
4100 target = old + size;
4102 /* try to jump over the atom with a seek */
4103 /* only bother if it seems worth doing so,
4104 * and avoids possible upstream/server problems */
4105 if (demux->upstream_seekable &&
4106 demux->upstream_size > 4 * (1 << 20)) {
4107 res = qtdemux_seek_offset (demux, target);
4109 GST_DEBUG_OBJECT (demux, "skipping seek");
4114 GST_DEBUG_OBJECT (demux, "seek success");
4115 /* remember the offset fo the first mdat so we can seek back to it
4116 * after we have the headers */
4117 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4118 demux->first_mdat = old;
4119 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4122 /* seek worked, continue reading */
4123 demux->offset = target;
4124 demux->neededbytes = 16;
4125 demux->state = QTDEMUX_STATE_INITIAL;
4127 /* seek failed, need to buffer */
4128 demux->offset = old;
4129 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4130 /* there may be multiple mdat (or alike) buffers */
4132 if (demux->mdatbuffer)
4133 bs = GST_BUFFER_SIZE (demux->mdatbuffer);
4136 if (size + bs > 10 * (1 << 20))
4138 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4139 demux->neededbytes = size;
4140 if (!demux->mdatbuffer)
4141 demux->mdatoffset = demux->offset;
4144 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4145 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4146 (_("This file is invalid and cannot be played.")),
4147 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4148 GST_FOURCC_ARGS (fourcc), size));
4149 ret = GST_FLOW_ERROR;
4152 /* this means we already started buffering and still no moov header,
4153 * let's continue buffering everything till we get moov */
4154 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
4156 demux->neededbytes = size;
4157 demux->state = QTDEMUX_STATE_HEADER;
4161 case QTDEMUX_STATE_HEADER:{
4165 GST_DEBUG_OBJECT (demux, "In header");
4167 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
4169 /* parse the header */
4170 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4172 if (fourcc == FOURCC_moov) {
4173 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4175 demux->got_moov = TRUE;
4177 /* prepare newsegment to send when streaming actually starts */
4178 if (!demux->pending_newsegment) {
4179 demux->pending_newsegment =
4180 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
4181 0, GST_CLOCK_TIME_NONE, 0);
4184 qtdemux_parse_moov (demux, data, demux->neededbytes);
4185 qtdemux_node_dump (demux, demux->moov_node);
4186 qtdemux_parse_tree (demux);
4187 qtdemux_expose_streams (demux);
4189 g_node_destroy (demux->moov_node);
4190 demux->moov_node = NULL;
4191 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4192 } else if (fourcc == FOURCC_moof) {
4193 if (demux->got_moov && demux->fragmented) {
4194 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4195 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4196 demux->offset, NULL)) {
4197 ret = GST_FLOW_ERROR;
4201 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4203 } else if (fourcc == FOURCC_ftyp) {
4204 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4205 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4206 } else if (fourcc == FOURCC_uuid) {
4207 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4208 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4210 GST_WARNING_OBJECT (demux,
4211 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4212 GST_FOURCC_ARGS (fourcc));
4213 /* Let's jump that one and go back to initial state */
4216 if (demux->mdatbuffer && demux->n_streams) {
4217 /* the mdat was before the header */
4218 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4219 demux->n_streams, demux->mdatbuffer);
4220 /* restore our adapter/offset view of things with upstream;
4221 * put preceding buffered data ahead of current moov data.
4222 * This should also handle evil mdat, moov, mdat cases and alike */
4223 gst_adapter_clear (demux->adapter);
4224 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4225 demux->mdatbuffer = NULL;
4226 demux->offset = demux->mdatoffset;
4227 demux->neededbytes = next_entry_size (demux);
4228 demux->state = QTDEMUX_STATE_MOVIE;
4229 demux->mdatleft = gst_adapter_available (demux->adapter);
4231 /* Only post, event on pads is done after newsegment */
4232 qtdemux_post_global_tags (demux);
4235 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4236 gst_adapter_flush (demux->adapter, demux->neededbytes);
4238 if (demux->got_moov && demux->first_mdat != -1) {
4241 /* we need to seek back */
4242 res = qtdemux_seek_offset (demux, demux->first_mdat);
4244 demux->offset = demux->first_mdat;
4246 GST_DEBUG_OBJECT (demux, "Seek back failed");
4249 demux->offset += demux->neededbytes;
4251 demux->neededbytes = 16;
4252 demux->state = QTDEMUX_STATE_INITIAL;
4257 case QTDEMUX_STATE_BUFFER_MDAT:{
4260 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4262 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4263 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4264 GST_FOURCC_ARGS (QT_FOURCC (GST_BUFFER_DATA (buf) + 4)));
4265 if (demux->mdatbuffer)
4266 demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
4268 demux->mdatbuffer = buf;
4269 demux->offset += demux->neededbytes;
4270 demux->neededbytes = 16;
4271 demux->state = QTDEMUX_STATE_INITIAL;
4272 gst_qtdemux_post_progress (demux, 1, 1);
4276 case QTDEMUX_STATE_MOVIE:{
4278 QtDemuxStream *stream = NULL;
4279 QtDemuxSample *sample;
4281 guint64 timestamp, duration, position;
4284 GST_DEBUG_OBJECT (demux,
4285 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4287 if (demux->fragmented) {
4288 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4290 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4291 /* if needed data starts within this atom,
4292 * then it should not exceed this atom */
4293 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4294 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4295 (_("This file is invalid and cannot be played.")),
4296 ("sample data crosses atom boundary"));
4297 ret = GST_FLOW_ERROR;
4300 demux->mdatleft -= demux->neededbytes;
4302 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4303 /* so we are dropping more than left in this atom */
4304 demux->todrop -= demux->mdatleft;
4305 demux->neededbytes -= demux->mdatleft;
4306 demux->mdatleft = 0;
4307 /* need to resume atom parsing so we do not miss any other pieces */
4308 demux->state = QTDEMUX_STATE_INITIAL;
4309 demux->neededbytes = 16;
4314 if (demux->todrop) {
4315 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4316 gst_adapter_flush (demux->adapter, demux->todrop);
4317 demux->neededbytes -= demux->todrop;
4318 demux->offset += demux->todrop;
4322 /* initial newsegment sent here after having added pads,
4323 * possible others in sink_event */
4324 if (G_UNLIKELY (demux->pending_newsegment)) {
4325 gst_qtdemux_push_event (demux, demux->pending_newsegment);
4326 demux->pending_newsegment = NULL;
4327 /* clear to send tags on all streams */
4328 for (i = 0; i < demux->n_streams; i++) {
4329 gst_qtdemux_push_tags (demux, demux->streams[i]);
4333 /* Figure out which stream this is packet belongs to */
4334 for (i = 0; i < demux->n_streams; i++) {
4335 stream = demux->streams[i];
4336 if (stream->sample_index >= stream->n_samples)
4338 GST_LOG_OBJECT (demux,
4339 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4340 " / size:%d)", i, stream->sample_index,
4341 stream->samples[stream->sample_index].offset,
4342 stream->samples[stream->sample_index].size);
4344 if (stream->samples[stream->sample_index].offset == demux->offset)
4348 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4349 goto unknown_stream;
4351 /* Put data in a buffer, set timestamps, caps, ... */
4352 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4353 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4354 GST_FOURCC_ARGS (stream->fourcc));
4356 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4358 sample = &stream->samples[stream->sample_index];
4360 position = QTSAMPLE_DTS (stream, sample);
4361 timestamp = QTSAMPLE_PTS (stream, sample);
4362 duration = QTSAMPLE_DUR_DTS (stream, sample, position);
4363 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4365 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4366 timestamp, duration, keyframe, position, demux->offset);
4369 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4371 stream->sample_index++;
4373 /* update current offset and figure out size of next buffer */
4374 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4375 demux->offset, demux->neededbytes);
4376 demux->offset += demux->neededbytes;
4377 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4380 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4381 if (demux->fragmented) {
4382 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4383 /* there may be more to follow, only finish this atom */
4384 demux->todrop = demux->mdatleft;
4385 demux->neededbytes = demux->todrop;
4397 /* when buffering movie data, at least show user something is happening */
4398 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4399 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4400 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4401 demux->neededbytes);
4404 gst_object_unref (demux);
4411 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4412 ret = GST_FLOW_ERROR;
4417 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4418 ret = GST_FLOW_UNEXPECTED;
4423 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4424 (NULL), ("qtdemuxer invalid state %d", demux->state));
4425 ret = GST_FLOW_ERROR;
4430 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4431 (NULL), ("no 'moov' atom within the first 10 MB"));
4432 ret = GST_FLOW_ERROR;
4438 qtdemux_sink_activate (GstPad * sinkpad)
4440 if (gst_pad_check_pull_range (sinkpad))
4441 return gst_pad_activate_pull (sinkpad, TRUE);
4443 return gst_pad_activate_push (sinkpad, TRUE);
4447 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
4449 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
4452 demux->pullbased = TRUE;
4453 demux->segment_running = TRUE;
4454 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4457 demux->segment_running = FALSE;
4458 return gst_pad_stop_task (sinkpad);
4463 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
4465 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
4467 demux->pullbased = FALSE;
4474 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4476 return g_malloc (items * size);
4480 qtdemux_zfree (void *opaque, void *addr)
4486 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4492 z = g_new0 (z_stream, 1);
4493 z->zalloc = qtdemux_zalloc;
4494 z->zfree = qtdemux_zfree;
4497 z->next_in = z_buffer;
4498 z->avail_in = z_length;
4500 buffer = (guint8 *) g_malloc (length);
4501 ret = inflateInit (z);
4502 while (z->avail_in > 0) {
4503 if (z->avail_out == 0) {
4505 buffer = (guint8 *) g_realloc (buffer, length);
4506 z->next_out = buffer + z->total_out;
4507 z->avail_out = 1024;
4509 ret = inflate (z, Z_SYNC_FLUSH);
4513 if (ret != Z_STREAM_END) {
4514 g_warning ("inflate() returned %d", ret);
4520 #endif /* HAVE_ZLIB */
4523 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4527 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4529 /* counts as header data */
4530 qtdemux->header_size += length;
4532 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4533 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4535 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4541 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4542 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4543 if (dcom == NULL || cmvd == NULL)
4544 goto invalid_compression;
4546 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4549 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4550 guint uncompressed_length;
4551 guint compressed_length;
4554 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4555 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4556 GST_LOG ("length = %u", uncompressed_length);
4559 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4560 compressed_length, uncompressed_length);
4562 qtdemux->moov_node_compressed = qtdemux->moov_node;
4563 qtdemux->moov_node = g_node_new (buf);
4565 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4566 uncompressed_length);
4569 #endif /* HAVE_ZLIB */
4571 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4572 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
4579 invalid_compression:
4581 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
4587 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
4590 while (G_UNLIKELY (buf < end)) {
4594 if (G_UNLIKELY (buf + 4 > end)) {
4595 GST_LOG_OBJECT (qtdemux, "buffer overrun");
4598 len = QT_UINT32 (buf);
4599 if (G_UNLIKELY (len == 0)) {
4600 GST_LOG_OBJECT (qtdemux, "empty container");
4603 if (G_UNLIKELY (len < 8)) {
4604 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
4607 if (G_UNLIKELY (len > (end - buf))) {
4608 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
4609 (gint) (end - buf));
4613 child = g_node_new ((guint8 *) buf);
4614 g_node_append (node, child);
4615 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
4616 qtdemux_parse_node (qtdemux, child, buf, len);
4624 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
4627 int len = QT_UINT32 (xdxt->data);
4628 guint8 *buf = xdxt->data;
4629 guint8 *end = buf + len;
4632 /* skip size and type */
4640 size = QT_UINT32 (buf);
4641 type = QT_FOURCC (buf + 4);
4643 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
4645 if (buf + size > end || size <= 0)
4651 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
4652 GST_FOURCC_ARGS (type));
4656 buffer = gst_buffer_new_and_alloc (size);
4657 memcpy (GST_BUFFER_DATA (buffer), buf, size);
4658 stream->buffers = g_slist_append (stream->buffers, buffer);
4659 GST_LOG_OBJECT (qtdemux, "parsing theora header");
4662 buffer = gst_buffer_new_and_alloc (size);
4663 memcpy (GST_BUFFER_DATA (buffer), buf, size);
4664 stream->buffers = g_slist_append (stream->buffers, buffer);
4665 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
4668 buffer = gst_buffer_new_and_alloc (size);
4669 memcpy (GST_BUFFER_DATA (buffer), buf, size);
4670 stream->buffers = g_slist_append (stream->buffers, buffer);
4671 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
4674 GST_WARNING_OBJECT (qtdemux,
4675 "unknown theora cookie %" GST_FOURCC_FORMAT,
4676 GST_FOURCC_ARGS (type));
4685 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
4689 guint32 node_length = 0;
4690 const QtNodeType *type;
4693 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
4695 if (G_UNLIKELY (length < 8))
4696 goto not_enough_data;
4698 node_length = QT_UINT32 (buffer);
4699 fourcc = QT_FOURCC (buffer + 4);
4701 /* ignore empty nodes */
4702 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
4705 type = qtdemux_type_get (fourcc);
4707 end = buffer + length;
4709 GST_LOG_OBJECT (qtdemux,
4710 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
4711 GST_FOURCC_ARGS (fourcc), node_length, type->name);
4713 if (node_length > length)
4714 goto broken_atom_size;
4716 if (type->flags & QT_FLAG_CONTAINER) {
4717 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
4722 if (node_length < 20) {
4723 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
4726 GST_DEBUG_OBJECT (qtdemux,
4727 "parsing stsd (sample table, sample description) atom");
4728 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
4738 /* also read alac (or whatever) in stead of mp4a in the following,
4739 * since a similar layout is used in other cases as well */
4740 if (fourcc == FOURCC_mp4a)
4745 /* There are two things we might encounter here: a true mp4a atom, and
4746 an mp4a entry in an stsd atom. The latter is what we're interested
4747 in, and it looks like an atom, but isn't really one. The true mp4a
4748 atom is short, so we detect it based on length here. */
4749 if (length < min_size) {
4750 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
4751 GST_FOURCC_ARGS (fourcc));
4755 /* 'version' here is the sound sample description version. Types 0 and
4756 1 are documented in the QTFF reference, but type 2 is not: it's
4757 described in Apple header files instead (struct SoundDescriptionV2
4759 version = QT_UINT16 (buffer + 16);
4761 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
4762 GST_FOURCC_ARGS (fourcc), version);
4764 /* parse any esds descriptors */
4776 GST_WARNING_OBJECT (qtdemux,
4777 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
4778 GST_FOURCC_ARGS (fourcc), version);
4783 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4795 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
4796 GST_FOURCC_ARGS (fourcc));
4797 version = QT_UINT32 (buffer + 16);
4798 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
4799 if (1 || version == 0x00000000) {
4800 buf = buffer + 0x32;
4802 /* FIXME Quicktime uses PASCAL string while
4803 * the iso format uses C strings. Check the file
4804 * type before attempting to parse the string here. */
4805 tlen = QT_UINT8 (buf);
4806 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
4808 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
4809 /* the string has a reserved space of 32 bytes so skip
4810 * the remaining 31 */
4812 buf += 4; /* and 4 bytes reserved */
4814 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
4816 qtdemux_parse_container (qtdemux, node, buf, end);
4822 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
4823 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
4828 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
4833 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
4834 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
4842 version = QT_UINT32 (buffer + 12);
4843 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
4850 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
4855 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4860 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
4864 if (!strcmp (type->name, "unknown"))
4865 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
4869 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
4870 GST_FOURCC_ARGS (fourcc));
4876 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4877 (_("This file is corrupt and cannot be played.")),
4878 ("Not enough data for an atom header, got only %u bytes", length));
4883 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4884 (_("This file is corrupt and cannot be played.")),
4885 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
4886 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
4893 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
4897 guint32 child_fourcc;
4899 for (child = g_node_first_child (node); child;
4900 child = g_node_next_sibling (child)) {
4901 buffer = (guint8 *) child->data;
4903 child_fourcc = QT_FOURCC (buffer + 4);
4905 if (G_UNLIKELY (child_fourcc == fourcc)) {
4913 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
4914 GstByteReader * parser)
4918 guint32 child_fourcc, child_len;
4920 for (child = g_node_first_child (node); child;
4921 child = g_node_next_sibling (child)) {
4922 buffer = (guint8 *) child->data;
4924 child_len = QT_UINT32 (buffer);
4925 child_fourcc = QT_FOURCC (buffer + 4);
4927 if (G_UNLIKELY (child_fourcc == fourcc)) {
4928 if (G_UNLIKELY (child_len < (4 + 4)))
4930 /* FIXME: must verify if atom length < parent atom length */
4931 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4939 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
4940 GstByteReader * parser)
4944 guint32 child_fourcc, child_len;
4946 for (child = g_node_next_sibling (node); child;
4947 child = g_node_next_sibling (child)) {
4948 buffer = (guint8 *) child->data;
4950 child_fourcc = QT_FOURCC (buffer + 4);
4952 if (child_fourcc == fourcc) {
4954 child_len = QT_UINT32 (buffer);
4955 if (G_UNLIKELY (child_len < (4 + 4)))
4957 /* FIXME: must verify if atom length < parent atom length */
4958 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4967 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
4969 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
4973 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
4974 QtDemuxStream * stream, GstTagList * list)
4976 /* consistent default for push based mode */
4977 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
4978 gst_segment_set_newsegment (&stream->segment, FALSE, 1.0, GST_FORMAT_TIME,
4979 0, GST_CLOCK_TIME_NONE, 0);
4981 if (stream->subtype == FOURCC_vide) {
4982 gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
4985 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
4988 /* fps is calculated base on the duration of the first frames since
4989 * qt does not have a fixed framerate. */
4990 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
4995 stream->fps_n = stream->timescale;
4996 if (stream->min_duration == 0)
4999 stream->fps_d = stream->min_duration;
5004 gint depth, palette_count;
5005 const guint32 *palette_data = NULL;
5007 gst_caps_set_simple (stream->caps,
5008 "width", G_TYPE_INT, stream->width,
5009 "height", G_TYPE_INT, stream->height,
5010 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5012 /* calculate pixel-aspect-ratio using display width and height */
5013 GST_DEBUG_OBJECT (qtdemux,
5014 "video size %dx%d, target display size %dx%d", stream->width,
5015 stream->height, stream->display_width, stream->display_height);
5017 if (stream->display_width > 0 && stream->display_height > 0 &&
5018 stream->width > 0 && stream->height > 0) {
5021 /* calculate the pixel aspect ratio using the display and pixel w/h */
5022 n = stream->display_width * stream->height;
5023 d = stream->display_height * stream->width;
5026 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5027 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5028 GST_TYPE_FRACTION, n, d, NULL);
5031 /* qt file might have pasp atom */
5032 if (stream->par_w > 0 && stream->par_h > 0) {
5033 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5034 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5035 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5038 depth = stream->bits_per_sample;
5040 /* more than 32 bits means grayscale */
5041 gray = (depth > 32);
5042 /* low 32 bits specify the depth */
5045 /* different number of palette entries is determined by depth. */
5047 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
5048 palette_count = (1 << depth);
5050 switch (palette_count) {
5054 palette_data = ff_qt_default_palette_2;
5057 palette_data = ff_qt_default_palette_4;
5061 palette_data = ff_qt_grayscale_palette_16;
5063 palette_data = ff_qt_default_palette_16;
5067 palette_data = ff_qt_grayscale_palette_256;
5069 palette_data = ff_qt_default_palette_256;
5072 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5073 (_("The video in this file might not play correctly.")),
5074 ("unsupported palette depth %d", depth));
5080 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5081 * don't free any of the buffer data. */
5082 palette = gst_buffer_new ();
5083 GST_BUFFER_FLAG_SET (palette, GST_BUFFER_FLAG_READONLY);
5084 GST_BUFFER_DATA (palette) = (guint8 *) palette_data;
5085 GST_BUFFER_SIZE (palette) = sizeof (guint32) * palette_count;
5087 gst_caps_set_simple (stream->caps, "palette_data",
5088 GST_TYPE_BUFFER, palette, NULL);
5089 gst_buffer_unref (palette);
5090 } else if (palette_count != 0) {
5091 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5092 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5094 gst_object_unref (stream->pad);
5098 qtdemux->n_video_streams++;
5099 } else if (stream->subtype == FOURCC_soun) {
5100 gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
5103 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5106 gst_caps_set_simple (stream->caps,
5107 "rate", G_TYPE_INT, (int) stream->rate,
5108 "channels", G_TYPE_INT, stream->n_channels, NULL);
5110 qtdemux->n_audio_streams++;
5111 } else if (stream->subtype == FOURCC_strm) {
5112 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5113 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
5114 gchar *name = g_strdup_printf ("subtitle_%02d", qtdemux->n_sub_streams);
5117 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5119 qtdemux->n_sub_streams++;
5121 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5126 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5128 gst_pad_use_fixed_caps (stream->pad);
5129 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5130 gst_pad_set_query_type_function (stream->pad,
5131 gst_qtdemux_get_src_query_types);
5132 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5134 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5135 gst_pad_set_caps (stream->pad, stream->caps);
5137 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5138 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5139 gst_pad_set_active (stream->pad, TRUE);
5140 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5141 if (stream->pending_tags)
5142 gst_tag_list_free (stream->pending_tags);
5143 stream->pending_tags = list;
5145 /* post now, send event on pad later */
5146 GST_DEBUG_OBJECT (qtdemux, "Posting tags %" GST_PTR_FORMAT, list);
5147 gst_element_post_message (GST_ELEMENT (qtdemux),
5148 gst_message_new_tag_full (GST_OBJECT (qtdemux), stream->pad,
5149 gst_tag_list_copy (list)));
5151 /* global tags go on each pad anyway */
5152 stream->send_global_tags = TRUE;
5158 /* find next atom with @fourcc starting at @offset */
5159 static GstFlowReturn
5160 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5161 guint64 * length, guint32 fourcc)
5167 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5168 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5171 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5172 if (G_UNLIKELY (ret != GST_FLOW_OK))
5174 if (G_LIKELY (GST_BUFFER_SIZE (buf) != 16)) {
5176 ret = GST_FLOW_UNEXPECTED;
5177 gst_buffer_unref (buf);
5180 extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf), 16, length,
5182 gst_buffer_unref (buf);
5184 if (G_UNLIKELY (*length == 0)) {
5185 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5186 ret = GST_FLOW_ERROR;
5190 if (lfourcc == fourcc) {
5191 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5195 GST_LOG_OBJECT (qtdemux,
5196 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5197 GST_FOURCC_ARGS (fourcc), *offset);
5206 /* might simply have had last one */
5207 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5212 /* should only do something in pull mode */
5213 /* call with OBJECT lock */
5214 static GstFlowReturn
5215 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5217 guint64 length, offset;
5218 GstBuffer *buf = NULL;
5219 GstFlowReturn ret = GST_FLOW_OK;
5220 GstFlowReturn res = GST_FLOW_OK;
5222 offset = qtdemux->moof_offset;
5223 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5226 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5227 return GST_FLOW_UNEXPECTED;
5230 /* best not do pull etc with lock held */
5231 GST_OBJECT_UNLOCK (qtdemux);
5233 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5234 if (ret != GST_FLOW_OK)
5237 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5238 if (G_UNLIKELY (ret != GST_FLOW_OK))
5240 if (!qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf),
5241 GST_BUFFER_SIZE (buf), offset, NULL)) {
5242 gst_buffer_unref (buf);
5247 gst_buffer_unref (buf);
5251 /* look for next moof */
5252 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5253 if (G_UNLIKELY (ret != GST_FLOW_OK))
5257 GST_OBJECT_LOCK (qtdemux);
5259 qtdemux->moof_offset = offset;
5265 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5267 res = GST_FLOW_ERROR;
5272 /* maybe upstream temporarily flushing */
5273 if (ret != GST_FLOW_WRONG_STATE) {
5274 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5277 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5278 /* resume at current position next time */
5285 /* initialise bytereaders for stbl sub-atoms */
5287 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5289 stream->stbl_index = -1; /* no samples have yet been parsed */
5291 /* time-to-sample atom */
5292 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5295 /* copy atom data into a new buffer for later use */
5296 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5298 /* skip version + flags */
5299 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5300 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5302 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5304 /* make sure there's enough data */
5305 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 2 * 4))
5308 /* sync sample atom */
5309 stream->stps_present = FALSE;
5310 if ((stream->stss_present =
5311 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5312 &stream->stss) ? TRUE : FALSE) == TRUE) {
5313 /* copy atom data into a new buffer for later use */
5314 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5316 /* skip version + flags */
5317 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5318 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5321 if (stream->n_sample_syncs) {
5322 /* make sure there's enough data */
5323 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5327 /* partial sync sample atom */
5328 if ((stream->stps_present =
5329 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5330 &stream->stps) ? TRUE : FALSE) == TRUE) {
5331 /* copy atom data into a new buffer for later use */
5332 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5334 /* skip version + flags */
5335 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5336 !gst_byte_reader_get_uint32_be (&stream->stps,
5337 &stream->n_sample_partial_syncs))
5340 /* if there are no entries, the stss table contains the real
5342 if (stream->n_sample_partial_syncs) {
5343 /* make sure there's enough data */
5344 if (!qt_atom_parser_has_chunks (&stream->stps,
5345 stream->n_sample_partial_syncs, 4))
5352 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5355 /* copy atom data into a new buffer for later use */
5356 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5358 /* skip version + flags */
5359 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5360 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5363 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5366 if (!stream->n_samples)
5369 /* sample-to-chunk atom */
5370 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5373 /* copy atom data into a new buffer for later use */
5374 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5376 /* skip version + flags */
5377 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5378 !gst_byte_reader_get_uint32_be (&stream->stsc,
5379 &stream->n_samples_per_chunk))
5382 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5383 stream->n_samples_per_chunk);
5385 /* make sure there's enough data */
5386 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5392 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5393 stream->co_size = sizeof (guint32);
5394 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5396 stream->co_size = sizeof (guint64);
5400 /* copy atom data into a new buffer for later use */
5401 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5403 /* skip version + flags */
5404 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5407 /* chunks_are_chunks == 0 means treat chunks as samples */
5408 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5409 if (stream->chunks_are_chunks) {
5410 /* skip number of entries */
5411 if (!gst_byte_reader_skip (&stream->stco, 4))
5414 /* make sure there are enough data in the stsz atom */
5415 if (!stream->sample_size) {
5416 /* different sizes for each sample */
5417 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5421 /* treat chunks as samples */
5422 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5426 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5427 stream->n_samples, (guint) sizeof (QtDemuxSample),
5428 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5430 if (stream->n_samples >=
5431 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5432 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5433 "be larger than %uMB (broken file?)", stream->n_samples,
5434 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5438 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5439 if (!stream->samples) {
5440 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5446 /* composition time-to-sample */
5447 if ((stream->ctts_present =
5448 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5449 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5450 /* copy atom data into a new buffer for later use */
5451 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5453 /* skip version + flags */
5454 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5455 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5456 &stream->n_composition_times))
5459 /* make sure there's enough data */
5460 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5469 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5470 (_("This file is corrupt and cannot be played.")), (NULL));
5475 gst_qtdemux_stbl_free (stream);
5476 if (!qtdemux->fragmented) {
5477 /* not quite good */
5478 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5481 /* may pick up samples elsewhere */
5487 /* collect samples from the next sample to be parsed up to sample @n for @stream
5488 * by reading the info from @stbl
5490 * This code can be executed from both the streaming thread and the seeking
5491 * thread so it takes the object lock to protect itself
5494 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
5497 QtDemuxSample *samples, *first, *cur, *last;
5498 guint32 n_samples_per_chunk;
5501 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
5502 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
5503 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
5505 n_samples = stream->n_samples;
5508 goto out_of_samples;
5510 GST_OBJECT_LOCK (qtdemux);
5511 if (n <= stream->stbl_index)
5512 goto already_parsed;
5514 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
5516 if (!stream->stsz.data) {
5517 /* so we already parsed and passed all the moov samples;
5518 * onto fragmented ones */
5519 g_assert (qtdemux->fragmented);
5523 /* pointer to the sample table */
5524 samples = stream->samples;
5526 /* starts from -1, moves to the next sample index to parse */
5527 stream->stbl_index++;
5529 /* keep track of the first and last sample to fill */
5530 first = &samples[stream->stbl_index];
5533 if (stream->chunks_are_chunks) {
5534 /* set the sample sizes */
5535 if (stream->sample_size == 0) {
5536 /* different sizes for each sample */
5537 for (cur = first; cur <= last; cur++) {
5538 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
5539 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
5540 (guint) (cur - samples), cur->size);
5543 /* samples have the same size */
5544 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
5545 for (cur = first; cur <= last; cur++)
5546 cur->size = stream->sample_size;
5550 n_samples_per_chunk = stream->n_samples_per_chunk;
5553 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
5556 if (stream->stsc_chunk_index >= stream->last_chunk
5557 || stream->stsc_chunk_index < stream->first_chunk) {
5558 stream->first_chunk =
5559 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5560 stream->samples_per_chunk =
5561 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5562 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
5564 /* chunk numbers are counted from 1 it seems */
5565 if (G_UNLIKELY (stream->first_chunk == 0))
5568 --stream->first_chunk;
5570 /* the last chunk of each entry is calculated by taking the first chunk
5571 * of the next entry; except if there is no next, where we fake it with
5573 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
5574 stream->last_chunk = G_MAXUINT32;
5576 stream->last_chunk =
5577 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
5578 if (G_UNLIKELY (stream->last_chunk == 0))
5581 --stream->last_chunk;
5584 GST_LOG_OBJECT (qtdemux,
5585 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
5586 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
5588 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
5591 if (stream->last_chunk != G_MAXUINT32) {
5592 if (!qt_atom_parser_peek_sub (&stream->stco,
5593 stream->first_chunk * stream->co_size,
5594 (stream->last_chunk - stream->first_chunk) * stream->co_size,
5599 stream->co_chunk = stream->stco;
5600 if (!gst_byte_reader_skip (&stream->co_chunk,
5601 stream->first_chunk * stream->co_size))
5605 stream->stsc_chunk_index = stream->first_chunk;
5608 last_chunk = stream->last_chunk;
5610 if (stream->chunks_are_chunks) {
5611 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5612 guint32 samples_per_chunk;
5613 guint64 chunk_offset;
5615 if (!stream->stsc_sample_index
5616 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
5617 &stream->chunk_offset))
5620 samples_per_chunk = stream->samples_per_chunk;
5621 chunk_offset = stream->chunk_offset;
5623 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
5624 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
5625 G_GUINT64_FORMAT, (guint) (cur - samples), stream->chunk_offset);
5627 cur->offset = chunk_offset;
5628 chunk_offset += cur->size;
5631 if (G_UNLIKELY (cur > last)) {
5633 stream->stsc_sample_index = k + 1;
5634 stream->chunk_offset = chunk_offset;
5635 stream->stsc_chunk_index = j;
5639 stream->stsc_sample_index = 0;
5641 stream->stsc_chunk_index = j;
5643 cur = &samples[stream->stsc_chunk_index];
5645 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5648 stream->stsc_chunk_index = j;
5653 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
5656 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
5657 "%" G_GUINT64_FORMAT, j, cur->offset);
5659 if (stream->samples_per_frame * stream->bytes_per_frame) {
5661 (stream->samples_per_chunk * stream->n_channels) /
5662 stream->samples_per_frame * stream->bytes_per_frame;
5664 cur->size = stream->samples_per_chunk;
5667 GST_DEBUG_OBJECT (qtdemux,
5668 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
5669 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
5670 GST_SECOND, stream->timescale)), cur->size);
5672 cur->timestamp = stream->stco_sample_index;
5673 cur->duration = stream->samples_per_chunk;
5674 cur->keyframe = TRUE;
5677 stream->stco_sample_index += stream->samples_per_chunk;
5679 stream->stsc_chunk_index = j;
5681 stream->stsc_index++;
5684 if (!stream->chunks_are_chunks)
5688 guint32 n_sample_times;
5690 n_sample_times = stream->n_sample_times;
5693 for (i = stream->stts_index; i < n_sample_times; i++) {
5694 guint32 stts_samples;
5695 gint32 stts_duration;
5698 if (stream->stts_sample_index >= stream->stts_samples
5699 || !stream->stts_sample_index) {
5701 stream->stts_samples =
5702 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5703 stream->stts_duration =
5704 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5706 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
5707 i, stream->stts_samples, stream->stts_duration);
5709 stream->stts_sample_index = 0;
5712 stts_samples = stream->stts_samples;
5713 stts_duration = stream->stts_duration;
5714 stts_time = stream->stts_time;
5716 for (j = stream->stts_sample_index; j < stts_samples; j++) {
5717 GST_DEBUG_OBJECT (qtdemux,
5718 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
5719 (guint) (cur - samples), j,
5720 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
5721 stream->timescale)));
5723 cur->timestamp = stts_time;
5724 cur->duration = stts_duration;
5726 /* avoid 32-bit wrap-around,
5727 * but still mind possible 'negative' duration */
5728 stts_time += (gint64) stts_duration;
5731 if (G_UNLIKELY (cur > last)) {
5733 stream->stts_time = stts_time;
5734 stream->stts_sample_index = j + 1;
5738 stream->stts_sample_index = 0;
5739 stream->stts_time = stts_time;
5740 stream->stts_index++;
5742 /* fill up empty timestamps with the last timestamp, this can happen when
5743 * the last samples do not decode and so we don't have timestamps for them.
5744 * We however look at the last timestamp to estimate the track length so we
5745 * need something in here. */
5746 for (; cur < last; cur++) {
5747 GST_DEBUG_OBJECT (qtdemux,
5748 "fill sample %d: timestamp %" GST_TIME_FORMAT,
5749 (guint) (cur - samples),
5750 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
5751 stream->timescale)));
5752 cur->timestamp = stream->stts_time;
5758 /* sample sync, can be NULL */
5759 if (stream->stss_present == TRUE) {
5760 guint32 n_sample_syncs;
5762 n_sample_syncs = stream->n_sample_syncs;
5764 if (!n_sample_syncs) {
5765 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
5766 stream->all_keyframe = TRUE;
5768 for (i = stream->stss_index; i < n_sample_syncs; i++) {
5769 /* note that the first sample is index 1, not 0 */
5772 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
5774 if (G_LIKELY (index > 0 && index <= n_samples)) {
5776 samples[index].keyframe = TRUE;
5777 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5778 /* and exit if we have enough samples */
5779 if (G_UNLIKELY (index >= n)) {
5786 stream->stss_index = i;
5789 /* stps marks partial sync frames like open GOP I-Frames */
5790 if (stream->stps_present == TRUE) {
5791 guint32 n_sample_partial_syncs;
5793 n_sample_partial_syncs = stream->n_sample_partial_syncs;
5795 /* if there are no entries, the stss table contains the real
5797 if (n_sample_partial_syncs) {
5798 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
5799 /* note that the first sample is index 1, not 0 */
5802 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
5804 if (G_LIKELY (index > 0 && index <= n_samples)) {
5806 samples[index].keyframe = TRUE;
5807 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5808 /* and exit if we have enough samples */
5809 if (G_UNLIKELY (index >= n)) {
5816 stream->stps_index = i;
5820 /* no stss, all samples are keyframes */
5821 stream->all_keyframe = TRUE;
5822 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
5827 /* composition time to sample */
5828 if (stream->ctts_present == TRUE) {
5829 guint32 n_composition_times;
5831 gint32 ctts_soffset;
5833 /* Fill in the pts_offsets */
5835 n_composition_times = stream->n_composition_times;
5837 for (i = stream->ctts_index; i < n_composition_times; i++) {
5838 if (stream->ctts_sample_index >= stream->ctts_count
5839 || !stream->ctts_sample_index) {
5840 stream->ctts_count =
5841 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
5842 stream->ctts_soffset =
5843 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
5844 stream->ctts_sample_index = 0;
5847 ctts_count = stream->ctts_count;
5848 ctts_soffset = stream->ctts_soffset;
5850 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
5851 cur->pts_offset = ctts_soffset;
5854 if (G_UNLIKELY (cur > last)) {
5856 stream->ctts_sample_index = j + 1;
5860 stream->ctts_sample_index = 0;
5861 stream->ctts_index++;
5865 stream->stbl_index = n;
5866 /* if index has been completely parsed, free data that is no-longer needed */
5867 if (n + 1 == stream->n_samples) {
5868 gst_qtdemux_stbl_free (stream);
5869 GST_DEBUG_OBJECT (qtdemux,
5870 "parsed all available samples; checking for more");
5871 while (n + 1 == stream->n_samples)
5872 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
5875 GST_OBJECT_UNLOCK (qtdemux);
5882 GST_LOG_OBJECT (qtdemux,
5883 "Tried to parse up to sample %u but this sample has already been parsed",
5885 /* if fragmented, there may be more */
5886 if (qtdemux->fragmented && n == stream->stbl_index)
5888 GST_OBJECT_UNLOCK (qtdemux);
5894 GST_LOG_OBJECT (qtdemux,
5895 "Tried to parse up to sample %u but there are only %u samples", n + 1,
5897 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5898 (_("This file is corrupt and cannot be played.")), (NULL));
5903 GST_OBJECT_UNLOCK (qtdemux);
5904 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5905 (_("This file is corrupt and cannot be played.")), (NULL));
5910 /* collect all segment info for @stream.
5913 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
5918 /* parse and prepare segment info from the edit list */
5919 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
5920 stream->n_segments = 0;
5921 stream->segments = NULL;
5922 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
5926 guint64 time, stime;
5929 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
5930 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
5933 buffer = elst->data;
5935 n_segments = QT_UINT32 (buffer + 12);
5937 /* we might allocate a bit too much, at least allocate 1 segment */
5938 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
5940 /* segments always start from 0 */
5944 for (i = 0; i < n_segments; i++) {
5947 QtDemuxSegment *segment;
5950 media_time = QT_UINT32 (buffer + 20 + i * 12);
5952 /* -1 media time is an empty segment, just ignore it */
5953 if (media_time == G_MAXUINT32)
5956 duration = QT_UINT32 (buffer + 16 + i * 12);
5958 segment = &stream->segments[count++];
5960 /* time and duration expressed in global timescale */
5961 segment->time = stime;
5962 /* add non scaled values so we don't cause roundoff errors */
5964 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
5965 segment->stop_time = stime;
5966 segment->duration = stime - segment->time;
5967 /* media_time expressed in stream timescale */
5968 segment->media_start =
5969 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
5970 segment->media_stop = segment->media_start + segment->duration;
5971 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
5973 if (rate_int <= 1) {
5974 /* 0 is not allowed, some programs write 1 instead of the floating point
5976 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
5980 segment->rate = rate_int / 65536.0;
5983 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
5984 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
5985 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
5986 GST_TIME_ARGS (segment->duration),
5987 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
5989 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
5990 stream->n_segments = count;
5994 /* push based does not handle segments, so act accordingly here,
5995 * and warn if applicable */
5996 if (!qtdemux->pullbased) {
5997 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
5998 /* remove and use default one below, we stream like it anyway */
5999 g_free (stream->segments);
6000 stream->segments = NULL;
6001 stream->n_segments = 0;
6004 /* no segments, create one to play the complete trak */
6005 if (stream->n_segments == 0) {
6006 GstClockTime stream_duration =
6007 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6009 if (stream->segments == NULL)
6010 stream->segments = g_new (QtDemuxSegment, 1);
6012 /* represent unknown our way */
6013 if (stream_duration == 0)
6014 stream_duration = -1;
6016 stream->segments[0].time = 0;
6017 stream->segments[0].stop_time = stream_duration;
6018 stream->segments[0].duration = stream_duration;
6019 stream->segments[0].media_start = 0;
6020 stream->segments[0].media_stop = stream_duration;
6021 stream->segments[0].rate = 1.0;
6023 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6024 GST_TIME_ARGS (stream_duration));
6025 stream->n_segments = 1;
6027 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6033 * Parses the stsd atom of a svq3 trak looking for
6034 * the SMI and gama atoms.
6037 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6038 guint8 ** gamma, GstBuffer ** seqh)
6040 guint8 *_gamma = NULL;
6041 GstBuffer *_seqh = NULL;
6042 guint8 *stsd_data = stsd->data;
6043 guint32 length = QT_UINT32 (stsd_data);
6047 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6053 version = QT_UINT16 (stsd_data);
6058 while (length > 8) {
6059 guint32 fourcc, size;
6061 size = QT_UINT32 (stsd_data);
6062 fourcc = QT_FOURCC (stsd_data + 4);
6063 data = stsd_data + 8;
6070 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6071 " for gama atom, expected 12", size);
6076 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6078 if (_seqh != NULL) {
6079 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6080 " found, ignoring");
6082 seqh_size = QT_UINT32 (data + 4);
6083 if (seqh_size > 0) {
6084 _seqh = gst_buffer_new_and_alloc (seqh_size);
6085 memcpy (GST_BUFFER_DATA (_seqh), data + 8, seqh_size);
6092 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6093 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6097 if (size <= length) {
6103 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6106 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6107 G_GUINT16_FORMAT, version);
6118 gst_buffer_unref (_seqh);
6123 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6130 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6131 * atom that might contain a 'data' atom with the rtsp uri.
6132 * This case was reported in bug #597497, some info about
6133 * the hndl atom can be found in TN1195
6135 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6136 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6139 guint32 dref_num_entries = 0;
6140 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6141 gst_byte_reader_skip (&dref, 4) &&
6142 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6145 /* search dref entries for hndl atom */
6146 for (i = 0; i < dref_num_entries; i++) {
6147 guint32 size = 0, type;
6148 guint8 string_len = 0;
6149 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6150 qt_atom_parser_get_fourcc (&dref, &type)) {
6151 if (type == FOURCC_hndl) {
6152 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6154 /* skip data reference handle bytes and the
6155 * following pascal string and some extra 4
6156 * bytes I have no idea what are */
6157 if (!gst_byte_reader_skip (&dref, 4) ||
6158 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6159 !gst_byte_reader_skip (&dref, string_len + 4)) {
6160 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6164 /* iterate over the atoms to find the data atom */
6165 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6169 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6170 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6171 if (atom_type == FOURCC_data) {
6172 const guint8 *uri_aux = NULL;
6174 /* found the data atom that might contain the rtsp uri */
6175 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6176 "hndl atom, interpreting it as an URI");
6177 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6179 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6180 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6182 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6183 "didn't contain a rtsp address");
6185 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6190 /* skipping to the next entry */
6191 gst_byte_reader_skip (&dref, atom_size - 8);
6193 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6200 /* skip to the next entry */
6201 gst_byte_reader_skip (&dref, size - 8);
6203 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6206 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6213 less_than (gconstpointer a, gconstpointer b)
6215 const guint32 *av = a, *bv = b;
6220 #define AMR_NB_ALL_MODES 0x81ff
6221 #define AMR_WB_ALL_MODES 0x83ff
6223 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
6225 /* The 'damr' atom is of the form:
6227 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
6228 * 32 b 8 b 16 b 8 b 8 b
6230 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
6231 * represents the highest mode used in the stream (and thus the maximum
6232 * bitrate), with a couple of special cases as seen below.
6235 /* Map of frame type ID -> bitrate */
6236 static const guint nb_bitrates[] = {
6237 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
6239 static const guint wb_bitrates[] = {
6240 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
6242 const guint8 *data = GST_BUFFER_DATA (buf);
6243 guint size = QT_UINT32 (data), max_mode;
6246 if (GST_BUFFER_SIZE (buf) != 0x11) {
6247 GST_DEBUG ("Atom should have size 0x11, not %u", size);
6251 if (QT_FOURCC (data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
6252 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
6253 GST_FOURCC_ARGS (QT_UINT32 (data + 4)));
6257 mode_set = QT_UINT16 (data + 13);
6259 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
6260 max_mode = 7 + (wb ? 1 : 0);
6262 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
6263 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
6265 if (max_mode == -1) {
6266 GST_DEBUG ("No mode indication was found (mode set) = %x",
6271 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
6278 * With each track we associate a new QtDemuxStream that contains all the info
6280 * traks that do not decode to something (like strm traks) will not have a pad.
6283 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6298 QtDemuxStream *stream;
6299 GstTagList *list = NULL;
6300 gchar *codec = NULL;
6301 const guint8 *stsd_data;
6302 guint16 lang_code; /* quicktime lang code or packed iso code */
6304 guint32 tkhd_flags = 0;
6305 guint8 tkhd_version = 0;
6307 guint value_size, len;
6309 stream = g_new0 (QtDemuxStream, 1);
6310 /* new streams always need a discont */
6311 stream->discont = TRUE;
6312 /* we enable clipping for raw audio/video streams */
6313 stream->need_clip = FALSE;
6314 stream->need_process = FALSE;
6315 stream->segment_index = -1;
6316 stream->time_position = 0;
6317 stream->sample_index = -1;
6318 stream->last_ret = GST_FLOW_OK;
6320 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6321 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6322 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6325 /* pick between 64 or 32 bits */
6326 value_size = tkhd_version == 1 ? 8 : 4;
6327 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6328 !gst_byte_reader_get_uint32_be (&tkhd, &stream->track_id))
6331 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6332 tkhd_version, tkhd_flags, stream->track_id);
6334 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6337 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6338 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6339 if (qtdemux->major_brand != FOURCC_mjp2 ||
6340 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6344 len = QT_UINT32 ((guint8 *) mdhd->data);
6345 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6346 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6347 if (version == 0x01000000) {
6350 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6351 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6352 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6356 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6357 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6358 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6361 if (lang_code < 0x800) {
6362 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6364 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6365 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6366 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6367 stream->lang_id[3] = 0;
6370 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6372 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6374 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6375 lang_code, stream->lang_id);
6377 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6380 /* fragmented files may have bogus duration in moov */
6381 if (!qtdemux->fragmented &&
6382 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6383 guint64 tdur1, tdur2;
6385 /* don't overflow */
6386 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6387 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6390 * some of those trailers, nowadays, have prologue images that are
6391 * themselves vide tracks as well. I haven't really found a way to
6392 * identify those yet, except for just looking at their duration. */
6393 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6394 GST_WARNING_OBJECT (qtdemux,
6395 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6396 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6397 "found, assuming preview image or something; skipping track",
6398 stream->duration, stream->timescale, qtdemux->duration,
6399 qtdemux->timescale);
6405 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6408 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6409 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6411 len = QT_UINT32 ((guint8 *) hdlr->data);
6413 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6414 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6415 GST_FOURCC_ARGS (stream->subtype));
6417 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6420 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6424 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6426 stsd_data = (const guint8 *) stsd->data;
6428 /* stsd should at least have one entry */
6429 len = QT_UINT32 (stsd_data);
6433 /* and that entry should fit within stsd */
6434 len = QT_UINT32 (stsd_data + 16);
6435 if (len > QT_UINT32 (stsd_data) + 16)
6437 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6439 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6440 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6441 GST_FOURCC_ARGS (stream->fourcc));
6443 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6444 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6445 goto error_encrypted;
6447 if (stream->subtype == FOURCC_vide) {
6448 guint32 w = 0, h = 0;
6450 stream->sampled = TRUE;
6452 /* version 1 uses some 64-bit ints */
6453 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6454 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6455 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6458 stream->display_width = w >> 16;
6459 stream->display_height = h >> 16;
6465 stream->width = QT_UINT16 (stsd_data + offset + 32);
6466 stream->height = QT_UINT16 (stsd_data + offset + 34);
6467 stream->fps_n = 0; /* this is filled in later */
6468 stream->fps_d = 0; /* this is filled in later */
6469 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6470 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6472 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6473 QT_UINT16 (stsd_data + offset + 48));
6476 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6478 list = gst_tag_list_new ();
6479 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6480 GST_TAG_VIDEO_CODEC, codec, NULL);
6487 /* pick 'the' stsd child */
6488 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
6490 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
6491 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
6495 const guint8 *pasp_data = (const guint8 *) pasp->data;
6497 stream->par_w = QT_UINT32 (pasp_data + 8);
6498 stream->par_h = QT_UINT32 (pasp_data + 12);
6505 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
6510 gint len = QT_UINT32 (stsd_data) - 0x66;
6511 const guint8 *avc_data = stsd_data + 0x66;
6514 while (len >= 0x8) {
6517 if (QT_UINT32 (avc_data) <= len)
6518 size = QT_UINT32 (avc_data) - 0x8;
6523 /* No real data, so break out */
6526 switch (QT_FOURCC (avc_data + 0x4)) {
6529 /* parse, if found */
6532 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
6534 /* First 4 bytes are the length of the atom, the next 4 bytes
6535 * are the fourcc, the next 1 byte is the version, and the
6536 * subsequent bytes are sequence parameter set like data. */
6537 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
6538 avc_data + 8 + 1, size - 1);
6540 buf = gst_buffer_new_and_alloc (size);
6541 memcpy (GST_BUFFER_DATA (buf), avc_data + 0x8, size);
6542 gst_caps_set_simple (stream->caps,
6543 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6544 gst_buffer_unref (buf);
6550 guint avg_bitrate, max_bitrate;
6552 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
6556 max_bitrate = QT_UINT32 (avc_data + 0xc);
6557 avg_bitrate = QT_UINT32 (avc_data + 0x10);
6559 if (!max_bitrate && !avg_bitrate)
6562 /* Some muxers seem to swap the average and maximum bitrates
6563 * (I'm looking at you, YouTube), so we swap for sanity. */
6564 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
6565 guint temp = avg_bitrate;
6567 avg_bitrate = max_bitrate;
6572 list = gst_tag_list_new ();
6574 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6575 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6576 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6578 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6579 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6580 GST_TAG_BITRATE, avg_bitrate, NULL);
6591 avc_data += size + 8;
6603 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
6604 GST_FOURCC_ARGS (fourcc));
6606 /* codec data might be in glbl extension atom */
6608 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
6614 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
6616 len = QT_UINT32 (data);
6619 buf = gst_buffer_new_and_alloc (len);
6620 memcpy (GST_BUFFER_DATA (buf), data + 8, len);
6621 gst_caps_set_simple (stream->caps,
6622 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6623 gst_buffer_unref (buf);
6630 /* see annex I of the jpeg2000 spec */
6631 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
6635 guint32 ncomp_map = 0;
6636 gint32 *comp_map = NULL;
6637 guint32 nchan_def = 0;
6638 gint32 *chan_def = NULL;
6640 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
6641 /* some required atoms */
6642 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
6645 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
6649 /* number of components; redundant with info in codestream, but useful
6651 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
6652 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
6654 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
6656 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
6659 GST_DEBUG_OBJECT (qtdemux, "found colr");
6660 /* extract colour space info */
6661 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
6662 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
6664 fourcc = GST_MAKE_FOURCC ('s', 'R', 'G', 'B');
6667 fourcc = GST_MAKE_FOURCC ('G', 'R', 'A', 'Y');
6670 fourcc = GST_MAKE_FOURCC ('s', 'Y', 'U', 'V');
6677 /* colr is required, and only values 16, 17, and 18 are specified,
6678 so error if we have no fourcc */
6681 /* extract component mapping */
6682 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
6684 guint32 cmap_len = 0;
6686 cmap_len = QT_UINT32 (cmap->data);
6687 if (cmap_len >= 8) {
6688 /* normal box, subtract off header */
6690 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
6691 if (cmap_len % 4 == 0) {
6692 ncomp_map = (cmap_len / 4);
6693 comp_map = g_new0 (gint32, ncomp_map);
6694 for (i = 0; i < ncomp_map; i++) {
6697 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
6698 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
6699 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
6700 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
6705 /* extract channel definitions */
6706 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
6708 guint32 cdef_len = 0;
6710 cdef_len = QT_UINT32 (cdef->data);
6711 if (cdef_len >= 10) {
6712 /* normal box, subtract off header and len */
6714 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
6715 if (cdef_len % 6 == 0) {
6716 nchan_def = (cdef_len / 6);
6717 chan_def = g_new0 (gint32, nchan_def);
6718 for (i = 0; i < nchan_def; i++)
6720 for (i = 0; i < nchan_def; i++) {
6721 guint16 cn, typ, asoc;
6722 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
6723 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
6724 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
6725 if (cn < nchan_def) {
6728 chan_def[cn] = asoc;
6731 chan_def[cn] = 0; /* alpha */
6734 chan_def[cn] = -typ;
6742 gst_caps_set_simple (stream->caps,
6743 "num-components", G_TYPE_INT, ncomp, NULL);
6744 gst_caps_set_simple (stream->caps,
6745 "fourcc", GST_TYPE_FOURCC, fourcc, NULL);
6748 GValue arr = { 0, };
6749 GValue elt = { 0, };
6751 g_value_init (&arr, GST_TYPE_ARRAY);
6752 g_value_init (&elt, G_TYPE_INT);
6753 for (i = 0; i < ncomp_map; i++) {
6754 g_value_set_int (&elt, comp_map[i]);
6755 gst_value_array_append_value (&arr, &elt);
6757 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6758 "component-map", &arr);
6759 g_value_unset (&elt);
6760 g_value_unset (&arr);
6765 GValue arr = { 0, };
6766 GValue elt = { 0, };
6768 g_value_init (&arr, GST_TYPE_ARRAY);
6769 g_value_init (&elt, G_TYPE_INT);
6770 for (i = 0; i < nchan_def; i++) {
6771 g_value_set_int (&elt, chan_def[i]);
6772 gst_value_array_append_value (&arr, &elt);
6774 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6775 "channel-definitions", &arr);
6776 g_value_unset (&elt);
6777 g_value_unset (&arr);
6781 /* some optional atoms */
6782 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
6783 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
6785 /* indicate possible fields in caps */
6787 data = (guint8 *) field->data + 8;
6789 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
6790 (gint) * data, NULL);
6792 /* add codec_data if provided */
6797 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
6798 data = prefix->data;
6799 len = QT_UINT32 (data);
6802 buf = gst_buffer_new_and_alloc (len);
6803 memcpy (GST_BUFFER_DATA (buf), data + 8, len);
6804 gst_caps_set_simple (stream->caps,
6805 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6806 gst_buffer_unref (buf);
6815 GstBuffer *seqh = NULL;
6816 guint8 *gamma_data = NULL;
6817 gint len = QT_UINT32 (stsd_data);
6819 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
6821 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
6822 QT_FP32 (gamma_data), NULL);
6825 /* sorry for the bad name, but we don't know what this is, other
6826 * than its own fourcc */
6827 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
6831 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
6832 buf = gst_buffer_new_and_alloc (len);
6833 memcpy (GST_BUFFER_DATA (buf), stsd_data, len);
6834 gst_caps_set_simple (stream->caps,
6835 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6836 gst_buffer_unref (buf);
6841 gst_caps_set_simple (stream->caps,
6842 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
6849 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
6850 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
6854 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
6858 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
6859 /* collect the headers and store them in a stream list so that we can
6860 * send them out first */
6861 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
6871 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
6872 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
6875 ovc1_data = ovc1->data;
6876 ovc1_len = QT_UINT32 (ovc1_data);
6877 if (ovc1_len <= 198) {
6878 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
6881 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
6882 memcpy (GST_BUFFER_DATA (buf), ovc1_data + 198, ovc1_len - 198);
6883 gst_caps_set_simple (stream->caps,
6884 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6885 gst_buffer_unref (buf);
6893 GST_INFO_OBJECT (qtdemux,
6894 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
6895 GST_FOURCC_ARGS (fourcc), stream->caps);
6897 } else if (stream->subtype == FOURCC_soun) {
6898 int version, samplesize;
6899 guint16 compression_id;
6900 gboolean amrwb = FALSE;
6906 version = QT_UINT32 (stsd_data + offset);
6907 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
6908 samplesize = QT_UINT16 (stsd_data + offset + 10);
6909 compression_id = QT_UINT16 (stsd_data + offset + 12);
6910 stream->rate = QT_FP32 (stsd_data + offset + 16);
6912 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
6913 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
6914 QT_UINT32 (stsd_data + offset + 4));
6915 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
6916 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
6917 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
6918 GST_LOG_OBJECT (qtdemux, "packet size: %d",
6919 QT_UINT16 (stsd_data + offset + 14));
6920 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
6922 if (compression_id == 0xfffe)
6923 stream->sampled = TRUE;
6925 /* first assume uncompressed audio */
6926 stream->bytes_per_sample = samplesize / 8;
6927 stream->samples_per_frame = stream->n_channels;
6928 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
6929 stream->samples_per_packet = stream->samples_per_frame;
6930 stream->bytes_per_packet = stream->bytes_per_sample;
6934 /* Yes, these have to be hard-coded */
6937 stream->samples_per_packet = 6;
6938 stream->bytes_per_packet = 1;
6939 stream->bytes_per_frame = 1 * stream->n_channels;
6940 stream->bytes_per_sample = 1;
6941 stream->samples_per_frame = 6 * stream->n_channels;
6946 stream->samples_per_packet = 3;
6947 stream->bytes_per_packet = 1;
6948 stream->bytes_per_frame = 1 * stream->n_channels;
6949 stream->bytes_per_sample = 1;
6950 stream->samples_per_frame = 3 * stream->n_channels;
6955 stream->samples_per_packet = 64;
6956 stream->bytes_per_packet = 34;
6957 stream->bytes_per_frame = 34 * stream->n_channels;
6958 stream->bytes_per_sample = 2;
6959 stream->samples_per_frame = 64 * stream->n_channels;
6965 stream->samples_per_packet = 1;
6966 stream->bytes_per_packet = 1;
6967 stream->bytes_per_frame = 1 * stream->n_channels;
6968 stream->bytes_per_sample = 1;
6969 stream->samples_per_frame = 1 * stream->n_channels;
6974 stream->samples_per_packet = 160;
6975 stream->bytes_per_packet = 33;
6976 stream->bytes_per_frame = 33 * stream->n_channels;
6977 stream->bytes_per_sample = 2;
6978 stream->samples_per_frame = 160 * stream->n_channels;
6985 if (version == 0x00010000) {
6993 /* only parse extra decoding config for non-pcm audio */
6994 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
6995 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
6996 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
6997 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
6999 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7000 stream->samples_per_packet);
7001 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7002 stream->bytes_per_packet);
7003 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
7004 stream->bytes_per_frame);
7005 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
7006 stream->bytes_per_sample);
7008 if (!stream->sampled && stream->bytes_per_packet) {
7009 stream->samples_per_frame = (stream->bytes_per_frame /
7010 stream->bytes_per_packet) * stream->samples_per_packet;
7011 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
7012 stream->samples_per_frame);
7017 } else if (version == 0x00020000) {
7024 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7025 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
7026 stream->rate = qtfp.fp;
7027 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
7029 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7030 stream->samples_per_packet);
7031 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7032 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7035 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
7038 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
7047 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
7049 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
7051 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
7053 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
7056 gst_caps_set_simple (stream->caps,
7057 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
7064 const gchar *owma_data, *codec_name = NULL;
7068 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
7069 /* FIXME this should also be gst_riff_strf_auds,
7070 * but the latter one is actually missing bits-per-sample :( */
7075 gint32 nSamplesPerSec;
7076 gint32 nAvgBytesPerSec;
7078 gint16 wBitsPerSample;
7083 GST_DEBUG_OBJECT (qtdemux, "parse owma");
7084 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
7087 owma_data = owma->data;
7088 owma_len = QT_UINT32 (owma_data);
7089 if (owma_len <= 54) {
7090 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
7093 wfex = (WAVEFORMATEX *) (owma_data + 36);
7094 buf = gst_buffer_new_and_alloc (owma_len - 54);
7095 memcpy (GST_BUFFER_DATA (buf), owma_data + 54, owma_len - 54);
7096 if (wfex->wFormatTag == 0x0161) {
7097 codec_name = "Windows Media Audio";
7099 } else if (wfex->wFormatTag == 0x0162) {
7100 codec_name = "Windows Media Audio 9 Pro";
7102 } else if (wfex->wFormatTag == 0x0163) {
7103 codec_name = "Windows Media Audio 9 Lossless";
7104 /* is that correct? gstffmpegcodecmap.c is missing it, but
7105 * fluendo codec seems to support it */
7109 gst_caps_set_simple (stream->caps,
7110 "codec_data", GST_TYPE_BUFFER, buf,
7111 "wmaversion", G_TYPE_INT, version,
7112 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
7113 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
7114 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7115 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7117 gst_buffer_unref (buf);
7121 codec = g_strdup (codec_name);
7133 list = gst_tag_list_new ();
7134 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7135 GST_TAG_AUDIO_CODEC, codec, NULL);
7139 /* some bitrate info may have ended up in caps */
7140 s = gst_caps_get_structure (stream->caps, 0);
7141 gst_structure_get_int (s, "bitrate", &bitrate);
7143 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7147 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7151 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7153 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7155 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7159 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7160 16 bits is a byte-swapped wave-style codec identifier,
7161 and we can find a WAVE header internally to a 'wave' atom here.
7162 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7163 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7166 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7167 if (len < offset + 20) {
7168 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7170 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7171 const guint8 *data = stsd_data + offset + 16;
7173 GNode *waveheadernode;
7175 wavenode = g_node_new ((guint8 *) data);
7176 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7177 const guint8 *waveheader;
7180 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7181 if (waveheadernode) {
7182 waveheader = (const guint8 *) waveheadernode->data;
7183 headerlen = QT_UINT32 (waveheader);
7185 if (headerlen > 8) {
7186 gst_riff_strf_auds *header = NULL;
7187 GstBuffer *headerbuf;
7193 headerbuf = gst_buffer_new ();
7194 GST_BUFFER_DATA (headerbuf) = (guint8 *) waveheader;
7195 GST_BUFFER_SIZE (headerbuf) = headerlen;
7197 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7198 headerbuf, &header, &extra)) {
7199 gst_caps_unref (stream->caps);
7200 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7201 header, extra, NULL, NULL);
7204 gst_buffer_unref (extra);
7208 GST_DEBUG ("Didn't find waveheadernode for this codec");
7210 g_node_destroy (wavenode);
7213 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7217 /* FIXME: what is in the chunk? */
7220 gint len = QT_UINT32 (stsd_data);
7222 /* seems to be always = 116 = 0x74 */
7228 gint len = QT_UINT32 (stsd_data);
7231 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7233 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x4C, len - 0x4C);
7234 gst_caps_set_simple (stream->caps,
7235 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7236 gst_buffer_unref (buf);
7238 gst_caps_set_simple (stream->caps,
7239 "samplesize", G_TYPE_INT, samplesize, NULL);
7244 GNode *alac, *wave = NULL;
7246 /* apparently, m4a has this atom appended directly in the stsd entry,
7247 * while mov has it in a wave atom */
7248 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7250 /* alac now refers to stsd entry atom */
7251 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7253 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7255 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7258 gint len = QT_UINT32 (alac->data);
7262 GST_DEBUG_OBJECT (qtdemux,
7263 "discarding alac atom with unexpected len %d", len);
7265 /* codec-data contains alac atom size and prefix,
7266 * ffmpeg likes it that way, not quite gst-ish though ...*/
7267 buf = gst_buffer_new_and_alloc (len);
7268 memcpy (GST_BUFFER_DATA (buf), alac->data, len);
7269 gst_caps_set_simple (stream->caps,
7270 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7271 gst_buffer_unref (buf);
7274 gst_caps_set_simple (stream->caps,
7275 "samplesize", G_TYPE_INT, samplesize, NULL);
7283 gint len = QT_UINT32 (stsd_data);
7286 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7289 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34);
7291 /* If we have enough data, let's try to get the 'damr' atom. See
7292 * the 3GPP container spec (26.244) for more details. */
7293 if ((len - 0x34) > 8 &&
7294 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
7296 list = gst_tag_list_new ();
7297 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7298 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
7301 gst_caps_set_simple (stream->caps,
7302 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7303 gst_buffer_unref (buf);
7311 GST_INFO_OBJECT (qtdemux,
7312 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7313 GST_FOURCC_ARGS (fourcc), stream->caps);
7315 } else if (stream->subtype == FOURCC_strm) {
7316 if (fourcc == FOURCC_rtsp) {
7317 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7319 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7320 GST_FOURCC_ARGS (fourcc));
7321 goto unknown_stream;
7323 stream->sampled = TRUE;
7324 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
7326 stream->sampled = TRUE;
7331 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7333 list = gst_tag_list_new ();
7334 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7335 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7340 /* hunt for sort-of codec data */
7347 /* look for palette */
7348 /* target mp4s atom */
7349 len = QT_UINT32 (stsd_data + offset);
7350 data = stsd_data + offset;
7351 /* verify sufficient length,
7352 * and esds present with decConfigDescr of expected size and position */
7353 if ((len >= 106 + 8)
7354 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7355 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7360 /* move to decConfigDescr data */
7361 data = data + 8 + 42;
7362 for (i = 0; i < 16; i++) {
7363 clut[i] = QT_UINT32 (data);
7367 s = gst_structure_new ("application/x-gst-dvd", "event",
7368 G_TYPE_STRING, "dvd-spu-clut-change",
7369 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7370 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7371 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7372 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7373 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7374 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7375 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7376 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7379 /* store event and trigger custom processing */
7380 stream->pending_event =
7381 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7382 stream->need_process = TRUE;
7390 goto unknown_stream;
7393 /* promote to sampled format */
7394 if (stream->fourcc == FOURCC_samr) {
7395 /* force mono 8000 Hz for AMR */
7396 stream->sampled = TRUE;
7397 stream->n_channels = 1;
7398 stream->rate = 8000;
7399 } else if (stream->fourcc == FOURCC_sawb) {
7400 /* force mono 16000 Hz for AMR-WB */
7401 stream->sampled = TRUE;
7402 stream->n_channels = 1;
7403 stream->rate = 16000;
7404 } else if (stream->fourcc == FOURCC_mp4a) {
7405 stream->sampled = TRUE;
7408 /* collect sample information */
7409 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7410 goto samples_failed;
7412 if (qtdemux->fragmented) {
7416 /* need all moov samples as basis; probably not many if any at all */
7417 /* prevent moof parsing taking of at this time */
7418 offset = qtdemux->moof_offset;
7419 qtdemux->moof_offset = 0;
7420 if (stream->n_samples &&
7421 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7422 qtdemux->moof_offset = offset;
7423 goto samples_failed;
7425 qtdemux->moof_offset = 0;
7426 /* movie duration more reliable in this case (e.g. mehd) */
7427 if (qtdemux->segment.duration &&
7428 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7429 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7430 stream->timescale, GST_SECOND);
7431 /* need defaults for fragments */
7432 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7435 /* configure segments */
7436 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7437 goto segments_failed;
7439 /* add some language tag, if useful */
7440 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7441 strcmp (stream->lang_id, "und")) {
7442 const gchar *lang_code;
7445 list = gst_tag_list_new ();
7447 /* convert ISO 639-2 code to ISO 639-1 */
7448 lang_code = gst_tag_get_language_code (stream->lang_id);
7449 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7450 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7453 /* now we are ready to add the stream */
7454 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7455 goto too_many_streams;
7457 stream->pending_tags = list;
7458 qtdemux->streams[qtdemux->n_streams] = stream;
7459 qtdemux->n_streams++;
7460 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7467 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7468 (_("This file is corrupt and cannot be played.")), (NULL));
7474 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7481 /* we posted an error already */
7482 /* free stbl sub-atoms */
7483 gst_qtdemux_stbl_free (stream);
7489 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7490 GST_FOURCC_ARGS (stream->subtype));
7496 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7497 (_("This file contains too many streams. Only playing first %d"),
7498 GST_QTDEMUX_MAX_STREAMS), (NULL));
7503 /* If we can estimate the overall bitrate, and don't have information about the
7504 * stream bitrate for exactly one stream, this guesses the stream bitrate as
7505 * the overall bitrate minus the sum of the bitrates of all other streams. This
7506 * should be useful for the common case where we have one audio and one video
7507 * stream and can estimate the bitrate of one, but not the other. */
7509 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
7511 GstFormat format = GST_FORMAT_BYTES;
7512 QtDemuxStream *stream = NULL;
7513 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
7517 if (qtdemux->fragmented)
7520 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
7522 if (!gst_pad_query_peer_duration (qtdemux->sinkpad, &format, &size) ||
7523 format != GST_FORMAT_BYTES) {
7524 GST_DEBUG_OBJECT (qtdemux,
7525 "Size in bytes of the stream not known - bailing");
7529 /* Subtract the header size */
7530 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
7531 size, qtdemux->header_size);
7532 g_assert (size >= qtdemux->header_size);
7533 size = size - qtdemux->header_size;
7535 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
7536 duration == GST_CLOCK_TIME_NONE) {
7537 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
7541 for (i = 0; i < qtdemux->n_streams; i++) {
7542 switch (qtdemux->streams[i]->subtype) {
7545 /* retrieve bitrate, prefer avg then max */
7547 if (qtdemux->streams[i]->pending_tags) {
7548 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7549 GST_TAG_MAXIMUM_BITRATE, &bitrate);
7550 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7551 GST_TAG_BITRATE, &bitrate);
7554 sum_bitrate += bitrate;
7557 GST_DEBUG_OBJECT (qtdemux,
7558 ">1 stream with unknown bitrate - bailing");
7561 stream = qtdemux->streams[i];
7565 /* For other subtypes, we assume no significant impact on bitrate */
7571 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
7575 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
7577 if (sys_bitrate < sum_bitrate) {
7578 /* This can happen, since sum_bitrate might be derived from maximum
7579 * bitrates and not average bitrates */
7580 GST_DEBUG_OBJECT (qtdemux,
7581 "System bitrate less than sum bitrate - bailing");
7585 bitrate = sys_bitrate - sum_bitrate;
7586 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
7587 ", Stream bitrate = %u", sys_bitrate, bitrate);
7589 if (!stream->pending_tags)
7590 stream->pending_tags = gst_tag_list_new ();
7592 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
7593 GST_TAG_BITRATE, bitrate, NULL);
7596 static GstFlowReturn
7597 qtdemux_expose_streams (GstQTDemux * qtdemux)
7600 GstFlowReturn ret = GST_FLOW_OK;
7602 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7604 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7605 QtDemuxStream *stream = qtdemux->streams[i];
7606 guint32 sample_num = 0;
7611 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7612 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7614 if (qtdemux->fragmented) {
7615 /* need all moov samples first */
7616 GST_OBJECT_LOCK (qtdemux);
7617 while (stream->n_samples == 0)
7618 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7620 GST_OBJECT_UNLOCK (qtdemux);
7622 /* discard any stray moof */
7623 qtdemux->moof_offset = 0;
7626 /* prepare braking */
7627 if (ret != GST_FLOW_ERROR)
7630 /* in pull mode, we should have parsed some sample info by now;
7631 * and quite some code will not handle no samples.
7632 * in push mode, we'll just have to deal with it */
7633 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7634 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7635 gst_qtdemux_stream_free (qtdemux, stream);
7636 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7637 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7638 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7639 qtdemux->n_streams--;
7644 /* parse number of initial sample to set frame rate cap */
7645 while (sample_num < stream->n_samples && sample_num < samples) {
7646 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7650 /* collect and sort durations */
7651 samples = MIN (stream->stbl_index + 1, samples);
7652 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7654 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7656 while (sample_num < samples) {
7657 g_array_append_val (durations, stream->samples[sample_num].duration);
7660 g_array_sort (durations, less_than);
7661 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7662 g_array_free (durations, TRUE);
7665 /* now we have all info and can expose */
7666 list = stream->pending_tags;
7667 stream->pending_tags = NULL;
7668 gst_qtdemux_add_stream (qtdemux, stream, list);
7671 gst_qtdemux_guess_bitrate (qtdemux);
7673 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7675 /* check if we should post a redirect in case there is a single trak
7676 * and it is a redirecting trak */
7677 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7680 qtdemux_post_global_tags (qtdemux);
7682 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7683 "an external content");
7684 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7685 gst_structure_new ("redirect",
7686 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7688 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7689 qtdemux->posted_redirect = TRUE;
7695 /* check if major or compatible brand is 3GP */
7696 static inline gboolean
7697 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7700 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7701 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7702 } else if (qtdemux->comp_brands != NULL) {
7703 guint8 *data = GST_BUFFER_DATA (qtdemux->comp_brands);
7704 guint size = GST_BUFFER_SIZE (qtdemux->comp_brands);
7705 gboolean res = FALSE;
7708 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7709 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7719 /* check if tag is a spec'ed 3GP tag keyword storing a string */
7720 static inline gboolean
7721 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
7723 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
7724 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
7725 || fourcc == FOURCC_albm;
7729 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
7730 const char *dummy, GNode * node)
7732 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7736 gdouble longitude, latitude, altitude;
7739 len = QT_UINT32 (node->data);
7746 /* TODO: language code skipped */
7748 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
7751 /* do not alarm in trivial case, but bail out otherwise */
7752 if (*(data + offset) != 0) {
7753 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
7757 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7758 GST_TAG_GEO_LOCATION_NAME, name, NULL);
7759 offset += strlen (name);
7763 if (len < offset + 2 + 4 + 4 + 4)
7766 /* +1 +1 = skip null-terminator and location role byte */
7768 /* table in spec says unsigned, semantics say negative has meaning ... */
7769 longitude = QT_SFP32 (data + offset);
7772 latitude = QT_SFP32 (data + offset);
7775 altitude = QT_SFP32 (data + offset);
7777 /* one invalid means all are invalid */
7778 if (longitude >= -180.0 && longitude <= 180.0 &&
7779 latitude >= -90.0 && latitude <= 90.0) {
7780 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7781 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
7782 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
7783 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
7786 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
7793 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
7800 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7807 len = QT_UINT32 (node->data);
7811 y = QT_UINT16 ((guint8 *) node->data + 12);
7813 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
7816 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
7818 date = g_date_new_dmy (1, 1, y);
7819 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
7824 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
7825 const char *dummy, GNode * node)
7828 char *tag_str = NULL;
7833 len = QT_UINT32 (node->data);
7838 entity = (guint8 *) node->data + offset;
7839 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
7840 GST_DEBUG_OBJECT (qtdemux,
7841 "classification info: %c%c%c%c invalid classification entity",
7842 entity[0], entity[1], entity[2], entity[3]);
7847 table = QT_UINT16 ((guint8 *) node->data + offset);
7849 /* Language code skipped */
7853 /* Tag format: "XXXX://Y[YYYY]/classification info string"
7854 * XXXX: classification entity, fixed length 4 chars.
7855 * Y[YYYY]: classification table, max 5 chars.
7857 tag_str = g_strdup_printf ("----://%u/%s",
7858 table, (char *) node->data + offset);
7860 /* memcpy To be sure we're preserving byte order */
7861 memcpy (tag_str, entity, 4);
7862 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
7864 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
7874 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
7880 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
7881 const char *dummy, GNode * node)
7883 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7889 gboolean ret = TRUE;
7891 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7893 len = QT_UINT32 (data->data);
7894 type = QT_UINT32 ((guint8 *) data->data + 8);
7895 if (type == 0x00000001 && len > 16) {
7896 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
7899 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7900 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
7904 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7908 len = QT_UINT32 (node->data);
7909 type = QT_UINT32 ((guint8 *) node->data + 4);
7910 if ((type >> 24) == 0xa9) {
7911 /* Type starts with the (C) symbol, so the next 32 bits are
7912 * the language code, which we ignore */
7914 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
7915 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
7916 QT_FOURCC ((guint8 *) node->data + 4))) {
7917 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
7919 /* we go for 3GP style encoding if major brands claims so,
7920 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
7921 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
7922 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
7923 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
7925 /* 16-bit Language code is ignored here as well */
7926 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
7933 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
7934 ret = FALSE; /* may have to fallback */
7936 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
7937 len - offset, env_vars);
7939 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7940 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
7944 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7951 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
7952 const char *dummy, GNode * node)
7954 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
7958 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
7959 const char *dummy, GNode * node)
7961 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7963 char *s, *t, *k = NULL;
7968 /* first try normal string tag if major brand not 3GP */
7969 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
7970 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
7971 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
7972 * let's try it 3gpp way after minor safety check */
7974 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
7980 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
7984 len = QT_UINT32 (data);
7988 count = QT_UINT8 (data + 14);
7990 for (; count; count--) {
7993 if (offset + 1 > len)
7995 slen = QT_UINT8 (data + offset);
7997 if (offset + slen > len)
7999 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8002 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
8004 t = g_strjoin (",", k, s, NULL);
8012 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
8019 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
8020 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
8029 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
8035 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
8036 const char *tag2, GNode * node)
8043 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8045 len = QT_UINT32 (data->data);
8046 type = QT_UINT32 ((guint8 *) data->data + 8);
8047 if (type == 0x00000000 && len >= 22) {
8048 n1 = QT_UINT16 ((guint8 *) data->data + 18);
8049 n2 = QT_UINT16 ((guint8 *) data->data + 20);
8051 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
8052 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8056 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
8057 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8065 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8073 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8075 len = QT_UINT32 (data->data);
8076 type = QT_UINT32 ((guint8 *) data->data + 8);
8077 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
8078 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8079 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
8080 n1 = QT_UINT16 ((guint8 *) data->data + 16);
8082 /* do not add bpm=0 */
8083 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
8084 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8085 tag1, (gdouble) n1, NULL);
8092 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
8093 const char *dummy, GNode * node)
8100 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8102 len = QT_UINT32 (data->data);
8103 type = QT_UINT32 ((guint8 *) data->data + 8);
8104 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
8105 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8106 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
8107 num = QT_UINT32 ((guint8 *) data->data + 16);
8109 /* do not add num=0 */
8110 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
8111 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8119 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8127 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8129 len = QT_UINT32 (data->data);
8130 type = QT_UINT32 ((guint8 *) data->data + 8);
8131 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
8132 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
8133 if ((buf = gst_tag_image_data_to_image_buffer ((guint8 *) data->data + 16,
8134 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
8135 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
8136 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8138 gst_buffer_unref (buf);
8145 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8153 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8155 len = QT_UINT32 (data->data);
8156 type = QT_UINT32 ((guint8 *) data->data + 8);
8157 if (type == 0x00000001 && len > 16) {
8158 guint y, m = 1, d = 1;
8161 s = g_strndup ((char *) data->data + 16, len - 16);
8162 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
8163 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
8164 if (ret >= 1 && y > 1500 && y < 3000) {
8167 date = g_date_new_dmy (d, m, y);
8168 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
8172 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
8180 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8185 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8187 /* re-route to normal string tag if major brand says so
8188 * or no data atom and compatible brand suggests so */
8189 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8190 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
8191 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
8198 len = QT_UINT32 (data->data);
8199 type = QT_UINT32 ((guint8 *) data->data + 8);
8200 if (type == 0x00000000 && len >= 18) {
8201 n = QT_UINT16 ((guint8 *) data->data + 16);
8205 genre = gst_tag_id3_genre_get (n - 1);
8206 if (genre != NULL) {
8207 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
8208 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8217 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
8218 guint8 * data, guint32 datasize)
8223 /* make a copy to have \0 at the end */
8224 datacopy = g_strndup ((gchar *) data, datasize);
8226 /* convert the str to double */
8227 if (sscanf (datacopy, "%lf", &value) == 1) {
8228 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
8229 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
8231 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
8239 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
8240 const char *tag_bis, GNode * node)
8249 const gchar *meanstr;
8250 const gchar *namestr;
8252 /* checking the whole ---- atom size for consistency */
8253 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8254 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8258 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8260 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8264 meansize = QT_UINT32 (mean->data);
8265 if (meansize <= 12) {
8266 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8269 meanstr = ((gchar *) mean->data) + 12;
8271 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8273 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8277 namesize = QT_UINT32 (name->data);
8278 if (namesize <= 12) {
8279 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8282 namestr = ((gchar *) name->data) + 12;
8289 * uint24 - data type
8293 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8295 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8298 datasize = QT_UINT32 (data->data);
8299 if (datasize <= 16) {
8300 GST_WARNING_OBJECT (demux, "Data atom too small");
8303 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8305 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8308 const gchar name[28];
8309 const gchar tag[28];
8312 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8313 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8314 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8315 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8316 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8317 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8318 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8319 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8323 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8324 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8325 switch (gst_tag_get_type (tags[i].tag)) {
8327 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8328 ((guint8 *) data->data) + 16, datasize - 16);
8331 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8340 if (i == G_N_ELEMENTS (tags))
8354 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8355 namestr_dbg = g_strndup (namestr, namesize - 12);
8357 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8358 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8360 g_free (namestr_dbg);
8361 g_free (meanstr_dbg);
8367 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
8368 const char *tag_bis, GNode * node)
8373 GstTagList *taglist = NULL;
8375 GST_LOG_OBJECT (demux, "parsing ID32");
8378 len = GST_READ_UINT32_BE (data);
8380 /* need at least full box and language tag */
8384 buf = gst_buffer_new ();
8385 GST_BUFFER_DATA (buf) = data + 14;
8386 GST_BUFFER_SIZE (buf) = len - 14;
8388 taglist = gst_tag_list_from_id3v2_tag (buf);
8390 GST_LOG_OBJECT (demux, "parsing ok");
8391 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
8393 GST_LOG_OBJECT (demux, "parsing failed");
8397 gst_tag_list_free (taglist);
8399 gst_buffer_unref (buf);
8402 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8403 const char *tag, const char *tag_bis, GNode * node);
8406 FOURCC_pcst -> if media is a podcast -> bool
8407 FOURCC_cpil -> if media is part of a compilation -> bool
8408 FOURCC_pgap -> if media is part of a gapless context -> bool
8409 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8415 const gchar *gst_tag;
8416 const gchar *gst_tag_bis;
8417 const GstQTDemuxAddTagFunc func;
8420 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8421 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8422 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8423 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8424 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8425 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8426 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8427 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8428 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8429 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8430 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8431 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8432 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8433 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8434 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8435 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8436 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8437 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8438 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8439 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8440 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8441 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8442 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8443 qtdemux_tag_add_num}, {
8444 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8445 qtdemux_tag_add_num}, {
8446 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8447 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8448 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8449 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8450 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8451 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8452 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8453 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8454 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8455 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8456 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8457 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8458 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8459 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8460 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8461 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8462 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8463 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8464 qtdemux_tag_add_classification}, {
8466 /* This is a special case, some tags are stored in this
8467 * 'reverse dns naming', according to:
8468 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8471 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
8472 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
8473 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
8477 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8489 len = QT_UINT32 (data);
8490 buf = gst_buffer_new_and_alloc (len);
8491 memcpy (GST_BUFFER_DATA (buf), data, len);
8493 /* heuristic to determine style of tag */
8494 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8495 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8497 else if (demux->major_brand == FOURCC_qt__)
8498 style = "quicktime";
8499 /* fall back to assuming iso/3gp tag style */
8503 /* santize the name for the caps. */
8504 for (i = 0; i < 4; i++) {
8505 guint8 d = data[4 + i];
8506 if (g_ascii_isalnum (d))
8507 ndata[i] = g_ascii_tolower (d);
8512 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8513 ndata[0], ndata[1], ndata[2], ndata[3]);
8514 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8516 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
8517 gst_buffer_set_caps (buf, caps);
8518 gst_caps_unref (caps);
8519 g_free (media_type);
8521 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
8522 GST_BUFFER_SIZE (buf), caps);
8524 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8525 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
8526 gst_buffer_unref (buf);
8530 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8538 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8540 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8542 GST_LOG_OBJECT (qtdemux, "no ilst");
8547 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8550 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8551 if (!qtdemux->tag_list)
8552 qtdemux->tag_list = gst_tag_list_new ();
8555 while (i < G_N_ELEMENTS (add_funcs)) {
8556 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8560 len = QT_UINT32 (node->data);
8562 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8563 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8565 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8566 add_funcs[i].gst_tag_bis, node);
8568 g_node_destroy (node);
8574 /* parsed nodes have been removed, pass along remainder as blob */
8575 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8576 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8578 /* parse up XMP_ node if existing */
8579 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8582 GstTagList *taglist;
8584 buf = gst_buffer_new ();
8585 GST_BUFFER_DATA (buf) = ((guint8 *) xmp_->data) + 8;
8586 GST_BUFFER_SIZE (buf) = QT_UINT32 ((guint8 *) xmp_->data) - 8;
8588 taglist = gst_tag_list_from_xmp_buffer (buf);
8589 gst_buffer_unref (buf);
8591 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8593 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8600 GstStructure *structure; /* helper for sort function */
8602 guint min_req_bitrate;
8603 guint min_req_qt_version;
8607 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8609 GstQtReference *ref_a = (GstQtReference *) a;
8610 GstQtReference *ref_b = (GstQtReference *) b;
8612 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8613 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8615 /* known bitrates go before unknown; higher bitrates go first */
8616 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8619 /* sort the redirects and post a message for the application.
8622 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8624 GstQtReference *best;
8627 GValue list_val = { 0, };
8630 g_assert (references != NULL);
8632 references = g_list_sort (references, qtdemux_redirects_sort_func);
8634 best = (GstQtReference *) references->data;
8636 g_value_init (&list_val, GST_TYPE_LIST);
8638 for (l = references; l != NULL; l = l->next) {
8639 GstQtReference *ref = (GstQtReference *) l->data;
8640 GValue struct_val = { 0, };
8642 ref->structure = gst_structure_new ("redirect",
8643 "new-location", G_TYPE_STRING, ref->location, NULL);
8645 if (ref->min_req_bitrate > 0) {
8646 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8647 ref->min_req_bitrate, NULL);
8650 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8651 g_value_set_boxed (&struct_val, ref->structure);
8652 gst_value_list_append_value (&list_val, &struct_val);
8653 g_value_unset (&struct_val);
8654 /* don't free anything here yet, since we need best->structure below */
8657 g_assert (best != NULL);
8658 s = gst_structure_copy (best->structure);
8660 if (g_list_length (references) > 1) {
8661 gst_structure_set_value (s, "locations", &list_val);
8664 g_value_unset (&list_val);
8666 for (l = references; l != NULL; l = l->next) {
8667 GstQtReference *ref = (GstQtReference *) l->data;
8669 gst_structure_free (ref->structure);
8670 g_free (ref->location);
8673 g_list_free (references);
8675 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8676 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8677 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8678 qtdemux->posted_redirect = TRUE;
8681 /* look for redirect nodes, collect all redirect information and
8685 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8687 GNode *rmra, *rmda, *rdrf;
8689 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8691 GList *redirects = NULL;
8693 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8695 GstQtReference ref = { NULL, NULL, 0, 0 };
8698 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8699 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8700 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8701 ref.min_req_bitrate);
8704 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
8705 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
8706 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
8708 #ifndef GST_DISABLE_GST_DEBUG
8709 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
8711 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
8713 GST_LOG_OBJECT (qtdemux,
8714 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
8715 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
8716 bitmask, check_type);
8717 if (package == FOURCC_qtim && check_type == 0) {
8718 ref.min_req_qt_version = version;
8722 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
8727 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
8728 ref_data = (guint8 *) rdrf->data + 20;
8729 if (ref_type == FOURCC_alis) {
8730 guint record_len, record_version, fn_len;
8732 /* MacOSX alias record, google for alias-layout.txt */
8733 record_len = QT_UINT16 (ref_data + 4);
8734 record_version = QT_UINT16 (ref_data + 4 + 2);
8735 fn_len = QT_UINT8 (ref_data + 50);
8736 if (record_len > 50 && record_version == 2 && fn_len > 0) {
8737 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
8739 } else if (ref_type == FOURCC_url_) {
8740 ref.location = g_strdup ((gchar *) ref_data);
8742 GST_DEBUG_OBJECT (qtdemux,
8743 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
8744 GST_FOURCC_ARGS (ref_type));
8746 if (ref.location != NULL) {
8747 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
8748 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
8750 GST_WARNING_OBJECT (qtdemux,
8751 "Failed to extract redirect location from rdrf atom");
8755 /* look for others */
8756 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
8759 if (redirects != NULL) {
8760 qtdemux_process_redirects (qtdemux, redirects);
8767 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
8772 tags = gst_tag_list_new ();
8774 if (qtdemux->major_brand == FOURCC_mjp2)
8775 fmt = "Motion JPEG 2000";
8776 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
8778 else if (qtdemux->major_brand == FOURCC_qt__)
8780 else if (qtdemux->fragmented)
8783 fmt = "ISO MP4/M4A";
8785 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
8786 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
8788 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
8794 /* we have read th complete moov node now.
8795 * This function parses all of the relevant info, creates the traks and
8796 * prepares all data structures for playback
8799 qtdemux_parse_tree (GstQTDemux * qtdemux)
8806 guint64 creation_time;
8807 GstDateTime *datetime = NULL;
8810 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
8812 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
8813 return qtdemux_parse_redirects (qtdemux);
8816 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
8818 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
8819 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
8820 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
8821 } else if (version == 0) {
8822 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
8823 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
8824 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
8826 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
8830 /* Moving qt creation time (secs since 1904) to unix time */
8831 if (creation_time != 0) {
8832 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
8833 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
8834 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
8836 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
8837 "please file a bug at http://bugzilla.gnome.org");
8841 if (!qtdemux->tag_list)
8842 qtdemux->tag_list = gst_tag_list_new ();
8844 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
8845 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
8847 gst_date_time_unref (datetime);
8850 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
8851 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
8853 /* check for fragmented file and get some (default) data */
8854 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
8857 GstByteReader mehd_data;
8859 /* let track parsing or anyone know weird stuff might happen ... */
8860 qtdemux->fragmented = TRUE;
8862 /* compensate for total duration */
8863 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
8865 qtdemux_parse_mehd (qtdemux, &mehd_data);
8868 /* set duration in the segment info */
8869 gst_qtdemux_get_duration (qtdemux, &duration);
8871 gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
8873 /* parse all traks */
8874 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
8876 qtdemux_parse_trak (qtdemux, trak);
8877 /* iterate all siblings */
8878 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
8882 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
8884 qtdemux_parse_udta (qtdemux, udta);
8886 GST_LOG_OBJECT (qtdemux, "No udta node found.");
8889 /* maybe also some tags in meta box */
8890 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
8892 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
8893 qtdemux_parse_udta (qtdemux, udta);
8895 GST_LOG_OBJECT (qtdemux, "No meta node found.");
8898 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
8903 /* taken from ffmpeg */
8905 get_size (guint8 * ptr, guint8 ** end)
8914 len = (len << 7) | (c & 0x7f);
8923 /* this can change the codec originally present in @list */
8925 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
8926 GNode * esds, GstTagList * list)
8928 int len = QT_UINT32 (esds->data);
8929 guint8 *ptr = esds->data;
8930 guint8 *end = ptr + len;
8932 guint8 *data_ptr = NULL;
8934 guint8 object_type_id = 0;
8935 const char *codec_name = NULL;
8936 GstCaps *caps = NULL;
8938 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
8940 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
8943 tag = QT_UINT8 (ptr);
8944 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
8946 len = get_size (ptr, &ptr);
8947 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
8951 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
8952 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
8956 guint max_bitrate, avg_bitrate;
8958 object_type_id = QT_UINT8 (ptr);
8959 max_bitrate = QT_UINT32 (ptr + 5);
8960 avg_bitrate = QT_UINT32 (ptr + 9);
8961 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
8962 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
8963 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
8964 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
8965 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
8966 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
8967 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8968 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
8970 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
8971 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
8978 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
8984 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
8988 GST_ERROR_OBJECT (qtdemux, "parse error");
8993 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
8994 * in use, and should also be used to override some other parameters for some
8996 switch (object_type_id) {
8997 case 0x20: /* MPEG-4 */
8998 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
8999 * profile_and_level_indication */
9000 if (data_ptr != NULL && data_len >= 5 &&
9001 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
9002 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
9003 data_ptr + 4, data_len - 4);
9005 break; /* Nothing special needed here */
9006 case 0x21: /* H.264 */
9007 codec_name = "H.264 / AVC";
9008 caps = gst_caps_new_simple ("video/x-h264",
9009 "stream-format", G_TYPE_STRING, "avc",
9010 "alignment", G_TYPE_STRING, "au", NULL);
9012 case 0x40: /* AAC (any) */
9013 case 0x66: /* AAC Main */
9014 case 0x67: /* AAC LC */
9015 case 0x68: /* AAC SSR */
9016 /* Override channels and rate based on the codec_data, as it's often
9018 /* Only do so for basic setup without HE-AAC extension */
9019 if (data_ptr && data_len == 2) {
9020 guint channels, rateindex, rate;
9022 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
9023 channels = (data_ptr[1] & 0x7f) >> 3;
9024 if (channels > 0 && channels < 7) {
9025 stream->n_channels = channels;
9026 } else if (channels == 7) {
9027 stream->n_channels = 8;
9030 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
9031 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
9033 stream->rate = rate;
9036 /* Set level and profile if possible */
9037 if (data_ptr != NULL && data_len >= 2) {
9038 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
9039 data_ptr, data_len);
9042 case 0x60: /* MPEG-2, various profiles */
9048 codec_name = "MPEG-2 video";
9050 gst_caps_unref (stream->caps);
9051 stream->caps = gst_caps_new_simple ("video/mpeg",
9052 "mpegversion", G_TYPE_INT, 2,
9053 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9055 case 0x69: /* MP3 has two different values, accept either */
9057 /* change to mpeg1 layer 3 audio */
9058 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
9059 "mpegversion", G_TYPE_INT, 1, NULL);
9060 codec_name = "MPEG-1 layer 3";
9062 case 0x6A: /* MPEG-1 */
9063 codec_name = "MPEG-1 video";
9065 gst_caps_unref (stream->caps);
9066 stream->caps = gst_caps_new_simple ("video/mpeg",
9067 "mpegversion", G_TYPE_INT, 1,
9068 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9070 case 0x6C: /* MJPEG */
9071 caps = gst_caps_new_simple ("image/jpeg", NULL);
9072 codec_name = "Motion-JPEG";
9074 case 0x6D: /* PNG */
9075 caps = gst_caps_new_simple ("image/png", NULL);
9076 codec_name = "PNG still images";
9078 case 0x6E: /* JPEG2000 */
9079 codec_name = "JPEG-2000";
9080 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9082 case 0xA4: /* Dirac */
9083 codec_name = "Dirac";
9084 caps = gst_caps_new_simple ("video/x-dirac", NULL);
9086 case 0xA5: /* AC3 */
9087 codec_name = "AC-3 audio";
9088 caps = gst_caps_new_simple ("audio/x-ac3",
9089 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9091 case 0xE1: /* QCELP */
9092 /* QCELP, the codec_data is a riff tag (little endian) with
9093 * more info (http://ftp.3gpp2.org/TSGC/Working/2003/2003-05-SanDiego/TSG-C-2003-05-San%20Diego/WG1/SWG12/C12-20030512-006%20=%20C12-20030217-015_Draft_Baseline%20Text%20of%20FFMS_R2.doc). */
9094 caps = gst_caps_new_simple ("audio/qcelp", NULL);
9095 codec_name = "QCELP";
9101 /* If we have a replacement caps, then change our caps for this stream */
9103 gst_caps_unref (stream->caps);
9104 stream->caps = caps;
9107 if (codec_name && list)
9108 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9109 GST_TAG_AUDIO_CODEC, codec_name, NULL);
9111 /* Add the codec_data attribute to caps, if we have it */
9115 buffer = gst_buffer_new_and_alloc (data_len);
9116 memcpy (GST_BUFFER_DATA (buffer), data_ptr, data_len);
9118 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
9119 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
9121 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
9123 gst_buffer_unref (buffer);
9128 #define _codec(name) \
9131 *codec_name = g_strdup (name); \
9136 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9137 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9140 const GstStructure *s;
9144 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
9145 _codec ("PNG still images");
9146 caps = gst_caps_new_simple ("image/png", NULL);
9148 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
9149 _codec ("JPEG still images");
9150 caps = gst_caps_new_simple ("image/jpeg", NULL);
9152 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
9153 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
9154 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
9155 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
9156 _codec ("Motion-JPEG");
9157 caps = gst_caps_new_simple ("image/jpeg", NULL);
9159 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
9160 _codec ("Motion-JPEG format B");
9161 caps = gst_caps_new_simple ("video/x-mjpeg-b", NULL);
9163 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
9164 _codec ("JPEG-2000");
9165 /* override to what it should be according to spec, avoid palette_data */
9166 stream->bits_per_sample = 24;
9167 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9169 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
9170 _codec ("Sorensen video v.3");
9171 caps = gst_caps_new_simple ("video/x-svq",
9172 "svqversion", G_TYPE_INT, 3, NULL);
9174 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
9175 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
9176 _codec ("Sorensen video v.1");
9177 caps = gst_caps_new_simple ("video/x-svq",
9178 "svqversion", G_TYPE_INT, 1, NULL);
9180 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9184 _codec ("Raw RGB video");
9185 bps = QT_UINT16 (stsd_data + 98);
9186 /* set common stuff */
9187 caps = gst_caps_new_simple ("video/x-raw-rgb",
9188 "endianness", G_TYPE_INT, G_BYTE_ORDER, "depth", G_TYPE_INT, bps,
9193 gst_caps_set_simple (caps,
9194 "bpp", G_TYPE_INT, 16,
9195 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9196 "red_mask", G_TYPE_INT, 0x7c00,
9197 "green_mask", G_TYPE_INT, 0x03e0,
9198 "blue_mask", G_TYPE_INT, 0x001f, NULL);
9201 gst_caps_set_simple (caps,
9202 "bpp", G_TYPE_INT, 16,
9203 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9204 "red_mask", G_TYPE_INT, 0xf800,
9205 "green_mask", G_TYPE_INT, 0x07e0,
9206 "blue_mask", G_TYPE_INT, 0x001f, NULL);
9209 gst_caps_set_simple (caps,
9210 "bpp", G_TYPE_INT, 24,
9211 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9212 "red_mask", G_TYPE_INT, 0xff0000,
9213 "green_mask", G_TYPE_INT, 0x00ff00,
9214 "blue_mask", G_TYPE_INT, 0x0000ff, NULL);
9217 gst_caps_set_simple (caps,
9218 "bpp", G_TYPE_INT, 32,
9219 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9220 "alpha_mask", G_TYPE_INT, 0xff000000,
9221 "red_mask", G_TYPE_INT, 0x00ff0000,
9222 "green_mask", G_TYPE_INT, 0x0000ff00,
9223 "blue_mask", G_TYPE_INT, 0x000000ff, NULL);
9231 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
9232 _codec ("Raw planar YUV 4:2:0");
9233 caps = gst_caps_new_simple ("video/x-raw-yuv",
9234 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
9237 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
9238 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
9239 _codec ("Raw packed YUV 4:2:2");
9240 caps = gst_caps_new_simple ("video/x-raw-yuv",
9241 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'),
9244 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
9245 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
9246 _codec ("Raw packed YUV 4:2:2");
9247 caps = gst_caps_new_simple ("video/x-raw-yuv",
9248 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'),
9251 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
9252 _codec ("Raw packed YUV 10-bit 4:2:2");
9253 caps = gst_caps_new_simple ("video/x-raw-yuv",
9254 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('v', '2', '1', '0'),
9257 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
9258 _codec ("Raw packed RGB 10-bit 4:4:4");
9259 caps = gst_caps_new_simple ("video/x-raw-rgb",
9260 "endianness", G_TYPE_INT, G_BIG_ENDIAN, "depth", G_TYPE_INT, 30,
9261 "bpp", G_TYPE_INT, 32,
9262 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9263 "red_mask", G_TYPE_INT, 0x3ff00000,
9264 "green_mask", G_TYPE_INT, 0x000ffc00,
9265 "blue_mask", G_TYPE_INT, 0x000003ff, NULL);
9267 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
9268 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
9269 _codec ("MPEG-1 video");
9270 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9271 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9273 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
9274 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
9275 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
9276 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
9277 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
9278 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
9279 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
9280 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
9281 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
9282 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
9283 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
9284 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
9285 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
9286 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
9287 _codec ("MPEG-2 video");
9288 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
9289 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9291 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
9292 _codec ("GIF still images");
9293 caps = gst_caps_new_simple ("image/gif", NULL);
9295 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
9296 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
9297 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
9298 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9300 /* ffmpeg uses the height/width props, don't know why */
9301 caps = gst_caps_new_simple ("video/x-h263", NULL);
9303 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9304 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9305 _codec ("MPEG-4 video");
9306 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9307 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9309 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9310 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9311 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9312 caps = gst_caps_new_simple ("video/x-msmpeg",
9313 "msmpegversion", G_TYPE_INT, 43, NULL);
9315 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9316 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9317 _codec ("3ivX video");
9318 caps = gst_caps_new_simple ("video/x-3ivx", NULL);
9320 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9322 caps = gst_caps_new_simple ("video/x-divx",
9323 "divxversion", G_TYPE_INT, 3, NULL);
9325 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9326 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9328 caps = gst_caps_new_simple ("video/x-divx",
9329 "divxversion", G_TYPE_INT, 4, NULL);
9331 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9333 caps = gst_caps_new_simple ("video/x-divx",
9334 "divxversion", G_TYPE_INT, 5, NULL);
9336 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9337 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9338 _codec ("XVID MPEG-4");
9339 caps = gst_caps_new_simple ("video/x-xvid", NULL);
9342 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9343 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9344 caps = gst_caps_new_simple ("video/mpeg",
9345 "mpegversion", G_TYPE_INT, 4, NULL);
9347 *codec_name = g_strdup ("FFmpeg MPEG-4");
9350 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9352 caps = gst_caps_new_simple ("video/x-cinepak", NULL);
9354 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9355 _codec ("Apple QuickDraw");
9356 caps = gst_caps_new_simple ("video/x-qdrw", NULL);
9358 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9359 _codec ("Apple video");
9360 caps = gst_caps_new_simple ("video/x-apple-video", NULL);
9362 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9363 _codec ("H.264 / AVC");
9364 caps = gst_caps_new_simple ("video/x-h264",
9365 "stream-format", G_TYPE_STRING, "avc",
9366 "alignment", G_TYPE_STRING, "au", NULL);
9368 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9369 _codec ("Run-length encoding");
9370 caps = gst_caps_new_simple ("video/x-rle",
9371 "layout", G_TYPE_STRING, "quicktime", NULL);
9373 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9374 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9375 _codec ("Indeo Video 3");
9376 caps = gst_caps_new_simple ("video/x-indeo",
9377 "indeoversion", G_TYPE_INT, 3, NULL);
9379 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9380 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9381 _codec ("Intel Video 4");
9382 caps = gst_caps_new_simple ("video/x-indeo",
9383 "indeoversion", G_TYPE_INT, 4, NULL);
9385 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9386 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9387 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9388 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9389 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9390 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9391 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9392 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9393 _codec ("DV Video");
9394 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9395 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9397 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9398 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9399 _codec ("DVCPro50 Video");
9400 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9401 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9403 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9404 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9405 _codec ("DVCProHD Video");
9406 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9407 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9409 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9410 _codec ("Apple Graphics (SMC)");
9411 caps = gst_caps_new_simple ("video/x-smc", NULL);
9413 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9415 caps = gst_caps_new_simple ("video/x-vp3", NULL);
9417 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9419 caps = gst_caps_new_simple ("video/x-theora", NULL);
9420 /* theora uses one byte of padding in the data stream because it does not
9421 * allow 0 sized packets while theora does */
9422 stream->padding = 1;
9424 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9426 caps = gst_caps_new_simple ("video/x-dirac", NULL);
9428 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9429 _codec ("TIFF still images");
9430 caps = gst_caps_new_simple ("image/tiff", NULL);
9432 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9433 _codec ("Apple Intermediate Codec");
9434 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9436 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9437 _codec ("AVID DNxHD");
9438 caps = gst_caps_from_string ("video/x-dnxhd");
9440 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9442 caps = gst_caps_from_string ("video/x-vp8");
9446 caps = gst_caps_new_simple ("video/x-wmv",
9447 "wmvversion", G_TYPE_INT, 3,
9448 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'V', 'C', '1'),
9451 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9456 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9457 GST_FOURCC_ARGS (fourcc));
9458 caps = gst_caps_new_simple (s, NULL);
9463 /* enable clipping for raw video streams */
9464 s = gst_caps_get_structure (caps, 0);
9465 name = gst_structure_get_name (s);
9466 if (g_str_has_prefix (name, "video/x-raw-")) {
9467 stream->need_clip = TRUE;
9473 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9474 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9477 const GstStructure *s;
9481 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9484 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9485 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9486 _codec ("Raw 8-bit PCM audio");
9487 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 8,
9488 "depth", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
9490 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9491 endian = G_BIG_ENDIAN;
9493 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9499 endian = G_LITTLE_ENDIAN;
9501 depth = stream->bytes_per_packet * 8;
9502 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9505 caps = gst_caps_new_simple ("audio/x-raw-int",
9506 "width", G_TYPE_INT, depth, "depth", G_TYPE_INT, depth,
9507 "endianness", G_TYPE_INT, endian,
9508 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
9511 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9512 _codec ("Raw 64-bit floating-point audio");
9513 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 64,
9514 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
9516 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9517 _codec ("Raw 32-bit floating-point audio");
9518 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 32,
9519 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
9522 _codec ("Raw 24-bit PCM audio");
9523 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9525 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 24,
9526 "depth", G_TYPE_INT, 24,
9527 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9528 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
9530 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9531 _codec ("Raw 32-bit PCM audio");
9532 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 32,
9533 "depth", G_TYPE_INT, 32,
9534 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9535 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
9537 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9538 _codec ("Mu-law audio");
9539 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
9541 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9542 _codec ("A-law audio");
9543 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
9547 _codec ("Microsoft ADPCM");
9548 /* Microsoft ADPCM-ACM code 2 */
9549 caps = gst_caps_new_simple ("audio/x-adpcm",
9550 "layout", G_TYPE_STRING, "microsoft", NULL);
9554 _codec ("DVI/IMA ADPCM");
9555 caps = gst_caps_new_simple ("audio/x-adpcm",
9556 "layout", G_TYPE_STRING, "dvi", NULL);
9560 _codec ("DVI/Intel IMA ADPCM");
9561 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9562 caps = gst_caps_new_simple ("audio/x-adpcm",
9563 "layout", G_TYPE_STRING, "quicktime", NULL);
9567 /* MPEG layer 3, CBR only (pre QT4.1) */
9568 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9569 _codec ("MPEG-1 layer 3");
9570 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9571 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9572 "mpegversion", G_TYPE_INT, 1, NULL);
9575 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9576 _codec ("EAC-3 audio");
9577 caps = gst_caps_new_simple ("audio/x-eac3",
9578 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9579 stream->sampled = TRUE;
9581 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9582 _codec ("AC-3 audio");
9583 caps = gst_caps_new_simple ("audio/x-ac3",
9584 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9585 stream->sampled = TRUE;
9587 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9589 caps = gst_caps_new_simple ("audio/x-mace",
9590 "maceversion", G_TYPE_INT, 3, NULL);
9592 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9594 caps = gst_caps_new_simple ("audio/x-mace",
9595 "maceversion", G_TYPE_INT, 6, NULL);
9597 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9599 caps = gst_caps_new_simple ("application/ogg", NULL);
9601 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9602 _codec ("DV audio");
9603 caps = gst_caps_new_simple ("audio/x-dv", NULL);
9605 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9606 _codec ("MPEG-4 AAC audio");
9607 caps = gst_caps_new_simple ("audio/mpeg",
9608 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9609 "stream-format", G_TYPE_STRING, "raw", NULL);
9611 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9612 _codec ("QDesign Music");
9613 caps = gst_caps_new_simple ("audio/x-qdm", NULL);
9615 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9616 _codec ("QDesign Music v.2");
9617 /* FIXME: QDesign music version 2 (no constant) */
9619 caps = gst_caps_new_simple ("audio/x-qdm2",
9620 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9621 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9622 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9624 caps = gst_caps_new_simple ("audio/x-qdm2", NULL);
9627 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9628 _codec ("GSM audio");
9629 caps = gst_caps_new_simple ("audio/x-gsm", NULL);
9631 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9632 _codec ("AMR audio");
9633 caps = gst_caps_new_simple ("audio/AMR", NULL);
9635 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9636 _codec ("AMR-WB audio");
9637 caps = gst_caps_new_simple ("audio/AMR-WB", NULL);
9639 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9640 _codec ("Quicktime IMA ADPCM");
9641 caps = gst_caps_new_simple ("audio/x-adpcm",
9642 "layout", G_TYPE_STRING, "quicktime", NULL);
9644 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9645 _codec ("Apple lossless audio");
9646 caps = gst_caps_new_simple ("audio/x-alac", NULL);
9648 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9649 _codec ("QualComm PureVoice");
9650 caps = gst_caps_from_string ("audio/qcelp");
9654 caps = gst_caps_new_simple ("audio/x-wma", NULL);
9656 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
9662 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9663 GST_FOURCC_ARGS (fourcc));
9664 caps = gst_caps_new_simple (s, NULL);
9669 /* enable clipping for raw audio streams */
9670 s = gst_caps_get_structure (caps, 0);
9671 name = gst_structure_get_name (s);
9672 if (g_str_has_prefix (name, "audio/x-raw-")) {
9673 stream->need_clip = TRUE;
9679 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9680 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9684 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9687 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
9688 _codec ("DVD subtitle");
9689 caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
9691 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
9692 _codec ("Quicktime timed text");
9694 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
9695 _codec ("3GPP timed text");
9697 caps = gst_caps_new_simple ("text/plain", NULL);
9698 /* actual text piece needs to be extracted */
9699 stream->need_process = TRUE;
9705 s = g_strdup_printf ("text/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9706 GST_FOURCC_ARGS (fourcc));
9707 caps = gst_caps_new_simple (s, NULL);