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) {
4144 /* the mdat was before the header */
4145 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4146 demux->n_streams, demux->mdatbuffer);
4147 /* restore our adapter/offset view of things with upstream;
4148 * put preceding buffered data ahead of current moov data.
4149 * This should also handle evil mdat, moov, mdat cases and alike */
4150 buf = gst_adapter_take_buffer (demux->adapter,
4151 gst_adapter_available (demux->adapter));
4152 gst_adapter_clear (demux->adapter);
4153 demux->mdatbuffer = NULL;
4154 demux->offset = demux->mdatoffset;
4155 demux->neededbytes = next_entry_size (demux);
4156 demux->state = QTDEMUX_STATE_MOVIE;
4157 demux->mdatleft = gst_adapter_available (demux->adapter);
4159 /* Only post, event on pads is done after newsegment */
4160 qtdemux_post_global_tags (demux);
4163 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4164 gst_adapter_flush (demux->adapter, demux->neededbytes);
4166 if (demux->got_moov && demux->first_mdat != -1) {
4169 /* we need to seek back */
4170 res = qtdemux_seek_offset (demux, demux->first_mdat);
4172 demux->offset = demux->first_mdat;
4174 GST_DEBUG_OBJECT (demux, "Seek back failed");
4177 demux->offset += demux->neededbytes;
4179 demux->neededbytes = 16;
4180 demux->state = QTDEMUX_STATE_INITIAL;
4185 case QTDEMUX_STATE_BUFFER_MDAT:{
4188 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4190 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4191 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4192 GST_FOURCC_ARGS (QT_FOURCC (GST_BUFFER_DATA (buf) + 4)));
4193 if (demux->mdatbuffer)
4194 demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
4196 demux->mdatbuffer = buf;
4197 demux->offset += demux->neededbytes;
4198 demux->neededbytes = 16;
4199 demux->state = QTDEMUX_STATE_INITIAL;
4200 gst_qtdemux_post_progress (demux, 1, 1);
4204 case QTDEMUX_STATE_MOVIE:{
4206 QtDemuxStream *stream = NULL;
4207 QtDemuxSample *sample;
4209 guint64 timestamp, duration, position;
4212 GST_DEBUG_OBJECT (demux,
4213 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4215 if (demux->fragmented) {
4216 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4218 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4219 /* if needed data starts within this atom,
4220 * then it should not exceed this atom */
4221 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4222 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4223 (_("This file is invalid and cannot be played.")),
4224 ("sample data crosses atom boundary"));
4225 ret = GST_FLOW_ERROR;
4228 demux->mdatleft -= demux->neededbytes;
4230 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4231 /* so we are dropping more than left in this atom */
4232 demux->todrop -= demux->mdatleft;
4233 demux->neededbytes -= demux->mdatleft;
4234 demux->mdatleft = 0;
4235 /* need to resume atom parsing so we do not miss any other pieces */
4236 demux->state = QTDEMUX_STATE_INITIAL;
4237 demux->neededbytes = 16;
4242 if (demux->todrop) {
4243 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4244 gst_adapter_flush (demux->adapter, demux->todrop);
4245 demux->neededbytes -= demux->todrop;
4246 demux->offset += demux->todrop;
4250 /* initial newsegment sent here after having added pads,
4251 * possible others in sink_event */
4252 if (G_UNLIKELY (demux->pending_newsegment)) {
4253 gst_qtdemux_push_event (demux, demux->pending_newsegment);
4254 demux->pending_newsegment = NULL;
4255 /* clear to send tags on all streams */
4256 for (i = 0; i < demux->n_streams; i++) {
4257 gst_qtdemux_push_tags (demux, demux->streams[i]);
4261 /* Figure out which stream this is packet belongs to */
4262 for (i = 0; i < demux->n_streams; i++) {
4263 stream = demux->streams[i];
4264 if (stream->sample_index >= stream->n_samples)
4266 GST_LOG_OBJECT (demux,
4267 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4268 " / size:%d)", i, stream->sample_index,
4269 stream->samples[stream->sample_index].offset,
4270 stream->samples[stream->sample_index].size);
4272 if (stream->samples[stream->sample_index].offset == demux->offset)
4276 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4277 goto unknown_stream;
4279 /* Put data in a buffer, set timestamps, caps, ... */
4280 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4281 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4282 GST_FOURCC_ARGS (stream->fourcc));
4284 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4286 sample = &stream->samples[stream->sample_index];
4288 position = QTSAMPLE_DTS (stream, sample);
4289 timestamp = QTSAMPLE_PTS (stream, sample);
4290 duration = QTSAMPLE_DUR_DTS (stream, sample, position);
4291 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4293 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4294 timestamp, duration, keyframe, position, demux->offset);
4297 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4299 stream->sample_index++;
4301 /* update current offset and figure out size of next buffer */
4302 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4303 demux->offset, demux->neededbytes);
4304 demux->offset += demux->neededbytes;
4305 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4308 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4309 if (demux->fragmented) {
4310 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4311 /* there may be more to follow, only finish this atom */
4312 demux->todrop = demux->mdatleft;
4313 demux->neededbytes = demux->todrop;
4325 /* when buffering movie data, at least show user something is happening */
4326 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4327 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4328 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4329 demux->neededbytes);
4332 gst_object_unref (demux);
4339 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4340 ret = GST_FLOW_ERROR;
4345 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4346 ret = GST_FLOW_UNEXPECTED;
4351 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4352 (NULL), ("qtdemuxer invalid state %d", demux->state));
4353 ret = GST_FLOW_ERROR;
4358 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4359 (NULL), ("no 'moov' atom within the first 10 MB"));
4360 ret = GST_FLOW_ERROR;
4366 qtdemux_sink_activate (GstPad * sinkpad)
4368 if (gst_pad_check_pull_range (sinkpad))
4369 return gst_pad_activate_pull (sinkpad, TRUE);
4371 return gst_pad_activate_push (sinkpad, TRUE);
4375 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
4377 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
4380 demux->pullbased = TRUE;
4381 demux->segment_running = TRUE;
4382 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4385 demux->segment_running = FALSE;
4386 return gst_pad_stop_task (sinkpad);
4391 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
4393 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
4395 demux->pullbased = FALSE;
4402 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4404 return g_malloc (items * size);
4408 qtdemux_zfree (void *opaque, void *addr)
4414 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4420 z = g_new0 (z_stream, 1);
4421 z->zalloc = qtdemux_zalloc;
4422 z->zfree = qtdemux_zfree;
4425 z->next_in = z_buffer;
4426 z->avail_in = z_length;
4428 buffer = (guint8 *) g_malloc (length);
4429 ret = inflateInit (z);
4430 while (z->avail_in > 0) {
4431 if (z->avail_out == 0) {
4433 buffer = (guint8 *) g_realloc (buffer, length);
4434 z->next_out = buffer + z->total_out;
4435 z->avail_out = 1024;
4437 ret = inflate (z, Z_SYNC_FLUSH);
4441 if (ret != Z_STREAM_END) {
4442 g_warning ("inflate() returned %d", ret);
4448 #endif /* HAVE_ZLIB */
4451 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4455 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4457 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4458 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4460 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4466 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4467 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4468 if (dcom == NULL || cmvd == NULL)
4469 goto invalid_compression;
4471 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4474 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4475 guint uncompressed_length;
4476 guint compressed_length;
4479 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4480 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4481 GST_LOG ("length = %u", uncompressed_length);
4484 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4485 compressed_length, uncompressed_length);
4487 qtdemux->moov_node_compressed = qtdemux->moov_node;
4488 qtdemux->moov_node = g_node_new (buf);
4490 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4491 uncompressed_length);
4494 #endif /* HAVE_ZLIB */
4496 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4497 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
4504 invalid_compression:
4506 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
4512 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
4515 while (G_UNLIKELY (buf < end)) {
4519 if (G_UNLIKELY (buf + 4 > end)) {
4520 GST_LOG_OBJECT (qtdemux, "buffer overrun");
4523 len = QT_UINT32 (buf);
4524 if (G_UNLIKELY (len == 0)) {
4525 GST_LOG_OBJECT (qtdemux, "empty container");
4528 if (G_UNLIKELY (len < 8)) {
4529 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
4532 if (G_UNLIKELY (len > (end - buf))) {
4533 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
4534 (gint) (end - buf));
4538 child = g_node_new ((guint8 *) buf);
4539 g_node_append (node, child);
4540 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
4541 qtdemux_parse_node (qtdemux, child, buf, len);
4549 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
4552 int len = QT_UINT32 (xdxt->data);
4553 guint8 *buf = xdxt->data;
4554 guint8 *end = buf + len;
4557 /* skip size and type */
4565 size = QT_UINT32 (buf);
4566 type = QT_FOURCC (buf + 4);
4568 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
4570 if (buf + size > end || size <= 0)
4576 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
4577 GST_FOURCC_ARGS (type));
4581 buffer = gst_buffer_new_and_alloc (size);
4582 memcpy (GST_BUFFER_DATA (buffer), buf, size);
4583 stream->buffers = g_slist_append (stream->buffers, buffer);
4584 GST_LOG_OBJECT (qtdemux, "parsing theora header");
4587 buffer = gst_buffer_new_and_alloc (size);
4588 memcpy (GST_BUFFER_DATA (buffer), buf, size);
4589 stream->buffers = g_slist_append (stream->buffers, buffer);
4590 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
4593 buffer = gst_buffer_new_and_alloc (size);
4594 memcpy (GST_BUFFER_DATA (buffer), buf, size);
4595 stream->buffers = g_slist_append (stream->buffers, buffer);
4596 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
4599 GST_WARNING_OBJECT (qtdemux,
4600 "unknown theora cookie %" GST_FOURCC_FORMAT,
4601 GST_FOURCC_ARGS (type));
4610 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
4614 guint32 node_length = 0;
4615 const QtNodeType *type;
4618 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
4620 if (G_UNLIKELY (length < 8))
4621 goto not_enough_data;
4623 node_length = QT_UINT32 (buffer);
4624 fourcc = QT_FOURCC (buffer + 4);
4626 /* ignore empty nodes */
4627 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
4630 type = qtdemux_type_get (fourcc);
4632 end = buffer + length;
4634 GST_LOG_OBJECT (qtdemux,
4635 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
4636 GST_FOURCC_ARGS (fourcc), node_length, type->name);
4638 if (node_length > length)
4639 goto broken_atom_size;
4641 if (type->flags & QT_FLAG_CONTAINER) {
4642 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
4647 if (node_length < 20) {
4648 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
4651 GST_DEBUG_OBJECT (qtdemux,
4652 "parsing stsd (sample table, sample description) atom");
4653 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
4663 /* also read alac (or whatever) in stead of mp4a in the following,
4664 * since a similar layout is used in other cases as well */
4665 if (fourcc == FOURCC_mp4a)
4670 /* There are two things we might encounter here: a true mp4a atom, and
4671 an mp4a entry in an stsd atom. The latter is what we're interested
4672 in, and it looks like an atom, but isn't really one. The true mp4a
4673 atom is short, so we detect it based on length here. */
4674 if (length < min_size) {
4675 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
4676 GST_FOURCC_ARGS (fourcc));
4680 /* 'version' here is the sound sample description version. Types 0 and
4681 1 are documented in the QTFF reference, but type 2 is not: it's
4682 described in Apple header files instead (struct SoundDescriptionV2
4684 version = QT_UINT16 (buffer + 16);
4686 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
4687 GST_FOURCC_ARGS (fourcc), version);
4689 /* parse any esds descriptors */
4701 GST_WARNING_OBJECT (qtdemux,
4702 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
4703 GST_FOURCC_ARGS (fourcc), version);
4708 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4720 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
4721 GST_FOURCC_ARGS (fourcc));
4722 version = QT_UINT32 (buffer + 16);
4723 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
4724 if (1 || version == 0x00000000) {
4725 buf = buffer + 0x32;
4727 /* FIXME Quicktime uses PASCAL string while
4728 * the iso format uses C strings. Check the file
4729 * type before attempting to parse the string here. */
4730 tlen = QT_UINT8 (buf);
4731 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
4733 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
4734 /* the string has a reserved space of 32 bytes so skip
4735 * the remaining 31 */
4737 buf += 4; /* and 4 bytes reserved */
4739 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
4741 qtdemux_parse_container (qtdemux, node, buf, end);
4747 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
4748 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
4753 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
4758 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
4759 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
4767 version = QT_UINT32 (buffer + 12);
4768 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
4775 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
4780 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4785 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
4789 if (!strcmp (type->name, "unknown"))
4790 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
4794 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
4795 GST_FOURCC_ARGS (fourcc));
4801 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4802 (_("This file is corrupt and cannot be played.")),
4803 ("Not enough data for an atom header, got only %u bytes", length));
4808 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4809 (_("This file is corrupt and cannot be played.")),
4810 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
4811 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
4818 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
4822 guint32 child_fourcc;
4824 for (child = g_node_first_child (node); child;
4825 child = g_node_next_sibling (child)) {
4826 buffer = (guint8 *) child->data;
4828 child_fourcc = QT_FOURCC (buffer + 4);
4830 if (G_UNLIKELY (child_fourcc == fourcc)) {
4838 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
4839 GstByteReader * parser)
4843 guint32 child_fourcc, child_len;
4845 for (child = g_node_first_child (node); child;
4846 child = g_node_next_sibling (child)) {
4847 buffer = (guint8 *) child->data;
4849 child_len = QT_UINT32 (buffer);
4850 child_fourcc = QT_FOURCC (buffer + 4);
4852 if (G_UNLIKELY (child_fourcc == fourcc)) {
4853 if (G_UNLIKELY (child_len < (4 + 4)))
4855 /* FIXME: must verify if atom length < parent atom length */
4856 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4864 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
4865 GstByteReader * parser)
4869 guint32 child_fourcc, child_len;
4871 for (child = g_node_next_sibling (node); child;
4872 child = g_node_next_sibling (child)) {
4873 buffer = (guint8 *) child->data;
4875 child_fourcc = QT_FOURCC (buffer + 4);
4877 if (child_fourcc == fourcc) {
4879 child_len = QT_UINT32 (buffer);
4880 if (G_UNLIKELY (child_len < (4 + 4)))
4882 /* FIXME: must verify if atom length < parent atom length */
4883 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4892 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
4894 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
4898 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
4899 QtDemuxStream * stream, GstTagList * list)
4901 /* consistent default for push based mode */
4902 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
4903 gst_segment_set_newsegment (&stream->segment, FALSE, 1.0, GST_FORMAT_TIME,
4904 0, GST_CLOCK_TIME_NONE, 0);
4906 if (stream->subtype == FOURCC_vide) {
4907 gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
4910 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
4913 /* fps is calculated base on the duration of the first frames since
4914 * qt does not have a fixed framerate. */
4915 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
4920 stream->fps_n = stream->timescale;
4921 if (stream->min_duration == 0)
4924 stream->fps_d = stream->min_duration;
4929 gint depth, palette_count;
4930 const guint32 *palette_data = NULL;
4932 gst_caps_set_simple (stream->caps,
4933 "width", G_TYPE_INT, stream->width,
4934 "height", G_TYPE_INT, stream->height,
4935 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
4937 /* calculate pixel-aspect-ratio using display width and height */
4938 GST_DEBUG_OBJECT (qtdemux,
4939 "video size %dx%d, target display size %dx%d", stream->width,
4940 stream->height, stream->display_width, stream->display_height);
4942 if (stream->display_width > 0 && stream->display_height > 0 &&
4943 stream->width > 0 && stream->height > 0) {
4946 /* calculate the pixel aspect ratio using the display and pixel w/h */
4947 n = stream->display_width * stream->height;
4948 d = stream->display_height * stream->width;
4951 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
4952 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
4953 GST_TYPE_FRACTION, n, d, NULL);
4956 /* qt file might have pasp atom */
4957 if (stream->par_w > 0 && stream->par_h > 0) {
4958 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
4959 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
4960 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
4963 depth = stream->bits_per_sample;
4965 /* more than 32 bits means grayscale */
4966 gray = (depth > 32);
4967 /* low 32 bits specify the depth */
4970 /* different number of palette entries is determined by depth. */
4972 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
4973 palette_count = (1 << depth);
4975 switch (palette_count) {
4979 palette_data = ff_qt_default_palette_2;
4982 palette_data = ff_qt_default_palette_4;
4986 palette_data = ff_qt_grayscale_palette_16;
4988 palette_data = ff_qt_default_palette_16;
4992 palette_data = ff_qt_grayscale_palette_256;
4994 palette_data = ff_qt_default_palette_256;
4997 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4998 (_("The video in this file might not play correctly.")),
4999 ("unsupported palette depth %d", depth));
5005 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5006 * don't free any of the buffer data. */
5007 palette = gst_buffer_new ();
5008 GST_BUFFER_FLAG_SET (palette, GST_BUFFER_FLAG_READONLY);
5009 GST_BUFFER_DATA (palette) = (guint8 *) palette_data;
5010 GST_BUFFER_SIZE (palette) = sizeof (guint32) * palette_count;
5012 gst_caps_set_simple (stream->caps, "palette_data",
5013 GST_TYPE_BUFFER, palette, NULL);
5014 gst_buffer_unref (palette);
5015 } else if (palette_count != 0) {
5016 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5017 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5019 gst_object_unref (stream->pad);
5023 qtdemux->n_video_streams++;
5024 } else if (stream->subtype == FOURCC_soun) {
5025 gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
5028 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5031 gst_caps_set_simple (stream->caps,
5032 "rate", G_TYPE_INT, (int) stream->rate,
5033 "channels", G_TYPE_INT, stream->n_channels, NULL);
5035 qtdemux->n_audio_streams++;
5036 } else if (stream->subtype == FOURCC_strm) {
5037 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5038 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
5039 gchar *name = g_strdup_printf ("subtitle_%02d", qtdemux->n_sub_streams);
5042 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5044 qtdemux->n_sub_streams++;
5046 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5051 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5053 gst_pad_use_fixed_caps (stream->pad);
5054 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5055 gst_pad_set_query_type_function (stream->pad,
5056 gst_qtdemux_get_src_query_types);
5057 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5059 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5060 gst_pad_set_caps (stream->pad, stream->caps);
5062 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5063 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5064 gst_pad_set_active (stream->pad, TRUE);
5065 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5066 if (stream->pending_tags)
5067 gst_tag_list_free (stream->pending_tags);
5068 stream->pending_tags = list;
5070 /* post now, send event on pad later */
5071 GST_DEBUG_OBJECT (qtdemux, "Posting tags %" GST_PTR_FORMAT, list);
5072 gst_element_post_message (GST_ELEMENT (qtdemux),
5073 gst_message_new_tag_full (GST_OBJECT (qtdemux), stream->pad,
5074 gst_tag_list_copy (list)));
5076 /* global tags go on each pad anyway */
5077 stream->send_global_tags = TRUE;
5083 /* find next atom with @fourcc starting at @offset */
5084 static GstFlowReturn
5085 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5086 guint64 * length, guint32 fourcc)
5092 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5093 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5096 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5097 if (G_UNLIKELY (ret != GST_FLOW_OK))
5099 if (G_LIKELY (GST_BUFFER_SIZE (buf) != 16)) {
5101 ret = GST_FLOW_UNEXPECTED;
5102 gst_buffer_unref (buf);
5105 extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf), 16, length,
5107 gst_buffer_unref (buf);
5109 if (G_UNLIKELY (*length == 0)) {
5110 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5111 ret = GST_FLOW_ERROR;
5115 if (lfourcc == fourcc) {
5116 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5120 GST_LOG_OBJECT (qtdemux,
5121 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5122 GST_FOURCC_ARGS (fourcc), *offset);
5131 /* might simply have had last one */
5132 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5137 /* should only do something in pull mode */
5138 /* call with OBJECT lock */
5139 static GstFlowReturn
5140 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5142 guint64 length, offset;
5143 GstBuffer *buf = NULL;
5144 GstFlowReturn ret = GST_FLOW_OK;
5145 GstFlowReturn res = TRUE;
5147 offset = qtdemux->moof_offset;
5148 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5151 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5152 return GST_FLOW_UNEXPECTED;
5155 /* best not do pull etc with lock held */
5156 GST_OBJECT_UNLOCK (qtdemux);
5158 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5159 if (ret != GST_FLOW_OK)
5162 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5163 if (G_UNLIKELY (ret != GST_FLOW_OK))
5165 if (!qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf),
5166 GST_BUFFER_SIZE (buf), offset, NULL)) {
5167 gst_buffer_unref (buf);
5172 gst_buffer_unref (buf);
5176 /* look for next moof */
5177 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5178 if (G_UNLIKELY (ret != GST_FLOW_OK))
5182 GST_OBJECT_LOCK (qtdemux);
5184 qtdemux->moof_offset = offset;
5190 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5192 res = GST_FLOW_ERROR;
5197 /* maybe upstream temporarily flushing */
5198 if (ret != GST_FLOW_WRONG_STATE) {
5199 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5202 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5203 /* resume at current position next time */
5210 /* initialise bytereaders for stbl sub-atoms */
5212 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5214 stream->stbl_index = -1; /* no samples have yet been parsed */
5216 /* time-to-sample atom */
5217 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5220 /* copy atom data into a new buffer for later use */
5221 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5223 /* skip version + flags */
5224 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5225 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5227 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5229 /* make sure there's enough data */
5230 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 2 * 4))
5233 /* sync sample atom */
5234 stream->stps_present = FALSE;
5235 if ((stream->stss_present =
5236 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5237 &stream->stss) ? TRUE : FALSE) == TRUE) {
5238 /* copy atom data into a new buffer for later use */
5239 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5241 /* skip version + flags */
5242 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5243 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5246 if (stream->n_sample_syncs) {
5247 /* make sure there's enough data */
5248 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5252 /* partial sync sample atom */
5253 if ((stream->stps_present =
5254 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5255 &stream->stps) ? TRUE : FALSE) == TRUE) {
5256 /* copy atom data into a new buffer for later use */
5257 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5259 /* skip version + flags */
5260 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5261 !gst_byte_reader_get_uint32_be (&stream->stps,
5262 &stream->n_sample_partial_syncs))
5265 /* if there are no entries, the stss table contains the real
5267 if (stream->n_sample_partial_syncs) {
5268 /* make sure there's enough data */
5269 if (!qt_atom_parser_has_chunks (&stream->stps,
5270 stream->n_sample_partial_syncs, 4))
5277 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5280 /* copy atom data into a new buffer for later use */
5281 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5283 /* skip version + flags */
5284 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5285 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5288 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5291 if (!stream->n_samples)
5294 /* sample-to-chunk atom */
5295 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5298 /* copy atom data into a new buffer for later use */
5299 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5301 /* skip version + flags */
5302 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5303 !gst_byte_reader_get_uint32_be (&stream->stsc,
5304 &stream->n_samples_per_chunk))
5307 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5308 stream->n_samples_per_chunk);
5310 /* make sure there's enough data */
5311 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5317 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5318 stream->co_size = sizeof (guint32);
5319 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5321 stream->co_size = sizeof (guint64);
5325 /* copy atom data into a new buffer for later use */
5326 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5328 /* skip version + flags */
5329 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5332 /* chunks_are_chunks == 0 means treat chunks as samples */
5333 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5334 if (stream->chunks_are_chunks) {
5335 /* skip number of entries */
5336 if (!gst_byte_reader_skip (&stream->stco, 4))
5339 /* make sure there are enough data in the stsz atom */
5340 if (!stream->sample_size) {
5341 /* different sizes for each sample */
5342 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5346 /* treat chunks as samples */
5347 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5351 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5352 stream->n_samples, (guint) sizeof (QtDemuxSample),
5353 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5355 if (stream->n_samples >=
5356 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5357 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5358 "be larger than %uMB (broken file?)", stream->n_samples,
5359 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5363 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5364 if (!stream->samples) {
5365 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5371 /* composition time-to-sample */
5372 if ((stream->ctts_present =
5373 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5374 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5375 /* copy atom data into a new buffer for later use */
5376 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5378 /* skip version + flags */
5379 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5380 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5381 &stream->n_composition_times))
5384 /* make sure there's enough data */
5385 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5394 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5395 (_("This file is corrupt and cannot be played.")), (NULL));
5400 gst_qtdemux_stbl_free (stream);
5401 if (!qtdemux->fragmented) {
5402 /* not quite good */
5403 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5406 /* may pick up samples elsewhere */
5412 /* collect samples from the next sample to be parsed up to sample @n for @stream
5413 * by reading the info from @stbl
5415 * This code can be executed from both the streaming thread and the seeking
5416 * thread so it takes the object lock to protect itself
5419 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
5422 QtDemuxSample *samples, *first, *cur, *last;
5423 guint32 n_samples_per_chunk;
5426 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
5427 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
5428 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
5430 n_samples = stream->n_samples;
5433 goto out_of_samples;
5435 GST_OBJECT_LOCK (qtdemux);
5436 if (n <= stream->stbl_index)
5437 goto already_parsed;
5439 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
5441 if (!stream->stsz.data) {
5442 /* so we already parsed and passed all the moov samples;
5443 * onto fragmented ones */
5444 g_assert (qtdemux->fragmented);
5448 /* pointer to the sample table */
5449 samples = stream->samples;
5451 /* starts from -1, moves to the next sample index to parse */
5452 stream->stbl_index++;
5454 /* keep track of the first and last sample to fill */
5455 first = &samples[stream->stbl_index];
5458 if (stream->chunks_are_chunks) {
5459 /* set the sample sizes */
5460 if (stream->sample_size == 0) {
5461 /* different sizes for each sample */
5462 for (cur = first; cur <= last; cur++) {
5463 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
5464 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
5465 (guint) (cur - samples), cur->size);
5468 /* samples have the same size */
5469 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
5470 for (cur = first; cur <= last; cur++)
5471 cur->size = stream->sample_size;
5475 n_samples_per_chunk = stream->n_samples_per_chunk;
5478 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
5481 if (stream->stsc_chunk_index >= stream->last_chunk
5482 || stream->stsc_chunk_index < stream->first_chunk) {
5483 stream->first_chunk =
5484 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5485 stream->samples_per_chunk =
5486 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5487 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
5489 /* chunk numbers are counted from 1 it seems */
5490 if (G_UNLIKELY (stream->first_chunk == 0))
5493 --stream->first_chunk;
5495 /* the last chunk of each entry is calculated by taking the first chunk
5496 * of the next entry; except if there is no next, where we fake it with
5498 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
5499 stream->last_chunk = G_MAXUINT32;
5501 stream->last_chunk =
5502 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
5503 if (G_UNLIKELY (stream->last_chunk == 0))
5506 --stream->last_chunk;
5509 GST_LOG_OBJECT (qtdemux,
5510 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
5511 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
5513 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
5516 if (stream->last_chunk != G_MAXUINT32) {
5517 if (!qt_atom_parser_peek_sub (&stream->stco,
5518 stream->first_chunk * stream->co_size,
5519 (stream->last_chunk - stream->first_chunk) * stream->co_size,
5524 stream->co_chunk = stream->stco;
5525 if (!gst_byte_reader_skip (&stream->co_chunk,
5526 stream->first_chunk * stream->co_size))
5530 stream->stsc_chunk_index = stream->first_chunk;
5533 last_chunk = stream->last_chunk;
5535 if (stream->chunks_are_chunks) {
5536 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5537 guint32 samples_per_chunk;
5538 guint64 chunk_offset;
5540 if (!stream->stsc_sample_index
5541 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
5542 &stream->chunk_offset))
5545 samples_per_chunk = stream->samples_per_chunk;
5546 chunk_offset = stream->chunk_offset;
5548 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
5549 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
5550 G_GUINT64_FORMAT, (guint) (cur - samples), stream->chunk_offset);
5552 cur->offset = chunk_offset;
5553 chunk_offset += cur->size;
5556 if (G_UNLIKELY (cur > last)) {
5558 stream->stsc_sample_index = k + 1;
5559 stream->chunk_offset = chunk_offset;
5560 stream->stsc_chunk_index = j;
5564 stream->stsc_sample_index = 0;
5566 stream->stsc_chunk_index = j;
5568 cur = &samples[stream->stsc_chunk_index];
5570 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5573 stream->stsc_chunk_index = j;
5578 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
5581 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
5582 "%" G_GUINT64_FORMAT, j, cur->offset);
5584 if (stream->samples_per_frame * stream->bytes_per_frame) {
5586 (stream->samples_per_chunk * stream->n_channels) /
5587 stream->samples_per_frame * stream->bytes_per_frame;
5589 cur->size = stream->samples_per_chunk;
5592 GST_DEBUG_OBJECT (qtdemux,
5593 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
5594 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
5595 GST_SECOND, stream->timescale)), cur->size);
5597 cur->timestamp = stream->stco_sample_index;
5598 cur->duration = stream->samples_per_chunk;
5599 cur->keyframe = TRUE;
5602 stream->stco_sample_index += stream->samples_per_chunk;
5604 stream->stsc_chunk_index = j;
5606 stream->stsc_index++;
5609 if (!stream->chunks_are_chunks)
5613 guint32 n_sample_times;
5615 n_sample_times = stream->n_sample_times;
5618 for (i = stream->stts_index; i < n_sample_times; i++) {
5619 guint32 stts_samples;
5620 guint32 stts_duration;
5623 if (stream->stts_sample_index >= stream->stts_samples
5624 || !stream->stts_sample_index) {
5626 stream->stts_samples =
5627 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5628 stream->stts_duration =
5629 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5631 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
5632 i, stream->stts_samples, stream->stts_duration);
5634 stream->stts_sample_index = 0;
5637 stts_samples = stream->stts_samples;
5638 stts_duration = stream->stts_duration;
5639 stts_time = stream->stts_time;
5641 for (j = stream->stts_sample_index; j < stts_samples; j++) {
5642 GST_DEBUG_OBJECT (qtdemux,
5643 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
5644 (guint) (cur - samples), j,
5645 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
5646 stream->timescale)));
5648 cur->timestamp = stts_time;
5649 cur->duration = stts_duration;
5651 stts_time += stts_duration;
5654 if (G_UNLIKELY (cur > last)) {
5656 stream->stts_time = stts_time;
5657 stream->stts_sample_index = j + 1;
5661 stream->stts_sample_index = 0;
5662 stream->stts_time = stts_time;
5663 stream->stts_index++;
5665 /* fill up empty timestamps with the last timestamp, this can happen when
5666 * the last samples do not decode and so we don't have timestamps for them.
5667 * We however look at the last timestamp to estimate the track length so we
5668 * need something in here. */
5669 for (; cur < last; cur++) {
5670 GST_DEBUG_OBJECT (qtdemux,
5671 "fill sample %d: timestamp %" GST_TIME_FORMAT,
5672 (guint) (cur - samples),
5673 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
5674 stream->timescale)));
5675 cur->timestamp = stream->stts_time;
5681 /* sample sync, can be NULL */
5682 if (stream->stss_present == TRUE) {
5683 guint32 n_sample_syncs;
5685 n_sample_syncs = stream->n_sample_syncs;
5687 if (!n_sample_syncs) {
5688 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
5689 stream->all_keyframe = TRUE;
5691 for (i = stream->stss_index; i < n_sample_syncs; i++) {
5692 /* note that the first sample is index 1, not 0 */
5695 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
5697 if (G_LIKELY (index > 0 && index <= n_samples)) {
5699 samples[index].keyframe = TRUE;
5700 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5701 /* and exit if we have enough samples */
5702 if (G_UNLIKELY (index >= n)) {
5709 stream->stss_index = i;
5712 /* stps marks partial sync frames like open GOP I-Frames */
5713 if (stream->stps_present == TRUE) {
5714 guint32 n_sample_partial_syncs;
5716 n_sample_partial_syncs = stream->n_sample_partial_syncs;
5718 /* if there are no entries, the stss table contains the real
5720 if (n_sample_partial_syncs) {
5721 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
5722 /* note that the first sample is index 1, not 0 */
5725 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
5727 if (G_LIKELY (index > 0 && index <= n_samples)) {
5729 samples[index].keyframe = TRUE;
5730 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5731 /* and exit if we have enough samples */
5732 if (G_UNLIKELY (index >= n)) {
5739 stream->stps_index = i;
5743 /* no stss, all samples are keyframes */
5744 stream->all_keyframe = TRUE;
5745 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
5750 /* composition time to sample */
5751 if (stream->ctts_present == TRUE) {
5752 guint32 n_composition_times;
5754 gint32 ctts_soffset;
5756 /* Fill in the pts_offsets */
5758 n_composition_times = stream->n_composition_times;
5760 for (i = stream->ctts_index; i < n_composition_times; i++) {
5761 if (stream->ctts_sample_index >= stream->ctts_count
5762 || !stream->ctts_sample_index) {
5763 stream->ctts_count =
5764 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
5765 stream->ctts_soffset =
5766 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
5767 stream->ctts_sample_index = 0;
5770 ctts_count = stream->ctts_count;
5771 ctts_soffset = stream->ctts_soffset;
5773 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
5774 cur->pts_offset = ctts_soffset;
5777 if (G_UNLIKELY (cur > last)) {
5779 stream->ctts_sample_index = j + 1;
5783 stream->ctts_sample_index = 0;
5784 stream->ctts_index++;
5788 stream->stbl_index = n;
5789 /* if index has been completely parsed, free data that is no-longer needed */
5790 if (n + 1 == stream->n_samples) {
5791 gst_qtdemux_stbl_free (stream);
5792 GST_DEBUG_OBJECT (qtdemux,
5793 "parsed all available samples; checking for more");
5794 while (n + 1 == stream->n_samples)
5795 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
5798 GST_OBJECT_UNLOCK (qtdemux);
5805 GST_LOG_OBJECT (qtdemux,
5806 "Tried to parse up to sample %u but this sample has already been parsed",
5808 /* if fragmented, there may be more */
5809 if (qtdemux->fragmented && n == stream->stbl_index)
5811 GST_OBJECT_UNLOCK (qtdemux);
5817 GST_LOG_OBJECT (qtdemux,
5818 "Tried to parse up to sample %u but there are only %u samples", n + 1,
5820 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5821 (_("This file is corrupt and cannot be played.")), (NULL));
5826 GST_OBJECT_UNLOCK (qtdemux);
5827 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5828 (_("This file is corrupt and cannot be played.")), (NULL));
5833 /* collect all segment info for @stream.
5836 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
5841 /* parse and prepare segment info from the edit list */
5842 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
5843 stream->n_segments = 0;
5844 stream->segments = NULL;
5845 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
5849 guint64 time, stime;
5852 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
5853 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
5856 buffer = elst->data;
5858 n_segments = QT_UINT32 (buffer + 12);
5860 /* we might allocate a bit too much, at least allocate 1 segment */
5861 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
5863 /* segments always start from 0 */
5867 for (i = 0; i < n_segments; i++) {
5870 QtDemuxSegment *segment;
5873 media_time = QT_UINT32 (buffer + 20 + i * 12);
5875 /* -1 media time is an empty segment, just ignore it */
5876 if (media_time == G_MAXUINT32)
5879 duration = QT_UINT32 (buffer + 16 + i * 12);
5881 segment = &stream->segments[count++];
5883 /* time and duration expressed in global timescale */
5884 segment->time = stime;
5885 /* add non scaled values so we don't cause roundoff errors */
5887 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
5888 segment->stop_time = stime;
5889 segment->duration = stime - segment->time;
5890 /* media_time expressed in stream timescale */
5891 segment->media_start =
5892 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
5893 segment->media_stop = segment->media_start + segment->duration;
5894 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
5896 if (rate_int <= 1) {
5897 /* 0 is not allowed, some programs write 1 instead of the floating point
5899 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
5903 segment->rate = rate_int / 65536.0;
5906 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
5907 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
5908 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
5909 GST_TIME_ARGS (segment->duration),
5910 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
5912 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
5913 stream->n_segments = count;
5917 /* push based does not handle segments, so act accordingly here,
5918 * and warn if applicable */
5919 if (!qtdemux->pullbased) {
5920 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
5921 /* remove and use default one below, we stream like it anyway */
5922 g_free (stream->segments);
5923 stream->segments = NULL;
5924 stream->n_segments = 0;
5927 /* no segments, create one to play the complete trak */
5928 if (stream->n_segments == 0) {
5929 GstClockTime stream_duration =
5930 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
5932 if (stream->segments == NULL)
5933 stream->segments = g_new (QtDemuxSegment, 1);
5935 /* represent unknown our way */
5936 if (stream_duration == 0)
5937 stream_duration = -1;
5939 stream->segments[0].time = 0;
5940 stream->segments[0].stop_time = stream_duration;
5941 stream->segments[0].duration = stream_duration;
5942 stream->segments[0].media_start = 0;
5943 stream->segments[0].media_stop = stream_duration;
5944 stream->segments[0].rate = 1.0;
5946 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
5947 GST_TIME_ARGS (stream_duration));
5948 stream->n_segments = 1;
5950 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
5956 * Parses the stsd atom of a svq3 trak looking for
5957 * the SMI and gama atoms.
5960 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
5961 guint8 ** gamma, GstBuffer ** seqh)
5963 guint8 *_gamma = NULL;
5964 GstBuffer *_seqh = NULL;
5965 guint8 *stsd_data = stsd->data;
5966 guint32 length = QT_UINT32 (stsd_data);
5970 GST_WARNING_OBJECT (qtdemux, "stsd too short");
5976 version = QT_UINT16 (stsd_data);
5981 while (length > 8) {
5982 guint32 fourcc, size;
5984 size = QT_UINT32 (stsd_data);
5985 fourcc = QT_FOURCC (stsd_data + 4);
5986 data = stsd_data + 8;
5993 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
5994 " for gama atom, expected 12", size);
5999 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6001 if (_seqh != NULL) {
6002 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6003 " found, ignoring");
6005 seqh_size = QT_UINT32 (data + 4);
6006 if (seqh_size > 0) {
6007 _seqh = gst_buffer_new_and_alloc (seqh_size);
6008 memcpy (GST_BUFFER_DATA (_seqh), data + 8, seqh_size);
6015 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6016 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6020 if (size <= length) {
6026 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6029 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6030 G_GUINT16_FORMAT, version);
6041 gst_buffer_unref (_seqh);
6046 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6054 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6055 * atom that might contain a 'data' atom with the rtsp uri.
6056 * This case was reported in bug #597497, some info about
6057 * the hndl atom can be found in TN1195
6059 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6060 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6063 guint32 dref_num_entries = 0;
6064 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6065 gst_byte_reader_skip (&dref, 4) &&
6066 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6070 /* search dref entries for hndl atom */
6071 for (i = 0; i < dref_num_entries; i++) {
6072 guint32 size = 0, type;
6073 guint8 string_len = 0;
6074 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6075 qt_atom_parser_get_fourcc (&dref, &type)) {
6076 if (type == FOURCC_hndl) {
6077 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6079 /* skip data reference handle bytes and the
6080 * following pascal string and some extra 4
6081 * bytes I have no idea what are */
6082 if (!gst_byte_reader_skip (&dref, 4) ||
6083 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6084 !gst_byte_reader_skip (&dref, string_len + 4)) {
6085 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6089 /* iterate over the atoms to find the data atom */
6090 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6094 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6095 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6096 if (atom_type == FOURCC_data) {
6097 const guint8 *uri_aux = NULL;
6099 /* found the data atom that might contain the rtsp uri */
6100 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6101 "hndl atom, interpreting it as an URI");
6102 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6104 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6105 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6107 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6108 "didn't contain a rtsp address");
6110 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6115 /* skipping to the next entry */
6116 gst_byte_reader_skip (&dref, atom_size - 8);
6118 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6125 /* skip to the next entry */
6126 gst_byte_reader_skip (&dref, size - 8);
6128 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6131 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6138 less_than (gconstpointer a, gconstpointer b)
6140 const guint32 *av = a, *bv = b;
6146 * With each track we associate a new QtDemuxStream that contains all the info
6148 * traks that do not decode to something (like strm traks) will not have a pad.
6151 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6166 QtDemuxStream *stream;
6167 GstTagList *list = NULL;
6168 gchar *codec = NULL;
6169 const guint8 *stsd_data;
6170 guint16 lang_code; /* quicktime lang code or packed iso code */
6172 guint32 tkhd_flags = 0;
6173 guint8 tkhd_version = 0;
6175 guint value_size, len;
6177 stream = g_new0 (QtDemuxStream, 1);
6178 /* new streams always need a discont */
6179 stream->discont = TRUE;
6180 /* we enable clipping for raw audio/video streams */
6181 stream->need_clip = FALSE;
6182 stream->need_process = FALSE;
6183 stream->segment_index = -1;
6184 stream->time_position = 0;
6185 stream->sample_index = -1;
6186 stream->last_ret = GST_FLOW_OK;
6188 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6189 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6190 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6193 /* pick between 64 or 32 bits */
6194 value_size = tkhd_version == 1 ? 8 : 4;
6195 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6196 !gst_byte_reader_get_uint32_be (&tkhd, &stream->track_id))
6199 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6200 tkhd_version, tkhd_flags, stream->track_id);
6202 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6205 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6206 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6207 if (qtdemux->major_brand != FOURCC_mjp2 ||
6208 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6212 len = QT_UINT32 ((guint8 *) mdhd->data);
6213 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6214 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6215 if (version == 0x01000000) {
6218 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6219 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6220 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6224 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6225 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6226 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6229 if (lang_code < 0x800) {
6230 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6232 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6233 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6234 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6235 stream->lang_id[3] = 0;
6238 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6240 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6242 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6243 lang_code, stream->lang_id);
6245 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6248 /* fragmented files may have bogus duration in moov */
6249 if (!qtdemux->fragmented &&
6250 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6251 guint64 tdur1, tdur2;
6253 /* don't overflow */
6254 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6255 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6258 * some of those trailers, nowadays, have prologue images that are
6259 * themselves vide tracks as well. I haven't really found a way to
6260 * identify those yet, except for just looking at their duration. */
6261 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6262 GST_WARNING_OBJECT (qtdemux,
6263 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6264 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6265 "found, assuming preview image or something; skipping track",
6266 stream->duration, stream->timescale, qtdemux->duration,
6267 qtdemux->timescale);
6273 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6276 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6277 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6279 len = QT_UINT32 ((guint8 *) hdlr->data);
6281 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6282 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6283 GST_FOURCC_ARGS (stream->subtype));
6285 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6288 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6292 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6294 stsd_data = (const guint8 *) stsd->data;
6296 /* stsd should at least have one entry */
6297 len = QT_UINT32 (stsd_data);
6301 /* and that entry should fit within stsd */
6302 len = QT_UINT32 (stsd_data + 16);
6303 if (len > QT_UINT32 (stsd_data) + 16)
6305 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6307 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6308 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6309 GST_FOURCC_ARGS (stream->fourcc));
6311 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6312 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6313 goto error_encrypted;
6315 if (stream->subtype == FOURCC_vide) {
6316 guint32 w = 0, h = 0;
6318 stream->sampled = TRUE;
6320 /* version 1 uses some 64-bit ints */
6321 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6322 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6323 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6326 stream->display_width = w >> 16;
6327 stream->display_height = h >> 16;
6333 stream->width = QT_UINT16 (stsd_data + offset + 32);
6334 stream->height = QT_UINT16 (stsd_data + offset + 34);
6335 stream->fps_n = 0; /* this is filled in later */
6336 stream->fps_d = 0; /* this is filled in later */
6337 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6338 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6340 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6341 QT_UINT16 (stsd_data + offset + 48));
6344 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6346 list = gst_tag_list_new ();
6347 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6348 GST_TAG_VIDEO_CODEC, codec, NULL);
6355 /* pick 'the' stsd child */
6356 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
6358 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
6359 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
6363 const guint8 *pasp_data = (const guint8 *) pasp->data;
6365 stream->par_w = QT_UINT32 (pasp_data + 8);
6366 stream->par_h = QT_UINT32 (pasp_data + 12);
6373 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
6378 gint len = QT_UINT32 (stsd_data) - 0x66;
6379 const guint8 *avc_data = stsd_data + 0x66;
6382 while (len >= 0x8) {
6385 if (QT_UINT32 (avc_data) <= len)
6386 size = QT_UINT32 (avc_data) - 0x8;
6391 /* No real data, so break out */
6394 switch (QT_FOURCC (avc_data + 0x4)) {
6397 /* parse, if found */
6400 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
6402 /* First 4 bytes are the length of the atom, the next 4 bytes
6403 * are the fourcc, the next 1 byte is the version, and the
6404 * subsequent bytes are sequence parameter set like data. */
6405 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
6406 avc_data + 8 + 1, size - 1);
6408 buf = gst_buffer_new_and_alloc (size);
6409 memcpy (GST_BUFFER_DATA (buf), avc_data + 0x8, size);
6410 gst_caps_set_simple (stream->caps,
6411 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6412 gst_buffer_unref (buf);
6418 guint avg_bitrate, max_bitrate;
6420 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
6424 max_bitrate = QT_UINT32 (avc_data + 0xc);
6425 avg_bitrate = QT_UINT32 (avc_data + 0x10);
6427 if (!max_bitrate && !avg_bitrate)
6430 /* Some muxers seem to swap the average and maximum bitrates
6431 * (I'm looking at you, YouTube), so we swap for sanity. */
6432 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
6433 guint temp = avg_bitrate;
6435 avg_bitrate = max_bitrate;
6440 list = gst_tag_list_new ();
6442 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6443 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6444 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6446 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6447 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6448 GST_TAG_BITRATE, avg_bitrate, NULL);
6459 avc_data += size + 8;
6471 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
6472 GST_FOURCC_ARGS (fourcc));
6474 /* codec data might be in glbl extension atom */
6476 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
6482 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
6484 len = QT_UINT32 (data);
6487 buf = gst_buffer_new_and_alloc (len);
6488 memcpy (GST_BUFFER_DATA (buf), data + 8, len);
6489 gst_caps_set_simple (stream->caps,
6490 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6491 gst_buffer_unref (buf);
6498 /* see annex I of the jpeg2000 spec */
6499 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
6503 guint32 ncomp_map = 0;
6504 gint32 *comp_map = NULL;
6505 guint32 nchan_def = 0;
6506 gint32 *chan_def = NULL;
6508 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
6509 /* some required atoms */
6510 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
6513 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
6517 /* number of components; redundant with info in codestream, but useful
6519 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
6520 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
6522 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
6524 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
6527 GST_DEBUG_OBJECT (qtdemux, "found colr");
6528 /* extract colour space info */
6529 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
6530 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
6532 fourcc = GST_MAKE_FOURCC ('s', 'R', 'G', 'B');
6535 fourcc = GST_MAKE_FOURCC ('G', 'R', 'A', 'Y');
6538 fourcc = GST_MAKE_FOURCC ('s', 'Y', 'U', 'V');
6545 /* colr is required, and only values 16, 17, and 18 are specified,
6546 so error if we have no fourcc */
6549 /* extract component mapping */
6550 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
6552 guint32 cmap_len = 0;
6554 cmap_len = QT_UINT32 (cmap->data);
6555 if (cmap_len >= 8) {
6556 /* normal box, subtract off header */
6558 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
6559 if (cmap_len % 4 == 0) {
6560 ncomp_map = (cmap_len / 4);
6561 comp_map = g_new0 (gint32, ncomp_map);
6562 for (i = 0; i < ncomp_map; i++) {
6565 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
6566 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
6567 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
6568 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
6573 /* extract channel definitions */
6574 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
6576 guint32 cdef_len = 0;
6578 cdef_len = QT_UINT32 (cdef->data);
6579 if (cdef_len >= 10) {
6580 /* normal box, subtract off header and len */
6582 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
6583 if (cdef_len % 6 == 0) {
6584 nchan_def = (cdef_len / 6);
6585 chan_def = g_new0 (gint32, nchan_def);
6586 for (i = 0; i < nchan_def; i++)
6588 for (i = 0; i < nchan_def; i++) {
6589 guint16 cn, typ, asoc;
6590 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
6591 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
6592 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
6593 if (cn < nchan_def) {
6596 chan_def[cn] = asoc;
6599 chan_def[cn] = 0; /* alpha */
6602 chan_def[cn] = -typ;
6610 gst_caps_set_simple (stream->caps,
6611 "num-components", G_TYPE_INT, ncomp, NULL);
6612 gst_caps_set_simple (stream->caps,
6613 "fourcc", GST_TYPE_FOURCC, fourcc, NULL);
6616 GValue arr = { 0, };
6617 GValue elt = { 0, };
6619 g_value_init (&arr, GST_TYPE_ARRAY);
6620 g_value_init (&elt, G_TYPE_INT);
6621 for (i = 0; i < ncomp_map; i++) {
6622 g_value_set_int (&elt, comp_map[i]);
6623 gst_value_array_append_value (&arr, &elt);
6625 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6626 "component-map", &arr);
6627 g_value_unset (&elt);
6628 g_value_unset (&arr);
6633 GValue arr = { 0, };
6634 GValue elt = { 0, };
6636 g_value_init (&arr, GST_TYPE_ARRAY);
6637 g_value_init (&elt, G_TYPE_INT);
6638 for (i = 0; i < nchan_def; i++) {
6639 g_value_set_int (&elt, chan_def[i]);
6640 gst_value_array_append_value (&arr, &elt);
6642 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6643 "channel-definitions", &arr);
6644 g_value_unset (&elt);
6645 g_value_unset (&arr);
6649 /* some optional atoms */
6650 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
6651 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
6653 /* indicate possible fields in caps */
6655 data = (guint8 *) field->data + 8;
6657 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
6658 (gint) * data, NULL);
6660 /* add codec_data if provided */
6665 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
6666 data = prefix->data;
6667 len = QT_UINT32 (data);
6670 buf = gst_buffer_new_and_alloc (len);
6671 memcpy (GST_BUFFER_DATA (buf), data + 8, len);
6672 gst_caps_set_simple (stream->caps,
6673 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6674 gst_buffer_unref (buf);
6683 GstBuffer *seqh = NULL;
6684 guint8 *gamma_data = NULL;
6685 gint len = QT_UINT32 (stsd_data);
6687 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
6689 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
6690 QT_FP32 (gamma_data), NULL);
6693 /* sorry for the bad name, but we don't know what this is, other
6694 * than its own fourcc */
6695 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
6699 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
6700 buf = gst_buffer_new_and_alloc (len);
6701 memcpy (GST_BUFFER_DATA (buf), stsd_data, len);
6702 gst_caps_set_simple (stream->caps,
6703 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6704 gst_buffer_unref (buf);
6709 gst_caps_set_simple (stream->caps,
6710 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
6717 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
6718 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
6722 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
6726 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
6727 /* collect the headers and store them in a stream list so that we can
6728 * send them out first */
6729 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
6739 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
6740 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
6743 ovc1_data = ovc1->data;
6744 ovc1_len = QT_UINT32 (ovc1_data);
6745 if (ovc1_len <= 198) {
6746 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
6749 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
6750 memcpy (GST_BUFFER_DATA (buf), ovc1_data + 198, ovc1_len - 198);
6751 gst_caps_set_simple (stream->caps,
6752 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6753 gst_buffer_unref (buf);
6761 GST_INFO_OBJECT (qtdemux,
6762 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
6763 GST_FOURCC_ARGS (fourcc), stream->caps);
6765 } else if (stream->subtype == FOURCC_soun) {
6766 int version, samplesize;
6767 guint16 compression_id;
6773 version = QT_UINT32 (stsd_data + offset);
6774 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
6775 samplesize = QT_UINT16 (stsd_data + offset + 10);
6776 compression_id = QT_UINT16 (stsd_data + offset + 12);
6777 stream->rate = QT_FP32 (stsd_data + offset + 16);
6779 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
6780 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
6781 QT_UINT32 (stsd_data + offset + 4));
6782 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
6783 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
6784 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
6785 GST_LOG_OBJECT (qtdemux, "packet size: %d",
6786 QT_UINT16 (stsd_data + offset + 14));
6787 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
6789 if (compression_id == 0xfffe)
6790 stream->sampled = TRUE;
6792 /* first assume uncompressed audio */
6793 stream->bytes_per_sample = samplesize / 8;
6794 stream->samples_per_frame = stream->n_channels;
6795 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
6796 stream->samples_per_packet = stream->samples_per_frame;
6797 stream->bytes_per_packet = stream->bytes_per_sample;
6801 /* Yes, these have to be hard-coded */
6804 stream->samples_per_packet = 6;
6805 stream->bytes_per_packet = 1;
6806 stream->bytes_per_frame = 1 * stream->n_channels;
6807 stream->bytes_per_sample = 1;
6808 stream->samples_per_frame = 6 * stream->n_channels;
6813 stream->samples_per_packet = 3;
6814 stream->bytes_per_packet = 1;
6815 stream->bytes_per_frame = 1 * stream->n_channels;
6816 stream->bytes_per_sample = 1;
6817 stream->samples_per_frame = 3 * stream->n_channels;
6822 stream->samples_per_packet = 64;
6823 stream->bytes_per_packet = 34;
6824 stream->bytes_per_frame = 34 * stream->n_channels;
6825 stream->bytes_per_sample = 2;
6826 stream->samples_per_frame = 64 * stream->n_channels;
6832 stream->samples_per_packet = 1;
6833 stream->bytes_per_packet = 1;
6834 stream->bytes_per_frame = 1 * stream->n_channels;
6835 stream->bytes_per_sample = 1;
6836 stream->samples_per_frame = 1 * stream->n_channels;
6841 stream->samples_per_packet = 160;
6842 stream->bytes_per_packet = 33;
6843 stream->bytes_per_frame = 33 * stream->n_channels;
6844 stream->bytes_per_sample = 2;
6845 stream->samples_per_frame = 160 * stream->n_channels;
6852 if (version == 0x00010000) {
6860 /* only parse extra decoding config for non-pcm audio */
6861 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
6862 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
6863 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
6864 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
6866 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
6867 stream->samples_per_packet);
6868 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
6869 stream->bytes_per_packet);
6870 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
6871 stream->bytes_per_frame);
6872 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
6873 stream->bytes_per_sample);
6875 if (!stream->sampled && stream->bytes_per_packet) {
6876 stream->samples_per_frame = (stream->bytes_per_frame /
6877 stream->bytes_per_packet) * stream->samples_per_packet;
6878 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
6879 stream->samples_per_frame);
6884 } else if (version == 0x00020000) {
6891 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
6892 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
6893 stream->rate = qtfp.fp;
6894 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
6896 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
6897 stream->samples_per_packet);
6898 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
6899 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
6902 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
6905 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
6914 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
6916 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
6918 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
6920 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
6923 gst_caps_set_simple (stream->caps,
6924 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
6931 const gchar *owma_data, *codec_name = NULL;
6935 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
6936 /* FIXME this should also be gst_riff_strf_auds,
6937 * but the latter one is actually missing bits-per-sample :( */
6942 gint32 nSamplesPerSec;
6943 gint32 nAvgBytesPerSec;
6945 gint16 wBitsPerSample;
6950 GST_DEBUG_OBJECT (qtdemux, "parse owma");
6951 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
6954 owma_data = owma->data;
6955 owma_len = QT_UINT32 (owma_data);
6956 if (owma_len <= 54) {
6957 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
6960 wfex = (WAVEFORMATEX *) (owma_data + 36);
6961 buf = gst_buffer_new_and_alloc (owma_len - 54);
6962 memcpy (GST_BUFFER_DATA (buf), owma_data + 54, owma_len - 54);
6963 if (wfex->wFormatTag == 0x0161) {
6964 codec_name = "Windows Media Audio";
6966 } else if (wfex->wFormatTag == 0x0162) {
6967 codec_name = "Windows Media Audio 9 Pro";
6969 } else if (wfex->wFormatTag == 0x0163) {
6970 codec_name = "Windows Media Audio 9 Lossless";
6971 /* is that correct? gstffmpegcodecmap.c is missing it, but
6972 * fluendo codec seems to support it */
6976 gst_caps_set_simple (stream->caps,
6977 "codec_data", GST_TYPE_BUFFER, buf,
6978 "wmaversion", G_TYPE_INT, version,
6979 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
6980 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
6981 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
6982 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
6984 gst_buffer_unref (buf);
6988 codec = g_strdup (codec_name);
6997 list = gst_tag_list_new ();
6998 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6999 GST_TAG_AUDIO_CODEC, codec, NULL);
7004 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7008 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7010 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7012 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7016 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7017 16 bits is a byte-swapped wave-style codec identifier,
7018 and we can find a WAVE header internally to a 'wave' atom here.
7019 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7020 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7023 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7024 if (len < offset + 20) {
7025 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7027 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7028 const guint8 *data = stsd_data + offset + 16;
7030 GNode *waveheadernode;
7032 wavenode = g_node_new ((guint8 *) data);
7033 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7034 const guint8 *waveheader;
7037 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7038 if (waveheadernode) {
7039 waveheader = (const guint8 *) waveheadernode->data;
7040 headerlen = QT_UINT32 (waveheader);
7042 if (headerlen > 8) {
7043 gst_riff_strf_auds *header = NULL;
7044 GstBuffer *headerbuf;
7050 headerbuf = gst_buffer_new ();
7051 GST_BUFFER_DATA (headerbuf) = (guint8 *) waveheader;
7052 GST_BUFFER_SIZE (headerbuf) = headerlen;
7054 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7055 headerbuf, &header, &extra)) {
7056 gst_caps_unref (stream->caps);
7057 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7058 header, extra, NULL, NULL);
7061 gst_buffer_unref (extra);
7065 GST_DEBUG ("Didn't find waveheadernode for this codec");
7067 g_node_destroy (wavenode);
7070 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7074 /* FIXME: what is in the chunk? */
7077 gint len = QT_UINT32 (stsd_data);
7079 /* seems to be always = 116 = 0x74 */
7085 gint len = QT_UINT32 (stsd_data);
7088 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7090 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x4C, len - 0x4C);
7091 gst_caps_set_simple (stream->caps,
7092 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7093 gst_buffer_unref (buf);
7095 gst_caps_set_simple (stream->caps,
7096 "samplesize", G_TYPE_INT, samplesize, NULL);
7101 GNode *alac, *wave = NULL;
7103 /* apparently, m4a has this atom appended directly in the stsd entry,
7104 * while mov has it in a wave atom */
7105 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7107 /* alac now refers to stsd entry atom */
7108 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7110 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7112 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7115 gint len = QT_UINT32 (alac->data);
7119 GST_DEBUG_OBJECT (qtdemux,
7120 "discarding alac atom with unexpected len %d", len);
7122 /* codec-data contains alac atom size and prefix,
7123 * ffmpeg likes it that way, not quite gst-ish though ...*/
7124 buf = gst_buffer_new_and_alloc (len);
7125 memcpy (GST_BUFFER_DATA (buf), alac->data, len);
7126 gst_caps_set_simple (stream->caps,
7127 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7128 gst_buffer_unref (buf);
7131 gst_caps_set_simple (stream->caps,
7132 "samplesize", G_TYPE_INT, samplesize, NULL);
7137 gint len = QT_UINT32 (stsd_data);
7140 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7142 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34);
7144 gst_caps_set_simple (stream->caps,
7145 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7146 gst_buffer_unref (buf);
7154 GST_INFO_OBJECT (qtdemux,
7155 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7156 GST_FOURCC_ARGS (fourcc), stream->caps);
7158 } else if (stream->subtype == FOURCC_strm) {
7159 if (fourcc == FOURCC_rtsp) {
7160 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7162 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7163 GST_FOURCC_ARGS (fourcc));
7164 goto unknown_stream;
7166 stream->sampled = TRUE;
7167 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
7169 stream->sampled = TRUE;
7174 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7176 list = gst_tag_list_new ();
7177 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7178 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7183 /* hunt for sort-of codec data */
7190 /* look for palette */
7191 /* target mp4s atom */
7192 len = QT_UINT32 (stsd_data + offset);
7193 data = stsd_data + offset;
7194 /* verify sufficient length,
7195 * and esds present with decConfigDescr of expected size and position */
7196 if ((len >= 106 + 8)
7197 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7198 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7203 /* move to decConfigDescr data */
7204 data = data + 8 + 42;
7205 for (i = 0; i < 16; i++) {
7206 clut[i] = QT_UINT32 (data);
7210 s = gst_structure_new ("application/x-gst-dvd", "event",
7211 G_TYPE_STRING, "dvd-spu-clut-change",
7212 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7213 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7214 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7215 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7216 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7217 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7218 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7219 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7222 /* store event and trigger custom processing */
7223 stream->pending_event =
7224 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7225 stream->need_process = TRUE;
7233 goto unknown_stream;
7236 /* promote to sampled format */
7237 if (stream->fourcc == FOURCC_samr) {
7238 /* force mono 8000 Hz for AMR */
7239 stream->sampled = TRUE;
7240 stream->n_channels = 1;
7241 stream->rate = 8000;
7242 } else if (stream->fourcc == FOURCC_sawb) {
7243 /* force mono 16000 Hz for AMR-WB */
7244 stream->sampled = TRUE;
7245 stream->n_channels = 1;
7246 stream->rate = 16000;
7247 } else if (stream->fourcc == FOURCC_mp4a) {
7248 stream->sampled = TRUE;
7251 /* collect sample information */
7252 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7253 goto samples_failed;
7255 if (qtdemux->fragmented) {
7259 /* need all moov samples as basis; probably not many if any at all */
7260 /* prevent moof parsing taking of at this time */
7261 offset = qtdemux->moof_offset;
7262 qtdemux->moof_offset = 0;
7263 if (stream->n_samples &&
7264 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7265 qtdemux->moof_offset = offset;
7266 goto samples_failed;
7268 qtdemux->moof_offset = 0;
7269 /* movie duration more reliable in this case (e.g. mehd) */
7270 if (qtdemux->segment.duration &&
7271 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7272 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7273 stream->timescale, GST_SECOND);
7274 /* need defaults for fragments */
7275 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7278 /* configure segments */
7279 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7280 goto segments_failed;
7282 /* add some language tag, if useful */
7283 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7284 strcmp (stream->lang_id, "und")) {
7285 const gchar *lang_code;
7288 list = gst_tag_list_new ();
7290 /* convert ISO 639-2 code to ISO 639-1 */
7291 lang_code = gst_tag_get_language_code (stream->lang_id);
7292 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7293 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7296 /* now we are ready to add the stream */
7297 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7298 goto too_many_streams;
7300 stream->pending_tags = list;
7301 qtdemux->streams[qtdemux->n_streams] = stream;
7302 qtdemux->n_streams++;
7303 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7310 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7311 (_("This file is corrupt and cannot be played.")), (NULL));
7317 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7324 /* we posted an error already */
7325 /* free stbl sub-atoms */
7326 gst_qtdemux_stbl_free (stream);
7332 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7333 GST_FOURCC_ARGS (stream->subtype));
7339 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7340 (_("This file contains too many streams. Only playing first %d"),
7341 GST_QTDEMUX_MAX_STREAMS), (NULL));
7346 static GstFlowReturn
7347 qtdemux_expose_streams (GstQTDemux * qtdemux)
7350 GstFlowReturn ret = GST_FLOW_OK;
7352 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7354 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7355 QtDemuxStream *stream = qtdemux->streams[i];
7356 guint32 sample_num = 0;
7361 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7362 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7364 if (qtdemux->fragmented) {
7365 /* need all moov samples first */
7366 GST_OBJECT_LOCK (qtdemux);
7367 while (stream->n_samples == 0)
7368 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7370 GST_OBJECT_UNLOCK (qtdemux);
7372 /* discard any stray moof */
7373 qtdemux->moof_offset = 0;
7376 /* prepare braking */
7377 if (ret != GST_FLOW_ERROR)
7380 /* in pull mode, we should have parsed some sample info by now;
7381 * and quite some code will not handle no samples.
7382 * in push mode, we'll just have to deal with it */
7383 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7384 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7385 gst_qtdemux_stream_free (qtdemux, stream);
7386 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7387 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7388 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7389 qtdemux->n_streams--;
7394 /* parse number of initial sample to set frame rate cap */
7395 while (sample_num < stream->n_samples && sample_num < samples) {
7396 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7400 /* collect and sort durations */
7401 samples = MIN (stream->stbl_index + 1, samples);
7402 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7404 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7406 while (sample_num < samples) {
7407 g_array_append_val (durations, stream->samples[sample_num].duration);
7410 g_array_sort (durations, less_than);
7411 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7412 g_array_free (durations, TRUE);
7415 /* now we have all info and can expose */
7416 list = stream->pending_tags;
7417 stream->pending_tags = NULL;
7418 gst_qtdemux_add_stream (qtdemux, stream, list);
7421 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7423 /* check if we should post a redirect in case there is a single trak
7424 * and it is a redirecting trak */
7425 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7428 qtdemux_post_global_tags (qtdemux);
7430 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7431 "an external content");
7432 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7433 gst_structure_new ("redirect",
7434 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7436 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7437 qtdemux->posted_redirect = TRUE;
7443 /* check if major or compatible brand is 3GP */
7444 static inline gboolean
7445 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7448 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7449 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7450 } else if (qtdemux->comp_brands != NULL) {
7451 guint8 *data = GST_BUFFER_DATA (qtdemux->comp_brands);
7452 guint size = GST_BUFFER_SIZE (qtdemux->comp_brands);
7453 gboolean res = FALSE;
7456 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7457 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7467 /* check if tag is a spec'ed 3GP tag keyword storing a string */
7468 static inline gboolean
7469 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
7471 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
7472 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
7473 || fourcc == FOURCC_albm;
7477 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
7478 const char *dummy, GNode * node)
7480 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7484 gdouble longitude, latitude, altitude;
7487 len = QT_UINT32 (node->data);
7494 /* TODO: language code skipped */
7496 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
7499 /* do not alarm in trivial case, but bail out otherwise */
7500 if (*(data + offset) != 0) {
7501 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
7505 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7506 GST_TAG_GEO_LOCATION_NAME, name, NULL);
7507 offset += strlen (name);
7511 if (len < offset + 2 + 4 + 4 + 4)
7514 /* +1 +1 = skip null-terminator and location role byte */
7516 /* table in spec says unsigned, semantics say negative has meaning ... */
7517 longitude = QT_SFP32 (data + offset);
7520 latitude = QT_SFP32 (data + offset);
7523 altitude = QT_SFP32 (data + offset);
7525 /* one invalid means all are invalid */
7526 if (longitude >= -180.0 && longitude <= 180.0 &&
7527 latitude >= -90.0 && latitude <= 90.0) {
7528 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7529 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
7530 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
7531 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
7534 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
7541 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
7548 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7555 len = QT_UINT32 (node->data);
7559 y = QT_UINT16 ((guint8 *) node->data + 12);
7561 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
7564 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
7566 date = g_date_new_dmy (1, 1, y);
7567 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
7572 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
7573 const char *dummy, GNode * node)
7576 char *tag_str = NULL;
7581 len = QT_UINT32 (node->data);
7586 entity = (guint8 *) node->data + offset;
7587 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
7588 GST_DEBUG_OBJECT (qtdemux,
7589 "classification info: %c%c%c%c invalid classification entity",
7590 entity[0], entity[1], entity[2], entity[3]);
7595 table = QT_UINT16 ((guint8 *) node->data + offset);
7597 /* Language code skipped */
7601 /* Tag format: "XXXX://Y[YYYY]/classification info string"
7602 * XXXX: classification entity, fixed length 4 chars.
7603 * Y[YYYY]: classification table, max 5 chars.
7605 tag_str = g_strdup_printf ("----://%u/%s",
7606 table, (char *) node->data + offset);
7608 /* memcpy To be sure we're preserving byte order */
7609 memcpy (tag_str, entity, 4);
7610 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
7612 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
7622 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
7628 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
7629 const char *dummy, GNode * node)
7631 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7637 gboolean ret = TRUE;
7639 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7641 len = QT_UINT32 (data->data);
7642 type = QT_UINT32 ((guint8 *) data->data + 8);
7643 if (type == 0x00000001 && len > 16) {
7644 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
7647 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7648 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
7652 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7656 len = QT_UINT32 (node->data);
7657 type = QT_UINT32 ((guint8 *) node->data + 4);
7658 if ((type >> 24) == 0xa9) {
7659 /* Type starts with the (C) symbol, so the next 32 bits are
7660 * the language code, which we ignore */
7662 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
7663 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
7664 QT_FOURCC ((guint8 *) node->data + 4))) {
7665 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
7667 /* we go for 3GP style encoding if major brands claims so,
7668 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
7669 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
7670 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
7671 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
7673 /* 16-bit Language code is ignored here as well */
7674 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
7681 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
7682 ret = FALSE; /* may have to fallback */
7684 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
7685 len - offset, env_vars);
7687 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7688 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
7692 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7699 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
7700 const char *dummy, GNode * node)
7702 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
7706 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
7707 const char *dummy, GNode * node)
7709 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7711 char *s, *t, *k = NULL;
7716 /* first try normal string tag if major brand not 3GP */
7717 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
7718 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
7719 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
7720 * let's try it 3gpp way after minor safety check */
7722 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
7728 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
7732 len = QT_UINT32 (data);
7736 count = QT_UINT8 (data + 14);
7738 for (; count; count--) {
7741 if (offset + 1 > len)
7743 slen = QT_UINT8 (data + offset);
7745 if (offset + slen > len)
7747 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
7750 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
7752 t = g_strjoin (",", k, s, NULL);
7760 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
7767 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
7768 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
7777 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
7783 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
7784 const char *tag2, GNode * node)
7791 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7793 len = QT_UINT32 (data->data);
7794 type = QT_UINT32 ((guint8 *) data->data + 8);
7795 if (type == 0x00000000 && len >= 22) {
7796 n1 = QT_UINT16 ((guint8 *) data->data + 18);
7797 n2 = QT_UINT16 ((guint8 *) data->data + 20);
7799 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
7800 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7804 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
7805 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7813 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
7821 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7823 len = QT_UINT32 (data->data);
7824 type = QT_UINT32 ((guint8 *) data->data + 8);
7825 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
7826 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
7827 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
7828 n1 = QT_UINT16 ((guint8 *) data->data + 16);
7830 /* do not add bpm=0 */
7831 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
7832 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7833 tag1, (gdouble) n1, NULL);
7840 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
7841 const char *dummy, GNode * node)
7848 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7850 len = QT_UINT32 (data->data);
7851 type = QT_UINT32 ((guint8 *) data->data + 8);
7852 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
7853 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
7854 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
7855 num = QT_UINT32 ((guint8 *) data->data + 16);
7857 /* do not add num=0 */
7858 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
7859 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7867 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
7875 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7877 len = QT_UINT32 (data->data);
7878 type = QT_UINT32 ((guint8 *) data->data + 8);
7879 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
7880 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
7881 if ((buf = gst_tag_image_data_to_image_buffer ((guint8 *) data->data + 16,
7882 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
7883 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
7884 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7886 gst_buffer_unref (buf);
7893 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7901 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7903 len = QT_UINT32 (data->data);
7904 type = QT_UINT32 ((guint8 *) data->data + 8);
7905 if (type == 0x00000001 && len > 16) {
7906 guint y, m = 1, d = 1;
7909 s = g_strndup ((char *) data->data + 16, len - 16);
7910 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
7911 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
7912 if (ret >= 1 && y > 1500 && y < 3000) {
7915 date = g_date_new_dmy (d, m, y);
7916 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
7920 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
7928 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7933 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7935 /* re-route to normal string tag if major brand says so
7936 * or no data atom and compatible brand suggests so */
7937 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
7938 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
7939 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
7946 len = QT_UINT32 (data->data);
7947 type = QT_UINT32 ((guint8 *) data->data + 8);
7948 if (type == 0x00000000 && len >= 18) {
7949 n = QT_UINT16 ((guint8 *) data->data + 16);
7953 genre = gst_tag_id3_genre_get (n - 1);
7954 if (genre != NULL) {
7955 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
7956 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7965 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
7966 guint8 * data, guint32 datasize)
7971 /* make a copy to have \0 at the end */
7972 datacopy = g_strndup ((gchar *) data, datasize);
7974 /* convert the str to double */
7975 if (sscanf (datacopy, "%lf", &value) == 1) {
7976 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
7977 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
7979 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
7987 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
7988 const char *tag_bis, GNode * node)
7997 const gchar *meanstr;
7998 const gchar *namestr;
8000 /* checking the whole ---- atom size for consistency */
8001 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8002 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8006 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8008 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8012 meansize = QT_UINT32 (mean->data);
8013 if (meansize <= 12) {
8014 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8017 meanstr = ((gchar *) mean->data) + 12;
8019 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8021 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8025 namesize = QT_UINT32 (name->data);
8026 if (namesize <= 12) {
8027 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8030 namestr = ((gchar *) name->data) + 12;
8037 * uint24 - data type
8041 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8043 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8046 datasize = QT_UINT32 (data->data);
8047 if (datasize <= 16) {
8048 GST_WARNING_OBJECT (demux, "Data atom too small");
8051 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8053 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8056 const gchar name[28];
8057 const gchar tag[28];
8060 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8061 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8062 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8063 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8064 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8065 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8066 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8067 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8071 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8072 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8073 switch (gst_tag_get_type (tags[i].tag)) {
8075 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8076 ((guint8 *) data->data) + 16, datasize - 16);
8079 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8088 if (i == G_N_ELEMENTS (tags))
8102 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8103 namestr_dbg = g_strndup (namestr, namesize - 12);
8105 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8106 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8108 g_free (namestr_dbg);
8109 g_free (meanstr_dbg);
8114 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8115 const char *tag, const char *tag_bis, GNode * node);
8118 FOURCC_pcst -> if media is a podcast -> bool
8119 FOURCC_cpil -> if media is part of a compilation -> bool
8120 FOURCC_pgap -> if media is part of a gapless context -> bool
8121 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8127 const gchar *gst_tag;
8128 const gchar *gst_tag_bis;
8129 const GstQTDemuxAddTagFunc func;
8132 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8133 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8134 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8135 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8136 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8137 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8138 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8139 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8140 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8141 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8142 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8143 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8144 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8145 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8146 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8147 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8148 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8149 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8150 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8151 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8152 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8153 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8154 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8155 qtdemux_tag_add_num}, {
8156 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8157 qtdemux_tag_add_num}, {
8158 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8159 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8160 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8161 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8162 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8163 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8164 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8165 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8166 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8167 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8168 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8169 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8170 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8171 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8172 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8173 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8174 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8175 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8176 qtdemux_tag_add_classification}, {
8178 /* This is a special case, some tags are stored in this
8179 * 'reverse dns naming', according to:
8180 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8183 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}
8187 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8199 len = QT_UINT32 (data);
8200 buf = gst_buffer_new_and_alloc (len);
8201 memcpy (GST_BUFFER_DATA (buf), data, len);
8203 /* heuristic to determine style of tag */
8204 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8205 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8207 else if (demux->major_brand == FOURCC_qt__)
8208 style = "quicktime";
8209 /* fall back to assuming iso/3gp tag style */
8213 /* santize the name for the caps. */
8214 for (i = 0; i < 4; i++) {
8215 guint8 d = data[4 + i];
8216 if (g_ascii_isalnum (d))
8217 ndata[i] = g_ascii_tolower (d);
8222 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8223 ndata[0], ndata[1], ndata[2], ndata[3]);
8224 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8226 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
8227 gst_buffer_set_caps (buf, caps);
8228 gst_caps_unref (caps);
8229 g_free (media_type);
8231 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
8232 GST_BUFFER_SIZE (buf), caps);
8234 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8235 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
8236 gst_buffer_unref (buf);
8240 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8248 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8250 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8252 GST_LOG_OBJECT (qtdemux, "no ilst");
8257 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8260 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8261 if (!qtdemux->tag_list)
8262 qtdemux->tag_list = gst_tag_list_new ();
8265 while (i < G_N_ELEMENTS (add_funcs)) {
8266 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8270 len = QT_UINT32 (node->data);
8272 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8273 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8275 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8276 add_funcs[i].gst_tag_bis, node);
8278 g_node_destroy (node);
8284 /* parsed nodes have been removed, pass along remainder as blob */
8285 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8286 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8288 /* parse up XMP_ node if existing */
8289 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8292 GstTagList *taglist;
8294 buf = gst_buffer_new ();
8295 GST_BUFFER_DATA (buf) = ((guint8 *) xmp_->data) + 8;
8296 GST_BUFFER_SIZE (buf) = QT_UINT32 ((guint8 *) xmp_->data) - 8;
8298 taglist = gst_tag_list_from_xmp_buffer (buf);
8299 gst_buffer_unref (buf);
8301 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8303 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8310 GstStructure *structure; /* helper for sort function */
8312 guint min_req_bitrate;
8313 guint min_req_qt_version;
8317 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8319 GstQtReference *ref_a = (GstQtReference *) a;
8320 GstQtReference *ref_b = (GstQtReference *) b;
8322 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8323 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8325 /* known bitrates go before unknown; higher bitrates go first */
8326 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8329 /* sort the redirects and post a message for the application.
8332 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8334 GstQtReference *best;
8337 GValue list_val = { 0, };
8340 g_assert (references != NULL);
8342 references = g_list_sort (references, qtdemux_redirects_sort_func);
8344 best = (GstQtReference *) references->data;
8346 g_value_init (&list_val, GST_TYPE_LIST);
8348 for (l = references; l != NULL; l = l->next) {
8349 GstQtReference *ref = (GstQtReference *) l->data;
8350 GValue struct_val = { 0, };
8352 ref->structure = gst_structure_new ("redirect",
8353 "new-location", G_TYPE_STRING, ref->location, NULL);
8355 if (ref->min_req_bitrate > 0) {
8356 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8357 ref->min_req_bitrate, NULL);
8360 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8361 g_value_set_boxed (&struct_val, ref->structure);
8362 gst_value_list_append_value (&list_val, &struct_val);
8363 g_value_unset (&struct_val);
8364 /* don't free anything here yet, since we need best->structure below */
8367 g_assert (best != NULL);
8368 s = gst_structure_copy (best->structure);
8370 if (g_list_length (references) > 1) {
8371 gst_structure_set_value (s, "locations", &list_val);
8374 g_value_unset (&list_val);
8376 for (l = references; l != NULL; l = l->next) {
8377 GstQtReference *ref = (GstQtReference *) l->data;
8379 gst_structure_free (ref->structure);
8380 g_free (ref->location);
8383 g_list_free (references);
8385 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8386 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8387 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8388 qtdemux->posted_redirect = TRUE;
8391 /* look for redirect nodes, collect all redirect information and
8395 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8397 GNode *rmra, *rmda, *rdrf;
8399 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8401 GList *redirects = NULL;
8403 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8405 GstQtReference ref = { NULL, NULL, 0, 0 };
8408 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8409 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8410 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8411 ref.min_req_bitrate);
8414 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
8415 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
8416 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
8418 #ifndef GST_DISABLE_GST_DEBUG
8419 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
8421 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
8423 GST_LOG_OBJECT (qtdemux,
8424 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
8425 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
8426 bitmask, check_type);
8427 if (package == FOURCC_qtim && check_type == 0) {
8428 ref.min_req_qt_version = version;
8432 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
8437 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
8438 ref_data = (guint8 *) rdrf->data + 20;
8439 if (ref_type == FOURCC_alis) {
8440 guint record_len, record_version, fn_len;
8442 /* MacOSX alias record, google for alias-layout.txt */
8443 record_len = QT_UINT16 (ref_data + 4);
8444 record_version = QT_UINT16 (ref_data + 4 + 2);
8445 fn_len = QT_UINT8 (ref_data + 50);
8446 if (record_len > 50 && record_version == 2 && fn_len > 0) {
8447 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
8449 } else if (ref_type == FOURCC_url_) {
8450 ref.location = g_strdup ((gchar *) ref_data);
8452 GST_DEBUG_OBJECT (qtdemux,
8453 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
8454 GST_FOURCC_ARGS (ref_type));
8456 if (ref.location != NULL) {
8457 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
8458 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
8460 GST_WARNING_OBJECT (qtdemux,
8461 "Failed to extract redirect location from rdrf atom");
8465 /* look for others */
8466 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
8469 if (redirects != NULL) {
8470 qtdemux_process_redirects (qtdemux, redirects);
8477 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
8482 tags = gst_tag_list_new ();
8484 if (qtdemux->major_brand == FOURCC_mjp2)
8485 fmt = "Motion JPEG 2000";
8486 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
8488 else if (qtdemux->major_brand == FOURCC_qt__)
8490 else if (qtdemux->fragmented)
8493 fmt = "ISO MP4/M4A";
8495 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
8496 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
8498 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
8504 /* we have read th complete moov node now.
8505 * This function parses all of the relevant info, creates the traks and
8506 * prepares all data structures for playback
8509 qtdemux_parse_tree (GstQTDemux * qtdemux)
8516 guint64 creation_time;
8517 GstDateTime *datetime = NULL;
8520 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
8522 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
8523 return qtdemux_parse_redirects (qtdemux);
8526 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
8528 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
8529 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
8530 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
8531 } else if (version == 0) {
8532 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
8533 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
8534 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
8536 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
8540 /* Moving qt creation time (secs since 1904) to unix time */
8541 if (creation_time != 0) {
8542 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
8543 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
8544 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
8546 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
8547 "please file a bug at http://bugzilla.gnome.org");
8551 if (!qtdemux->tag_list)
8552 qtdemux->tag_list = gst_tag_list_new ();
8554 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
8555 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
8557 gst_date_time_unref (datetime);
8560 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
8561 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
8563 /* check for fragmented file and get some (default) data */
8564 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
8567 GstByteReader mehd_data;
8569 /* let track parsing or anyone know weird stuff might happen ... */
8570 qtdemux->fragmented = TRUE;
8572 /* compensate for total duration */
8573 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
8575 qtdemux_parse_mehd (qtdemux, &mehd_data);
8578 /* set duration in the segment info */
8579 gst_qtdemux_get_duration (qtdemux, &duration);
8581 gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
8583 /* parse all traks */
8584 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
8586 qtdemux_parse_trak (qtdemux, trak);
8587 /* iterate all siblings */
8588 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
8592 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
8594 qtdemux_parse_udta (qtdemux, udta);
8596 GST_LOG_OBJECT (qtdemux, "No udta node found.");
8599 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
8604 /* taken from ffmpeg */
8606 get_size (guint8 * ptr, guint8 ** end)
8615 len = (len << 7) | (c & 0x7f);
8624 /* this can change the codec originally present in @list */
8626 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
8627 GNode * esds, GstTagList * list)
8629 int len = QT_UINT32 (esds->data);
8630 guint8 *ptr = esds->data;
8631 guint8 *end = ptr + len;
8633 guint8 *data_ptr = NULL;
8635 guint8 object_type_id = 0;
8636 const char *codec_name = NULL;
8637 GstCaps *caps = NULL;
8639 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
8641 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
8644 tag = QT_UINT8 (ptr);
8645 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
8647 len = get_size (ptr, &ptr);
8648 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
8652 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
8653 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
8657 guint max_bitrate, avg_bitrate;
8659 object_type_id = QT_UINT8 (ptr);
8660 max_bitrate = QT_UINT32 (ptr + 5);
8661 avg_bitrate = QT_UINT32 (ptr + 9);
8662 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
8663 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
8664 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
8665 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
8666 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
8667 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
8668 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8669 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
8671 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
8672 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
8679 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
8685 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
8689 GST_ERROR_OBJECT (qtdemux, "parse error");
8694 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
8695 * in use, and should also be used to override some other parameters for some
8697 switch (object_type_id) {
8698 case 0x20: /* MPEG-4 */
8699 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
8700 * profile_and_level_indication */
8701 if (data_ptr != NULL && data_len >= 5 &&
8702 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
8703 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
8704 data_ptr + 4, data_len - 4);
8706 break; /* Nothing special needed here */
8707 case 0x21: /* H.264 */
8708 codec_name = "H.264 / AVC";
8709 caps = gst_caps_new_simple ("video/x-h264",
8710 "stream-format", G_TYPE_STRING, "avc",
8711 "alignment", G_TYPE_STRING, "au", NULL);
8713 case 0x40: /* AAC (any) */
8714 case 0x66: /* AAC Main */
8715 case 0x67: /* AAC LC */
8716 case 0x68: /* AAC SSR */
8717 /* Override channels and rate based on the codec_data, as it's often
8719 /* Only do so for basic setup without HE-AAC extension */
8720 if (data_ptr && data_len == 2) {
8721 guint channels, rateindex, rate;
8723 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
8724 channels = (data_ptr[1] & 0x7f) >> 3;
8725 if (channels > 0 && channels < 7) {
8726 stream->n_channels = channels;
8727 } else if (channels == 7) {
8728 stream->n_channels = 8;
8731 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
8732 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
8734 stream->rate = rate;
8737 /* Set level and profile if possible */
8738 if (data_ptr != NULL && data_len >= 2) {
8739 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
8740 data_ptr, data_len);
8743 case 0x60: /* MPEG-2, various profiles */
8749 codec_name = "MPEG-2 video";
8751 gst_caps_unref (stream->caps);
8752 stream->caps = gst_caps_new_simple ("video/mpeg",
8753 "mpegversion", G_TYPE_INT, 2,
8754 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
8756 case 0x69: /* MP3 has two different values, accept either */
8758 /* change to mpeg1 layer 3 audio */
8759 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
8760 "mpegversion", G_TYPE_INT, 1, NULL);
8761 codec_name = "MPEG-1 layer 3";
8763 case 0x6A: /* MPEG-1 */
8764 codec_name = "MPEG-1 video";
8766 gst_caps_unref (stream->caps);
8767 stream->caps = gst_caps_new_simple ("video/mpeg",
8768 "mpegversion", G_TYPE_INT, 1,
8769 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
8771 case 0x6C: /* MJPEG */
8772 caps = gst_caps_new_simple ("image/jpeg", NULL);
8773 codec_name = "Motion-JPEG";
8775 case 0x6D: /* PNG */
8776 caps = gst_caps_new_simple ("image/png", NULL);
8777 codec_name = "PNG still images";
8779 case 0x6E: /* JPEG2000 */
8780 codec_name = "JPEG-2000";
8781 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
8783 case 0xA4: /* Dirac */
8784 codec_name = "Dirac";
8785 caps = gst_caps_new_simple ("video/x-dirac", NULL);
8787 case 0xA5: /* AC3 */
8788 codec_name = "AC-3 audio";
8789 caps = gst_caps_new_simple ("audio/x-ac3",
8790 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
8792 case 0xE1: /* QCELP */
8793 /* QCELP, the codec_data is a riff tag (little endian) with
8794 * 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). */
8795 caps = gst_caps_new_simple ("audio/qcelp", NULL);
8796 codec_name = "QCELP";
8802 /* If we have a replacement caps, then change our caps for this stream */
8804 gst_caps_unref (stream->caps);
8805 stream->caps = caps;
8808 if (codec_name && list)
8809 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8810 GST_TAG_AUDIO_CODEC, codec_name, NULL);
8812 /* Add the codec_data attribute to caps, if we have it */
8816 buffer = gst_buffer_new_and_alloc (data_len);
8817 memcpy (GST_BUFFER_DATA (buffer), data_ptr, data_len);
8819 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
8820 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
8822 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
8824 gst_buffer_unref (buffer);
8829 #define _codec(name) \
8832 *codec_name = g_strdup (name); \
8837 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
8838 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
8841 const GstStructure *s;
8845 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
8846 _codec ("PNG still images");
8847 caps = gst_caps_new_simple ("image/png", NULL);
8849 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
8850 _codec ("JPEG still images");
8851 caps = gst_caps_new_simple ("image/jpeg", NULL);
8853 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
8854 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
8855 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
8856 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
8857 _codec ("Motion-JPEG");
8858 caps = gst_caps_new_simple ("image/jpeg", NULL);
8860 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
8861 _codec ("Motion-JPEG format B");
8862 caps = gst_caps_new_simple ("video/x-mjpeg-b", NULL);
8864 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
8865 _codec ("JPEG-2000");
8866 /* override to what it should be according to spec, avoid palette_data */
8867 stream->bits_per_sample = 24;
8868 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
8870 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
8871 _codec ("Sorensen video v.3");
8872 caps = gst_caps_new_simple ("video/x-svq",
8873 "svqversion", G_TYPE_INT, 3, NULL);
8875 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
8876 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
8877 _codec ("Sorensen video v.1");
8878 caps = gst_caps_new_simple ("video/x-svq",
8879 "svqversion", G_TYPE_INT, 1, NULL);
8881 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
8885 _codec ("Raw RGB video");
8886 bps = QT_UINT16 (stsd_data + 98);
8887 /* set common stuff */
8888 caps = gst_caps_new_simple ("video/x-raw-rgb",
8889 "endianness", G_TYPE_INT, G_BYTE_ORDER, "depth", G_TYPE_INT, bps,
8894 gst_caps_set_simple (caps,
8895 "bpp", G_TYPE_INT, 16,
8896 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
8897 "red_mask", G_TYPE_INT, 0x7c00,
8898 "green_mask", G_TYPE_INT, 0x03e0,
8899 "blue_mask", G_TYPE_INT, 0x001f, NULL);
8902 gst_caps_set_simple (caps,
8903 "bpp", G_TYPE_INT, 16,
8904 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
8905 "red_mask", G_TYPE_INT, 0xf800,
8906 "green_mask", G_TYPE_INT, 0x07e0,
8907 "blue_mask", G_TYPE_INT, 0x001f, NULL);
8910 gst_caps_set_simple (caps,
8911 "bpp", G_TYPE_INT, 24,
8912 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
8913 "red_mask", G_TYPE_INT, 0xff0000,
8914 "green_mask", G_TYPE_INT, 0x00ff00,
8915 "blue_mask", G_TYPE_INT, 0x0000ff, NULL);
8918 gst_caps_set_simple (caps,
8919 "bpp", G_TYPE_INT, 32,
8920 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
8921 "alpha_mask", G_TYPE_INT, 0xff000000,
8922 "red_mask", G_TYPE_INT, 0x00ff0000,
8923 "green_mask", G_TYPE_INT, 0x0000ff00,
8924 "blue_mask", G_TYPE_INT, 0x000000ff, NULL);
8932 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
8933 _codec ("Raw planar YUV 4:2:0");
8934 caps = gst_caps_new_simple ("video/x-raw-yuv",
8935 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
8938 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
8939 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
8940 _codec ("Raw packed YUV 4:2:2");
8941 caps = gst_caps_new_simple ("video/x-raw-yuv",
8942 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'),
8945 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
8946 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
8947 _codec ("Raw packed YUV 4:2:2");
8948 caps = gst_caps_new_simple ("video/x-raw-yuv",
8949 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'),
8952 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
8953 _codec ("Raw packed YUV 10-bit 4:2:2");
8954 caps = gst_caps_new_simple ("video/x-raw-yuv",
8955 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('v', '2', '1', '0'),
8958 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
8959 _codec ("Raw packed RGB 10-bit 4:4:4");
8960 caps = gst_caps_new_simple ("video/x-raw-rgb",
8961 "endianness", G_TYPE_INT, G_BIG_ENDIAN, "depth", G_TYPE_INT, 30,
8962 "bpp", G_TYPE_INT, 32,
8963 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
8964 "red_mask", G_TYPE_INT, 0x3ff00000,
8965 "green_mask", G_TYPE_INT, 0x000ffc00,
8966 "blue_mask", G_TYPE_INT, 0x000003ff, NULL);
8968 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
8969 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
8970 _codec ("MPEG-1 video");
8971 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
8972 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
8974 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
8975 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
8976 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
8977 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
8978 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
8979 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
8980 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
8981 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
8982 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
8983 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
8984 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
8985 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
8986 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
8987 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
8988 _codec ("MPEG-2 video");
8989 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
8990 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
8992 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
8993 _codec ("GIF still images");
8994 caps = gst_caps_new_simple ("image/gif", NULL);
8996 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
8997 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
8998 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
8999 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9001 /* ffmpeg uses the height/width props, don't know why */
9002 caps = gst_caps_new_simple ("video/x-h263", NULL);
9004 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9005 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9006 _codec ("MPEG-4 video");
9007 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9008 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9010 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9011 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9012 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9013 caps = gst_caps_new_simple ("video/x-msmpeg",
9014 "msmpegversion", G_TYPE_INT, 43, NULL);
9016 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9017 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9018 _codec ("3ivX video");
9019 caps = gst_caps_new_simple ("video/x-3ivx", NULL);
9021 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9023 caps = gst_caps_new_simple ("video/x-divx",
9024 "divxversion", G_TYPE_INT, 3, NULL);
9026 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9027 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9029 caps = gst_caps_new_simple ("video/x-divx",
9030 "divxversion", G_TYPE_INT, 4, NULL);
9032 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9034 caps = gst_caps_new_simple ("video/x-divx",
9035 "divxversion", G_TYPE_INT, 5, NULL);
9037 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9038 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9039 _codec ("XVID MPEG-4");
9040 caps = gst_caps_new_simple ("video/x-xvid", NULL);
9043 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9044 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9045 caps = gst_caps_new_simple ("video/mpeg",
9046 "mpegversion", G_TYPE_INT, 4, NULL);
9048 *codec_name = g_strdup ("FFmpeg MPEG-4");
9051 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9053 caps = gst_caps_new_simple ("video/x-cinepak", NULL);
9055 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9056 _codec ("Apple QuickDraw");
9057 caps = gst_caps_new_simple ("video/x-qdrw", NULL);
9059 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9060 _codec ("Apple video");
9061 caps = gst_caps_new_simple ("video/x-apple-video", NULL);
9063 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9064 _codec ("H.264 / AVC");
9065 caps = gst_caps_new_simple ("video/x-h264",
9066 "stream-format", G_TYPE_STRING, "avc",
9067 "alignment", G_TYPE_STRING, "au", NULL);
9069 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9070 _codec ("Run-length encoding");
9071 caps = gst_caps_new_simple ("video/x-rle",
9072 "layout", G_TYPE_STRING, "quicktime", NULL);
9074 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9075 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9076 _codec ("Indeo Video 3");
9077 caps = gst_caps_new_simple ("video/x-indeo",
9078 "indeoversion", G_TYPE_INT, 3, NULL);
9080 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9081 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9082 _codec ("Intel Video 4");
9083 caps = gst_caps_new_simple ("video/x-indeo",
9084 "indeoversion", G_TYPE_INT, 4, NULL);
9086 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9087 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9088 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9089 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9090 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9091 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9092 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9093 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9094 _codec ("DV Video");
9095 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9096 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9098 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9099 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9100 _codec ("DVCPro50 Video");
9101 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9102 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9104 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9105 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9106 _codec ("DVCProHD Video");
9107 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9108 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9110 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9111 _codec ("Apple Graphics (SMC)");
9112 caps = gst_caps_new_simple ("video/x-smc", NULL);
9114 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9116 caps = gst_caps_new_simple ("video/x-vp3", NULL);
9118 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9120 caps = gst_caps_new_simple ("video/x-theora", NULL);
9121 /* theora uses one byte of padding in the data stream because it does not
9122 * allow 0 sized packets while theora does */
9123 stream->padding = 1;
9125 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9127 caps = gst_caps_new_simple ("video/x-dirac", NULL);
9129 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9130 _codec ("TIFF still images");
9131 caps = gst_caps_new_simple ("image/tiff", NULL);
9133 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9134 _codec ("Apple Intermediate Codec");
9135 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9137 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9138 _codec ("AVID DNxHD");
9139 caps = gst_caps_from_string ("video/x-dnxhd");
9141 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9143 caps = gst_caps_from_string ("video/x-vp8");
9146 caps = gst_caps_new_simple ("video/x-wmv",
9147 "wmvversion", G_TYPE_INT, 3,
9148 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'V', 'C', '1'),
9151 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9156 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9157 GST_FOURCC_ARGS (fourcc));
9158 caps = gst_caps_new_simple (s, NULL);
9163 /* enable clipping for raw video streams */
9164 s = gst_caps_get_structure (caps, 0);
9165 name = gst_structure_get_name (s);
9166 if (g_str_has_prefix (name, "video/x-raw-")) {
9167 stream->need_clip = TRUE;
9173 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9174 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9177 const GstStructure *s;
9181 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9184 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9185 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9186 _codec ("Raw 8-bit PCM audio");
9187 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 8,
9188 "depth", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
9190 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9191 endian = G_BIG_ENDIAN;
9193 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9199 endian = G_LITTLE_ENDIAN;
9201 depth = stream->bytes_per_packet * 8;
9202 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9205 caps = gst_caps_new_simple ("audio/x-raw-int",
9206 "width", G_TYPE_INT, depth, "depth", G_TYPE_INT, depth,
9207 "endianness", G_TYPE_INT, endian,
9208 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
9211 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9212 _codec ("Raw 64-bit floating-point audio");
9213 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 64,
9214 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
9216 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9217 _codec ("Raw 32-bit floating-point audio");
9218 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 32,
9219 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
9222 _codec ("Raw 24-bit PCM audio");
9223 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9225 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 24,
9226 "depth", G_TYPE_INT, 24,
9227 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9228 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
9230 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9231 _codec ("Raw 32-bit PCM audio");
9232 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 32,
9233 "depth", G_TYPE_INT, 32,
9234 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9235 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
9237 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9238 _codec ("Mu-law audio");
9239 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
9241 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9242 _codec ("A-law audio");
9243 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
9247 _codec ("Microsoft ADPCM");
9248 /* Microsoft ADPCM-ACM code 2 */
9249 caps = gst_caps_new_simple ("audio/x-adpcm",
9250 "layout", G_TYPE_STRING, "microsoft", NULL);
9254 _codec ("DVI/IMA ADPCM");
9255 caps = gst_caps_new_simple ("audio/x-adpcm",
9256 "layout", G_TYPE_STRING, "dvi", NULL);
9260 _codec ("DVI/Intel IMA ADPCM");
9261 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9262 caps = gst_caps_new_simple ("audio/x-adpcm",
9263 "layout", G_TYPE_STRING, "quicktime", NULL);
9267 /* MPEG layer 3, CBR only (pre QT4.1) */
9268 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9269 _codec ("MPEG-1 layer 3");
9270 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9271 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9272 "mpegversion", G_TYPE_INT, 1, NULL);
9275 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9276 _codec ("EAC-3 audio");
9277 caps = gst_caps_new_simple ("audio/x-eac3",
9278 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9279 stream->sampled = TRUE;
9281 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9282 _codec ("AC-3 audio");
9283 caps = gst_caps_new_simple ("audio/x-ac3",
9284 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9285 stream->sampled = TRUE;
9287 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9289 caps = gst_caps_new_simple ("audio/x-mace",
9290 "maceversion", G_TYPE_INT, 3, NULL);
9292 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9294 caps = gst_caps_new_simple ("audio/x-mace",
9295 "maceversion", G_TYPE_INT, 6, NULL);
9297 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9299 caps = gst_caps_new_simple ("application/ogg", NULL);
9301 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9302 _codec ("DV audio");
9303 caps = gst_caps_new_simple ("audio/x-dv", NULL);
9305 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9306 _codec ("MPEG-4 AAC audio");
9307 caps = gst_caps_new_simple ("audio/mpeg",
9308 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9309 "stream-format", G_TYPE_STRING, "raw", NULL);
9311 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9312 _codec ("QDesign Music");
9313 caps = gst_caps_new_simple ("audio/x-qdm", NULL);
9315 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9316 _codec ("QDesign Music v.2");
9317 /* FIXME: QDesign music version 2 (no constant) */
9319 caps = gst_caps_new_simple ("audio/x-qdm2",
9320 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9321 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9322 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9324 caps = gst_caps_new_simple ("audio/x-qdm2", NULL);
9327 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9328 _codec ("GSM audio");
9329 caps = gst_caps_new_simple ("audio/x-gsm", NULL);
9331 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9332 _codec ("AMR audio");
9333 caps = gst_caps_new_simple ("audio/AMR", NULL);
9335 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9336 _codec ("AMR-WB audio");
9337 caps = gst_caps_new_simple ("audio/AMR-WB", NULL);
9339 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9340 _codec ("Quicktime IMA ADPCM");
9341 caps = gst_caps_new_simple ("audio/x-adpcm",
9342 "layout", G_TYPE_STRING, "quicktime", NULL);
9344 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9345 _codec ("Apple lossless audio");
9346 caps = gst_caps_new_simple ("audio/x-alac", NULL);
9348 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9349 _codec ("QualComm PureVoice");
9350 caps = gst_caps_from_string ("audio/qcelp");
9354 caps = gst_caps_new_simple ("audio/x-wma", NULL);
9356 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
9362 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9363 GST_FOURCC_ARGS (fourcc));
9364 caps = gst_caps_new_simple (s, NULL);
9369 /* enable clipping for raw audio streams */
9370 s = gst_caps_get_structure (caps, 0);
9371 name = gst_structure_get_name (s);
9372 if (g_str_has_prefix (name, "audio/x-raw-")) {
9373 stream->need_clip = TRUE;
9379 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9380 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9384 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9387 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
9388 _codec ("DVD subtitle");
9389 caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
9391 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
9392 _codec ("Quicktime timed text");
9394 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
9395 _codec ("3GPP timed text");
9397 caps = gst_caps_new_simple ("text/plain", NULL);
9398 /* actual text piece needs to be extracted */
9399 stream->need_process = TRUE;
9405 s = g_strdup_printf ("text/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9406 GST_FOURCC_ARGS (fourcc));
9407 caps = gst_caps_new_simple (s, NULL);