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);
432 gst_qtdemux_base_init (gpointer klass)
434 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
436 gst_element_class_add_pad_template (element_class,
437 gst_static_pad_template_get (&gst_qtdemux_sink_template));
438 gst_element_class_add_pad_template (element_class,
439 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
440 gst_element_class_add_pad_template (element_class,
441 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
442 gst_element_class_add_pad_template (element_class,
443 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
444 gst_element_class_set_details_simple (element_class, "QuickTime demuxer",
446 "Demultiplex a QuickTime file into audio and video streams",
447 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
449 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
453 gst_qtdemux_class_init (GstQTDemuxClass * klass)
455 GObjectClass *gobject_class;
456 GstElementClass *gstelement_class;
458 gobject_class = (GObjectClass *) klass;
459 gstelement_class = (GstElementClass *) klass;
461 parent_class = g_type_class_peek_parent (klass);
463 gobject_class->dispose = gst_qtdemux_dispose;
465 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
467 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
468 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
470 gst_tag_register_musicbrainz_tags ();
474 gst_qtdemux_init (GstQTDemux * qtdemux, GstQTDemuxClass * klass)
477 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
478 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
479 gst_pad_set_activatepull_function (qtdemux->sinkpad,
480 qtdemux_sink_activate_pull);
481 gst_pad_set_activatepush_function (qtdemux->sinkpad,
482 qtdemux_sink_activate_push);
483 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
484 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
485 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
487 qtdemux->state = QTDEMUX_STATE_INITIAL;
488 qtdemux->pullbased = FALSE;
489 qtdemux->posted_redirect = FALSE;
490 qtdemux->neededbytes = 16;
492 qtdemux->adapter = gst_adapter_new ();
494 qtdemux->first_mdat = -1;
495 qtdemux->got_moov = FALSE;
496 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
497 qtdemux->mdatbuffer = NULL;
498 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
502 gst_qtdemux_dispose (GObject * object)
504 GstQTDemux *qtdemux = GST_QTDEMUX (object);
506 if (qtdemux->adapter) {
507 g_object_unref (G_OBJECT (qtdemux->adapter));
508 qtdemux->adapter = NULL;
511 G_OBJECT_CLASS (parent_class)->dispose (object);
515 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
517 if (qtdemux->posted_redirect) {
518 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
519 (_("This file contains no playable streams.")),
520 ("no known streams found, a redirect message has been posted"));
522 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
523 (_("This file contains no playable streams.")),
524 ("no known streams found"));
529 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
534 if (G_UNLIKELY (size == 0)) {
536 GstBuffer *tmp = NULL;
538 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
539 if (ret != GST_FLOW_OK)
542 size = QT_UINT32 (GST_BUFFER_DATA (tmp));
543 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
545 gst_buffer_unref (tmp);
548 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
549 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
550 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
551 /* we're pulling header but already got most interesting bits,
552 * so never mind the rest (e.g. tags) (that much) */
553 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
555 return GST_FLOW_UNEXPECTED;
557 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
558 (_("This file is invalid and cannot be played.")),
559 ("atom has bogus size %" G_GUINT64_FORMAT, size));
560 return GST_FLOW_ERROR;
564 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
566 if (G_UNLIKELY (flow != GST_FLOW_OK))
569 /* Catch short reads - we don't want any partial atoms */
570 if (G_UNLIKELY (GST_BUFFER_SIZE (*buf) < size)) {
571 GST_WARNING_OBJECT (qtdemux, "short read: %u < %" G_GUINT64_FORMAT,
572 GST_BUFFER_SIZE (*buf), size);
573 gst_buffer_unref (*buf);
575 return GST_FLOW_UNEXPECTED;
583 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
584 GstFormat dest_format, gint64 * dest_value)
587 QtDemuxStream *stream = gst_pad_get_element_private (pad);
588 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
591 if (stream->subtype != FOURCC_vide) {
596 switch (src_format) {
597 case GST_FORMAT_TIME:
598 switch (dest_format) {
599 case GST_FORMAT_BYTES:{
600 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
604 *dest_value = stream->samples[index].offset;
606 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
607 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
608 GST_TIME_ARGS (src_value), *dest_value);
616 case GST_FORMAT_BYTES:
617 switch (dest_format) {
618 case GST_FORMAT_TIME:{
620 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
627 gst_util_uint64_scale (stream->samples[index].timestamp,
628 GST_SECOND, stream->timescale);
629 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
630 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
631 src_value, GST_TIME_ARGS (*dest_value));
644 gst_object_unref (qtdemux);
650 static const GstQueryType *
651 gst_qtdemux_get_src_query_types (GstPad * pad)
653 static const GstQueryType src_types[] = {
666 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
670 *duration = GST_CLOCK_TIME_NONE;
672 if (qtdemux->duration != 0) {
673 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
674 *duration = gst_util_uint64_scale (qtdemux->duration,
675 GST_SECOND, qtdemux->timescale);
682 gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
684 gboolean res = FALSE;
685 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
687 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
689 switch (GST_QUERY_TYPE (query)) {
690 case GST_QUERY_POSITION:
691 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.last_stop)) {
692 gst_query_set_position (query, GST_FORMAT_TIME,
693 qtdemux->segment.last_stop);
697 case GST_QUERY_DURATION:{
700 gst_query_parse_duration (query, &fmt, NULL);
701 if (fmt == GST_FORMAT_TIME) {
702 gint64 duration = -1;
704 gst_qtdemux_get_duration (qtdemux, &duration);
706 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
712 case GST_QUERY_CONVERT:{
713 GstFormat src_fmt, dest_fmt;
714 gint64 src_value, dest_value = 0;
716 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
718 res = gst_qtdemux_src_convert (pad,
719 src_fmt, src_value, dest_fmt, &dest_value);
721 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
726 case GST_QUERY_FORMATS:
727 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
730 case GST_QUERY_SEEKING:{
734 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
735 if (fmt == GST_FORMAT_TIME) {
736 gint64 duration = -1;
738 gst_qtdemux_get_duration (qtdemux, &duration);
740 if (!qtdemux->pullbased) {
743 /* we might be able with help from upstream */
745 q = gst_query_new_seeking (GST_FORMAT_BYTES);
746 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
747 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
748 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
752 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
758 res = gst_pad_query_default (pad, query);
762 gst_object_unref (qtdemux);
768 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
770 if (G_LIKELY (stream->pad)) {
771 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
772 GST_DEBUG_PAD_NAME (stream->pad));
774 if (G_UNLIKELY (stream->pending_tags)) {
775 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
776 stream->pending_tags);
777 gst_pad_push_event (stream->pad,
778 gst_event_new_tag (stream->pending_tags));
779 stream->pending_tags = NULL;
782 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
783 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
785 gst_pad_push_event (stream->pad,
786 gst_event_new_tag (gst_tag_list_copy (qtdemux->tag_list)));
787 stream->send_global_tags = FALSE;
792 /* push event on all source pads; takes ownership of the event */
794 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
797 gboolean has_valid_stream = FALSE;
798 GstEventType etype = GST_EVENT_TYPE (event);
800 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
801 GST_EVENT_TYPE_NAME (event));
803 for (n = 0; n < qtdemux->n_streams; n++) {
805 QtDemuxStream *stream = qtdemux->streams[n];
807 if ((pad = stream->pad)) {
808 has_valid_stream = TRUE;
810 if (etype == GST_EVENT_EOS) {
811 /* let's not send twice */
812 if (stream->sent_eos)
814 stream->sent_eos = TRUE;
817 gst_pad_push_event (pad, gst_event_ref (event));
821 gst_event_unref (event);
823 /* if it is EOS and there are no pads, post an error */
824 if (!has_valid_stream && etype == GST_EVENT_EOS) {
825 gst_qtdemux_post_no_playable_stream_error (qtdemux);
829 /* push a pending newsegment event, if any from the streaming thread */
831 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
833 if (qtdemux->pending_newsegment) {
834 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
835 qtdemux->pending_newsegment = NULL;
845 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
847 if (s1->timestamp > *media_time)
853 /* find the index of the sample that includes the data for @media_time using a
854 * binary search. Only to be called in optimized cases of linear search below.
856 * Returns the index of the sample.
859 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
862 QtDemuxSample *result;
865 /* convert media_time to mov format */
867 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
869 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
870 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
871 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
873 if (G_LIKELY (result))
874 index = result - str->samples;
883 /* find the index of the sample that includes the data for @media_offset using a
886 * Returns the index of the sample.
889 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
890 QtDemuxStream * str, gint64 media_offset)
892 QtDemuxSample *result = str->samples;
895 if (result == NULL || str->n_samples == 0)
898 if (media_offset == result->offset)
902 while (index < str->n_samples - 1) {
903 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
906 if (media_offset < result->offset)
917 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
922 /* find the index of the sample that includes the data for @media_time using a
923 * linear search, and keeping in mind that not all samples may have been parsed
924 * yet. If possible, it will delegate to binary search.
926 * Returns the index of the sample.
929 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
935 /* convert media_time to mov format */
937 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
939 if (mov_time == str->samples[0].timestamp)
942 /* use faster search if requested time in already parsed range */
943 if (str->stbl_index >= 0 &&
944 mov_time <= str->samples[str->stbl_index].timestamp)
945 return gst_qtdemux_find_index (qtdemux, str, media_time);
947 while (index < str->n_samples - 1) {
948 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
951 if (mov_time < str->samples[index + 1].timestamp)
961 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
966 /* find the index of the keyframe needed to decode the sample at @index
969 * Returns the index of the keyframe.
972 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
975 guint32 new_index = index;
977 if (index >= str->n_samples) {
978 new_index = str->n_samples;
982 /* all keyframes, return index */
983 if (str->all_keyframe) {
988 /* else go back until we have a keyframe */
990 if (str->samples[new_index].keyframe)
1000 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1001 "gave %u", index, new_index);
1006 /* find the segment for @time_position for @stream
1008 * Returns -1 if the segment cannot be found.
1011 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1012 guint64 time_position)
1017 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1018 GST_TIME_ARGS (time_position));
1020 /* find segment corresponding to time_position if we are looking
1023 for (i = 0; i < stream->n_segments; i++) {
1024 QtDemuxSegment *segment = &stream->segments[i];
1026 GST_LOG_OBJECT (qtdemux,
1027 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1028 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1030 /* For the last segment we include stop_time in the last segment */
1031 if (i < stream->n_segments - 1) {
1032 if (segment->time <= time_position && time_position < segment->stop_time) {
1033 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1038 if (segment->time <= time_position && time_position <= segment->stop_time) {
1039 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1048 /* move the stream @str to the sample position @index.
1050 * Updates @str->sample_index and marks discontinuity if needed.
1053 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1056 /* no change needed */
1057 if (index == str->sample_index)
1060 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1063 /* position changed, we have a discont */
1064 str->sample_index = index;
1065 /* Each time we move in the stream we store the position where we are
1067 str->from_sample = index;
1068 str->discont = TRUE;
1072 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1073 gint64 * key_time, gint64 * key_offset)
1076 gint64 min_byte_offset = -1;
1079 min_offset = desired_time;
1081 /* for each stream, find the index of the sample in the segment
1082 * and move back to the previous keyframe. */
1083 for (n = 0; n < qtdemux->n_streams; n++) {
1085 guint32 index, kindex;
1087 guint64 media_start;
1090 QtDemuxSegment *seg;
1092 str = qtdemux->streams[n];
1094 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1095 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1097 /* segment not found, continue with normal flow */
1101 /* get segment and time in the segment */
1102 seg = &str->segments[seg_idx];
1103 seg_time = desired_time - seg->time;
1105 /* get the media time in the segment */
1106 media_start = seg->media_start + seg_time;
1108 /* get the index of the sample with media time */
1109 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1110 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
1111 GST_TIME_ARGS (media_start), index);
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 kindex, GST_TIME_ARGS (media_time));
1128 /* keyframes in the segment get a chance to change the
1129 * desired_offset. keyframes out of the segment are
1131 if (media_time >= seg->media_start) {
1134 /* this keyframe is inside the segment, convert back to
1136 seg_time = (media_time - seg->media_start) + seg->time;
1137 if (seg_time < min_offset)
1138 min_offset = seg_time;
1142 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1143 min_byte_offset = str->samples[index].offset;
1147 *key_time = min_offset;
1149 *key_offset = min_byte_offset;
1153 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1154 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1159 g_return_val_if_fail (format != NULL, FALSE);
1160 g_return_val_if_fail (cur != NULL, FALSE);
1161 g_return_val_if_fail (stop != NULL, FALSE);
1163 if (*format == GST_FORMAT_TIME)
1166 fmt = GST_FORMAT_TIME;
1168 if (cur_type != GST_SEEK_TYPE_NONE)
1169 res = gst_pad_query_convert (pad, *format, *cur, &fmt, cur);
1170 if (res && stop_type != GST_SEEK_TYPE_NONE)
1171 res = gst_pad_query_convert (pad, *format, *stop, &fmt, stop);
1174 *format = GST_FORMAT_TIME;
1179 /* perform seek in push based mode:
1180 find BYTE position to move to based on time and delegate to upstream
1183 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1188 GstSeekType cur_type, stop_type;
1193 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1195 gst_event_parse_seek (event, &rate, &format, &flags,
1196 &cur_type, &cur, &stop_type, &stop);
1198 /* FIXME, always play to the end */
1201 /* only forward streaming and seeking is possible */
1203 goto unsupported_seek;
1205 /* convert to TIME if needed and possible */
1206 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1210 /* find reasonable corresponding BYTE position,
1211 * also try to mind about keyframes, since we can not go back a bit for them
1213 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1218 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1219 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1222 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1223 GST_DEBUG_OBJECT (qtdemux,
1224 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1225 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1226 GST_OBJECT_LOCK (qtdemux);
1227 qtdemux->requested_seek_time = cur;
1228 qtdemux->seek_offset = byte_cur;
1229 GST_OBJECT_UNLOCK (qtdemux);
1232 /* BYTE seek event */
1233 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1235 res = gst_pad_push_event (qtdemux->sinkpad, event);
1242 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1248 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1253 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1258 /* perform the seek.
1260 * We set all segment_indexes in the streams to unknown and
1261 * adjust the time_position to the desired position. this is enough
1262 * to trigger a segment switch in the streaming thread to start
1263 * streaming from the desired position.
1265 * Keyframe seeking is a little more complicated when dealing with
1266 * segments. Ideally we want to move to the previous keyframe in
1267 * the segment but there might not be a keyframe in the segment. In
1268 * fact, none of the segments could contain a keyframe. We take a
1269 * practical approach: seek to the previous keyframe in the segment,
1270 * if there is none, seek to the beginning of the segment.
1272 * Called with STREAM_LOCK
1275 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1277 gint64 desired_offset;
1280 desired_offset = segment->last_stop;
1282 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1283 GST_TIME_ARGS (desired_offset));
1285 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
1288 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1289 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1290 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1291 desired_offset = min_offset;
1294 /* and set all streams to the final position */
1295 for (n = 0; n < qtdemux->n_streams; n++) {
1296 QtDemuxStream *stream = qtdemux->streams[n];
1298 stream->time_position = desired_offset;
1299 stream->sample_index = -1;
1300 stream->segment_index = -1;
1301 stream->last_ret = GST_FLOW_OK;
1302 stream->sent_eos = FALSE;
1304 segment->last_stop = desired_offset;
1305 segment->time = desired_offset;
1307 /* we stop at the end */
1308 if (segment->stop == -1)
1309 segment->stop = segment->duration;
1314 /* do a seek in pull based mode */
1316 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1321 GstSeekType cur_type, stop_type;
1325 GstSegment seeksegment;
1329 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1331 gst_event_parse_seek (event, &rate, &format, &flags,
1332 &cur_type, &cur, &stop_type, &stop);
1334 /* we have to have a format as the segment format. Try to convert
1336 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1340 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1342 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1346 flush = flags & GST_SEEK_FLAG_FLUSH;
1348 /* stop streaming, either by flushing or by pausing the task */
1350 /* unlock upstream pull_range */
1351 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1352 /* make sure out loop function exits */
1353 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1355 /* non flushing seek, pause the task */
1356 gst_pad_pause_task (qtdemux->sinkpad);
1359 /* wait for streaming to finish */
1360 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1362 /* copy segment, we need this because we still need the old
1363 * segment when we close the current segment. */
1364 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1367 /* configure the segment with the seek variables */
1368 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1369 gst_segment_set_seek (&seeksegment, rate, format, flags,
1370 cur_type, cur, stop_type, stop, &update);
1373 /* now do the seek, this actually never returns FALSE */
1374 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1376 /* prepare for streaming again */
1378 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop ());
1379 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop ());
1380 } else if (qtdemux->segment_running) {
1381 /* we are running the current segment and doing a non-flushing seek,
1382 * close the segment first based on the last_stop. */
1383 GST_DEBUG_OBJECT (qtdemux, "closing running segment %" G_GINT64_FORMAT
1384 " to %" G_GINT64_FORMAT, qtdemux->segment.start,
1385 qtdemux->segment.last_stop);
1387 if (qtdemux->segment.rate >= 0) {
1388 /* FIXME, rate is the product of the global rate and the (quicktime)
1390 qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
1391 qtdemux->segment.rate, qtdemux->segment.format,
1392 qtdemux->segment.start, qtdemux->segment.last_stop,
1393 qtdemux->segment.time);
1394 } else { /* For Reverse Playback */
1397 if ((stop = qtdemux->segment.stop) == -1)
1398 stop = qtdemux->segment.duration;
1399 /* for reverse playback, we played from stop to last_stop. */
1400 qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
1401 qtdemux->segment.rate, qtdemux->segment.format,
1402 qtdemux->segment.last_stop, stop, qtdemux->segment.last_stop);
1406 /* commit the new segment */
1407 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1409 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1410 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1411 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1412 qtdemux->segment.format, qtdemux->segment.last_stop));
1415 /* restart streaming, NEWSEGMENT will be sent from the streaming
1417 qtdemux->segment_running = TRUE;
1418 for (i = 0; i < qtdemux->n_streams; i++)
1419 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1421 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1424 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1431 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1437 qtdemux_ensure_index (GstQTDemux * qtdemux)
1441 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1443 /* Build complete index */
1444 for (i = 0; i < qtdemux->n_streams; i++) {
1445 QtDemuxStream *stream = qtdemux->streams[i];
1447 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1455 GST_LOG_OBJECT (qtdemux,
1456 "Building complete index of stream %u for seeking failed!", i);
1462 gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
1464 gboolean res = TRUE;
1465 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
1467 switch (GST_EVENT_TYPE (event)) {
1468 case GST_EVENT_SEEK:
1470 #ifndef GST_DISABLE_GST_DEBUG
1471 GstClockTime ts = gst_util_get_timestamp ();
1473 /* Build complete index for seeking;
1474 * if not a fragmented file at least */
1475 if (!qtdemux->fragmented)
1476 if (!qtdemux_ensure_index (qtdemux))
1478 #ifndef GST_DISABLE_GST_DEBUG
1479 ts = gst_util_get_timestamp () - ts;
1480 GST_INFO_OBJECT (qtdemux,
1481 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1484 if (qtdemux->pullbased) {
1485 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1486 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams &&
1487 !qtdemux->fragmented) {
1488 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1490 GST_DEBUG_OBJECT (qtdemux,
1491 "ignoring seek in push mode in current state");
1494 gst_event_unref (event);
1497 case GST_EVENT_NAVIGATION:
1499 gst_event_unref (event);
1502 res = gst_pad_event_default (pad, event);
1506 gst_object_unref (qtdemux);
1514 GST_ERROR_OBJECT (qtdemux, "Index failed");
1515 gst_event_unref (event);
1521 /* stream/index return sample that is min/max w.r.t. byte position,
1522 * time is min/max w.r.t. time of samples,
1523 * the latter need not be time of the former sample */
1525 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1526 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1529 gint64 time, min_time;
1530 QtDemuxStream *stream;
1536 for (n = 0; n < qtdemux->n_streams; ++n) {
1539 gboolean set_sample;
1541 str = qtdemux->streams[n];
1548 i = str->n_samples - 1;
1551 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1552 if (str->samples[i].size &&
1553 ((fw && (str->samples[i].offset >= byte_pos)) ||
1555 (str->samples[i].offset + str->samples[i].size <=
1557 /* move stream to first available sample */
1559 gst_qtdemux_move_stream (qtdemux, str, i);
1562 /* determine min/max time */
1563 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1564 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1565 if (min_time == -1 || (!fw && time > min_time) ||
1566 (fw && time < min_time)) {
1569 /* determine stream with leading sample, to get its position */
1571 && (str->samples[i].offset < stream->samples[index].offset))
1573 && (str->samples[i].offset > stream->samples[index].offset))) {
1580 /* no sample for this stream, mark eos */
1582 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1594 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
1596 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1599 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1601 switch (GST_EVENT_TYPE (event)) {
1602 case GST_EVENT_NEWSEGMENT:
1605 gdouble rate, arate;
1606 gint64 start, stop, time, offset = 0;
1607 QtDemuxStream *stream;
1612 /* some debug output */
1613 gst_segment_init (&segment, GST_FORMAT_UNDEFINED);
1614 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
1615 &start, &stop, &time);
1616 gst_segment_set_newsegment_full (&segment, update, rate, arate, format,
1618 GST_DEBUG_OBJECT (demux,
1619 "received format %d newsegment %" GST_SEGMENT_FORMAT, format,
1622 /* chain will send initial newsegment after pads have been added */
1623 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1624 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1628 /* we only expect a BYTE segment, e.g. following a seek */
1629 if (format == GST_FORMAT_BYTES) {
1631 gint64 requested_seek_time;
1632 guint64 seek_offset;
1636 GST_OBJECT_LOCK (demux);
1637 requested_seek_time = demux->requested_seek_time;
1638 seek_offset = demux->seek_offset;
1639 demux->requested_seek_time = -1;
1640 demux->seek_offset = -1;
1641 GST_OBJECT_UNLOCK (demux);
1643 if (offset == seek_offset) {
1644 start = requested_seek_time;
1646 gst_qtdemux_find_sample (demux, start, TRUE, FALSE, NULL, NULL,
1648 start = MAX (start, 0);
1652 gst_qtdemux_find_sample (demux, stop, FALSE, FALSE, NULL, NULL,
1654 /* keyframe seeking should already arrange for start >= stop,
1655 * but make sure in other rare cases */
1656 stop = MAX (stop, start);
1659 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1663 /* accept upstream's notion of segment and distribute along */
1664 gst_segment_set_newsegment_full (&demux->segment, update, rate, arate,
1665 GST_FORMAT_TIME, start, stop, start);
1666 GST_DEBUG_OBJECT (demux, "Pushing newseg update %d, rate %g, "
1667 "applied rate %g, format %d, start %" GST_TIME_FORMAT ", "
1668 "stop %" GST_TIME_FORMAT, update, rate, arate, GST_FORMAT_TIME,
1669 GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1671 gst_qtdemux_push_event (demux,
1672 gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME,
1673 start, stop, start));
1675 /* clear leftover in current segment, if any */
1676 gst_adapter_clear (demux->adapter);
1677 /* set up streaming thread */
1678 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1679 demux->offset = offset;
1681 demux->todrop = stream->samples[idx].offset - offset;
1682 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1684 /* set up for EOS */
1685 demux->neededbytes = -1;
1689 gst_event_unref (event);
1694 case GST_EVENT_FLUSH_STOP:
1698 /* clean up, force EOS if no more info follows */
1699 gst_adapter_clear (demux->adapter);
1701 demux->neededbytes = -1;
1702 /* reset flow return, e.g. following seek */
1703 for (i = 0; i < demux->n_streams; i++) {
1704 demux->streams[i]->last_ret = GST_FLOW_OK;
1705 demux->streams[i]->sent_eos = FALSE;
1710 /* If we are in push mode, and get an EOS before we've seen any streams,
1711 * then error out - we have nowhere to send the EOS */
1712 if (!demux->pullbased) {
1714 gboolean has_valid_stream = FALSE;
1715 for (i = 0; i < demux->n_streams; i++) {
1716 if (demux->streams[i]->pad != NULL) {
1717 has_valid_stream = TRUE;
1721 if (!has_valid_stream)
1722 gst_qtdemux_post_no_playable_stream_error (demux);
1729 res = gst_pad_event_default (demux->sinkpad, event);
1736 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1738 GstQTDemux *demux = GST_QTDEMUX (element);
1740 GST_OBJECT_LOCK (demux);
1741 if (demux->element_index)
1742 gst_object_unref (demux->element_index);
1744 demux->element_index = gst_object_ref (index);
1746 demux->element_index = NULL;
1748 GST_OBJECT_UNLOCK (demux);
1749 /* object lock might be taken again */
1751 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1752 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
1753 demux->element_index, demux->index_id);
1757 gst_qtdemux_get_index (GstElement * element)
1759 GstIndex *result = NULL;
1760 GstQTDemux *demux = GST_QTDEMUX (element);
1762 GST_OBJECT_LOCK (demux);
1763 if (demux->element_index)
1764 result = gst_object_ref (demux->element_index);
1765 GST_OBJECT_UNLOCK (demux);
1767 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1773 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1775 g_free ((gpointer) stream->stco.data);
1776 stream->stco.data = NULL;
1777 g_free ((gpointer) stream->stsz.data);
1778 stream->stsz.data = NULL;
1779 g_free ((gpointer) stream->stsc.data);
1780 stream->stsc.data = NULL;
1781 g_free ((gpointer) stream->stts.data);
1782 stream->stts.data = NULL;
1783 g_free ((gpointer) stream->stss.data);
1784 stream->stss.data = NULL;
1785 g_free ((gpointer) stream->stps.data);
1786 stream->stps.data = NULL;
1787 g_free ((gpointer) stream->ctts.data);
1788 stream->ctts.data = NULL;
1792 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
1794 while (stream->buffers) {
1795 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1796 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1799 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
1800 g_free (stream->samples);
1802 gst_caps_unref (stream->caps);
1803 g_free (stream->segments);
1804 if (stream->pending_tags)
1805 gst_tag_list_free (stream->pending_tags);
1806 g_free (stream->redirect_uri);
1807 /* free stbl sub-atoms */
1808 gst_qtdemux_stbl_free (stream);
1812 static GstStateChangeReturn
1813 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1815 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1816 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1818 switch (transition) {
1819 case GST_STATE_CHANGE_PAUSED_TO_READY:
1825 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1827 switch (transition) {
1828 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1831 qtdemux->state = QTDEMUX_STATE_INITIAL;
1832 qtdemux->neededbytes = 16;
1833 qtdemux->todrop = 0;
1834 qtdemux->pullbased = FALSE;
1835 qtdemux->posted_redirect = FALSE;
1836 qtdemux->offset = 0;
1837 qtdemux->first_mdat = -1;
1838 qtdemux->got_moov = FALSE;
1839 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1840 if (qtdemux->mdatbuffer)
1841 gst_buffer_unref (qtdemux->mdatbuffer);
1842 qtdemux->mdatbuffer = NULL;
1843 if (qtdemux->comp_brands)
1844 gst_buffer_unref (qtdemux->comp_brands);
1845 qtdemux->comp_brands = NULL;
1846 if (qtdemux->tag_list)
1847 gst_tag_list_free (qtdemux->tag_list);
1848 qtdemux->tag_list = NULL;
1849 if (qtdemux->element_index)
1850 gst_object_unref (qtdemux->element_index);
1851 qtdemux->element_index = NULL;
1852 gst_adapter_clear (qtdemux->adapter);
1853 for (n = 0; n < qtdemux->n_streams; n++) {
1854 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1855 qtdemux->streams[n] = NULL;
1857 qtdemux->major_brand = 0;
1858 qtdemux->n_streams = 0;
1859 qtdemux->n_video_streams = 0;
1860 qtdemux->n_audio_streams = 0;
1861 qtdemux->n_sub_streams = 0;
1862 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1863 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1864 qtdemux->seek_offset = 0;
1875 qtdemux_post_global_tags (GstQTDemux * qtdemux)
1877 if (qtdemux->tag_list) {
1878 /* all header tags ready and parsed, push them */
1879 GST_INFO_OBJECT (qtdemux, "posting global tags: %" GST_PTR_FORMAT,
1881 /* post now, send event on pads later */
1882 gst_element_post_message (GST_ELEMENT (qtdemux),
1883 gst_message_new_tag (GST_OBJECT (qtdemux),
1884 gst_tag_list_copy (qtdemux->tag_list)));
1889 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1891 /* only consider at least a sufficiently complete ftyp atom */
1895 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1896 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1897 GST_FOURCC_ARGS (qtdemux->major_brand));
1898 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1899 memcpy (GST_BUFFER_DATA (buf), buffer + 16, GST_BUFFER_SIZE (buf));
1904 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
1906 /* Strip out bogus fields */
1908 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
1910 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
1912 if (qtdemux->tag_list) {
1913 /* prioritize native tags using _KEEP mode */
1914 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
1915 gst_tag_list_free (taglist);
1917 qtdemux->tag_list = taglist;
1922 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1924 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
1925 0x97, 0xA9, 0x42, 0xE8,
1926 0x9C, 0x71, 0x99, 0x94,
1927 0x91, 0xE3, 0xAF, 0xAC
1931 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
1933 if (length <= offset + 16) {
1934 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
1938 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
1940 GstTagList *taglist;
1942 buf = gst_buffer_new ();
1943 GST_BUFFER_DATA (buf) = (guint8 *) buffer + offset + 16;
1944 GST_BUFFER_SIZE (buf) = length - offset - 16;
1946 taglist = gst_tag_list_from_xmp_buffer (buf);
1947 gst_buffer_unref (buf);
1949 qtdemux_handle_xmp_taglist (qtdemux, taglist);
1952 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
1956 /* caller verifies at least 8 bytes in buf */
1958 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1959 guint64 * plength, guint32 * pfourcc)
1964 length = QT_UINT32 (data);
1965 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1966 fourcc = QT_FOURCC (data + 4);
1967 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1970 length = G_MAXUINT32;
1971 } else if (length == 1 && size >= 16) {
1972 /* this means we have an extended size, which is the 64 bit value of
1973 * the next 8 bytes */
1974 length = QT_UINT64 (data + 8);
1975 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1985 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
1987 guint32 version = 0;
1988 guint64 duration = 0;
1990 if (!gst_byte_reader_get_uint32_be (br, &version))
1995 if (!gst_byte_reader_get_uint64_be (br, &duration))
2000 if (!gst_byte_reader_get_uint32_be (br, &dur))
2005 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2006 qtdemux->duration = duration;
2012 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2018 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2019 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2021 if (!stream->parsed_trex && qtdemux->moov_node) {
2023 GstByteReader trex_data;
2025 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2027 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2030 guint32 id = 0, dur = 0, size = 0, flags = 0;
2032 /* skip version/flags */
2033 if (!gst_byte_reader_skip (&trex_data, 4))
2035 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2037 if (id != stream->track_id)
2039 /* sample description index; ignore */
2040 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2042 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2044 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2046 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2049 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2050 "duration %d, size %d, flags 0x%x", stream->track_id,
2053 stream->parsed_trex = TRUE;
2054 stream->def_sample_duration = dur;
2055 stream->def_sample_size = size;
2056 stream->def_sample_flags = flags;
2059 /* iterate all siblings */
2060 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2066 *ds_duration = stream->def_sample_duration;
2067 *ds_size = stream->def_sample_size;
2068 *ds_size = stream->def_sample_size;
2070 /* even then, above values are better than random ... */
2071 if (G_UNLIKELY (!stream->parsed_trex)) {
2072 GST_WARNING_OBJECT (qtdemux,
2073 "failed to find fragment defaults for stream %d", stream->track_id);
2081 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2082 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2083 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2084 gint64 * base_offset, gint64 * running_offset)
2087 gint32 data_offset = 0;
2088 guint32 flags = 0, first_flags = 0, samples_count = 0;
2091 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2092 QtDemuxSample *sample;
2093 gboolean ismv = FALSE;
2095 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2096 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2097 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2100 if (!gst_byte_reader_skip (trun, 1) ||
2101 !gst_byte_reader_get_uint24_be (trun, &flags))
2104 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2107 if (flags & TR_DATA_OFFSET) {
2108 /* note this is really signed */
2109 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2111 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2112 /* default base offset = first byte of moof */
2113 if (*base_offset == -1) {
2114 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2115 *base_offset = moof_offset;
2117 *running_offset = *base_offset + data_offset;
2119 /* if no offset at all, that would mean data starts at moof start,
2120 * which is a bit wrong and is ismv crappy way, so compensate
2121 * assuming data is in mdat following moof */
2122 if (*base_offset == -1) {
2123 *base_offset = moof_offset + moof_length + 8;
2124 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2127 if (*running_offset == -1)
2128 *running_offset = *base_offset;
2131 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2133 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2134 data_offset, flags, samples_count);
2136 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2137 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2138 GST_DEBUG_OBJECT (qtdemux,
2139 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2140 flags ^= TR_FIRST_SAMPLE_FLAGS;
2142 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2144 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2148 /* FIXME ? spec says other bits should also be checked to determine
2149 * entry size (and prefix size for that matter) */
2151 dur_offset = size_offset = 0;
2152 if (flags & TR_SAMPLE_DURATION) {
2153 GST_LOG_OBJECT (qtdemux, "entry duration present");
2154 dur_offset = entry_size;
2157 if (flags & TR_SAMPLE_SIZE) {
2158 GST_LOG_OBJECT (qtdemux, "entry size present");
2159 size_offset = entry_size;
2162 if (flags & TR_SAMPLE_FLAGS) {
2163 GST_LOG_OBJECT (qtdemux, "entry flags present");
2164 flags_offset = entry_size;
2167 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2168 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2169 ct_offset = entry_size;
2173 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2175 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2177 if (stream->n_samples >=
2178 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2181 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2182 stream->n_samples, (guint) sizeof (QtDemuxSample),
2183 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2185 /* create a new array of samples if it's the first sample parsed */
2186 if (stream->n_samples == 0)
2187 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2188 /* or try to reallocate it with space enough to insert the new samples */
2190 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2191 stream->n_samples + samples_count);
2192 if (stream->samples == NULL)
2195 if (G_UNLIKELY (stream->n_samples == 0)) {
2196 /* the timestamp of the first sample is also provided by the tfra entry
2197 * but we shouldn't rely on it as it is at the end of files */
2200 /* subsequent fragments extend stream */
2202 stream->samples[stream->n_samples - 1].timestamp +
2203 stream->samples[stream->n_samples - 1].duration;
2205 sample = stream->samples + stream->n_samples;
2206 for (i = 0; i < samples_count; i++) {
2207 guint32 dur, size, sflags, ct;
2209 /* first read sample data */
2210 if (flags & TR_SAMPLE_DURATION) {
2211 dur = QT_UINT32 (data + dur_offset);
2213 dur = d_sample_duration;
2215 if (flags & TR_SAMPLE_SIZE) {
2216 size = QT_UINT32 (data + size_offset);
2218 size = d_sample_size;
2220 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2222 sflags = first_flags;
2224 sflags = d_sample_flags;
2226 } else if (flags & TR_SAMPLE_FLAGS) {
2227 sflags = QT_UINT32 (data + flags_offset);
2229 sflags = d_sample_flags;
2231 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2232 ct = QT_UINT32 (data + ct_offset);
2238 /* fill the sample information */
2239 sample->offset = *running_offset;
2240 sample->pts_offset = ct;
2241 sample->size = size;
2242 sample->timestamp = timestamp;
2243 sample->duration = dur;
2244 /* sample-is-difference-sample */
2245 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2246 * now idea how it relates to bitfield other than massive LE/BE confusion */
2247 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2248 *running_offset += size;
2253 stream->n_samples += samples_count;
2259 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2264 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2270 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2271 "be larger than %uMB (broken file?)", stream->n_samples,
2272 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2277 /* find stream with @id */
2278 static inline QtDemuxStream *
2279 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2281 QtDemuxStream *stream;
2285 if (G_UNLIKELY (!id)) {
2286 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2290 /* try to get it fast and simple */
2291 if (G_LIKELY (id <= qtdemux->n_streams)) {
2292 stream = qtdemux->streams[id - 1];
2293 if (G_LIKELY (stream->track_id == id))
2297 /* linear search otherwise */
2298 for (i = 0; i < qtdemux->n_streams; i++) {
2299 stream = qtdemux->streams[i];
2300 if (stream->track_id == id)
2308 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2309 QtDemuxStream ** stream, guint32 * default_sample_duration,
2310 guint32 * default_sample_size, guint32 * default_sample_flags,
2311 gint64 * base_offset)
2314 guint32 track_id = 0;
2316 if (!gst_byte_reader_skip (tfhd, 1) ||
2317 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2320 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2323 *stream = qtdemux_find_stream (qtdemux, track_id);
2324 if (G_UNLIKELY (!*stream))
2325 goto unknown_stream;
2327 if (flags & TF_BASE_DATA_OFFSET)
2328 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2331 /* obtain stream defaults */
2332 qtdemux_parse_trex (qtdemux, *stream,
2333 default_sample_duration, default_sample_size, default_sample_flags);
2335 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2336 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2337 if (!gst_byte_reader_skip (tfhd, 4))
2340 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2341 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2344 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2345 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2348 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2349 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2356 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2361 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2367 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2368 guint64 moof_offset, QtDemuxStream * stream)
2370 GNode *moof_node, *traf_node, *tfhd_node, *trun_node;
2371 GstByteReader trun_data, tfhd_data;
2372 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2373 gint64 base_offset, running_offset;
2375 /* NOTE @stream ignored */
2377 moof_node = g_node_new ((guint8 *) buffer);
2378 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2379 qtdemux_node_dump (qtdemux, moof_node);
2381 /* unknown base_offset to start with */
2382 base_offset = running_offset = -1;
2383 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2385 /* Fragment Header node */
2387 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2391 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2392 &ds_size, &ds_flags, &base_offset))
2394 if (G_UNLIKELY (!stream)) {
2395 /* we lost track of offset, we'll need to regain it,
2396 * but can delay complaining until later or avoid doing so altogether */
2400 if (G_UNLIKELY (base_offset < -1))
2402 /* Track Run node */
2404 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2407 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2408 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2410 /* iterate all siblings */
2411 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2414 /* if no new base_offset provided for next traf,
2415 * base is end of current traf */
2416 base_offset = running_offset;
2417 running_offset = -1;
2419 /* iterate all siblings */
2420 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2422 g_node_destroy (moof_node);
2427 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2432 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2437 g_node_destroy (moof_node);
2438 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2439 (_("This file is corrupt and cannot be played.")), (NULL));
2444 /* might be used if some day we actually use mfra & co
2445 * for random access to fragments,
2446 * but that will require quite some modifications and much less relying
2447 * on a sample array */
2450 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2451 QtDemuxStream * stream)
2453 guint64 time = 0, moof_offset = 0;
2454 guint32 ver_flags, track_id, len, num_entries, i;
2455 guint value_size, traf_size, trun_size, sample_size;
2456 GstBuffer *buf = NULL;
2460 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2461 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2463 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2466 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2467 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2468 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2471 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2472 track_id, stream->track_id);
2473 if (track_id != stream->track_id) {
2477 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2478 sample_size = (len & 3) + 1;
2479 trun_size = ((len & 12) >> 2) + 1;
2480 traf_size = ((len & 48) >> 4) + 1;
2482 if (num_entries == 0)
2485 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2486 value_size + value_size + traf_size + trun_size + sample_size))
2489 for (i = 0; i < num_entries; i++) {
2490 qt_atom_parser_get_offset (&tfra, value_size, &time);
2491 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2492 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2493 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2494 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2496 GST_LOG_OBJECT (qtdemux,
2497 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2498 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2499 stream->timescale)), moof_offset);
2501 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2502 if (ret != GST_FLOW_OK)
2504 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2505 moof_offset, stream);
2506 gst_buffer_unref (buf);
2514 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2515 (_("This file is corrupt and cannot be played.")), (NULL));
2520 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2526 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2529 GNode *mfra_node, *tfra_node;
2532 if (!qtdemux->mfra_offset)
2535 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2536 if (ret != GST_FLOW_OK)
2539 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2540 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2541 GST_BUFFER_SIZE (buffer));
2543 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2546 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2547 /* iterate all siblings */
2548 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2550 g_node_destroy (mfra_node);
2551 gst_buffer_unref (buffer);
2557 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2558 (_("This file is corrupt and cannot be played.")), (NULL));
2563 static GstFlowReturn
2564 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2565 guint32 * mfro_size)
2567 GstFlowReturn ret = GST_FLOW_ERROR;
2568 GstBuffer *mfro = NULL;
2571 GstFormat fmt = GST_FORMAT_BYTES;
2573 if (!gst_pad_query_peer_duration (qtdemux->sinkpad, &fmt, &len)) {
2574 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2575 "can not locate mfro");
2579 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2580 if (ret != GST_FLOW_OK)
2583 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2584 if (fourcc != FOURCC_mfro)
2587 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2588 if (GST_BUFFER_SIZE (mfro) >= 16) {
2589 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
2590 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
2591 if (*mfro_size >= len) {
2592 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
2593 ret = GST_FLOW_ERROR;
2596 *mfra_offset = len - *mfro_size;
2601 gst_buffer_unref (mfro);
2607 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
2610 guint32 mfra_size = 0;
2611 guint64 mfra_offset = 0;
2614 qtdemux->fragmented = FALSE;
2616 /* We check here if it is a fragmented mp4 container */
2617 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
2618 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
2619 qtdemux->fragmented = TRUE;
2620 GST_DEBUG_OBJECT (qtdemux,
2621 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
2622 qtdemux->mfra_offset = mfra_offset;
2627 static GstFlowReturn
2628 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
2632 GstBuffer *buf = NULL;
2633 GstFlowReturn ret = GST_FLOW_OK;
2634 guint64 cur_offset = qtdemux->offset;
2636 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
2637 if (G_UNLIKELY (ret != GST_FLOW_OK))
2639 if (G_LIKELY (GST_BUFFER_SIZE (buf) >= 8))
2640 extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf),
2641 GST_BUFFER_SIZE (buf), &length, &fourcc);
2642 gst_buffer_unref (buf);
2644 /* maybe we already got most we needed, so only consider this eof */
2645 if (G_UNLIKELY (length == 0)) {
2646 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
2647 (_("Invalid atom size.")),
2648 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
2649 GST_FOURCC_ARGS (fourcc)));
2650 ret = GST_FLOW_UNEXPECTED;
2656 /* record for later parsing when needed */
2657 if (!qtdemux->moof_offset) {
2658 qtdemux->moof_offset = qtdemux->offset;
2667 GST_LOG_OBJECT (qtdemux,
2668 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
2669 GST_FOURCC_ARGS (fourcc), cur_offset);
2670 qtdemux->offset += length;
2677 if (qtdemux->got_moov) {
2678 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
2679 qtdemux->offset += length;
2683 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
2684 if (ret != GST_FLOW_OK)
2686 if (length != GST_BUFFER_SIZE (moov)) {
2687 /* Some files have a 'moov' atom at the end of the file which contains
2688 * a terminal 'free' atom where the body of the atom is missing.
2689 * Check for, and permit, this special case.
2691 if (GST_BUFFER_SIZE (moov) >= 8) {
2692 guint8 *final_data = GST_BUFFER_DATA (moov) +
2693 (GST_BUFFER_SIZE (moov) - 8);
2694 guint32 final_length = QT_UINT32 (final_data);
2695 guint32 final_fourcc = QT_FOURCC (final_data + 4);
2696 if (final_fourcc == FOURCC_free &&
2697 GST_BUFFER_SIZE (moov) + final_length - 8 == length) {
2698 /* Ok, we've found that special case. Allocate a new buffer with
2699 * that free atom actually present. */
2700 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
2701 gst_buffer_copy_metadata (newmoov, moov,
2702 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
2703 GST_BUFFER_COPY_CAPS);
2704 memcpy (GST_BUFFER_DATA (newmoov), GST_BUFFER_DATA (moov),
2705 GST_BUFFER_SIZE (moov));
2706 memset (GST_BUFFER_DATA (newmoov) + GST_BUFFER_SIZE (moov), 0,
2708 gst_buffer_unref (moov);
2714 if (length != GST_BUFFER_SIZE (moov)) {
2715 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2716 (_("This file is incomplete and cannot be played.")),
2717 ("We got less than expected (received %u, wanted %u, offset %"
2718 G_GUINT64_FORMAT ")",
2719 GST_BUFFER_SIZE (moov), (guint) length, cur_offset));
2720 ret = GST_FLOW_ERROR;
2723 qtdemux->offset += length;
2725 qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
2726 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
2728 qtdemux_parse_tree (qtdemux);
2729 g_node_destroy (qtdemux->moov_node);
2730 gst_buffer_unref (moov);
2731 qtdemux->moov_node = NULL;
2732 qtdemux->got_moov = TRUE;
2740 /* extract major brand; might come in handy for ISO vs QT issues */
2741 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
2742 if (ret != GST_FLOW_OK)
2744 qtdemux->offset += length;
2745 qtdemux_parse_ftyp (qtdemux, GST_BUFFER_DATA (ftyp),
2746 GST_BUFFER_SIZE (ftyp));
2747 gst_buffer_unref (ftyp);
2754 /* uuid are extension atoms */
2755 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
2756 if (ret != GST_FLOW_OK)
2758 qtdemux->offset += length;
2759 qtdemux_parse_uuid (qtdemux, GST_BUFFER_DATA (uuid),
2760 GST_BUFFER_SIZE (uuid));
2761 gst_buffer_unref (uuid);
2768 GST_LOG_OBJECT (qtdemux,
2769 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
2770 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
2772 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
2773 if (ret != GST_FLOW_OK)
2775 GST_MEMDUMP ("Unknown tag", GST_BUFFER_DATA (unknown),
2776 GST_BUFFER_SIZE (unknown));
2777 gst_buffer_unref (unknown);
2778 qtdemux->offset += length;
2784 if (ret == GST_FLOW_UNEXPECTED && qtdemux->got_moov) {
2785 /* digested all data, show what we have */
2786 ret = qtdemux_expose_streams (qtdemux);
2788 /* Only post, event on pads is done after newsegment */
2789 qtdemux_post_global_tags (qtdemux);
2791 qtdemux->state = QTDEMUX_STATE_MOVIE;
2792 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
2799 /* Seeks to the previous keyframe of the indexed stream and
2800 * aligns other streams with respect to the keyframe timestamp
2801 * of indexed stream. Only called in case of Reverse Playback
2803 static GstFlowReturn
2804 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
2807 guint32 seg_idx = 0, k_index = 0;
2808 guint32 ref_seg_idx, ref_k_index;
2809 guint64 k_pos = 0, last_stop = 0;
2810 QtDemuxSegment *seg = NULL;
2811 QtDemuxStream *ref_str = NULL;
2812 guint64 seg_media_start_mov; /* segment media start time in mov format */
2814 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
2815 * and finally align all the other streams on that timestamp with their
2816 * respective keyframes */
2817 for (n = 0; n < qtdemux->n_streams; n++) {
2818 QtDemuxStream *str = qtdemux->streams[n];
2820 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
2821 qtdemux->segment.last_stop);
2823 /* segment not found, continue with normal flow */
2827 /* No candidate yet, take that one */
2833 /* So that stream has a segment, we prefer video streams */
2834 if (str->subtype == FOURCC_vide) {
2840 if (G_UNLIKELY (!ref_str)) {
2841 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
2845 if (G_UNLIKELY (!ref_str->from_sample)) {
2846 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
2850 /* So that stream has been playing from from_sample to to_sample. We will
2851 * get the timestamp of the previous sample and search for a keyframe before
2852 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
2853 if (ref_str->subtype == FOURCC_vide) {
2854 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
2855 ref_str->from_sample - 1);
2857 if (ref_str->from_sample >= 10)
2858 k_index = ref_str->from_sample - 10;
2863 /* get current segment for that stream */
2864 seg = &ref_str->segments[ref_str->segment_index];
2865 /* convert seg->media_start to mov format time for timestamp comparison */
2866 seg_media_start_mov =
2867 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
2868 /* Crawl back through segments to find the one containing this I frame */
2869 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
2870 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
2871 ref_str->segment_index);
2872 if (G_UNLIKELY (!ref_str->segment_index)) {
2873 /* Reached first segment, let's consider it's EOS */
2876 ref_str->segment_index--;
2877 seg = &ref_str->segments[ref_str->segment_index];
2878 /* convert seg->media_start to mov format time for timestamp comparison */
2879 seg_media_start_mov =
2880 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
2883 /* Calculate time position of the keyframe and where we should stop */
2885 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
2886 ref_str->timescale) - seg->media_start) + seg->time;
2888 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
2889 GST_SECOND, ref_str->timescale);
2890 last_stop = (last_stop - seg->media_start) + seg->time;
2892 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
2893 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
2894 k_index, GST_TIME_ARGS (k_pos));
2896 /* Set last_stop with the keyframe timestamp we pushed of that stream */
2897 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, last_stop);
2898 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
2899 GST_TIME_ARGS (last_stop));
2901 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
2902 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
2906 ref_seg_idx = ref_str->segment_index;
2907 ref_k_index = k_index;
2909 /* Align them all on this */
2910 for (n = 0; n < qtdemux->n_streams; n++) {
2912 guint64 media_start = 0, seg_time = 0;
2913 QtDemuxStream *str = qtdemux->streams[n];
2915 /* aligning reference stream again might lead to backing up to yet another
2916 * keyframe (due to timestamp rounding issues),
2917 * potentially putting more load on downstream; so let's try to avoid */
2918 if (str == ref_str) {
2919 seg_idx = ref_seg_idx;
2920 seg = &str->segments[seg_idx];
2921 k_index = ref_k_index;
2922 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
2923 "sample at index %d", ref_str->segment_index, k_index);
2925 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
2926 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
2928 /* segment not found, continue with normal flow */
2932 /* get segment and time in the segment */
2933 seg = &str->segments[seg_idx];
2934 seg_time = k_pos - seg->time;
2936 /* get the media time in the segment */
2937 media_start = seg->media_start + seg_time;
2939 /* get the index of the sample with media time */
2940 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
2941 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
2942 GST_TIME_ARGS (media_start), index);
2944 /* find previous keyframe */
2945 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
2948 /* Remember until where we want to go */
2949 str->to_sample = str->from_sample - 1;
2950 /* Define our time position */
2951 str->time_position =
2952 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
2953 str->timescale) - seg->media_start) + seg->time;
2954 /* Now seek back in time */
2955 gst_qtdemux_move_stream (qtdemux, str, k_index);
2956 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
2957 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
2958 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
2964 return GST_FLOW_UNEXPECTED;
2967 /* activate the given segment number @seg_idx of @stream at time @offset.
2968 * @offset is an absolute global position over all the segments.
2970 * This will push out a NEWSEGMENT event with the right values and
2971 * position the stream index to the first decodable sample before
2975 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
2976 guint32 seg_idx, guint64 offset)
2979 QtDemuxSegment *segment;
2980 guint32 index, kf_index;
2982 guint64 start, stop, time;
2985 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
2988 /* update the current segment */
2989 stream->segment_index = seg_idx;
2991 /* get the segment */
2992 segment = &stream->segments[seg_idx];
2994 if (G_UNLIKELY (offset < segment->time)) {
2995 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3000 /* segment lies beyond total indicated duration */
3001 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3002 segment->time > qtdemux->segment.duration)) {
3003 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3004 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3009 /* get time in this segment */
3010 seg_time = offset - segment->time;
3012 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3013 GST_TIME_ARGS (seg_time));
3015 if (G_UNLIKELY (seg_time > segment->duration)) {
3016 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3017 GST_TIME_ARGS (segment->duration));
3021 /* qtdemux->segment.stop is in outside-time-realm, whereas
3022 * segment->media_stop is in track-time-realm.
3024 * In order to compare the two, we need to bring segment.stop
3025 * into the track-time-realm */
3027 stop = qtdemux->segment.stop;
3029 stop = qtdemux->segment.duration;
3031 stop = segment->media_stop;
3034 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3036 if (qtdemux->segment.rate >= 0) {
3037 start = MIN (segment->media_start + seg_time, stop);
3040 if (segment->media_start >= qtdemux->segment.start) {
3041 start = segment->media_start;
3042 time = segment->time;
3044 start = qtdemux->segment.start;
3045 time = segment->time + (qtdemux->segment.start - segment->media_start);
3048 start = MAX (segment->media_start, qtdemux->segment.start);
3049 stop = MIN (segment->media_start + seg_time, stop);
3052 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3053 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3054 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3056 /* combine global rate with that of the segment */
3057 rate = segment->rate * qtdemux->segment.rate;
3059 /* update the segment values used for clipping */
3060 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
3061 gst_segment_set_newsegment (&stream->segment, FALSE, rate, GST_FORMAT_TIME,
3064 /* now prepare and send the segment */
3066 event = gst_event_new_new_segment (FALSE, rate, GST_FORMAT_TIME,
3068 gst_pad_push_event (stream->pad, event);
3069 /* assume we can send more data now */
3070 stream->last_ret = GST_FLOW_OK;
3071 /* clear to send tags on this pad now */
3072 gst_qtdemux_push_tags (qtdemux, stream);
3075 /* and move to the keyframe before the indicated media time of the
3077 if (qtdemux->segment.rate >= 0) {
3078 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3079 stream->to_sample = G_MAXUINT32;
3080 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3081 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3082 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3083 GST_SECOND, stream->timescale)));
3085 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3086 stream->to_sample = index;
3087 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3088 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3089 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3090 GST_SECOND, stream->timescale)));
3093 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3094 * encountered an error and printed a message so we return appropriately */
3098 /* we're at the right spot */
3099 if (index == stream->sample_index) {
3100 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3104 /* find keyframe of the target index */
3105 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3108 /* indent does stupid stuff with stream->samples[].timestamp */
3110 /* if we move forwards, we don't have to go back to the previous
3111 * keyframe since we already sent that. We can also just jump to
3112 * the keyframe right before the target index if there is one. */
3113 if (index > stream->sample_index) {
3114 /* moving forwards check if we move past a keyframe */
3115 if (kf_index > stream->sample_index) {
3116 GST_DEBUG_OBJECT (qtdemux,
3117 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3118 GST_TIME_ARGS (gst_util_uint64_scale (
3119 stream->samples[kf_index].timestamp,
3120 GST_SECOND, stream->timescale)));
3121 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3123 GST_DEBUG_OBJECT (qtdemux,
3124 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3125 " already sent", kf_index,
3126 GST_TIME_ARGS (gst_util_uint64_scale (
3127 stream->samples[kf_index].timestamp,
3128 GST_SECOND, stream->timescale)));
3131 GST_DEBUG_OBJECT (qtdemux,
3132 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3133 GST_TIME_ARGS (gst_util_uint64_scale (
3134 stream->samples[kf_index].timestamp,
3135 GST_SECOND, stream->timescale)));
3136 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3144 /* prepare to get the current sample of @stream, getting essential values.
3146 * This function will also prepare and send the segment when needed.
3148 * Return FALSE if the stream is EOS.
3151 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3152 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp,
3153 guint64 * duration, gboolean * keyframe)
3155 QtDemuxSample *sample;
3156 guint64 time_position;
3159 g_return_val_if_fail (stream != NULL, FALSE);
3161 time_position = stream->time_position;
3162 if (G_UNLIKELY (time_position == -1))
3165 seg_idx = stream->segment_index;
3166 if (G_UNLIKELY (seg_idx == -1)) {
3167 /* find segment corresponding to time_position if we are looking
3169 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3171 /* nothing found, we're really eos */
3176 /* different segment, activate it, sample_index will be set. */
3177 if (G_UNLIKELY (stream->segment_index != seg_idx))
3178 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3180 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3181 stream->sample_index, stream->n_samples);
3183 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3186 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3187 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3188 stream->sample_index);
3192 /* now get the info for the sample we're at */
3193 sample = &stream->samples[stream->sample_index];
3195 *timestamp = QTSAMPLE_PTS (stream, sample);
3196 *offset = sample->offset;
3197 *size = sample->size;
3198 *duration = QTSAMPLE_DUR_PTS (stream, sample, *timestamp);
3199 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3206 stream->time_position = -1;
3211 /* move to the next sample in @stream.
3213 * Moves to the next segment when needed.
3216 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3218 QtDemuxSample *sample;
3219 QtDemuxSegment *segment;
3221 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3222 /* Mark the stream as EOS */
3223 GST_DEBUG_OBJECT (qtdemux,
3224 "reached max allowed sample %u, mark EOS", stream->to_sample);
3225 stream->time_position = -1;
3229 /* move to next sample */
3230 stream->sample_index++;
3232 /* get current segment */
3233 segment = &stream->segments[stream->segment_index];
3235 /* reached the last sample, we need the next segment */
3236 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3239 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3240 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3241 stream->sample_index);
3245 /* get next sample */
3246 sample = &stream->samples[stream->sample_index];
3248 /* see if we are past the segment */
3249 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3250 GST_SECOND, stream->timescale) >= segment->media_stop))
3253 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3254 stream->timescale) >= segment->media_start) {
3255 /* inside the segment, update time_position, looks very familiar to
3256 * GStreamer segments, doesn't it? */
3257 stream->time_position =
3258 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3259 stream->timescale) - segment->media_start) + segment->time;
3261 /* not yet in segment, time does not yet increment. This means
3262 * that we are still prerolling keyframes to the decoder so it can
3263 * decode the first sample of the segment. */
3264 stream->time_position = segment->time;
3268 /* move to the next segment */
3271 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3273 if (stream->segment_index == stream->n_segments - 1) {
3274 /* are we at the end of the last segment, we're EOS */
3275 stream->time_position = -1;
3277 /* else we're only at the end of the current segment */
3278 stream->time_position = segment->stop_time;
3280 /* make sure we select a new segment */
3281 stream->segment_index = -1;
3286 gst_qtdemux_sync_streams (GstQTDemux * demux)
3290 if (demux->n_streams <= 1)
3293 for (i = 0; i < demux->n_streams; i++) {
3294 QtDemuxStream *stream;
3295 GstClockTime end_time;
3297 stream = demux->streams[i];
3302 /* TODO advance time on subtitle streams here, if any some day */
3304 /* some clips/trailers may have unbalanced streams at the end,
3305 * so send EOS on shorter stream to prevent stalling others */
3307 /* do not mess with EOS if SEGMENT seeking */
3308 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3311 if (demux->pullbased) {
3312 /* loop mode is sample time based */
3313 if (stream->time_position != -1)
3316 /* push mode is byte position based */
3317 if (stream->n_samples &&
3318 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3322 if (stream->sent_eos)
3325 /* only act if some gap */
3326 end_time = stream->segments[stream->n_segments - 1].stop_time;
3327 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3328 ", stream end: %" GST_TIME_FORMAT,
3329 GST_TIME_ARGS (demux->segment.last_stop), GST_TIME_ARGS (end_time));
3330 if (end_time + 2 * GST_SECOND < demux->segment.last_stop) {
3331 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3332 GST_PAD_NAME (stream->pad));
3333 stream->sent_eos = TRUE;
3334 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3339 /* UNEXPECTED and NOT_LINKED need to be combined. This means that we return:
3341 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3342 * GST_FLOW_UNEXPECTED: when all pads UNEXPECTED or NOT_LINKED.
3344 static GstFlowReturn
3345 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3349 gboolean unexpected = FALSE, not_linked = TRUE;
3351 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3353 /* store the value */
3354 stream->last_ret = ret;
3356 /* any other error that is not-linked or eos can be returned right away */
3357 if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
3360 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3361 for (i = 0; i < demux->n_streams; i++) {
3362 QtDemuxStream *ostream = demux->streams[i];
3364 ret = ostream->last_ret;
3366 /* no unexpected or unlinked, return */
3367 if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
3370 /* we check to see if we have at least 1 unexpected or all unlinked */
3371 unexpected |= (ret == GST_FLOW_UNEXPECTED);
3372 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3375 /* when we get here, we all have unlinked or unexpected */
3377 ret = GST_FLOW_NOT_LINKED;
3378 else if (unexpected)
3379 ret = GST_FLOW_UNEXPECTED;
3381 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3385 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3386 * completely cliped */
3388 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3391 gint64 start, stop, cstart, cstop, diff;
3392 GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
3395 gint num_rate, denom_rate;
3399 data = GST_BUFFER_DATA (buf);
3400 size = GST_BUFFER_SIZE (buf);
3402 /* depending on the type, setup the clip parameters */
3403 if (stream->subtype == FOURCC_soun) {
3404 frame_size = stream->bytes_per_frame;
3405 num_rate = GST_SECOND;
3406 denom_rate = (gint) stream->rate;
3408 } else if (stream->subtype == FOURCC_vide) {
3410 num_rate = stream->fps_n;
3411 denom_rate = stream->fps_d;
3416 /* we can only clip if we have a valid timestamp */
3417 timestamp = GST_BUFFER_TIMESTAMP (buf);
3418 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
3421 if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf))) {
3422 duration = GST_BUFFER_DURATION (buf);
3425 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3429 stop = start + duration;
3431 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3432 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3435 /* see if some clipping happened */
3436 diff = cstart - start;
3442 /* bring clipped time to samples and to bytes */
3443 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3446 GST_DEBUG_OBJECT (qtdemux,
3447 "clipping start to %" GST_TIME_FORMAT " %"
3448 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3454 diff = stop - cstop;
3459 /* bring clipped time to samples and then to bytes */
3460 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3462 GST_DEBUG_OBJECT (qtdemux,
3463 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3464 " bytes", GST_TIME_ARGS (cstop), diff);
3469 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3470 GST_BUFFER_DURATION (buf) = duration;
3471 GST_BUFFER_SIZE (buf) = size;
3472 GST_BUFFER_DATA (buf) = data;
3476 /* dropped buffer */
3479 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3484 GST_DEBUG_OBJECT (qtdemux, "no timestamp on buffer");
3489 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3490 gst_buffer_unref (buf);
3495 /* the input buffer metadata must be writable,
3496 * but time/duration etc not yet set and need not be preserved */
3498 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3502 guint size, nsize = 0;
3505 data = GST_BUFFER_DATA (buf);
3506 size = GST_BUFFER_SIZE (buf);
3508 /* not many cases for now */
3509 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3510 /* send a one time dvd clut event */
3511 if (stream->pending_event && stream->pad)
3512 gst_pad_push_event (stream->pad, stream->pending_event);
3513 stream->pending_event = NULL;
3514 /* no further processing needed */
3515 stream->need_process = FALSE;
3518 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
3522 if (G_LIKELY (size >= 2)) {
3523 nsize = GST_READ_UINT16_BE (data);
3524 nsize = MIN (nsize, size - 2);
3527 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%d", nsize, size);
3529 /* takes care of UTF-8 validation or UTF-16 recognition,
3530 * no other encoding expected */
3531 str = gst_tag_freeform_string_to_utf8 ((gchar *) data + 2, nsize, NULL);
3533 gst_buffer_unref (buf);
3534 buf = gst_buffer_new ();
3535 GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = (guint8 *) str;
3536 GST_BUFFER_SIZE (buf) = strlen (str);
3538 /* may be 0-size subtitle, which is also sent to keep pipeline going */
3539 GST_BUFFER_DATA (buf) = data + 2;
3540 GST_BUFFER_SIZE (buf) = nsize;
3543 /* FIXME ? convert optional subsequent style info to markup */
3548 /* Sets a buffer's attributes properly and pushes it downstream.
3549 * Also checks for additional actions and custom processing that may
3550 * need to be done first.
3553 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3554 QtDemuxStream * stream, GstBuffer * buf,
3555 guint64 timestamp, guint64 duration, gboolean keyframe, guint64 position,
3556 guint64 byte_position)
3558 GstFlowReturn ret = GST_FLOW_OK;
3560 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
3563 url = g_strndup ((gchar *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
3564 if (url != NULL && strlen (url) != 0) {
3565 /* we have RTSP redirect now */
3566 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3567 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
3568 gst_structure_new ("redirect",
3569 "new-location", G_TYPE_STRING, url, NULL)));
3570 qtdemux->posted_redirect = TRUE;
3572 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
3578 /* position reporting */
3579 if (qtdemux->segment.rate >= 0) {
3580 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, position);
3581 gst_qtdemux_sync_streams (qtdemux);
3584 if (G_UNLIKELY (!stream->pad)) {
3585 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
3586 gst_buffer_unref (buf);
3590 /* send out pending buffers */
3591 while (stream->buffers) {
3592 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
3594 if (G_UNLIKELY (stream->discont)) {
3595 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3596 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
3597 stream->discont = FALSE;
3599 gst_buffer_set_caps (buffer, stream->caps);
3601 gst_pad_push (stream->pad, buffer);
3603 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
3606 /* we're going to modify the metadata */
3607 buf = gst_buffer_make_metadata_writable (buf);
3609 if (G_UNLIKELY (stream->need_process))
3610 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
3612 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3613 GST_BUFFER_DURATION (buf) = duration;
3614 GST_BUFFER_OFFSET (buf) = -1;
3615 GST_BUFFER_OFFSET_END (buf) = -1;
3617 if (G_UNLIKELY (stream->padding)) {
3618 GST_BUFFER_DATA (buf) += stream->padding;
3619 GST_BUFFER_SIZE (buf) -= stream->padding;
3622 if (G_UNLIKELY (qtdemux->element_index)) {
3623 GstClockTime stream_time;
3626 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
3628 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
3629 GST_LOG_OBJECT (qtdemux,
3630 "adding association %" GST_TIME_FORMAT "-> %"
3631 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
3632 gst_index_add_association (qtdemux->element_index,
3634 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
3635 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
3636 GST_FORMAT_BYTES, byte_position, NULL);
3640 if (stream->need_clip)
3641 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
3643 if (G_UNLIKELY (buf == NULL))
3646 if (G_UNLIKELY (stream->discont)) {
3647 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3648 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3649 stream->discont = FALSE;
3653 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3655 gst_buffer_set_caps (buf, stream->caps);
3657 GST_LOG_OBJECT (qtdemux,
3658 "Pushing buffer with time %" GST_TIME_FORMAT ", duration %"
3659 GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
3660 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
3662 ret = gst_pad_push (stream->pad, buf);
3668 static GstFlowReturn
3669 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
3671 GstFlowReturn ret = GST_FLOW_OK;
3672 GstBuffer *buf = NULL;
3673 QtDemuxStream *stream;
3676 guint64 timestamp = GST_CLOCK_TIME_NONE;
3677 guint64 duration = 0;
3678 gboolean keyframe = FALSE;
3683 gst_qtdemux_push_pending_newsegment (qtdemux);
3685 /* Figure out the next stream sample to output, min_time is expressed in
3686 * global time and runs over the edit list segments. */
3687 min_time = G_MAXUINT64;
3689 for (i = 0; i < qtdemux->n_streams; i++) {
3692 stream = qtdemux->streams[i];
3693 position = stream->time_position;
3695 /* position of -1 is EOS */
3696 if (position != -1 && position < min_time) {
3697 min_time = position;
3702 if (G_UNLIKELY (index == -1)) {
3703 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
3707 /* check for segment end */
3708 if (G_UNLIKELY (qtdemux->segment.stop != -1
3709 && qtdemux->segment.stop < min_time)) {
3710 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
3714 stream = qtdemux->streams[index];
3716 /* fetch info for the current sample of this stream */
3717 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
3718 &size, ×tamp, &duration, &keyframe)))
3721 GST_LOG_OBJECT (qtdemux,
3722 "pushing from stream %d, offset %" G_GUINT64_FORMAT
3723 ", size %d, timestamp=%" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
3724 index, offset, size, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
3726 /* hmm, empty sample, skip and move to next sample */
3727 if (G_UNLIKELY (size <= 0))
3730 /* last pushed sample was out of boundary, goto next sample */
3731 if (G_UNLIKELY (stream->last_ret == GST_FLOW_UNEXPECTED))
3734 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
3737 ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
3738 if (G_UNLIKELY (ret != GST_FLOW_OK))
3741 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
3742 timestamp, duration, keyframe, min_time, offset);
3745 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
3746 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
3747 * we have no more data for the pad to push */
3748 if (ret == GST_FLOW_UNEXPECTED)
3752 gst_qtdemux_advance_sample (qtdemux, stream);
3760 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
3761 ret = GST_FLOW_UNEXPECTED;
3766 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
3767 /* EOS will be raised if all are EOS */
3774 gst_qtdemux_loop (GstPad * pad)
3776 GstQTDemux *qtdemux;
3780 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
3782 cur_offset = qtdemux->offset;
3783 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
3784 cur_offset, qtdemux->state);
3786 switch (qtdemux->state) {
3787 case QTDEMUX_STATE_INITIAL:
3788 case QTDEMUX_STATE_HEADER:
3789 ret = gst_qtdemux_loop_state_header (qtdemux);
3791 case QTDEMUX_STATE_MOVIE:
3792 ret = gst_qtdemux_loop_state_movie (qtdemux);
3793 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_UNEXPECTED) {
3794 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
3802 /* if something went wrong, pause */
3803 if (ret != GST_FLOW_OK)
3807 gst_object_unref (qtdemux);
3813 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3814 (NULL), ("streaming stopped, invalid state"));
3815 qtdemux->segment_running = FALSE;
3816 gst_pad_pause_task (pad);
3817 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3822 const gchar *reason = gst_flow_get_name (ret);
3824 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
3826 qtdemux->segment_running = FALSE;
3827 gst_pad_pause_task (pad);
3829 /* fatal errors need special actions */
3831 if (ret == GST_FLOW_UNEXPECTED) {
3832 if (qtdemux->n_streams == 0) {
3833 /* we have no streams, post an error */
3834 gst_qtdemux_post_no_playable_stream_error (qtdemux);
3836 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3839 /* FIXME: I am not sure this is the right fix. If the sinks are
3840 * supposed to detect the segment is complete and accumulate
3841 * automatically, it does not seem to work here. Need more work */
3842 qtdemux->segment_running = TRUE;
3844 if ((stop = qtdemux->segment.stop) == -1)
3845 stop = qtdemux->segment.duration;
3847 if (qtdemux->segment.rate >= 0) {
3848 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
3849 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3850 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3851 GST_FORMAT_TIME, stop));
3853 /* For Reverse Playback */
3854 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
3855 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3856 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3857 GST_FORMAT_TIME, qtdemux->segment.start));
3860 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
3861 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3863 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
3864 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3865 (NULL), ("streaming stopped, reason %s", reason));
3866 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3875 * Returns the size of the first entry at the current offset.
3876 * If -1, there are none (which means EOS or empty file).
3879 next_entry_size (GstQTDemux * demux)
3881 QtDemuxStream *stream;
3884 guint64 smalloffs = (guint64) - 1;
3885 QtDemuxSample *sample;
3887 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
3890 for (i = 0; i < demux->n_streams; i++) {
3891 stream = demux->streams[i];
3893 if (stream->sample_index == -1)
3894 stream->sample_index = 0;
3896 if (stream->sample_index >= stream->n_samples) {
3897 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
3901 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
3902 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
3903 stream->sample_index);
3907 sample = &stream->samples[stream->sample_index];
3909 GST_LOG_OBJECT (demux,
3910 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3911 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
3912 sample->offset, sample->size);
3914 if (((smalloffs == -1)
3915 || (sample->offset < smalloffs)) && (sample->size)) {
3917 smalloffs = sample->offset;
3921 GST_LOG_OBJECT (demux,
3922 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
3923 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
3928 stream = demux->streams[smallidx];
3929 sample = &stream->samples[stream->sample_index];
3931 if (sample->offset >= demux->offset) {
3932 demux->todrop = sample->offset - demux->offset;
3933 return sample->size + demux->todrop;
3936 GST_DEBUG_OBJECT (demux,
3937 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
3942 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
3944 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
3946 gst_element_post_message (GST_ELEMENT_CAST (demux),
3947 gst_message_new_element (GST_OBJECT_CAST (demux),
3948 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
3952 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
3957 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
3960 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
3961 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
3962 GST_SEEK_TYPE_NONE, -1);
3964 res = gst_pad_push_event (demux->sinkpad, event);
3969 /* FIXME, unverified after edit list updates */
3970 static GstFlowReturn
3971 gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
3974 GstFlowReturn ret = GST_FLOW_OK;
3976 demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad));
3978 gst_adapter_push (demux->adapter, inbuf);
3980 /* we never really mean to buffer that much */
3981 if (demux->neededbytes == -1)
3984 GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
3985 inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
3987 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
3988 (ret == GST_FLOW_OK)) {
3990 GST_DEBUG_OBJECT (demux,
3991 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
3992 demux->state, demux->neededbytes, demux->offset);
3994 switch (demux->state) {
3995 case QTDEMUX_STATE_INITIAL:{
4000 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
4002 /* get fourcc/length, set neededbytes */
4003 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4005 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4006 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4008 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4009 (_("This file is invalid and cannot be played.")),
4010 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4011 GST_FOURCC_ARGS (fourcc)));
4012 ret = GST_FLOW_ERROR;
4015 if (fourcc == FOURCC_mdat) {
4016 if (demux->n_streams > 0) {
4017 /* we have the headers, start playback */
4018 demux->state = QTDEMUX_STATE_MOVIE;
4019 demux->neededbytes = next_entry_size (demux);
4020 demux->mdatleft = size;
4022 /* Only post, event on pads is done after newsegment */
4023 qtdemux_post_global_tags (demux);
4026 /* no headers yet, try to get them */
4029 guint64 old, target;
4032 old = demux->offset;
4033 target = old + size;
4035 /* try to jump over the atom with a seek */
4036 res = qtdemux_seek_offset (demux, target);
4039 GST_DEBUG_OBJECT (demux, "seek success");
4040 /* remember the offset fo the first mdat so we can seek back to it
4041 * after we have the headers */
4042 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4043 demux->first_mdat = old;
4044 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4047 /* seek worked, continue reading */
4048 demux->offset = target;
4049 demux->neededbytes = 16;
4050 demux->state = QTDEMUX_STATE_INITIAL;
4052 /* seek failed, need to buffer */
4053 demux->offset = old;
4054 GST_DEBUG_OBJECT (demux, "seek failed");
4055 /* there may be multiple mdat (or alike) buffers */
4057 if (demux->mdatbuffer)
4058 bs = GST_BUFFER_SIZE (demux->mdatbuffer);
4061 if (size + bs > 10 * (1 << 20))
4063 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4064 demux->neededbytes = size;
4065 if (!demux->mdatbuffer)
4066 demux->mdatoffset = demux->offset;
4069 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4070 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4071 (_("This file is invalid and cannot be played.")),
4072 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4073 GST_FOURCC_ARGS (fourcc), size));
4074 ret = GST_FLOW_ERROR;
4077 /* this means we already started buffering and still no moov header,
4078 * let's continue buffering everything till we get moov */
4079 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
4081 demux->neededbytes = size;
4082 demux->state = QTDEMUX_STATE_HEADER;
4086 case QTDEMUX_STATE_HEADER:{
4090 GST_DEBUG_OBJECT (demux, "In header");
4092 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
4094 /* parse the header */
4095 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4097 if (fourcc == FOURCC_moov) {
4098 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4100 demux->got_moov = TRUE;
4102 /* prepare newsegment to send when streaming actually starts */
4103 if (!demux->pending_newsegment) {
4104 demux->pending_newsegment =
4105 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
4106 0, GST_CLOCK_TIME_NONE, 0);
4109 qtdemux_parse_moov (demux, data, demux->neededbytes);
4110 qtdemux_node_dump (demux, demux->moov_node);
4111 qtdemux_parse_tree (demux);
4112 qtdemux_expose_streams (demux);
4114 g_node_destroy (demux->moov_node);
4115 demux->moov_node = NULL;
4116 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4117 } else if (fourcc == FOURCC_moof) {
4118 if (demux->got_moov && demux->fragmented) {
4119 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4120 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4121 demux->offset, NULL)) {
4122 ret = GST_FLOW_ERROR;
4126 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4128 } else if (fourcc == FOURCC_ftyp) {
4129 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4130 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4131 } else if (fourcc == FOURCC_uuid) {
4132 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4133 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4135 GST_WARNING_OBJECT (demux,
4136 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4137 GST_FOURCC_ARGS (fourcc));
4138 /* Let's jump that one and go back to initial state */
4141 if (demux->mdatbuffer && demux->n_streams) {
4142 /* the mdat was before the header */
4143 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4144 demux->n_streams, demux->mdatbuffer);
4145 /* restore our adapter/offset view of things with upstream;
4146 * put preceding buffered data ahead of current moov data.
4147 * This should also handle evil mdat, moov, mdat cases and alike */
4148 gst_adapter_clear (demux->adapter);
4149 demux->mdatbuffer = NULL;
4150 demux->offset = demux->mdatoffset;
4151 demux->neededbytes = next_entry_size (demux);
4152 demux->state = QTDEMUX_STATE_MOVIE;
4153 demux->mdatleft = gst_adapter_available (demux->adapter);
4155 /* Only post, event on pads is done after newsegment */
4156 qtdemux_post_global_tags (demux);
4159 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4160 gst_adapter_flush (demux->adapter, demux->neededbytes);
4162 if (demux->got_moov && demux->first_mdat != -1) {
4165 /* we need to seek back */
4166 res = qtdemux_seek_offset (demux, demux->first_mdat);
4168 demux->offset = demux->first_mdat;
4170 GST_DEBUG_OBJECT (demux, "Seek back failed");
4173 demux->offset += demux->neededbytes;
4175 demux->neededbytes = 16;
4176 demux->state = QTDEMUX_STATE_INITIAL;
4181 case QTDEMUX_STATE_BUFFER_MDAT:{
4184 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4186 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4187 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4188 GST_FOURCC_ARGS (QT_FOURCC (GST_BUFFER_DATA (buf) + 4)));
4189 if (demux->mdatbuffer)
4190 demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
4192 demux->mdatbuffer = buf;
4193 demux->offset += demux->neededbytes;
4194 demux->neededbytes = 16;
4195 demux->state = QTDEMUX_STATE_INITIAL;
4196 gst_qtdemux_post_progress (demux, 1, 1);
4200 case QTDEMUX_STATE_MOVIE:{
4202 QtDemuxStream *stream = NULL;
4203 QtDemuxSample *sample;
4205 guint64 timestamp, duration, position;
4208 GST_DEBUG_OBJECT (demux,
4209 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4211 if (demux->fragmented) {
4212 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4214 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4215 /* if needed data starts within this atom,
4216 * then it should not exceed this atom */
4217 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4218 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4219 (_("This file is invalid and cannot be played.")),
4220 ("sample data crosses atom boundary"));
4221 ret = GST_FLOW_ERROR;
4224 demux->mdatleft -= demux->neededbytes;
4226 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4227 /* so we are dropping more than left in this atom */
4228 demux->todrop -= demux->mdatleft;
4229 demux->neededbytes -= demux->mdatleft;
4230 demux->mdatleft = 0;
4231 /* need to resume atom parsing so we do not miss any other pieces */
4232 demux->state = QTDEMUX_STATE_INITIAL;
4233 demux->neededbytes = 16;
4238 if (demux->todrop) {
4239 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4240 gst_adapter_flush (demux->adapter, demux->todrop);
4241 demux->neededbytes -= demux->todrop;
4242 demux->offset += demux->todrop;
4246 /* initial newsegment sent here after having added pads,
4247 * possible others in sink_event */
4248 if (G_UNLIKELY (demux->pending_newsegment)) {
4249 gst_qtdemux_push_event (demux, demux->pending_newsegment);
4250 demux->pending_newsegment = NULL;
4251 /* clear to send tags on all streams */
4252 for (i = 0; i < demux->n_streams; i++) {
4253 gst_qtdemux_push_tags (demux, demux->streams[i]);
4257 /* Figure out which stream this is packet belongs to */
4258 for (i = 0; i < demux->n_streams; i++) {
4259 stream = demux->streams[i];
4260 if (stream->sample_index >= stream->n_samples)
4262 GST_LOG_OBJECT (demux,
4263 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4264 " / size:%d)", i, stream->sample_index,
4265 stream->samples[stream->sample_index].offset,
4266 stream->samples[stream->sample_index].size);
4268 if (stream->samples[stream->sample_index].offset == demux->offset)
4272 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4273 goto unknown_stream;
4275 /* Put data in a buffer, set timestamps, caps, ... */
4276 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4277 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4278 GST_FOURCC_ARGS (stream->fourcc));
4280 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4282 sample = &stream->samples[stream->sample_index];
4284 position = QTSAMPLE_DTS (stream, sample);
4285 timestamp = QTSAMPLE_PTS (stream, sample);
4286 duration = QTSAMPLE_DUR_DTS (stream, sample, position);
4287 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4289 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4290 timestamp, duration, keyframe, position, demux->offset);
4293 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4295 stream->sample_index++;
4297 /* update current offset and figure out size of next buffer */
4298 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4299 demux->offset, demux->neededbytes);
4300 demux->offset += demux->neededbytes;
4301 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4304 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4305 if (demux->fragmented) {
4306 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4307 /* there may be more to follow, only finish this atom */
4308 demux->todrop = demux->mdatleft;
4309 demux->neededbytes = demux->todrop;
4321 /* when buffering movie data, at least show user something is happening */
4322 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4323 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4324 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4325 demux->neededbytes);
4328 gst_object_unref (demux);
4335 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4336 ret = GST_FLOW_ERROR;
4341 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4342 ret = GST_FLOW_UNEXPECTED;
4347 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4348 (NULL), ("qtdemuxer invalid state %d", demux->state));
4349 ret = GST_FLOW_ERROR;
4354 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4355 (NULL), ("no 'moov' atom within the first 10 MB"));
4356 ret = GST_FLOW_ERROR;
4362 qtdemux_sink_activate (GstPad * sinkpad)
4364 if (gst_pad_check_pull_range (sinkpad))
4365 return gst_pad_activate_pull (sinkpad, TRUE);
4367 return gst_pad_activate_push (sinkpad, TRUE);
4371 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
4373 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
4376 demux->pullbased = TRUE;
4377 demux->segment_running = TRUE;
4378 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4381 demux->segment_running = FALSE;
4382 return gst_pad_stop_task (sinkpad);
4387 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
4389 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
4391 demux->pullbased = FALSE;
4398 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4400 return g_malloc (items * size);
4404 qtdemux_zfree (void *opaque, void *addr)
4410 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4416 z = g_new0 (z_stream, 1);
4417 z->zalloc = qtdemux_zalloc;
4418 z->zfree = qtdemux_zfree;
4421 z->next_in = z_buffer;
4422 z->avail_in = z_length;
4424 buffer = (guint8 *) g_malloc (length);
4425 ret = inflateInit (z);
4426 while (z->avail_in > 0) {
4427 if (z->avail_out == 0) {
4429 buffer = (guint8 *) g_realloc (buffer, length);
4430 z->next_out = buffer + z->total_out;
4431 z->avail_out = 1024;
4433 ret = inflate (z, Z_SYNC_FLUSH);
4437 if (ret != Z_STREAM_END) {
4438 g_warning ("inflate() returned %d", ret);
4444 #endif /* HAVE_ZLIB */
4447 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4451 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4453 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4454 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4456 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4462 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4463 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4464 if (dcom == NULL || cmvd == NULL)
4465 goto invalid_compression;
4467 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4470 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4471 guint uncompressed_length;
4472 guint compressed_length;
4475 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4476 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4477 GST_LOG ("length = %u", uncompressed_length);
4480 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4481 compressed_length, uncompressed_length);
4483 qtdemux->moov_node_compressed = qtdemux->moov_node;
4484 qtdemux->moov_node = g_node_new (buf);
4486 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4487 uncompressed_length);
4490 #endif /* HAVE_ZLIB */
4492 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4493 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
4500 invalid_compression:
4502 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
4508 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
4511 while (G_UNLIKELY (buf < end)) {
4515 if (G_UNLIKELY (buf + 4 > end)) {
4516 GST_LOG_OBJECT (qtdemux, "buffer overrun");
4519 len = QT_UINT32 (buf);
4520 if (G_UNLIKELY (len == 0)) {
4521 GST_LOG_OBJECT (qtdemux, "empty container");
4524 if (G_UNLIKELY (len < 8)) {
4525 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
4528 if (G_UNLIKELY (len > (end - buf))) {
4529 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
4530 (gint) (end - buf));
4534 child = g_node_new ((guint8 *) buf);
4535 g_node_append (node, child);
4536 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
4537 qtdemux_parse_node (qtdemux, child, buf, len);
4545 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
4548 int len = QT_UINT32 (xdxt->data);
4549 guint8 *buf = xdxt->data;
4550 guint8 *end = buf + len;
4553 /* skip size and type */
4561 size = QT_UINT32 (buf);
4562 type = QT_FOURCC (buf + 4);
4564 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
4566 if (buf + size > end || size <= 0)
4572 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
4573 GST_FOURCC_ARGS (type));
4577 buffer = gst_buffer_new_and_alloc (size);
4578 memcpy (GST_BUFFER_DATA (buffer), buf, size);
4579 stream->buffers = g_slist_append (stream->buffers, buffer);
4580 GST_LOG_OBJECT (qtdemux, "parsing theora header");
4583 buffer = gst_buffer_new_and_alloc (size);
4584 memcpy (GST_BUFFER_DATA (buffer), buf, size);
4585 stream->buffers = g_slist_append (stream->buffers, buffer);
4586 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
4589 buffer = gst_buffer_new_and_alloc (size);
4590 memcpy (GST_BUFFER_DATA (buffer), buf, size);
4591 stream->buffers = g_slist_append (stream->buffers, buffer);
4592 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
4595 GST_WARNING_OBJECT (qtdemux,
4596 "unknown theora cookie %" GST_FOURCC_FORMAT,
4597 GST_FOURCC_ARGS (type));
4606 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
4610 guint32 node_length = 0;
4611 const QtNodeType *type;
4614 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
4616 if (G_UNLIKELY (length < 8))
4617 goto not_enough_data;
4619 node_length = QT_UINT32 (buffer);
4620 fourcc = QT_FOURCC (buffer + 4);
4622 /* ignore empty nodes */
4623 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
4626 type = qtdemux_type_get (fourcc);
4628 end = buffer + length;
4630 GST_LOG_OBJECT (qtdemux,
4631 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
4632 GST_FOURCC_ARGS (fourcc), node_length, type->name);
4634 if (node_length > length)
4635 goto broken_atom_size;
4637 if (type->flags & QT_FLAG_CONTAINER) {
4638 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
4643 if (node_length < 20) {
4644 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
4647 GST_DEBUG_OBJECT (qtdemux,
4648 "parsing stsd (sample table, sample description) atom");
4649 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
4659 /* also read alac (or whatever) in stead of mp4a in the following,
4660 * since a similar layout is used in other cases as well */
4661 if (fourcc == FOURCC_mp4a)
4666 /* There are two things we might encounter here: a true mp4a atom, and
4667 an mp4a entry in an stsd atom. The latter is what we're interested
4668 in, and it looks like an atom, but isn't really one. The true mp4a
4669 atom is short, so we detect it based on length here. */
4670 if (length < min_size) {
4671 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
4672 GST_FOURCC_ARGS (fourcc));
4676 /* 'version' here is the sound sample description version. Types 0 and
4677 1 are documented in the QTFF reference, but type 2 is not: it's
4678 described in Apple header files instead (struct SoundDescriptionV2
4680 version = QT_UINT16 (buffer + 16);
4682 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
4683 GST_FOURCC_ARGS (fourcc), version);
4685 /* parse any esds descriptors */
4697 GST_WARNING_OBJECT (qtdemux,
4698 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
4699 GST_FOURCC_ARGS (fourcc), version);
4704 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4716 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
4717 GST_FOURCC_ARGS (fourcc));
4718 version = QT_UINT32 (buffer + 16);
4719 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
4720 if (1 || version == 0x00000000) {
4721 buf = buffer + 0x32;
4723 /* FIXME Quicktime uses PASCAL string while
4724 * the iso format uses C strings. Check the file
4725 * type before attempting to parse the string here. */
4726 tlen = QT_UINT8 (buf);
4727 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
4729 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
4730 /* the string has a reserved space of 32 bytes so skip
4731 * the remaining 31 */
4733 buf += 4; /* and 4 bytes reserved */
4735 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
4737 qtdemux_parse_container (qtdemux, node, buf, end);
4743 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
4744 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
4749 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
4754 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
4755 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
4763 version = QT_UINT32 (buffer + 12);
4764 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
4771 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
4776 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4781 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
4785 if (!strcmp (type->name, "unknown"))
4786 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
4790 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
4791 GST_FOURCC_ARGS (fourcc));
4797 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4798 (_("This file is corrupt and cannot be played.")),
4799 ("Not enough data for an atom header, got only %u bytes", length));
4804 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4805 (_("This file is corrupt and cannot be played.")),
4806 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
4807 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
4814 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
4818 guint32 child_fourcc;
4820 for (child = g_node_first_child (node); child;
4821 child = g_node_next_sibling (child)) {
4822 buffer = (guint8 *) child->data;
4824 child_fourcc = QT_FOURCC (buffer + 4);
4826 if (G_UNLIKELY (child_fourcc == fourcc)) {
4834 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
4835 GstByteReader * parser)
4839 guint32 child_fourcc, child_len;
4841 for (child = g_node_first_child (node); child;
4842 child = g_node_next_sibling (child)) {
4843 buffer = (guint8 *) child->data;
4845 child_len = QT_UINT32 (buffer);
4846 child_fourcc = QT_FOURCC (buffer + 4);
4848 if (G_UNLIKELY (child_fourcc == fourcc)) {
4849 if (G_UNLIKELY (child_len < (4 + 4)))
4851 /* FIXME: must verify if atom length < parent atom length */
4852 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4860 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
4861 GstByteReader * parser)
4865 guint32 child_fourcc, child_len;
4867 for (child = g_node_next_sibling (node); child;
4868 child = g_node_next_sibling (child)) {
4869 buffer = (guint8 *) child->data;
4871 child_fourcc = QT_FOURCC (buffer + 4);
4873 if (child_fourcc == fourcc) {
4875 child_len = QT_UINT32 (buffer);
4876 if (G_UNLIKELY (child_len < (4 + 4)))
4878 /* FIXME: must verify if atom length < parent atom length */
4879 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4888 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
4890 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
4894 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
4895 QtDemuxStream * stream, GstTagList * list)
4897 /* consistent default for push based mode */
4898 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
4899 gst_segment_set_newsegment (&stream->segment, FALSE, 1.0, GST_FORMAT_TIME,
4900 0, GST_CLOCK_TIME_NONE, 0);
4902 if (stream->subtype == FOURCC_vide) {
4903 gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
4906 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
4909 /* fps is calculated base on the duration of the first frames since
4910 * qt does not have a fixed framerate. */
4911 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
4916 stream->fps_n = stream->timescale;
4917 if (stream->min_duration == 0)
4920 stream->fps_d = stream->min_duration;
4925 gint depth, palette_count;
4926 const guint32 *palette_data = NULL;
4928 gst_caps_set_simple (stream->caps,
4929 "width", G_TYPE_INT, stream->width,
4930 "height", G_TYPE_INT, stream->height,
4931 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
4933 /* calculate pixel-aspect-ratio using display width and height */
4934 GST_DEBUG_OBJECT (qtdemux,
4935 "video size %dx%d, target display size %dx%d", stream->width,
4936 stream->height, stream->display_width, stream->display_height);
4938 if (stream->display_width > 0 && stream->display_height > 0 &&
4939 stream->width > 0 && stream->height > 0) {
4942 /* calculate the pixel aspect ratio using the display and pixel w/h */
4943 n = stream->display_width * stream->height;
4944 d = stream->display_height * stream->width;
4947 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
4948 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
4949 GST_TYPE_FRACTION, n, d, NULL);
4952 /* qt file might have pasp atom */
4953 if (stream->par_w > 0 && stream->par_h > 0) {
4954 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
4955 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
4956 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
4959 depth = stream->bits_per_sample;
4961 /* more than 32 bits means grayscale */
4962 gray = (depth > 32);
4963 /* low 32 bits specify the depth */
4966 /* different number of palette entries is determined by depth. */
4968 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
4969 palette_count = (1 << depth);
4971 switch (palette_count) {
4975 palette_data = ff_qt_default_palette_2;
4978 palette_data = ff_qt_default_palette_4;
4982 palette_data = ff_qt_grayscale_palette_16;
4984 palette_data = ff_qt_default_palette_16;
4988 palette_data = ff_qt_grayscale_palette_256;
4990 palette_data = ff_qt_default_palette_256;
4993 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4994 (_("The video in this file might not play correctly.")),
4995 ("unsupported palette depth %d", depth));
5001 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5002 * don't free any of the buffer data. */
5003 palette = gst_buffer_new ();
5004 GST_BUFFER_FLAG_SET (palette, GST_BUFFER_FLAG_READONLY);
5005 GST_BUFFER_DATA (palette) = (guint8 *) palette_data;
5006 GST_BUFFER_SIZE (palette) = sizeof (guint32) * palette_count;
5008 gst_caps_set_simple (stream->caps, "palette_data",
5009 GST_TYPE_BUFFER, palette, NULL);
5010 gst_buffer_unref (palette);
5011 } else if (palette_count != 0) {
5012 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5013 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5015 gst_object_unref (stream->pad);
5019 qtdemux->n_video_streams++;
5020 } else if (stream->subtype == FOURCC_soun) {
5021 gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
5024 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5027 gst_caps_set_simple (stream->caps,
5028 "rate", G_TYPE_INT, (int) stream->rate,
5029 "channels", G_TYPE_INT, stream->n_channels, NULL);
5031 qtdemux->n_audio_streams++;
5032 } else if (stream->subtype == FOURCC_strm) {
5033 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5034 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
5035 gchar *name = g_strdup_printf ("subtitle_%02d", qtdemux->n_sub_streams);
5038 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5040 qtdemux->n_sub_streams++;
5042 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5047 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5049 gst_pad_use_fixed_caps (stream->pad);
5050 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5051 gst_pad_set_query_type_function (stream->pad,
5052 gst_qtdemux_get_src_query_types);
5053 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5055 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5056 gst_pad_set_caps (stream->pad, stream->caps);
5058 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5059 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5060 gst_pad_set_active (stream->pad, TRUE);
5061 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5062 if (stream->pending_tags)
5063 gst_tag_list_free (stream->pending_tags);
5064 stream->pending_tags = list;
5066 /* post now, send event on pad later */
5067 GST_DEBUG_OBJECT (qtdemux, "Posting tags %" GST_PTR_FORMAT, list);
5068 gst_element_post_message (GST_ELEMENT (qtdemux),
5069 gst_message_new_tag_full (GST_OBJECT (qtdemux), stream->pad,
5070 gst_tag_list_copy (list)));
5072 /* global tags go on each pad anyway */
5073 stream->send_global_tags = TRUE;
5079 /* find next atom with @fourcc starting at @offset */
5080 static GstFlowReturn
5081 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5082 guint64 * length, guint32 fourcc)
5088 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5089 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5092 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5093 if (G_UNLIKELY (ret != GST_FLOW_OK))
5095 if (G_LIKELY (GST_BUFFER_SIZE (buf) != 16)) {
5097 ret = GST_FLOW_UNEXPECTED;
5098 gst_buffer_unref (buf);
5101 extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf), 16, length,
5103 gst_buffer_unref (buf);
5105 if (G_UNLIKELY (*length == 0)) {
5106 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5107 ret = GST_FLOW_ERROR;
5111 if (lfourcc == fourcc) {
5112 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5116 GST_LOG_OBJECT (qtdemux,
5117 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5118 GST_FOURCC_ARGS (fourcc), *offset);
5127 /* might simply have had last one */
5128 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5133 /* should only do something in pull mode */
5134 /* call with OBJECT lock */
5135 static GstFlowReturn
5136 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5138 guint64 length, offset;
5139 GstBuffer *buf = NULL;
5140 GstFlowReturn ret = GST_FLOW_OK;
5141 GstFlowReturn res = TRUE;
5143 offset = qtdemux->moof_offset;
5144 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5147 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5148 return GST_FLOW_UNEXPECTED;
5151 /* best not do pull etc with lock held */
5152 GST_OBJECT_UNLOCK (qtdemux);
5154 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5155 if (ret != GST_FLOW_OK)
5158 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5159 if (G_UNLIKELY (ret != GST_FLOW_OK))
5161 if (!qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf),
5162 GST_BUFFER_SIZE (buf), offset, NULL)) {
5163 gst_buffer_unref (buf);
5168 gst_buffer_unref (buf);
5172 /* look for next moof */
5173 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5174 if (G_UNLIKELY (ret != GST_FLOW_OK))
5178 GST_OBJECT_LOCK (qtdemux);
5180 qtdemux->moof_offset = offset;
5186 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5188 res = GST_FLOW_ERROR;
5193 /* maybe upstream temporarily flushing */
5194 if (ret != GST_FLOW_WRONG_STATE) {
5195 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5198 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5199 /* resume at current position next time */
5206 /* initialise bytereaders for stbl sub-atoms */
5208 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5210 stream->stbl_index = -1; /* no samples have yet been parsed */
5212 /* time-to-sample atom */
5213 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5216 /* copy atom data into a new buffer for later use */
5217 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5219 /* skip version + flags */
5220 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5221 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5223 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5225 /* make sure there's enough data */
5226 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 2 * 4))
5229 /* sync sample atom */
5230 stream->stps_present = FALSE;
5231 if ((stream->stss_present =
5232 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5233 &stream->stss) ? TRUE : FALSE) == TRUE) {
5234 /* copy atom data into a new buffer for later use */
5235 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5237 /* skip version + flags */
5238 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5239 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5242 if (stream->n_sample_syncs) {
5243 /* make sure there's enough data */
5244 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5248 /* partial sync sample atom */
5249 if ((stream->stps_present =
5250 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5251 &stream->stps) ? TRUE : FALSE) == TRUE) {
5252 /* copy atom data into a new buffer for later use */
5253 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5255 /* skip version + flags */
5256 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5257 !gst_byte_reader_get_uint32_be (&stream->stps,
5258 &stream->n_sample_partial_syncs))
5261 /* if there are no entries, the stss table contains the real
5263 if (stream->n_sample_partial_syncs) {
5264 /* make sure there's enough data */
5265 if (!qt_atom_parser_has_chunks (&stream->stps,
5266 stream->n_sample_partial_syncs, 4))
5273 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5276 /* copy atom data into a new buffer for later use */
5277 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5279 /* skip version + flags */
5280 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5281 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5284 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5287 if (!stream->n_samples)
5290 /* sample-to-chunk atom */
5291 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5294 /* copy atom data into a new buffer for later use */
5295 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5297 /* skip version + flags */
5298 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5299 !gst_byte_reader_get_uint32_be (&stream->stsc,
5300 &stream->n_samples_per_chunk))
5303 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5304 stream->n_samples_per_chunk);
5306 /* make sure there's enough data */
5307 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5313 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5314 stream->co_size = sizeof (guint32);
5315 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5317 stream->co_size = sizeof (guint64);
5321 /* copy atom data into a new buffer for later use */
5322 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5324 /* skip version + flags */
5325 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5328 /* chunks_are_chunks == 0 means treat chunks as samples */
5329 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5330 if (stream->chunks_are_chunks) {
5331 /* skip number of entries */
5332 if (!gst_byte_reader_skip (&stream->stco, 4))
5335 /* make sure there are enough data in the stsz atom */
5336 if (!stream->sample_size) {
5337 /* different sizes for each sample */
5338 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5342 /* treat chunks as samples */
5343 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5347 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5348 stream->n_samples, (guint) sizeof (QtDemuxSample),
5349 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5351 if (stream->n_samples >=
5352 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5353 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5354 "be larger than %uMB (broken file?)", stream->n_samples,
5355 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5359 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5360 if (!stream->samples) {
5361 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5367 /* composition time-to-sample */
5368 if ((stream->ctts_present =
5369 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5370 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5371 /* copy atom data into a new buffer for later use */
5372 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5374 /* skip version + flags */
5375 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5376 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5377 &stream->n_composition_times))
5380 /* make sure there's enough data */
5381 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5390 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5391 (_("This file is corrupt and cannot be played.")), (NULL));
5396 gst_qtdemux_stbl_free (stream);
5397 if (!qtdemux->fragmented) {
5398 /* not quite good */
5399 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5402 /* may pick up samples elsewhere */
5408 /* collect samples from the next sample to be parsed up to sample @n for @stream
5409 * by reading the info from @stbl
5411 * This code can be executed from both the streaming thread and the seeking
5412 * thread so it takes the object lock to protect itself
5415 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
5418 QtDemuxSample *samples, *first, *cur, *last;
5419 guint32 n_samples_per_chunk;
5422 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
5423 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
5424 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
5426 n_samples = stream->n_samples;
5429 goto out_of_samples;
5431 GST_OBJECT_LOCK (qtdemux);
5432 if (n <= stream->stbl_index)
5433 goto already_parsed;
5435 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
5437 if (!stream->stsz.data) {
5438 /* so we already parsed and passed all the moov samples;
5439 * onto fragmented ones */
5440 g_assert (qtdemux->fragmented);
5444 /* pointer to the sample table */
5445 samples = stream->samples;
5447 /* starts from -1, moves to the next sample index to parse */
5448 stream->stbl_index++;
5450 /* keep track of the first and last sample to fill */
5451 first = &samples[stream->stbl_index];
5454 if (stream->chunks_are_chunks) {
5455 /* set the sample sizes */
5456 if (stream->sample_size == 0) {
5457 /* different sizes for each sample */
5458 for (cur = first; cur <= last; cur++) {
5459 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
5460 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
5461 (guint) (cur - samples), cur->size);
5464 /* samples have the same size */
5465 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
5466 for (cur = first; cur <= last; cur++)
5467 cur->size = stream->sample_size;
5471 n_samples_per_chunk = stream->n_samples_per_chunk;
5474 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
5477 if (stream->stsc_chunk_index >= stream->last_chunk
5478 || stream->stsc_chunk_index < stream->first_chunk) {
5479 stream->first_chunk =
5480 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5481 stream->samples_per_chunk =
5482 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5483 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
5485 /* chunk numbers are counted from 1 it seems */
5486 if (G_UNLIKELY (stream->first_chunk == 0))
5489 --stream->first_chunk;
5491 /* the last chunk of each entry is calculated by taking the first chunk
5492 * of the next entry; except if there is no next, where we fake it with
5494 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
5495 stream->last_chunk = G_MAXUINT32;
5497 stream->last_chunk =
5498 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
5499 if (G_UNLIKELY (stream->last_chunk == 0))
5502 --stream->last_chunk;
5505 GST_LOG_OBJECT (qtdemux,
5506 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
5507 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
5509 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
5512 if (stream->last_chunk != G_MAXUINT32) {
5513 if (!qt_atom_parser_peek_sub (&stream->stco,
5514 stream->first_chunk * stream->co_size,
5515 (stream->last_chunk - stream->first_chunk) * stream->co_size,
5520 stream->co_chunk = stream->stco;
5521 if (!gst_byte_reader_skip (&stream->co_chunk,
5522 stream->first_chunk * stream->co_size))
5526 stream->stsc_chunk_index = stream->first_chunk;
5529 last_chunk = stream->last_chunk;
5531 if (stream->chunks_are_chunks) {
5532 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5533 guint32 samples_per_chunk;
5534 guint64 chunk_offset;
5536 if (!stream->stsc_sample_index
5537 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
5538 &stream->chunk_offset))
5541 samples_per_chunk = stream->samples_per_chunk;
5542 chunk_offset = stream->chunk_offset;
5544 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
5545 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
5546 G_GUINT64_FORMAT, (guint) (cur - samples), stream->chunk_offset);
5548 cur->offset = chunk_offset;
5549 chunk_offset += cur->size;
5552 if (G_UNLIKELY (cur > last)) {
5554 stream->stsc_sample_index = k + 1;
5555 stream->chunk_offset = chunk_offset;
5556 stream->stsc_chunk_index = j;
5560 stream->stsc_sample_index = 0;
5562 stream->stsc_chunk_index = j;
5564 cur = &samples[stream->stsc_chunk_index];
5566 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5569 stream->stsc_chunk_index = j;
5574 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
5577 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
5578 "%" G_GUINT64_FORMAT, j, cur->offset);
5580 if (stream->samples_per_frame * stream->bytes_per_frame) {
5582 (stream->samples_per_chunk * stream->n_channels) /
5583 stream->samples_per_frame * stream->bytes_per_frame;
5585 cur->size = stream->samples_per_chunk;
5588 GST_DEBUG_OBJECT (qtdemux,
5589 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
5590 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
5591 GST_SECOND, stream->timescale)), cur->size);
5593 cur->timestamp = stream->stco_sample_index;
5594 cur->duration = stream->samples_per_chunk;
5595 cur->keyframe = TRUE;
5598 stream->stco_sample_index += stream->samples_per_chunk;
5600 stream->stsc_chunk_index = j;
5602 stream->stsc_index++;
5605 if (!stream->chunks_are_chunks)
5609 guint32 n_sample_times;
5611 n_sample_times = stream->n_sample_times;
5614 for (i = stream->stts_index; i < n_sample_times; i++) {
5615 guint32 stts_samples;
5616 guint32 stts_duration;
5619 if (stream->stts_sample_index >= stream->stts_samples
5620 || !stream->stts_sample_index) {
5622 stream->stts_samples =
5623 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5624 stream->stts_duration =
5625 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5627 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
5628 i, stream->stts_samples, stream->stts_duration);
5630 stream->stts_sample_index = 0;
5633 stts_samples = stream->stts_samples;
5634 stts_duration = stream->stts_duration;
5635 stts_time = stream->stts_time;
5637 for (j = stream->stts_sample_index; j < stts_samples; j++) {
5638 GST_DEBUG_OBJECT (qtdemux,
5639 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
5640 (guint) (cur - samples), j,
5641 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
5642 stream->timescale)));
5644 cur->timestamp = stts_time;
5645 cur->duration = stts_duration;
5647 stts_time += stts_duration;
5650 if (G_UNLIKELY (cur > last)) {
5652 stream->stts_time = stts_time;
5653 stream->stts_sample_index = j + 1;
5657 stream->stts_sample_index = 0;
5658 stream->stts_time = stts_time;
5659 stream->stts_index++;
5661 /* fill up empty timestamps with the last timestamp, this can happen when
5662 * the last samples do not decode and so we don't have timestamps for them.
5663 * We however look at the last timestamp to estimate the track length so we
5664 * need something in here. */
5665 for (; cur < last; cur++) {
5666 GST_DEBUG_OBJECT (qtdemux,
5667 "fill sample %d: timestamp %" GST_TIME_FORMAT,
5668 (guint) (cur - samples),
5669 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
5670 stream->timescale)));
5671 cur->timestamp = stream->stts_time;
5677 /* sample sync, can be NULL */
5678 if (stream->stss_present == TRUE) {
5679 guint32 n_sample_syncs;
5681 n_sample_syncs = stream->n_sample_syncs;
5683 if (!n_sample_syncs) {
5684 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
5685 stream->all_keyframe = TRUE;
5687 for (i = stream->stss_index; i < n_sample_syncs; i++) {
5688 /* note that the first sample is index 1, not 0 */
5691 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
5693 if (G_LIKELY (index > 0 && index <= n_samples)) {
5695 samples[index].keyframe = TRUE;
5696 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5697 /* and exit if we have enough samples */
5698 if (G_UNLIKELY (index >= n)) {
5705 stream->stss_index = i;
5708 /* stps marks partial sync frames like open GOP I-Frames */
5709 if (stream->stps_present == TRUE) {
5710 guint32 n_sample_partial_syncs;
5712 n_sample_partial_syncs = stream->n_sample_partial_syncs;
5714 /* if there are no entries, the stss table contains the real
5716 if (n_sample_partial_syncs) {
5717 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
5718 /* note that the first sample is index 1, not 0 */
5721 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
5723 if (G_LIKELY (index > 0 && index <= n_samples)) {
5725 samples[index].keyframe = TRUE;
5726 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5727 /* and exit if we have enough samples */
5728 if (G_UNLIKELY (index >= n)) {
5735 stream->stps_index = i;
5739 /* no stss, all samples are keyframes */
5740 stream->all_keyframe = TRUE;
5741 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
5746 /* composition time to sample */
5747 if (stream->ctts_present == TRUE) {
5748 guint32 n_composition_times;
5750 gint32 ctts_soffset;
5752 /* Fill in the pts_offsets */
5754 n_composition_times = stream->n_composition_times;
5756 for (i = stream->ctts_index; i < n_composition_times; i++) {
5757 if (stream->ctts_sample_index >= stream->ctts_count
5758 || !stream->ctts_sample_index) {
5759 stream->ctts_count =
5760 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
5761 stream->ctts_soffset =
5762 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
5763 stream->ctts_sample_index = 0;
5766 ctts_count = stream->ctts_count;
5767 ctts_soffset = stream->ctts_soffset;
5769 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
5770 cur->pts_offset = ctts_soffset;
5773 if (G_UNLIKELY (cur > last)) {
5775 stream->ctts_sample_index = j + 1;
5779 stream->ctts_sample_index = 0;
5780 stream->ctts_index++;
5784 stream->stbl_index = n;
5785 /* if index has been completely parsed, free data that is no-longer needed */
5786 if (n + 1 == stream->n_samples) {
5787 gst_qtdemux_stbl_free (stream);
5788 GST_DEBUG_OBJECT (qtdemux,
5789 "parsed all available samples; checking for more");
5790 while (n + 1 == stream->n_samples)
5791 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
5794 GST_OBJECT_UNLOCK (qtdemux);
5801 GST_LOG_OBJECT (qtdemux,
5802 "Tried to parse up to sample %u but this sample has already been parsed",
5804 /* if fragmented, there may be more */
5805 if (qtdemux->fragmented && n == stream->stbl_index)
5807 GST_OBJECT_UNLOCK (qtdemux);
5813 GST_LOG_OBJECT (qtdemux,
5814 "Tried to parse up to sample %u but there are only %u samples", n + 1,
5816 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5817 (_("This file is corrupt and cannot be played.")), (NULL));
5822 GST_OBJECT_UNLOCK (qtdemux);
5823 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5824 (_("This file is corrupt and cannot be played.")), (NULL));
5829 /* collect all segment info for @stream.
5832 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
5837 /* parse and prepare segment info from the edit list */
5838 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
5839 stream->n_segments = 0;
5840 stream->segments = NULL;
5841 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
5845 guint64 time, stime;
5848 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
5849 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
5852 buffer = elst->data;
5854 n_segments = QT_UINT32 (buffer + 12);
5856 /* we might allocate a bit too much, at least allocate 1 segment */
5857 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
5859 /* segments always start from 0 */
5863 for (i = 0; i < n_segments; i++) {
5866 QtDemuxSegment *segment;
5869 media_time = QT_UINT32 (buffer + 20 + i * 12);
5871 /* -1 media time is an empty segment, just ignore it */
5872 if (media_time == G_MAXUINT32)
5875 duration = QT_UINT32 (buffer + 16 + i * 12);
5877 segment = &stream->segments[count++];
5879 /* time and duration expressed in global timescale */
5880 segment->time = stime;
5881 /* add non scaled values so we don't cause roundoff errors */
5883 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
5884 segment->stop_time = stime;
5885 segment->duration = stime - segment->time;
5886 /* media_time expressed in stream timescale */
5887 segment->media_start =
5888 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
5889 segment->media_stop = segment->media_start + segment->duration;
5890 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
5892 if (rate_int <= 1) {
5893 /* 0 is not allowed, some programs write 1 instead of the floating point
5895 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
5899 segment->rate = rate_int / 65536.0;
5902 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
5903 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
5904 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
5905 GST_TIME_ARGS (segment->duration),
5906 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
5908 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
5909 stream->n_segments = count;
5913 /* push based does not handle segments, so act accordingly here,
5914 * and warn if applicable */
5915 if (!qtdemux->pullbased) {
5916 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
5917 /* remove and use default one below, we stream like it anyway */
5918 g_free (stream->segments);
5919 stream->segments = NULL;
5920 stream->n_segments = 0;
5923 /* no segments, create one to play the complete trak */
5924 if (stream->n_segments == 0) {
5925 GstClockTime stream_duration =
5926 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
5928 if (stream->segments == NULL)
5929 stream->segments = g_new (QtDemuxSegment, 1);
5931 /* represent unknown our way */
5932 if (stream_duration == 0)
5933 stream_duration = -1;
5935 stream->segments[0].time = 0;
5936 stream->segments[0].stop_time = stream_duration;
5937 stream->segments[0].duration = stream_duration;
5938 stream->segments[0].media_start = 0;
5939 stream->segments[0].media_stop = stream_duration;
5940 stream->segments[0].rate = 1.0;
5942 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
5943 GST_TIME_ARGS (stream_duration));
5944 stream->n_segments = 1;
5946 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
5952 * Parses the stsd atom of a svq3 trak looking for
5953 * the SMI and gama atoms.
5956 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
5957 guint8 ** gamma, GstBuffer ** seqh)
5959 guint8 *_gamma = NULL;
5960 GstBuffer *_seqh = NULL;
5961 guint8 *stsd_data = stsd->data;
5962 guint32 length = QT_UINT32 (stsd_data);
5966 GST_WARNING_OBJECT (qtdemux, "stsd too short");
5972 version = QT_UINT16 (stsd_data);
5977 while (length > 8) {
5978 guint32 fourcc, size;
5980 size = QT_UINT32 (stsd_data);
5981 fourcc = QT_FOURCC (stsd_data + 4);
5982 data = stsd_data + 8;
5989 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
5990 " for gama atom, expected 12", size);
5995 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
5997 if (_seqh != NULL) {
5998 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
5999 " found, ignoring");
6001 seqh_size = QT_UINT32 (data + 4);
6002 if (seqh_size > 0) {
6003 _seqh = gst_buffer_new_and_alloc (seqh_size);
6004 memcpy (GST_BUFFER_DATA (_seqh), data + 8, seqh_size);
6011 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6012 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6016 if (size <= length) {
6022 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6025 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6026 G_GUINT16_FORMAT, version);
6037 gst_buffer_unref (_seqh);
6042 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6049 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6050 * atom that might contain a 'data' atom with the rtsp uri.
6051 * This case was reported in bug #597497, some info about
6052 * the hndl atom can be found in TN1195
6054 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6055 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6058 guint32 dref_num_entries = 0;
6059 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6060 gst_byte_reader_skip (&dref, 4) &&
6061 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6064 /* search dref entries for hndl atom */
6065 for (i = 0; i < dref_num_entries; i++) {
6066 guint32 size = 0, type;
6067 guint8 string_len = 0;
6068 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6069 qt_atom_parser_get_fourcc (&dref, &type)) {
6070 if (type == FOURCC_hndl) {
6071 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6073 /* skip data reference handle bytes and the
6074 * following pascal string and some extra 4
6075 * bytes I have no idea what are */
6076 if (!gst_byte_reader_skip (&dref, 4) ||
6077 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6078 !gst_byte_reader_skip (&dref, string_len + 4)) {
6079 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6083 /* iterate over the atoms to find the data atom */
6084 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6088 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6089 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6090 if (atom_type == FOURCC_data) {
6091 const guint8 *uri_aux = NULL;
6093 /* found the data atom that might contain the rtsp uri */
6094 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6095 "hndl atom, interpreting it as an URI");
6096 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6098 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6099 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6101 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6102 "didn't contain a rtsp address");
6104 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6109 /* skipping to the next entry */
6110 gst_byte_reader_skip (&dref, atom_size - 8);
6112 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6119 /* skip to the next entry */
6120 gst_byte_reader_skip (&dref, size - 8);
6122 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6125 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6132 less_than (gconstpointer a, gconstpointer b)
6134 const guint32 *av = a, *bv = b;
6140 * With each track we associate a new QtDemuxStream that contains all the info
6142 * traks that do not decode to something (like strm traks) will not have a pad.
6145 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6160 QtDemuxStream *stream;
6161 GstTagList *list = NULL;
6162 gchar *codec = NULL;
6163 const guint8 *stsd_data;
6164 guint16 lang_code; /* quicktime lang code or packed iso code */
6166 guint32 tkhd_flags = 0;
6167 guint8 tkhd_version = 0;
6169 guint value_size, len;
6171 stream = g_new0 (QtDemuxStream, 1);
6172 /* new streams always need a discont */
6173 stream->discont = TRUE;
6174 /* we enable clipping for raw audio/video streams */
6175 stream->need_clip = FALSE;
6176 stream->need_process = FALSE;
6177 stream->segment_index = -1;
6178 stream->time_position = 0;
6179 stream->sample_index = -1;
6180 stream->last_ret = GST_FLOW_OK;
6182 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6183 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6184 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6187 /* pick between 64 or 32 bits */
6188 value_size = tkhd_version == 1 ? 8 : 4;
6189 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6190 !gst_byte_reader_get_uint32_be (&tkhd, &stream->track_id))
6193 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6194 tkhd_version, tkhd_flags, stream->track_id);
6196 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6199 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6200 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6201 if (qtdemux->major_brand != FOURCC_mjp2 ||
6202 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6206 len = QT_UINT32 ((guint8 *) mdhd->data);
6207 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6208 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6209 if (version == 0x01000000) {
6212 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6213 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6214 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6218 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6219 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6220 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6223 if (lang_code < 0x800) {
6224 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6226 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6227 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6228 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6229 stream->lang_id[3] = 0;
6232 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6234 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6236 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6237 lang_code, stream->lang_id);
6239 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6242 /* fragmented files may have bogus duration in moov */
6243 if (!qtdemux->fragmented &&
6244 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6245 guint64 tdur1, tdur2;
6247 /* don't overflow */
6248 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6249 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6252 * some of those trailers, nowadays, have prologue images that are
6253 * themselves vide tracks as well. I haven't really found a way to
6254 * identify those yet, except for just looking at their duration. */
6255 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6256 GST_WARNING_OBJECT (qtdemux,
6257 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6258 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6259 "found, assuming preview image or something; skipping track",
6260 stream->duration, stream->timescale, qtdemux->duration,
6261 qtdemux->timescale);
6267 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6270 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6271 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6273 len = QT_UINT32 ((guint8 *) hdlr->data);
6275 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6276 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6277 GST_FOURCC_ARGS (stream->subtype));
6279 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6282 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6286 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6288 stsd_data = (const guint8 *) stsd->data;
6290 /* stsd should at least have one entry */
6291 len = QT_UINT32 (stsd_data);
6295 /* and that entry should fit within stsd */
6296 len = QT_UINT32 (stsd_data + 16);
6297 if (len > QT_UINT32 (stsd_data) + 16)
6299 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6301 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6302 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6303 GST_FOURCC_ARGS (stream->fourcc));
6305 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6306 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6307 goto error_encrypted;
6309 if (stream->subtype == FOURCC_vide) {
6310 guint32 w = 0, h = 0;
6312 stream->sampled = TRUE;
6314 /* version 1 uses some 64-bit ints */
6315 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6316 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6317 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6320 stream->display_width = w >> 16;
6321 stream->display_height = h >> 16;
6327 stream->width = QT_UINT16 (stsd_data + offset + 32);
6328 stream->height = QT_UINT16 (stsd_data + offset + 34);
6329 stream->fps_n = 0; /* this is filled in later */
6330 stream->fps_d = 0; /* this is filled in later */
6331 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6332 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6334 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6335 QT_UINT16 (stsd_data + offset + 48));
6338 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6340 list = gst_tag_list_new ();
6341 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6342 GST_TAG_VIDEO_CODEC, codec, NULL);
6349 /* pick 'the' stsd child */
6350 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
6352 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
6353 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
6357 const guint8 *pasp_data = (const guint8 *) pasp->data;
6359 stream->par_w = QT_UINT32 (pasp_data + 8);
6360 stream->par_h = QT_UINT32 (pasp_data + 12);
6367 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
6372 gint len = QT_UINT32 (stsd_data) - 0x66;
6373 const guint8 *avc_data = stsd_data + 0x66;
6376 while (len >= 0x8) {
6379 if (QT_UINT32 (avc_data) <= len)
6380 size = QT_UINT32 (avc_data) - 0x8;
6385 /* No real data, so break out */
6388 switch (QT_FOURCC (avc_data + 0x4)) {
6391 /* parse, if found */
6394 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
6396 /* First 4 bytes are the length of the atom, the next 4 bytes
6397 * are the fourcc, the next 1 byte is the version, and the
6398 * subsequent bytes are sequence parameter set like data. */
6399 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
6400 avc_data + 8 + 1, size - 1);
6402 buf = gst_buffer_new_and_alloc (size);
6403 memcpy (GST_BUFFER_DATA (buf), avc_data + 0x8, size);
6404 gst_caps_set_simple (stream->caps,
6405 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6406 gst_buffer_unref (buf);
6412 guint avg_bitrate, max_bitrate;
6414 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
6418 max_bitrate = QT_UINT32 (avc_data + 0xc);
6419 avg_bitrate = QT_UINT32 (avc_data + 0x10);
6421 if (!max_bitrate && !avg_bitrate)
6424 /* Some muxers seem to swap the average and maximum bitrates
6425 * (I'm looking at you, YouTube), so we swap for sanity. */
6426 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
6427 guint temp = avg_bitrate;
6429 avg_bitrate = max_bitrate;
6434 list = gst_tag_list_new ();
6436 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6437 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6438 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6440 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6441 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6442 GST_TAG_BITRATE, avg_bitrate, NULL);
6453 avc_data += size + 8;
6465 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
6466 GST_FOURCC_ARGS (fourcc));
6468 /* codec data might be in glbl extension atom */
6470 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
6476 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
6478 len = QT_UINT32 (data);
6481 buf = gst_buffer_new_and_alloc (len);
6482 memcpy (GST_BUFFER_DATA (buf), data + 8, len);
6483 gst_caps_set_simple (stream->caps,
6484 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6485 gst_buffer_unref (buf);
6492 /* see annex I of the jpeg2000 spec */
6493 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
6497 guint32 ncomp_map = 0;
6498 gint32 *comp_map = NULL;
6499 guint32 nchan_def = 0;
6500 gint32 *chan_def = NULL;
6502 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
6503 /* some required atoms */
6504 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
6507 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
6511 /* number of components; redundant with info in codestream, but useful
6513 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
6514 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
6516 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
6518 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
6521 GST_DEBUG_OBJECT (qtdemux, "found colr");
6522 /* extract colour space info */
6523 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
6524 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
6526 fourcc = GST_MAKE_FOURCC ('s', 'R', 'G', 'B');
6529 fourcc = GST_MAKE_FOURCC ('G', 'R', 'A', 'Y');
6532 fourcc = GST_MAKE_FOURCC ('s', 'Y', 'U', 'V');
6539 /* colr is required, and only values 16, 17, and 18 are specified,
6540 so error if we have no fourcc */
6543 /* extract component mapping */
6544 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
6546 guint32 cmap_len = 0;
6548 cmap_len = QT_UINT32 (cmap->data);
6549 if (cmap_len >= 8) {
6550 /* normal box, subtract off header */
6552 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
6553 if (cmap_len % 4 == 0) {
6554 ncomp_map = (cmap_len / 4);
6555 comp_map = g_new0 (gint32, ncomp_map);
6556 for (i = 0; i < ncomp_map; i++) {
6559 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
6560 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
6561 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
6562 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
6567 /* extract channel definitions */
6568 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
6570 guint32 cdef_len = 0;
6572 cdef_len = QT_UINT32 (cdef->data);
6573 if (cdef_len >= 10) {
6574 /* normal box, subtract off header and len */
6576 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
6577 if (cdef_len % 6 == 0) {
6578 nchan_def = (cdef_len / 6);
6579 chan_def = g_new0 (gint32, nchan_def);
6580 for (i = 0; i < nchan_def; i++)
6582 for (i = 0; i < nchan_def; i++) {
6583 guint16 cn, typ, asoc;
6584 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
6585 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
6586 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
6587 if (cn < nchan_def) {
6590 chan_def[cn] = asoc;
6593 chan_def[cn] = 0; /* alpha */
6596 chan_def[cn] = -typ;
6604 gst_caps_set_simple (stream->caps,
6605 "num-components", G_TYPE_INT, ncomp, NULL);
6606 gst_caps_set_simple (stream->caps,
6607 "fourcc", GST_TYPE_FOURCC, fourcc, NULL);
6610 GValue arr = { 0, };
6611 GValue elt = { 0, };
6613 g_value_init (&arr, GST_TYPE_ARRAY);
6614 g_value_init (&elt, G_TYPE_INT);
6615 for (i = 0; i < ncomp_map; i++) {
6616 g_value_set_int (&elt, comp_map[i]);
6617 gst_value_array_append_value (&arr, &elt);
6619 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6620 "component-map", &arr);
6621 g_value_unset (&elt);
6622 g_value_unset (&arr);
6627 GValue arr = { 0, };
6628 GValue elt = { 0, };
6630 g_value_init (&arr, GST_TYPE_ARRAY);
6631 g_value_init (&elt, G_TYPE_INT);
6632 for (i = 0; i < nchan_def; i++) {
6633 g_value_set_int (&elt, chan_def[i]);
6634 gst_value_array_append_value (&arr, &elt);
6636 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6637 "channel-definitions", &arr);
6638 g_value_unset (&elt);
6639 g_value_unset (&arr);
6643 /* some optional atoms */
6644 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
6645 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
6647 /* indicate possible fields in caps */
6649 data = (guint8 *) field->data + 8;
6651 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
6652 (gint) * data, NULL);
6654 /* add codec_data if provided */
6659 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
6660 data = prefix->data;
6661 len = QT_UINT32 (data);
6664 buf = gst_buffer_new_and_alloc (len);
6665 memcpy (GST_BUFFER_DATA (buf), data + 8, len);
6666 gst_caps_set_simple (stream->caps,
6667 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6668 gst_buffer_unref (buf);
6677 GstBuffer *seqh = NULL;
6678 guint8 *gamma_data = NULL;
6679 gint len = QT_UINT32 (stsd_data);
6681 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
6683 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
6684 QT_FP32 (gamma_data), NULL);
6687 /* sorry for the bad name, but we don't know what this is, other
6688 * than its own fourcc */
6689 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
6693 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
6694 buf = gst_buffer_new_and_alloc (len);
6695 memcpy (GST_BUFFER_DATA (buf), stsd_data, len);
6696 gst_caps_set_simple (stream->caps,
6697 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6698 gst_buffer_unref (buf);
6703 gst_caps_set_simple (stream->caps,
6704 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
6711 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
6712 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
6716 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
6720 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
6721 /* collect the headers and store them in a stream list so that we can
6722 * send them out first */
6723 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
6733 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
6734 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
6737 ovc1_data = ovc1->data;
6738 ovc1_len = QT_UINT32 (ovc1_data);
6739 if (ovc1_len <= 198) {
6740 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
6743 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
6744 memcpy (GST_BUFFER_DATA (buf), ovc1_data + 198, ovc1_len - 198);
6745 gst_caps_set_simple (stream->caps,
6746 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6747 gst_buffer_unref (buf);
6755 GST_INFO_OBJECT (qtdemux,
6756 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
6757 GST_FOURCC_ARGS (fourcc), stream->caps);
6759 } else if (stream->subtype == FOURCC_soun) {
6760 int version, samplesize;
6761 guint16 compression_id;
6767 version = QT_UINT32 (stsd_data + offset);
6768 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
6769 samplesize = QT_UINT16 (stsd_data + offset + 10);
6770 compression_id = QT_UINT16 (stsd_data + offset + 12);
6771 stream->rate = QT_FP32 (stsd_data + offset + 16);
6773 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
6774 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
6775 QT_UINT32 (stsd_data + offset + 4));
6776 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
6777 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
6778 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
6779 GST_LOG_OBJECT (qtdemux, "packet size: %d",
6780 QT_UINT16 (stsd_data + offset + 14));
6781 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
6783 if (compression_id == 0xfffe)
6784 stream->sampled = TRUE;
6786 /* first assume uncompressed audio */
6787 stream->bytes_per_sample = samplesize / 8;
6788 stream->samples_per_frame = stream->n_channels;
6789 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
6790 stream->samples_per_packet = stream->samples_per_frame;
6791 stream->bytes_per_packet = stream->bytes_per_sample;
6795 /* Yes, these have to be hard-coded */
6798 stream->samples_per_packet = 6;
6799 stream->bytes_per_packet = 1;
6800 stream->bytes_per_frame = 1 * stream->n_channels;
6801 stream->bytes_per_sample = 1;
6802 stream->samples_per_frame = 6 * stream->n_channels;
6807 stream->samples_per_packet = 3;
6808 stream->bytes_per_packet = 1;
6809 stream->bytes_per_frame = 1 * stream->n_channels;
6810 stream->bytes_per_sample = 1;
6811 stream->samples_per_frame = 3 * stream->n_channels;
6816 stream->samples_per_packet = 64;
6817 stream->bytes_per_packet = 34;
6818 stream->bytes_per_frame = 34 * stream->n_channels;
6819 stream->bytes_per_sample = 2;
6820 stream->samples_per_frame = 64 * stream->n_channels;
6826 stream->samples_per_packet = 1;
6827 stream->bytes_per_packet = 1;
6828 stream->bytes_per_frame = 1 * stream->n_channels;
6829 stream->bytes_per_sample = 1;
6830 stream->samples_per_frame = 1 * stream->n_channels;
6835 stream->samples_per_packet = 160;
6836 stream->bytes_per_packet = 33;
6837 stream->bytes_per_frame = 33 * stream->n_channels;
6838 stream->bytes_per_sample = 2;
6839 stream->samples_per_frame = 160 * stream->n_channels;
6846 if (version == 0x00010000) {
6854 /* only parse extra decoding config for non-pcm audio */
6855 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
6856 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
6857 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
6858 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
6860 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
6861 stream->samples_per_packet);
6862 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
6863 stream->bytes_per_packet);
6864 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
6865 stream->bytes_per_frame);
6866 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
6867 stream->bytes_per_sample);
6869 if (!stream->sampled && stream->bytes_per_packet) {
6870 stream->samples_per_frame = (stream->bytes_per_frame /
6871 stream->bytes_per_packet) * stream->samples_per_packet;
6872 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
6873 stream->samples_per_frame);
6878 } else if (version == 0x00020000) {
6885 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
6886 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
6887 stream->rate = qtfp.fp;
6888 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
6890 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
6891 stream->samples_per_packet);
6892 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
6893 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
6896 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
6899 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
6908 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
6910 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
6912 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
6914 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
6917 gst_caps_set_simple (stream->caps,
6918 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
6925 const gchar *owma_data, *codec_name = NULL;
6929 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
6930 /* FIXME this should also be gst_riff_strf_auds,
6931 * but the latter one is actually missing bits-per-sample :( */
6936 gint32 nSamplesPerSec;
6937 gint32 nAvgBytesPerSec;
6939 gint16 wBitsPerSample;
6944 GST_DEBUG_OBJECT (qtdemux, "parse owma");
6945 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
6948 owma_data = owma->data;
6949 owma_len = QT_UINT32 (owma_data);
6950 if (owma_len <= 54) {
6951 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
6954 wfex = (WAVEFORMATEX *) (owma_data + 36);
6955 buf = gst_buffer_new_and_alloc (owma_len - 54);
6956 memcpy (GST_BUFFER_DATA (buf), owma_data + 54, owma_len - 54);
6957 if (wfex->wFormatTag == 0x0161) {
6958 codec_name = "Windows Media Audio";
6960 } else if (wfex->wFormatTag == 0x0162) {
6961 codec_name = "Windows Media Audio 9 Pro";
6963 } else if (wfex->wFormatTag == 0x0163) {
6964 codec_name = "Windows Media Audio 9 Lossless";
6965 /* is that correct? gstffmpegcodecmap.c is missing it, but
6966 * fluendo codec seems to support it */
6970 gst_caps_set_simple (stream->caps,
6971 "codec_data", GST_TYPE_BUFFER, buf,
6972 "wmaversion", G_TYPE_INT, version,
6973 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
6974 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
6975 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
6976 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
6978 gst_buffer_unref (buf);
6982 codec = g_strdup (codec_name);
6991 list = gst_tag_list_new ();
6992 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6993 GST_TAG_AUDIO_CODEC, codec, NULL);
6998 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7002 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7004 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7006 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7010 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7011 16 bits is a byte-swapped wave-style codec identifier,
7012 and we can find a WAVE header internally to a 'wave' atom here.
7013 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7014 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7017 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7018 if (len < offset + 20) {
7019 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7021 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7022 const guint8 *data = stsd_data + offset + 16;
7024 GNode *waveheadernode;
7026 wavenode = g_node_new ((guint8 *) data);
7027 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7028 const guint8 *waveheader;
7031 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7032 if (waveheadernode) {
7033 waveheader = (const guint8 *) waveheadernode->data;
7034 headerlen = QT_UINT32 (waveheader);
7036 if (headerlen > 8) {
7037 gst_riff_strf_auds *header = NULL;
7038 GstBuffer *headerbuf;
7044 headerbuf = gst_buffer_new ();
7045 GST_BUFFER_DATA (headerbuf) = (guint8 *) waveheader;
7046 GST_BUFFER_SIZE (headerbuf) = headerlen;
7048 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7049 headerbuf, &header, &extra)) {
7050 gst_caps_unref (stream->caps);
7051 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7052 header, extra, NULL, NULL);
7055 gst_buffer_unref (extra);
7059 GST_DEBUG ("Didn't find waveheadernode for this codec");
7061 g_node_destroy (wavenode);
7064 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7068 /* FIXME: what is in the chunk? */
7071 gint len = QT_UINT32 (stsd_data);
7073 /* seems to be always = 116 = 0x74 */
7079 gint len = QT_UINT32 (stsd_data);
7082 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7084 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x4C, len - 0x4C);
7085 gst_caps_set_simple (stream->caps,
7086 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7087 gst_buffer_unref (buf);
7089 gst_caps_set_simple (stream->caps,
7090 "samplesize", G_TYPE_INT, samplesize, NULL);
7095 GNode *alac, *wave = NULL;
7097 /* apparently, m4a has this atom appended directly in the stsd entry,
7098 * while mov has it in a wave atom */
7099 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7101 /* alac now refers to stsd entry atom */
7102 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7104 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7106 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7109 gint len = QT_UINT32 (alac->data);
7113 GST_DEBUG_OBJECT (qtdemux,
7114 "discarding alac atom with unexpected len %d", len);
7116 /* codec-data contains alac atom size and prefix,
7117 * ffmpeg likes it that way, not quite gst-ish though ...*/
7118 buf = gst_buffer_new_and_alloc (len);
7119 memcpy (GST_BUFFER_DATA (buf), alac->data, len);
7120 gst_caps_set_simple (stream->caps,
7121 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7122 gst_buffer_unref (buf);
7125 gst_caps_set_simple (stream->caps,
7126 "samplesize", G_TYPE_INT, samplesize, NULL);
7131 gint len = QT_UINT32 (stsd_data);
7134 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7136 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34);
7138 gst_caps_set_simple (stream->caps,
7139 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7140 gst_buffer_unref (buf);
7148 GST_INFO_OBJECT (qtdemux,
7149 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7150 GST_FOURCC_ARGS (fourcc), stream->caps);
7152 } else if (stream->subtype == FOURCC_strm) {
7153 if (fourcc == FOURCC_rtsp) {
7154 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7156 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7157 GST_FOURCC_ARGS (fourcc));
7158 goto unknown_stream;
7160 stream->sampled = TRUE;
7161 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
7163 stream->sampled = TRUE;
7168 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7170 list = gst_tag_list_new ();
7171 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7172 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7177 /* hunt for sort-of codec data */
7184 /* look for palette */
7185 /* target mp4s atom */
7186 len = QT_UINT32 (stsd_data + offset);
7187 data = stsd_data + offset;
7188 /* verify sufficient length,
7189 * and esds present with decConfigDescr of expected size and position */
7190 if ((len >= 106 + 8)
7191 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7192 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7197 /* move to decConfigDescr data */
7198 data = data + 8 + 42;
7199 for (i = 0; i < 16; i++) {
7200 clut[i] = QT_UINT32 (data);
7204 s = gst_structure_new ("application/x-gst-dvd", "event",
7205 G_TYPE_STRING, "dvd-spu-clut-change",
7206 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7207 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7208 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7209 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7210 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7211 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7212 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7213 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7216 /* store event and trigger custom processing */
7217 stream->pending_event =
7218 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7219 stream->need_process = TRUE;
7227 goto unknown_stream;
7230 /* promote to sampled format */
7231 if (stream->fourcc == FOURCC_samr) {
7232 /* force mono 8000 Hz for AMR */
7233 stream->sampled = TRUE;
7234 stream->n_channels = 1;
7235 stream->rate = 8000;
7236 } else if (stream->fourcc == FOURCC_sawb) {
7237 /* force mono 16000 Hz for AMR-WB */
7238 stream->sampled = TRUE;
7239 stream->n_channels = 1;
7240 stream->rate = 16000;
7241 } else if (stream->fourcc == FOURCC_mp4a) {
7242 stream->sampled = TRUE;
7245 /* collect sample information */
7246 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7247 goto samples_failed;
7249 if (qtdemux->fragmented) {
7253 /* need all moov samples as basis; probably not many if any at all */
7254 /* prevent moof parsing taking of at this time */
7255 offset = qtdemux->moof_offset;
7256 qtdemux->moof_offset = 0;
7257 if (stream->n_samples &&
7258 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7259 qtdemux->moof_offset = offset;
7260 goto samples_failed;
7262 qtdemux->moof_offset = 0;
7263 /* movie duration more reliable in this case (e.g. mehd) */
7264 if (qtdemux->segment.duration &&
7265 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7266 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7267 stream->timescale, GST_SECOND);
7268 /* need defaults for fragments */
7269 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7272 /* configure segments */
7273 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7274 goto segments_failed;
7276 /* add some language tag, if useful */
7277 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7278 strcmp (stream->lang_id, "und")) {
7279 const gchar *lang_code;
7282 list = gst_tag_list_new ();
7284 /* convert ISO 639-2 code to ISO 639-1 */
7285 lang_code = gst_tag_get_language_code (stream->lang_id);
7286 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7287 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7290 /* now we are ready to add the stream */
7291 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7292 goto too_many_streams;
7294 stream->pending_tags = list;
7295 qtdemux->streams[qtdemux->n_streams] = stream;
7296 qtdemux->n_streams++;
7297 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7304 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7305 (_("This file is corrupt and cannot be played.")), (NULL));
7311 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7318 /* we posted an error already */
7319 /* free stbl sub-atoms */
7320 gst_qtdemux_stbl_free (stream);
7326 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7327 GST_FOURCC_ARGS (stream->subtype));
7333 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7334 (_("This file contains too many streams. Only playing first %d"),
7335 GST_QTDEMUX_MAX_STREAMS), (NULL));
7340 static GstFlowReturn
7341 qtdemux_expose_streams (GstQTDemux * qtdemux)
7344 GstFlowReturn ret = GST_FLOW_OK;
7346 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7348 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7349 QtDemuxStream *stream = qtdemux->streams[i];
7350 guint32 sample_num = 0;
7355 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7356 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7358 if (qtdemux->fragmented) {
7359 /* need all moov samples first */
7360 GST_OBJECT_LOCK (qtdemux);
7361 while (stream->n_samples == 0)
7362 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7364 GST_OBJECT_UNLOCK (qtdemux);
7366 /* discard any stray moof */
7367 qtdemux->moof_offset = 0;
7370 /* prepare braking */
7371 if (ret != GST_FLOW_ERROR)
7374 /* in pull mode, we should have parsed some sample info by now;
7375 * and quite some code will not handle no samples.
7376 * in push mode, we'll just have to deal with it */
7377 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7378 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7379 gst_qtdemux_stream_free (qtdemux, stream);
7380 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7381 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7382 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7383 qtdemux->n_streams--;
7388 /* parse number of initial sample to set frame rate cap */
7389 while (sample_num < stream->n_samples && sample_num < samples) {
7390 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7394 /* collect and sort durations */
7395 samples = MIN (stream->stbl_index + 1, samples);
7396 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7398 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7400 while (sample_num < samples) {
7401 g_array_append_val (durations, stream->samples[sample_num].duration);
7404 g_array_sort (durations, less_than);
7405 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7406 g_array_free (durations, TRUE);
7409 /* now we have all info and can expose */
7410 list = stream->pending_tags;
7411 stream->pending_tags = NULL;
7412 gst_qtdemux_add_stream (qtdemux, stream, list);
7415 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7417 /* check if we should post a redirect in case there is a single trak
7418 * and it is a redirecting trak */
7419 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7422 qtdemux_post_global_tags (qtdemux);
7424 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7425 "an external content");
7426 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7427 gst_structure_new ("redirect",
7428 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7430 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7431 qtdemux->posted_redirect = TRUE;
7437 /* check if major or compatible brand is 3GP */
7438 static inline gboolean
7439 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7442 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7443 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7444 } else if (qtdemux->comp_brands != NULL) {
7445 guint8 *data = GST_BUFFER_DATA (qtdemux->comp_brands);
7446 guint size = GST_BUFFER_SIZE (qtdemux->comp_brands);
7447 gboolean res = FALSE;
7450 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7451 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7461 /* check if tag is a spec'ed 3GP tag keyword storing a string */
7462 static inline gboolean
7463 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
7465 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
7466 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
7467 || fourcc == FOURCC_albm;
7471 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
7472 const char *dummy, GNode * node)
7474 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7478 gdouble longitude, latitude, altitude;
7481 len = QT_UINT32 (node->data);
7488 /* TODO: language code skipped */
7490 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
7493 /* do not alarm in trivial case, but bail out otherwise */
7494 if (*(data + offset) != 0) {
7495 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
7499 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7500 GST_TAG_GEO_LOCATION_NAME, name, NULL);
7501 offset += strlen (name);
7505 if (len < offset + 2 + 4 + 4 + 4)
7508 /* +1 +1 = skip null-terminator and location role byte */
7510 /* table in spec says unsigned, semantics say negative has meaning ... */
7511 longitude = QT_SFP32 (data + offset);
7514 latitude = QT_SFP32 (data + offset);
7517 altitude = QT_SFP32 (data + offset);
7519 /* one invalid means all are invalid */
7520 if (longitude >= -180.0 && longitude <= 180.0 &&
7521 latitude >= -90.0 && latitude <= 90.0) {
7522 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7523 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
7524 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
7525 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
7528 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
7535 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
7542 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7549 len = QT_UINT32 (node->data);
7553 y = QT_UINT16 ((guint8 *) node->data + 12);
7555 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
7558 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
7560 date = g_date_new_dmy (1, 1, y);
7561 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
7566 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
7567 const char *dummy, GNode * node)
7570 char *tag_str = NULL;
7575 len = QT_UINT32 (node->data);
7580 entity = (guint8 *) node->data + offset;
7581 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
7582 GST_DEBUG_OBJECT (qtdemux,
7583 "classification info: %c%c%c%c invalid classification entity",
7584 entity[0], entity[1], entity[2], entity[3]);
7589 table = QT_UINT16 ((guint8 *) node->data + offset);
7591 /* Language code skipped */
7595 /* Tag format: "XXXX://Y[YYYY]/classification info string"
7596 * XXXX: classification entity, fixed length 4 chars.
7597 * Y[YYYY]: classification table, max 5 chars.
7599 tag_str = g_strdup_printf ("----://%u/%s",
7600 table, (char *) node->data + offset);
7602 /* memcpy To be sure we're preserving byte order */
7603 memcpy (tag_str, entity, 4);
7604 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
7606 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
7616 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
7622 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
7623 const char *dummy, GNode * node)
7625 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7631 gboolean ret = TRUE;
7633 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7635 len = QT_UINT32 (data->data);
7636 type = QT_UINT32 ((guint8 *) data->data + 8);
7637 if (type == 0x00000001 && len > 16) {
7638 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
7641 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7642 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
7646 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7650 len = QT_UINT32 (node->data);
7651 type = QT_UINT32 ((guint8 *) node->data + 4);
7652 if ((type >> 24) == 0xa9) {
7653 /* Type starts with the (C) symbol, so the next 32 bits are
7654 * the language code, which we ignore */
7656 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
7657 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
7658 QT_FOURCC ((guint8 *) node->data + 4))) {
7659 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
7661 /* we go for 3GP style encoding if major brands claims so,
7662 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
7663 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
7664 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
7665 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
7667 /* 16-bit Language code is ignored here as well */
7668 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
7675 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
7676 ret = FALSE; /* may have to fallback */
7678 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
7679 len - offset, env_vars);
7681 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7682 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
7686 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7693 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
7694 const char *dummy, GNode * node)
7696 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
7700 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
7701 const char *dummy, GNode * node)
7703 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7705 char *s, *t, *k = NULL;
7710 /* first try normal string tag if major brand not 3GP */
7711 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
7712 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
7713 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
7714 * let's try it 3gpp way after minor safety check */
7716 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
7722 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
7726 len = QT_UINT32 (data);
7730 count = QT_UINT8 (data + 14);
7732 for (; count; count--) {
7735 if (offset + 1 > len)
7737 slen = QT_UINT8 (data + offset);
7739 if (offset + slen > len)
7741 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
7744 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
7746 t = g_strjoin (",", k, s, NULL);
7754 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
7761 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
7762 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
7771 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
7777 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
7778 const char *tag2, GNode * node)
7785 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7787 len = QT_UINT32 (data->data);
7788 type = QT_UINT32 ((guint8 *) data->data + 8);
7789 if (type == 0x00000000 && len >= 22) {
7790 n1 = QT_UINT16 ((guint8 *) data->data + 18);
7791 n2 = QT_UINT16 ((guint8 *) data->data + 20);
7793 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
7794 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7798 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
7799 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7807 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
7815 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7817 len = QT_UINT32 (data->data);
7818 type = QT_UINT32 ((guint8 *) data->data + 8);
7819 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
7820 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
7821 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
7822 n1 = QT_UINT16 ((guint8 *) data->data + 16);
7824 /* do not add bpm=0 */
7825 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
7826 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7827 tag1, (gdouble) n1, NULL);
7834 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
7835 const char *dummy, GNode * node)
7842 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7844 len = QT_UINT32 (data->data);
7845 type = QT_UINT32 ((guint8 *) data->data + 8);
7846 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
7847 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
7848 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
7849 num = QT_UINT32 ((guint8 *) data->data + 16);
7851 /* do not add num=0 */
7852 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
7853 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7861 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
7869 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7871 len = QT_UINT32 (data->data);
7872 type = QT_UINT32 ((guint8 *) data->data + 8);
7873 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
7874 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
7875 if ((buf = gst_tag_image_data_to_image_buffer ((guint8 *) data->data + 16,
7876 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
7877 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
7878 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7880 gst_buffer_unref (buf);
7887 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7895 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7897 len = QT_UINT32 (data->data);
7898 type = QT_UINT32 ((guint8 *) data->data + 8);
7899 if (type == 0x00000001 && len > 16) {
7900 guint y, m = 1, d = 1;
7903 s = g_strndup ((char *) data->data + 16, len - 16);
7904 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
7905 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
7906 if (ret >= 1 && y > 1500 && y < 3000) {
7909 date = g_date_new_dmy (d, m, y);
7910 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
7914 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
7922 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7927 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7929 /* re-route to normal string tag if major brand says so
7930 * or no data atom and compatible brand suggests so */
7931 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
7932 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
7933 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
7940 len = QT_UINT32 (data->data);
7941 type = QT_UINT32 ((guint8 *) data->data + 8);
7942 if (type == 0x00000000 && len >= 18) {
7943 n = QT_UINT16 ((guint8 *) data->data + 16);
7947 genre = gst_tag_id3_genre_get (n - 1);
7948 if (genre != NULL) {
7949 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
7950 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7959 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
7960 guint8 * data, guint32 datasize)
7965 /* make a copy to have \0 at the end */
7966 datacopy = g_strndup ((gchar *) data, datasize);
7968 /* convert the str to double */
7969 if (sscanf (datacopy, "%lf", &value) == 1) {
7970 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
7971 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
7973 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
7981 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
7982 const char *tag_bis, GNode * node)
7991 const gchar *meanstr;
7992 const gchar *namestr;
7994 /* checking the whole ---- atom size for consistency */
7995 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
7996 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8000 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8002 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8006 meansize = QT_UINT32 (mean->data);
8007 if (meansize <= 12) {
8008 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8011 meanstr = ((gchar *) mean->data) + 12;
8013 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8015 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8019 namesize = QT_UINT32 (name->data);
8020 if (namesize <= 12) {
8021 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8024 namestr = ((gchar *) name->data) + 12;
8031 * uint24 - data type
8035 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8037 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8040 datasize = QT_UINT32 (data->data);
8041 if (datasize <= 16) {
8042 GST_WARNING_OBJECT (demux, "Data atom too small");
8045 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8047 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8050 const gchar name[28];
8051 const gchar tag[28];
8054 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8055 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8056 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8057 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8058 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8059 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8060 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8061 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8065 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8066 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8067 switch (gst_tag_get_type (tags[i].tag)) {
8069 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8070 ((guint8 *) data->data) + 16, datasize - 16);
8073 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8082 if (i == G_N_ELEMENTS (tags))
8096 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8097 namestr_dbg = g_strndup (namestr, namesize - 12);
8099 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8100 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8102 g_free (namestr_dbg);
8103 g_free (meanstr_dbg);
8108 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8109 const char *tag, const char *tag_bis, GNode * node);
8112 FOURCC_pcst -> if media is a podcast -> bool
8113 FOURCC_cpil -> if media is part of a compilation -> bool
8114 FOURCC_pgap -> if media is part of a gapless context -> bool
8115 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8121 const gchar *gst_tag;
8122 const gchar *gst_tag_bis;
8123 const GstQTDemuxAddTagFunc func;
8126 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8127 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8128 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8129 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8130 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8131 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8132 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8133 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8134 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8135 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8136 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8137 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8138 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8139 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8140 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8141 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8142 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8143 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8144 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8145 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8146 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8147 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8148 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8149 qtdemux_tag_add_num}, {
8150 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8151 qtdemux_tag_add_num}, {
8152 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8153 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8154 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8155 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8156 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8157 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8158 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8159 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8160 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8161 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8162 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8163 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8164 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8165 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8166 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8167 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8168 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8169 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8170 qtdemux_tag_add_classification}, {
8172 /* This is a special case, some tags are stored in this
8173 * 'reverse dns naming', according to:
8174 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8177 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}
8181 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8193 len = QT_UINT32 (data);
8194 buf = gst_buffer_new_and_alloc (len);
8195 memcpy (GST_BUFFER_DATA (buf), data, len);
8197 /* heuristic to determine style of tag */
8198 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8199 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8201 else if (demux->major_brand == FOURCC_qt__)
8202 style = "quicktime";
8203 /* fall back to assuming iso/3gp tag style */
8207 /* santize the name for the caps. */
8208 for (i = 0; i < 4; i++) {
8209 guint8 d = data[4 + i];
8210 if (g_ascii_isalnum (d))
8211 ndata[i] = g_ascii_tolower (d);
8216 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8217 ndata[0], ndata[1], ndata[2], ndata[3]);
8218 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8220 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
8221 gst_buffer_set_caps (buf, caps);
8222 gst_caps_unref (caps);
8223 g_free (media_type);
8225 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
8226 GST_BUFFER_SIZE (buf), caps);
8228 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8229 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
8230 gst_buffer_unref (buf);
8234 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8242 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8244 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8246 GST_LOG_OBJECT (qtdemux, "no ilst");
8251 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8254 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8255 if (!qtdemux->tag_list)
8256 qtdemux->tag_list = gst_tag_list_new ();
8259 while (i < G_N_ELEMENTS (add_funcs)) {
8260 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8264 len = QT_UINT32 (node->data);
8266 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8267 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8269 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8270 add_funcs[i].gst_tag_bis, node);
8272 g_node_destroy (node);
8278 /* parsed nodes have been removed, pass along remainder as blob */
8279 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8280 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8282 /* parse up XMP_ node if existing */
8283 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8286 GstTagList *taglist;
8288 buf = gst_buffer_new ();
8289 GST_BUFFER_DATA (buf) = ((guint8 *) xmp_->data) + 8;
8290 GST_BUFFER_SIZE (buf) = QT_UINT32 ((guint8 *) xmp_->data) - 8;
8292 taglist = gst_tag_list_from_xmp_buffer (buf);
8293 gst_buffer_unref (buf);
8295 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8297 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8304 GstStructure *structure; /* helper for sort function */
8306 guint min_req_bitrate;
8307 guint min_req_qt_version;
8311 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8313 GstQtReference *ref_a = (GstQtReference *) a;
8314 GstQtReference *ref_b = (GstQtReference *) b;
8316 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8317 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8319 /* known bitrates go before unknown; higher bitrates go first */
8320 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8323 /* sort the redirects and post a message for the application.
8326 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8328 GstQtReference *best;
8331 GValue list_val = { 0, };
8334 g_assert (references != NULL);
8336 references = g_list_sort (references, qtdemux_redirects_sort_func);
8338 best = (GstQtReference *) references->data;
8340 g_value_init (&list_val, GST_TYPE_LIST);
8342 for (l = references; l != NULL; l = l->next) {
8343 GstQtReference *ref = (GstQtReference *) l->data;
8344 GValue struct_val = { 0, };
8346 ref->structure = gst_structure_new ("redirect",
8347 "new-location", G_TYPE_STRING, ref->location, NULL);
8349 if (ref->min_req_bitrate > 0) {
8350 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8351 ref->min_req_bitrate, NULL);
8354 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8355 g_value_set_boxed (&struct_val, ref->structure);
8356 gst_value_list_append_value (&list_val, &struct_val);
8357 g_value_unset (&struct_val);
8358 /* don't free anything here yet, since we need best->structure below */
8361 g_assert (best != NULL);
8362 s = gst_structure_copy (best->structure);
8364 if (g_list_length (references) > 1) {
8365 gst_structure_set_value (s, "locations", &list_val);
8368 g_value_unset (&list_val);
8370 for (l = references; l != NULL; l = l->next) {
8371 GstQtReference *ref = (GstQtReference *) l->data;
8373 gst_structure_free (ref->structure);
8374 g_free (ref->location);
8377 g_list_free (references);
8379 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8380 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8381 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8382 qtdemux->posted_redirect = TRUE;
8385 /* look for redirect nodes, collect all redirect information and
8389 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8391 GNode *rmra, *rmda, *rdrf;
8393 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8395 GList *redirects = NULL;
8397 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8399 GstQtReference ref = { NULL, NULL, 0, 0 };
8402 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8403 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8404 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8405 ref.min_req_bitrate);
8408 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
8409 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
8410 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
8412 #ifndef GST_DISABLE_GST_DEBUG
8413 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
8415 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
8417 GST_LOG_OBJECT (qtdemux,
8418 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
8419 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
8420 bitmask, check_type);
8421 if (package == FOURCC_qtim && check_type == 0) {
8422 ref.min_req_qt_version = version;
8426 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
8431 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
8432 ref_data = (guint8 *) rdrf->data + 20;
8433 if (ref_type == FOURCC_alis) {
8434 guint record_len, record_version, fn_len;
8436 /* MacOSX alias record, google for alias-layout.txt */
8437 record_len = QT_UINT16 (ref_data + 4);
8438 record_version = QT_UINT16 (ref_data + 4 + 2);
8439 fn_len = QT_UINT8 (ref_data + 50);
8440 if (record_len > 50 && record_version == 2 && fn_len > 0) {
8441 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
8443 } else if (ref_type == FOURCC_url_) {
8444 ref.location = g_strdup ((gchar *) ref_data);
8446 GST_DEBUG_OBJECT (qtdemux,
8447 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
8448 GST_FOURCC_ARGS (ref_type));
8450 if (ref.location != NULL) {
8451 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
8452 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
8454 GST_WARNING_OBJECT (qtdemux,
8455 "Failed to extract redirect location from rdrf atom");
8459 /* look for others */
8460 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
8463 if (redirects != NULL) {
8464 qtdemux_process_redirects (qtdemux, redirects);
8471 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
8476 tags = gst_tag_list_new ();
8478 if (qtdemux->major_brand == FOURCC_mjp2)
8479 fmt = "Motion JPEG 2000";
8480 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
8482 else if (qtdemux->major_brand == FOURCC_qt__)
8484 else if (qtdemux->fragmented)
8487 fmt = "ISO MP4/M4A";
8489 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
8490 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
8492 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
8498 /* we have read th complete moov node now.
8499 * This function parses all of the relevant info, creates the traks and
8500 * prepares all data structures for playback
8503 qtdemux_parse_tree (GstQTDemux * qtdemux)
8510 guint64 creation_time;
8511 GstDateTime *datetime = NULL;
8514 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
8516 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
8517 return qtdemux_parse_redirects (qtdemux);
8520 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
8522 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
8523 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
8524 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
8525 } else if (version == 0) {
8526 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
8527 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
8528 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
8530 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
8534 /* Moving qt creation time (secs since 1904) to unix time */
8535 if (creation_time != 0) {
8536 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
8537 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
8538 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
8540 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
8541 "please file a bug at http://bugzilla.gnome.org");
8545 if (!qtdemux->tag_list)
8546 qtdemux->tag_list = gst_tag_list_new ();
8548 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
8549 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
8551 gst_date_time_unref (datetime);
8554 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
8555 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
8557 /* check for fragmented file and get some (default) data */
8558 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
8561 GstByteReader mehd_data;
8563 /* let track parsing or anyone know weird stuff might happen ... */
8564 qtdemux->fragmented = TRUE;
8566 /* compensate for total duration */
8567 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
8569 qtdemux_parse_mehd (qtdemux, &mehd_data);
8572 /* set duration in the segment info */
8573 gst_qtdemux_get_duration (qtdemux, &duration);
8575 gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
8577 /* parse all traks */
8578 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
8580 qtdemux_parse_trak (qtdemux, trak);
8581 /* iterate all siblings */
8582 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
8586 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
8588 qtdemux_parse_udta (qtdemux, udta);
8590 GST_LOG_OBJECT (qtdemux, "No udta node found.");
8593 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
8598 /* taken from ffmpeg */
8600 get_size (guint8 * ptr, guint8 ** end)
8609 len = (len << 7) | (c & 0x7f);
8618 /* this can change the codec originally present in @list */
8620 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
8621 GNode * esds, GstTagList * list)
8623 int len = QT_UINT32 (esds->data);
8624 guint8 *ptr = esds->data;
8625 guint8 *end = ptr + len;
8627 guint8 *data_ptr = NULL;
8629 guint8 object_type_id = 0;
8630 const char *codec_name = NULL;
8631 GstCaps *caps = NULL;
8633 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
8635 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
8638 tag = QT_UINT8 (ptr);
8639 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
8641 len = get_size (ptr, &ptr);
8642 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
8646 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
8647 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
8651 guint max_bitrate, avg_bitrate;
8653 object_type_id = QT_UINT8 (ptr);
8654 max_bitrate = QT_UINT32 (ptr + 5);
8655 avg_bitrate = QT_UINT32 (ptr + 9);
8656 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
8657 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
8658 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
8659 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
8660 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
8661 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
8662 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8663 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
8665 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
8666 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
8673 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
8679 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
8683 GST_ERROR_OBJECT (qtdemux, "parse error");
8688 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
8689 * in use, and should also be used to override some other parameters for some
8691 switch (object_type_id) {
8692 case 0x20: /* MPEG-4 */
8693 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
8694 * profile_and_level_indication */
8695 if (data_ptr != NULL && data_len >= 5 &&
8696 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
8697 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
8698 data_ptr + 4, data_len - 4);
8700 break; /* Nothing special needed here */
8701 case 0x21: /* H.264 */
8702 codec_name = "H.264 / AVC";
8703 caps = gst_caps_new_simple ("video/x-h264",
8704 "stream-format", G_TYPE_STRING, "avc",
8705 "alignment", G_TYPE_STRING, "au", NULL);
8707 case 0x40: /* AAC (any) */
8708 case 0x66: /* AAC Main */
8709 case 0x67: /* AAC LC */
8710 case 0x68: /* AAC SSR */
8711 /* Override channels and rate based on the codec_data, as it's often
8713 /* Only do so for basic setup without HE-AAC extension */
8714 if (data_ptr && data_len == 2) {
8715 guint channels, rateindex, rate;
8717 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
8718 channels = (data_ptr[1] & 0x7f) >> 3;
8719 if (channels > 0 && channels < 7) {
8720 stream->n_channels = channels;
8721 } else if (channels == 7) {
8722 stream->n_channels = 8;
8725 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
8726 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
8728 stream->rate = rate;
8731 /* Set level and profile if possible */
8732 if (data_ptr != NULL && data_len >= 2) {
8733 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
8734 data_ptr, data_len);
8737 case 0x60: /* MPEG-2, various profiles */
8743 codec_name = "MPEG-2 video";
8745 gst_caps_unref (stream->caps);
8746 stream->caps = gst_caps_new_simple ("video/mpeg",
8747 "mpegversion", G_TYPE_INT, 2,
8748 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
8750 case 0x69: /* MP3 has two different values, accept either */
8752 /* change to mpeg1 layer 3 audio */
8753 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
8754 "mpegversion", G_TYPE_INT, 1, NULL);
8755 codec_name = "MPEG-1 layer 3";
8757 case 0x6A: /* MPEG-1 */
8758 codec_name = "MPEG-1 video";
8760 gst_caps_unref (stream->caps);
8761 stream->caps = gst_caps_new_simple ("video/mpeg",
8762 "mpegversion", G_TYPE_INT, 1,
8763 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
8765 case 0x6C: /* MJPEG */
8766 caps = gst_caps_new_simple ("image/jpeg", NULL);
8767 codec_name = "Motion-JPEG";
8769 case 0x6D: /* PNG */
8770 caps = gst_caps_new_simple ("image/png", NULL);
8771 codec_name = "PNG still images";
8773 case 0x6E: /* JPEG2000 */
8774 codec_name = "JPEG-2000";
8775 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
8777 case 0xA4: /* Dirac */
8778 codec_name = "Dirac";
8779 caps = gst_caps_new_simple ("video/x-dirac", NULL);
8781 case 0xA5: /* AC3 */
8782 codec_name = "AC-3 audio";
8783 caps = gst_caps_new_simple ("audio/x-ac3",
8784 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
8786 case 0xE1: /* QCELP */
8787 /* QCELP, the codec_data is a riff tag (little endian) with
8788 * 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). */
8789 caps = gst_caps_new_simple ("audio/qcelp", NULL);
8790 codec_name = "QCELP";
8796 /* If we have a replacement caps, then change our caps for this stream */
8798 gst_caps_unref (stream->caps);
8799 stream->caps = caps;
8802 if (codec_name && list)
8803 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8804 GST_TAG_AUDIO_CODEC, codec_name, NULL);
8806 /* Add the codec_data attribute to caps, if we have it */
8810 buffer = gst_buffer_new_and_alloc (data_len);
8811 memcpy (GST_BUFFER_DATA (buffer), data_ptr, data_len);
8813 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
8814 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
8816 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
8818 gst_buffer_unref (buffer);
8823 #define _codec(name) \
8826 *codec_name = g_strdup (name); \
8831 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
8832 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
8835 const GstStructure *s;
8839 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
8840 _codec ("PNG still images");
8841 caps = gst_caps_new_simple ("image/png", NULL);
8843 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
8844 _codec ("JPEG still images");
8845 caps = gst_caps_new_simple ("image/jpeg", NULL);
8847 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
8848 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
8849 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
8850 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
8851 _codec ("Motion-JPEG");
8852 caps = gst_caps_new_simple ("image/jpeg", NULL);
8854 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
8855 _codec ("Motion-JPEG format B");
8856 caps = gst_caps_new_simple ("video/x-mjpeg-b", NULL);
8858 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
8859 _codec ("JPEG-2000");
8860 /* override to what it should be according to spec, avoid palette_data */
8861 stream->bits_per_sample = 24;
8862 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
8864 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
8865 _codec ("Sorensen video v.3");
8866 caps = gst_caps_new_simple ("video/x-svq",
8867 "svqversion", G_TYPE_INT, 3, NULL);
8869 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
8870 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
8871 _codec ("Sorensen video v.1");
8872 caps = gst_caps_new_simple ("video/x-svq",
8873 "svqversion", G_TYPE_INT, 1, NULL);
8875 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
8879 _codec ("Raw RGB video");
8880 bps = QT_UINT16 (stsd_data + 98);
8881 /* set common stuff */
8882 caps = gst_caps_new_simple ("video/x-raw-rgb",
8883 "endianness", G_TYPE_INT, G_BYTE_ORDER, "depth", G_TYPE_INT, bps,
8888 gst_caps_set_simple (caps,
8889 "bpp", G_TYPE_INT, 16,
8890 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
8891 "red_mask", G_TYPE_INT, 0x7c00,
8892 "green_mask", G_TYPE_INT, 0x03e0,
8893 "blue_mask", G_TYPE_INT, 0x001f, NULL);
8896 gst_caps_set_simple (caps,
8897 "bpp", G_TYPE_INT, 16,
8898 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
8899 "red_mask", G_TYPE_INT, 0xf800,
8900 "green_mask", G_TYPE_INT, 0x07e0,
8901 "blue_mask", G_TYPE_INT, 0x001f, NULL);
8904 gst_caps_set_simple (caps,
8905 "bpp", G_TYPE_INT, 24,
8906 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
8907 "red_mask", G_TYPE_INT, 0xff0000,
8908 "green_mask", G_TYPE_INT, 0x00ff00,
8909 "blue_mask", G_TYPE_INT, 0x0000ff, NULL);
8912 gst_caps_set_simple (caps,
8913 "bpp", G_TYPE_INT, 32,
8914 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
8915 "alpha_mask", G_TYPE_INT, 0xff000000,
8916 "red_mask", G_TYPE_INT, 0x00ff0000,
8917 "green_mask", G_TYPE_INT, 0x0000ff00,
8918 "blue_mask", G_TYPE_INT, 0x000000ff, NULL);
8926 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
8927 _codec ("Raw planar YUV 4:2:0");
8928 caps = gst_caps_new_simple ("video/x-raw-yuv",
8929 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
8932 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
8933 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
8934 _codec ("Raw packed YUV 4:2:2");
8935 caps = gst_caps_new_simple ("video/x-raw-yuv",
8936 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'),
8939 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
8940 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
8941 _codec ("Raw packed YUV 4:2:2");
8942 caps = gst_caps_new_simple ("video/x-raw-yuv",
8943 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'),
8946 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
8947 _codec ("Raw packed YUV 10-bit 4:2:2");
8948 caps = gst_caps_new_simple ("video/x-raw-yuv",
8949 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('v', '2', '1', '0'),
8952 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
8953 _codec ("Raw packed RGB 10-bit 4:4:4");
8954 caps = gst_caps_new_simple ("video/x-raw-rgb",
8955 "endianness", G_TYPE_INT, G_BIG_ENDIAN, "depth", G_TYPE_INT, 30,
8956 "bpp", G_TYPE_INT, 32,
8957 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
8958 "red_mask", G_TYPE_INT, 0x3ff00000,
8959 "green_mask", G_TYPE_INT, 0x000ffc00,
8960 "blue_mask", G_TYPE_INT, 0x000003ff, NULL);
8962 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
8963 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
8964 _codec ("MPEG-1 video");
8965 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
8966 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
8968 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
8969 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
8970 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
8971 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
8972 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
8973 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
8974 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
8975 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
8976 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
8977 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
8978 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
8979 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
8980 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
8981 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
8982 _codec ("MPEG-2 video");
8983 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
8984 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
8986 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
8987 _codec ("GIF still images");
8988 caps = gst_caps_new_simple ("image/gif", NULL);
8990 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
8991 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
8992 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
8993 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
8995 /* ffmpeg uses the height/width props, don't know why */
8996 caps = gst_caps_new_simple ("video/x-h263", NULL);
8998 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
8999 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9000 _codec ("MPEG-4 video");
9001 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9002 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9004 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9005 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9006 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9007 caps = gst_caps_new_simple ("video/x-msmpeg",
9008 "msmpegversion", G_TYPE_INT, 43, NULL);
9010 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9011 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9012 _codec ("3ivX video");
9013 caps = gst_caps_new_simple ("video/x-3ivx", NULL);
9015 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9017 caps = gst_caps_new_simple ("video/x-divx",
9018 "divxversion", G_TYPE_INT, 3, NULL);
9020 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9021 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9023 caps = gst_caps_new_simple ("video/x-divx",
9024 "divxversion", G_TYPE_INT, 4, NULL);
9026 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9028 caps = gst_caps_new_simple ("video/x-divx",
9029 "divxversion", G_TYPE_INT, 5, NULL);
9031 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9032 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9033 _codec ("XVID MPEG-4");
9034 caps = gst_caps_new_simple ("video/x-xvid", NULL);
9037 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9038 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9039 caps = gst_caps_new_simple ("video/mpeg",
9040 "mpegversion", G_TYPE_INT, 4, NULL);
9042 *codec_name = g_strdup ("FFmpeg MPEG-4");
9045 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9047 caps = gst_caps_new_simple ("video/x-cinepak", NULL);
9049 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9050 _codec ("Apple QuickDraw");
9051 caps = gst_caps_new_simple ("video/x-qdrw", NULL);
9053 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9054 _codec ("Apple video");
9055 caps = gst_caps_new_simple ("video/x-apple-video", NULL);
9057 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9058 _codec ("H.264 / AVC");
9059 caps = gst_caps_new_simple ("video/x-h264",
9060 "stream-format", G_TYPE_STRING, "avc",
9061 "alignment", G_TYPE_STRING, "au", NULL);
9063 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9064 _codec ("Run-length encoding");
9065 caps = gst_caps_new_simple ("video/x-rle",
9066 "layout", G_TYPE_STRING, "quicktime", NULL);
9068 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9069 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9070 _codec ("Indeo Video 3");
9071 caps = gst_caps_new_simple ("video/x-indeo",
9072 "indeoversion", G_TYPE_INT, 3, NULL);
9074 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9075 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9076 _codec ("Intel Video 4");
9077 caps = gst_caps_new_simple ("video/x-indeo",
9078 "indeoversion", G_TYPE_INT, 4, NULL);
9080 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9081 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9082 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9083 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9084 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9085 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9086 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9087 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9088 _codec ("DV Video");
9089 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9090 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9092 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9093 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9094 _codec ("DVCPro50 Video");
9095 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9096 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9098 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9099 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9100 _codec ("DVCProHD Video");
9101 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9102 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9104 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9105 _codec ("Apple Graphics (SMC)");
9106 caps = gst_caps_new_simple ("video/x-smc", NULL);
9108 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9110 caps = gst_caps_new_simple ("video/x-vp3", NULL);
9112 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9114 caps = gst_caps_new_simple ("video/x-theora", NULL);
9115 /* theora uses one byte of padding in the data stream because it does not
9116 * allow 0 sized packets while theora does */
9117 stream->padding = 1;
9119 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9121 caps = gst_caps_new_simple ("video/x-dirac", NULL);
9123 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9124 _codec ("TIFF still images");
9125 caps = gst_caps_new_simple ("image/tiff", NULL);
9127 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9128 _codec ("Apple Intermediate Codec");
9129 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9131 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9132 _codec ("AVID DNxHD");
9133 caps = gst_caps_from_string ("video/x-dnxhd");
9135 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9137 caps = gst_caps_from_string ("video/x-vp8");
9140 caps = gst_caps_new_simple ("video/x-wmv",
9141 "wmvversion", G_TYPE_INT, 3,
9142 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'V', 'C', '1'),
9145 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9150 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9151 GST_FOURCC_ARGS (fourcc));
9152 caps = gst_caps_new_simple (s, NULL);
9157 /* enable clipping for raw video streams */
9158 s = gst_caps_get_structure (caps, 0);
9159 name = gst_structure_get_name (s);
9160 if (g_str_has_prefix (name, "video/x-raw-")) {
9161 stream->need_clip = TRUE;
9167 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9168 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9171 const GstStructure *s;
9175 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9178 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9179 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9180 _codec ("Raw 8-bit PCM audio");
9181 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 8,
9182 "depth", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
9184 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9185 endian = G_BIG_ENDIAN;
9187 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9193 endian = G_LITTLE_ENDIAN;
9195 depth = stream->bytes_per_packet * 8;
9196 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9199 caps = gst_caps_new_simple ("audio/x-raw-int",
9200 "width", G_TYPE_INT, depth, "depth", G_TYPE_INT, depth,
9201 "endianness", G_TYPE_INT, endian,
9202 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
9205 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9206 _codec ("Raw 64-bit floating-point audio");
9207 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 64,
9208 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
9210 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9211 _codec ("Raw 32-bit floating-point audio");
9212 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 32,
9213 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
9216 _codec ("Raw 24-bit PCM audio");
9217 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9219 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 24,
9220 "depth", G_TYPE_INT, 24,
9221 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9222 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
9224 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9225 _codec ("Raw 32-bit PCM audio");
9226 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 32,
9227 "depth", G_TYPE_INT, 32,
9228 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9229 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
9231 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9232 _codec ("Mu-law audio");
9233 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
9235 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9236 _codec ("A-law audio");
9237 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
9241 _codec ("Microsoft ADPCM");
9242 /* Microsoft ADPCM-ACM code 2 */
9243 caps = gst_caps_new_simple ("audio/x-adpcm",
9244 "layout", G_TYPE_STRING, "microsoft", NULL);
9248 _codec ("DVI/IMA ADPCM");
9249 caps = gst_caps_new_simple ("audio/x-adpcm",
9250 "layout", G_TYPE_STRING, "dvi", NULL);
9254 _codec ("DVI/Intel IMA ADPCM");
9255 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9256 caps = gst_caps_new_simple ("audio/x-adpcm",
9257 "layout", G_TYPE_STRING, "quicktime", NULL);
9261 /* MPEG layer 3, CBR only (pre QT4.1) */
9262 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9263 _codec ("MPEG-1 layer 3");
9264 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9265 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9266 "mpegversion", G_TYPE_INT, 1, NULL);
9269 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9270 _codec ("EAC-3 audio");
9271 caps = gst_caps_new_simple ("audio/x-eac3",
9272 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9273 stream->sampled = TRUE;
9275 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9276 _codec ("AC-3 audio");
9277 caps = gst_caps_new_simple ("audio/x-ac3",
9278 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9279 stream->sampled = TRUE;
9281 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9283 caps = gst_caps_new_simple ("audio/x-mace",
9284 "maceversion", G_TYPE_INT, 3, NULL);
9286 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9288 caps = gst_caps_new_simple ("audio/x-mace",
9289 "maceversion", G_TYPE_INT, 6, NULL);
9291 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9293 caps = gst_caps_new_simple ("application/ogg", NULL);
9295 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9296 _codec ("DV audio");
9297 caps = gst_caps_new_simple ("audio/x-dv", NULL);
9299 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9300 _codec ("MPEG-4 AAC audio");
9301 caps = gst_caps_new_simple ("audio/mpeg",
9302 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9303 "stream-format", G_TYPE_STRING, "raw", NULL);
9305 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9306 _codec ("QDesign Music");
9307 caps = gst_caps_new_simple ("audio/x-qdm", NULL);
9309 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9310 _codec ("QDesign Music v.2");
9311 /* FIXME: QDesign music version 2 (no constant) */
9313 caps = gst_caps_new_simple ("audio/x-qdm2",
9314 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9315 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9316 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9318 caps = gst_caps_new_simple ("audio/x-qdm2", NULL);
9321 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9322 _codec ("GSM audio");
9323 caps = gst_caps_new_simple ("audio/x-gsm", NULL);
9325 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9326 _codec ("AMR audio");
9327 caps = gst_caps_new_simple ("audio/AMR", NULL);
9329 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9330 _codec ("AMR-WB audio");
9331 caps = gst_caps_new_simple ("audio/AMR-WB", NULL);
9333 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9334 _codec ("Quicktime IMA ADPCM");
9335 caps = gst_caps_new_simple ("audio/x-adpcm",
9336 "layout", G_TYPE_STRING, "quicktime", NULL);
9338 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9339 _codec ("Apple lossless audio");
9340 caps = gst_caps_new_simple ("audio/x-alac", NULL);
9342 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9343 _codec ("QualComm PureVoice");
9344 caps = gst_caps_from_string ("audio/qcelp");
9348 caps = gst_caps_new_simple ("audio/x-wma", NULL);
9350 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
9356 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9357 GST_FOURCC_ARGS (fourcc));
9358 caps = gst_caps_new_simple (s, NULL);
9363 /* enable clipping for raw audio streams */
9364 s = gst_caps_get_structure (caps, 0);
9365 name = gst_structure_get_name (s);
9366 if (g_str_has_prefix (name, "audio/x-raw-")) {
9367 stream->need_clip = TRUE;
9373 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9374 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9378 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9381 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
9382 _codec ("DVD subtitle");
9383 caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
9385 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
9386 _codec ("Quicktime timed text");
9388 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
9389 _codec ("3GPP timed text");
9391 caps = gst_caps_new_simple ("text/plain", NULL);
9392 /* actual text piece needs to be extracted */
9393 stream->need_process = TRUE;
9399 s = g_strdup_printf ("text/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9400 GST_FOURCC_ARGS (fourcc));
9401 caps = gst_caps_new_simple (s, NULL);