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., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, 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-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! 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>
54 #include <gst/audio/audio.h>
56 #include "qtatomparser.h"
57 #include "qtdemux_types.h"
58 #include "qtdemux_dump.h"
59 #include "qtdemux_fourcc.h"
60 #include "qtdemux_lang.h"
62 #include "qtpalette.h"
64 #include "gst/riff/riff-media.h"
65 #include "gst/riff/riff-read.h"
67 #include <gst/pbutils/pbutils.h>
77 /* max. size considered 'sane' for non-mdat atoms */
78 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
80 /* if the sample index is larger than this, something is likely wrong */
81 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
83 /* For converting qt creation times to unix epoch times */
84 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
85 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
86 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
87 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
89 GST_DEBUG_CATEGORY (qtdemux_debug);
91 /*typedef struct _QtNode QtNode; */
92 typedef struct _QtDemuxSegment QtDemuxSegment;
93 typedef struct _QtDemuxSample QtDemuxSample;
102 struct _QtDemuxSample
105 gint32 pts_offset; /* Add this value to timestamp to get the pts */
107 guint64 timestamp; /* DTS In mov time */
108 guint32 duration; /* In mov time */
109 gboolean keyframe; /* TRUE when this packet is a keyframe */
112 /* timestamp is the DTS */
113 #define QTSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
114 GST_SECOND, (stream)->timescale)
115 /* timestamp + offset is the PTS */
116 #define QTSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
117 (sample)->pts_offset, GST_SECOND, (stream)->timescale)
118 /* timestamp + duration - dts is the duration */
119 #define QTSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
120 (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
122 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
125 * Quicktime has tracks and segments. A track is a continuous piece of
126 * multimedia content. The track is not always played from start to finish but
127 * instead, pieces of the track are 'cut out' and played in sequence. This is
128 * what the segments do.
130 * Inside the track we have keyframes (K) and delta frames. The track has its
131 * own timing, which starts from 0 and extends to end. The position in the track
132 * is called the media_time.
134 * The segments now describe the pieces that should be played from this track
135 * and are basically tupples of media_time/duration/rate entries. We can have
136 * multiple segments and they are all played after one another. An example:
138 * segment 1: media_time: 1 second, duration: 1 second, rate 1
139 * segment 2: media_time: 3 second, duration: 2 second, rate 2
141 * To correctly play back this track, one must play: 1 second of media starting
142 * from media_time 1 followed by 2 seconds of media starting from media_time 3
145 * Each of the segments will be played at a specific time, the first segment at
146 * time 0, the second one after the duration of the first one, etc.. Note that
147 * the time in resulting playback is not identical to the media_time of the
150 * Visually, assuming the track has 4 second of media_time:
153 * .-----------------------------------------------------------.
154 * track: | K.....K.........K........K.......K.......K...........K... |
155 * '-----------------------------------------------------------'
157 * .------------^ ^ .----------^ ^
158 * / .-------------' / .------------------'
160 * .--------------. .--------------.
161 * | segment 1 | | segment 2 |
162 * '--------------' '--------------'
164 * The challenge here is to cut out the right pieces of the track for each of
165 * the playback segments. This fortunatly can easily be done with the SEGMENT
166 * events of gstreamer.
168 * For playback of segment 1, we need to provide the decoder with the keyframe
169 * (a), in the above figure, but we must instruct it only to output the decoded
170 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
171 * position set to the time of the segment: 0.
173 * We then proceed to push data from keyframe (a) to frame (b). The decoder
174 * decodes but clips all before media_time 1.
176 * After finishing a segment, we push out a new SEGMENT event with the clipping
177 * boundaries of the new data.
179 * This is a good usecase for the GStreamer accumulated SEGMENT events.
182 struct _QtDemuxSegment
184 /* global time and duration, all gst time */
188 /* media time of trak, all gst time */
194 struct _QtDemuxStream
203 /* if the stream has a redirect URI in its headers, we store it here */
210 guint64 duration; /* in timescale */
214 gchar lang_id[4]; /* ISO 639-2T language code */
218 QtDemuxSample *samples;
219 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
220 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
221 the framerate, in timescale units */
222 guint32 offset_in_sample;
223 guint32 max_buffer_size;
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;
254 gboolean use_allocator;
255 GstAllocator *allocator;
256 GstAllocationParams params;
258 /* when a discontinuity is pending */
261 /* list of buffers to push first */
264 /* if we need to clip this buffer. This is only needed for uncompressed
268 /* buffer needs some custom processing, e.g. subtitles */
269 gboolean need_process;
271 /* current position */
272 guint32 segment_index;
273 guint32 sample_index;
274 guint64 time_position; /* in gst time */
276 /* the Gst segment we are processing out, used for clipping */
279 /* last GstFlowReturn */
280 GstFlowReturn last_ret;
282 /* quicktime segments */
284 QtDemuxSegment *segments;
289 GstTagList *pending_tags;
290 gboolean send_global_tags;
292 GstEvent *pending_event;
302 gboolean chunks_are_chunks;
306 GstByteReader co_chunk;
308 guint32 current_chunk;
310 guint32 samples_per_chunk;
311 guint32 stco_sample_index;
313 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
316 guint32 n_samples_per_chunk;
317 guint32 stsc_chunk_index;
318 guint32 stsc_sample_index;
319 guint64 chunk_offset;
322 guint32 stts_samples;
323 guint32 n_sample_times;
324 guint32 stts_sample_index;
326 guint32 stts_duration;
328 gboolean stss_present;
329 guint32 n_sample_syncs;
332 gboolean stps_present;
333 guint32 n_sample_partial_syncs;
336 gboolean ctts_present;
337 guint32 n_composition_times;
339 guint32 ctts_sample_index;
344 gboolean parsed_trex;
345 guint32 def_sample_duration;
346 guint32 def_sample_size;
347 guint32 def_sample_flags;
352 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
353 QTDEMUX_STATE_HEADER, /* Parsing the header */
354 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
355 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
358 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
359 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
360 guint32 fourcc, GstByteReader * parser);
361 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
362 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
363 guint32 fourcc, GstByteReader * parser);
365 static GstStaticPadTemplate gst_qtdemux_sink_template =
366 GST_STATIC_PAD_TEMPLATE ("sink",
369 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
373 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
374 GST_STATIC_PAD_TEMPLATE ("video_%u",
377 GST_STATIC_CAPS_ANY);
379 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
380 GST_STATIC_PAD_TEMPLATE ("audio_%u",
383 GST_STATIC_CAPS_ANY);
385 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
386 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
389 GST_STATIC_CAPS_ANY);
391 #define gst_qtdemux_parent_class parent_class
392 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
394 static void gst_qtdemux_dispose (GObject * object);
397 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
400 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
401 QtDemuxStream * str, gint64 media_offset);
404 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
405 static GstIndex *gst_qtdemux_get_index (GstElement * element);
407 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
408 GstStateChange transition);
409 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
410 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
411 GstObject * parent, GstPadMode mode, gboolean active);
413 static void gst_qtdemux_loop (GstPad * pad);
414 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
416 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
419 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
420 const guint8 * buffer, guint length);
421 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
422 const guint8 * buffer, guint length);
423 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
425 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
426 QtDemuxStream * stream, GNode * esds, GstTagList * list);
427 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
428 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
429 gchar ** codec_name);
430 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
431 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
432 gchar ** codec_name);
433 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
434 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
435 gchar ** codec_name);
436 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
437 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
438 gchar ** codec_name);
440 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
441 QtDemuxStream * stream, guint32 n);
442 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
445 gst_qtdemux_class_init (GstQTDemuxClass * klass)
447 GObjectClass *gobject_class;
448 GstElementClass *gstelement_class;
450 gobject_class = (GObjectClass *) klass;
451 gstelement_class = (GstElementClass *) klass;
453 parent_class = g_type_class_peek_parent (klass);
455 gobject_class->dispose = gst_qtdemux_dispose;
457 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
459 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
460 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
463 gst_tag_register_musicbrainz_tags ();
465 gst_element_class_add_pad_template (gstelement_class,
466 gst_static_pad_template_get (&gst_qtdemux_sink_template));
467 gst_element_class_add_pad_template (gstelement_class,
468 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
469 gst_element_class_add_pad_template (gstelement_class,
470 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
471 gst_element_class_add_pad_template (gstelement_class,
472 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
473 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
475 "Demultiplex a QuickTime file into audio and video streams",
476 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
478 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
483 gst_qtdemux_init (GstQTDemux * qtdemux)
486 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
487 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
488 gst_pad_set_activatemode_function (qtdemux->sinkpad,
489 qtdemux_sink_activate_mode);
490 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
491 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
492 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
494 qtdemux->state = QTDEMUX_STATE_INITIAL;
495 qtdemux->pullbased = FALSE;
496 qtdemux->posted_redirect = FALSE;
497 qtdemux->neededbytes = 16;
499 qtdemux->adapter = gst_adapter_new ();
501 qtdemux->first_mdat = -1;
502 qtdemux->got_moov = FALSE;
503 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
504 qtdemux->mdatbuffer = NULL;
505 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
507 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
511 gst_qtdemux_dispose (GObject * object)
513 GstQTDemux *qtdemux = GST_QTDEMUX (object);
515 if (qtdemux->adapter) {
516 g_object_unref (G_OBJECT (qtdemux->adapter));
517 qtdemux->adapter = NULL;
520 G_OBJECT_CLASS (parent_class)->dispose (object);
524 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
526 if (qtdemux->posted_redirect) {
527 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
528 (_("This file contains no playable streams.")),
529 ("no known streams found, a redirect message has been posted"));
531 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
532 (_("This file contains no playable streams.")),
533 ("no known streams found"));
538 _gst_buffer_copy_into_mem (GstBuffer * dest, gsize offset, const guint8 * src,
543 g_return_if_fail (gst_buffer_is_writable (dest));
545 bsize = gst_buffer_get_size (dest);
546 g_return_if_fail (bsize >= offset + size);
548 gst_buffer_fill (dest, offset, src, size);
552 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
556 buf = gst_buffer_new ();
557 gst_buffer_append_memory (buf,
558 gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
559 mem, size, 0, size, mem, free_func));
565 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
572 if (G_UNLIKELY (size == 0)) {
574 GstBuffer *tmp = NULL;
576 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
577 if (ret != GST_FLOW_OK)
580 gst_buffer_map (tmp, &map, GST_MAP_READ);
581 size = QT_UINT32 (map.data);
582 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
584 gst_buffer_unmap (tmp, &map);
585 gst_buffer_unref (tmp);
588 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
589 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
590 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
591 /* we're pulling header but already got most interesting bits,
592 * so never mind the rest (e.g. tags) (that much) */
593 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
597 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
598 (_("This file is invalid and cannot be played.")),
599 ("atom has bogus size %" G_GUINT64_FORMAT, size));
600 return GST_FLOW_ERROR;
604 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
606 if (G_UNLIKELY (flow != GST_FLOW_OK))
609 bsize = gst_buffer_get_size (*buf);
610 /* Catch short reads - we don't want any partial atoms */
611 if (G_UNLIKELY (bsize < size)) {
612 GST_WARNING_OBJECT (qtdemux,
613 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
614 gst_buffer_unref (*buf);
624 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
625 GstFormat dest_format, gint64 * dest_value)
628 QtDemuxStream *stream = gst_pad_get_element_private (pad);
629 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
632 if (stream->subtype != FOURCC_vide) {
637 switch (src_format) {
638 case GST_FORMAT_TIME:
639 switch (dest_format) {
640 case GST_FORMAT_BYTES:{
641 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
645 *dest_value = stream->samples[index].offset;
647 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
648 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
649 GST_TIME_ARGS (src_value), *dest_value);
657 case GST_FORMAT_BYTES:
658 switch (dest_format) {
659 case GST_FORMAT_TIME:{
661 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
668 gst_util_uint64_scale (stream->samples[index].timestamp,
669 GST_SECOND, stream->timescale);
670 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
671 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
672 src_value, GST_TIME_ARGS (*dest_value));
685 gst_object_unref (qtdemux);
692 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
696 *duration = GST_CLOCK_TIME_NONE;
698 if (qtdemux->duration != 0) {
699 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
700 *duration = gst_util_uint64_scale (qtdemux->duration,
701 GST_SECOND, qtdemux->timescale);
708 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
711 gboolean res = FALSE;
712 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
714 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
716 switch (GST_QUERY_TYPE (query)) {
717 case GST_QUERY_POSITION:
718 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
719 gst_query_set_position (query, GST_FORMAT_TIME,
720 qtdemux->segment.position);
724 case GST_QUERY_DURATION:{
727 gst_query_parse_duration (query, &fmt, NULL);
728 if (fmt == GST_FORMAT_TIME) {
729 /* First try to query upstream */
730 res = gst_pad_query_default (pad, parent, query);
732 gint64 duration = -1;
734 gst_qtdemux_get_duration (qtdemux, &duration);
736 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
743 case GST_QUERY_CONVERT:{
744 GstFormat src_fmt, dest_fmt;
745 gint64 src_value, dest_value = 0;
747 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
749 res = gst_qtdemux_src_convert (pad,
750 src_fmt, src_value, dest_fmt, &dest_value);
752 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
757 case GST_QUERY_FORMATS:
758 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
761 case GST_QUERY_SEEKING:{
765 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
766 if (fmt == GST_FORMAT_TIME) {
767 gint64 duration = -1;
769 gst_qtdemux_get_duration (qtdemux, &duration);
771 if (!qtdemux->pullbased) {
774 /* we might be able with help from upstream */
776 q = gst_query_new_seeking (GST_FORMAT_BYTES);
777 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
778 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
779 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
783 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
789 res = gst_pad_query_default (pad, parent, query);
797 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
799 if (G_LIKELY (stream->pad)) {
800 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
801 GST_DEBUG_PAD_NAME (stream->pad));
803 if (G_UNLIKELY (stream->pending_tags)) {
804 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
805 stream->pending_tags);
806 gst_pad_push_event (stream->pad,
807 gst_event_new_tag (stream->pending_tags));
808 stream->pending_tags = NULL;
811 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
812 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
814 gst_pad_push_event (stream->pad,
815 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
816 stream->send_global_tags = FALSE;
821 /* push event on all source pads; takes ownership of the event */
823 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
826 gboolean has_valid_stream = FALSE;
827 GstEventType etype = GST_EVENT_TYPE (event);
829 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
830 GST_EVENT_TYPE_NAME (event));
832 for (n = 0; n < qtdemux->n_streams; n++) {
834 QtDemuxStream *stream = qtdemux->streams[n];
836 if ((pad = stream->pad)) {
837 has_valid_stream = TRUE;
839 if (etype == GST_EVENT_EOS) {
840 /* let's not send twice */
841 if (stream->sent_eos)
843 stream->sent_eos = TRUE;
846 gst_pad_push_event (pad, gst_event_ref (event));
850 gst_event_unref (event);
852 /* if it is EOS and there are no pads, post an error */
853 if (!has_valid_stream && etype == GST_EVENT_EOS) {
854 gst_qtdemux_post_no_playable_stream_error (qtdemux);
858 /* push a pending newsegment event, if any from the streaming thread */
860 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
862 if (qtdemux->pending_newsegment) {
863 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
864 qtdemux->pending_newsegment = NULL;
874 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
876 if (s1->timestamp > *media_time)
882 /* find the index of the sample that includes the data for @media_time using a
883 * binary search. Only to be called in optimized cases of linear search below.
885 * Returns the index of the sample.
888 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
891 QtDemuxSample *result;
894 /* convert media_time to mov format */
896 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
898 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
899 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
900 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
902 if (G_LIKELY (result))
903 index = result - str->samples;
912 /* find the index of the sample that includes the data for @media_offset using a
915 * Returns the index of the sample.
918 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
919 QtDemuxStream * str, gint64 media_offset)
921 QtDemuxSample *result = str->samples;
924 if (result == NULL || str->n_samples == 0)
927 if (media_offset == result->offset)
931 while (index < str->n_samples - 1) {
932 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
935 if (media_offset < result->offset)
946 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
951 /* find the index of the sample that includes the data for @media_time using a
952 * linear search, and keeping in mind that not all samples may have been parsed
953 * yet. If possible, it will delegate to binary search.
955 * Returns the index of the sample.
958 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
964 /* convert media_time to mov format */
966 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
968 if (mov_time == str->samples[0].timestamp)
971 /* use faster search if requested time in already parsed range */
972 if (str->stbl_index >= 0 &&
973 mov_time <= str->samples[str->stbl_index].timestamp)
974 return gst_qtdemux_find_index (qtdemux, str, media_time);
976 while (index < str->n_samples - 1) {
977 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
980 if (mov_time < str->samples[index + 1].timestamp)
990 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
995 /* find the index of the keyframe needed to decode the sample at @index
998 * Returns the index of the keyframe.
1001 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1004 guint32 new_index = index;
1006 if (index >= str->n_samples) {
1007 new_index = str->n_samples;
1011 /* all keyframes, return index */
1012 if (str->all_keyframe) {
1017 /* else go back until we have a keyframe */
1019 if (str->samples[new_index].keyframe)
1029 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1030 "gave %u", index, new_index);
1035 /* find the segment for @time_position for @stream
1037 * Returns -1 if the segment cannot be found.
1040 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1041 guint64 time_position)
1046 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1047 GST_TIME_ARGS (time_position));
1049 /* find segment corresponding to time_position if we are looking
1052 for (i = 0; i < stream->n_segments; i++) {
1053 QtDemuxSegment *segment = &stream->segments[i];
1055 GST_LOG_OBJECT (qtdemux,
1056 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1057 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1059 /* For the last segment we include stop_time in the last segment */
1060 if (i < stream->n_segments - 1) {
1061 if (segment->time <= time_position && time_position < segment->stop_time) {
1062 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1067 if (segment->time <= time_position && time_position <= segment->stop_time) {
1068 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1077 /* move the stream @str to the sample position @index.
1079 * Updates @str->sample_index and marks discontinuity if needed.
1082 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1085 /* no change needed */
1086 if (index == str->sample_index)
1089 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1092 /* position changed, we have a discont */
1093 str->sample_index = index;
1094 str->offset_in_sample = 0;
1095 /* Each time we move in the stream we store the position where we are
1097 str->from_sample = index;
1098 str->discont = TRUE;
1102 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1103 gint64 * key_time, gint64 * key_offset)
1106 gint64 min_byte_offset = -1;
1109 min_offset = desired_time;
1111 /* for each stream, find the index of the sample in the segment
1112 * and move back to the previous keyframe. */
1113 for (n = 0; n < qtdemux->n_streams; n++) {
1115 guint32 index, kindex;
1117 guint64 media_start;
1120 QtDemuxSegment *seg;
1122 str = qtdemux->streams[n];
1124 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1125 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1127 /* segment not found, continue with normal flow */
1131 /* get segment and time in the segment */
1132 seg = &str->segments[seg_idx];
1133 seg_time = desired_time - seg->time;
1135 /* get the media time in the segment */
1136 media_start = seg->media_start + seg_time;
1138 /* get the index of the sample with media time */
1139 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1140 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1141 " at offset %" G_GUINT64_FORMAT,
1142 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1144 /* find previous keyframe */
1145 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1147 /* if the keyframe is at a different position, we need to update the
1148 * requested seek time */
1149 if (index != kindex) {
1152 /* get timestamp of keyframe */
1154 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1156 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT
1157 " at offset %" G_GUINT64_FORMAT,
1158 kindex, GST_TIME_ARGS (media_time), str->samples[kindex].offset);
1160 /* keyframes in the segment get a chance to change the
1161 * desired_offset. keyframes out of the segment are
1163 if (media_time >= seg->media_start) {
1166 /* this keyframe is inside the segment, convert back to
1168 seg_time = (media_time - seg->media_start) + seg->time;
1169 if (seg_time < min_offset)
1170 min_offset = seg_time;
1174 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1175 min_byte_offset = str->samples[index].offset;
1179 *key_time = min_offset;
1181 *key_offset = min_byte_offset;
1185 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1186 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1190 g_return_val_if_fail (format != NULL, FALSE);
1191 g_return_val_if_fail (cur != NULL, FALSE);
1192 g_return_val_if_fail (stop != NULL, FALSE);
1194 if (*format == GST_FORMAT_TIME)
1198 if (cur_type != GST_SEEK_TYPE_NONE)
1199 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1200 if (res && stop_type != GST_SEEK_TYPE_NONE)
1201 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1204 *format = GST_FORMAT_TIME;
1209 /* perform seek in push based mode:
1210 find BYTE position to move to based on time and delegate to upstream
1213 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1218 GstSeekType cur_type, stop_type;
1223 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1225 gst_event_parse_seek (event, &rate, &format, &flags,
1226 &cur_type, &cur, &stop_type, &stop);
1228 /* FIXME, always play to the end */
1231 /* only forward streaming and seeking is possible */
1233 goto unsupported_seek;
1235 /* convert to TIME if needed and possible */
1236 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1240 /* find reasonable corresponding BYTE position,
1241 * also try to mind about keyframes, since we can not go back a bit for them
1243 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1248 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1249 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1252 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1253 GST_DEBUG_OBJECT (qtdemux,
1254 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1255 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1256 GST_OBJECT_LOCK (qtdemux);
1257 qtdemux->requested_seek_time = cur;
1258 qtdemux->seek_offset = byte_cur;
1259 GST_OBJECT_UNLOCK (qtdemux);
1262 /* BYTE seek event */
1263 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1265 res = gst_pad_push_event (qtdemux->sinkpad, event);
1272 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1278 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1283 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1288 /* perform the seek.
1290 * We set all segment_indexes in the streams to unknown and
1291 * adjust the time_position to the desired position. this is enough
1292 * to trigger a segment switch in the streaming thread to start
1293 * streaming from the desired position.
1295 * Keyframe seeking is a little more complicated when dealing with
1296 * segments. Ideally we want to move to the previous keyframe in
1297 * the segment but there might not be a keyframe in the segment. In
1298 * fact, none of the segments could contain a keyframe. We take a
1299 * practical approach: seek to the previous keyframe in the segment,
1300 * if there is none, seek to the beginning of the segment.
1302 * Called with STREAM_LOCK
1305 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1307 gint64 desired_offset;
1310 desired_offset = segment->position;
1312 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1313 GST_TIME_ARGS (desired_offset));
1315 /* may not have enough fragmented info to do this adjustment,
1316 * and we can't scan (and probably should not) at this time with
1317 * possibly flushing upstream */
1318 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1321 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1322 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1323 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1324 desired_offset = min_offset;
1327 /* and set all streams to the final position */
1328 for (n = 0; n < qtdemux->n_streams; n++) {
1329 QtDemuxStream *stream = qtdemux->streams[n];
1331 stream->time_position = desired_offset;
1332 stream->sample_index = -1;
1333 stream->offset_in_sample = 0;
1334 stream->segment_index = -1;
1335 stream->last_ret = GST_FLOW_OK;
1336 stream->sent_eos = FALSE;
1338 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1339 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1341 segment->position = desired_offset;
1342 segment->time = desired_offset;
1344 /* we stop at the end */
1345 if (segment->stop == -1)
1346 segment->stop = segment->duration;
1351 /* do a seek in pull based mode */
1353 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1358 GstSeekType cur_type, stop_type;
1362 GstSegment seeksegment;
1366 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1368 gst_event_parse_seek (event, &rate, &format, &flags,
1369 &cur_type, &cur, &stop_type, &stop);
1371 /* we have to have a format as the segment format. Try to convert
1373 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1377 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1379 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1383 flush = flags & GST_SEEK_FLAG_FLUSH;
1385 /* stop streaming, either by flushing or by pausing the task */
1387 /* unlock upstream pull_range */
1388 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1389 /* make sure out loop function exits */
1390 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1392 /* non flushing seek, pause the task */
1393 gst_pad_pause_task (qtdemux->sinkpad);
1396 /* wait for streaming to finish */
1397 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1399 /* copy segment, we need this because we still need the old
1400 * segment when we close the current segment. */
1401 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1404 /* configure the segment with the seek variables */
1405 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1406 gst_segment_do_seek (&seeksegment, rate, format, flags,
1407 cur_type, cur, stop_type, stop, &update);
1410 /* now do the seek, this actually never returns FALSE */
1411 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1413 /* prepare for streaming again */
1415 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop (TRUE));
1416 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop (TRUE));
1419 /* commit the new segment */
1420 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1422 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1423 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1424 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1425 qtdemux->segment.format, qtdemux->segment.position));
1428 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1429 for (i = 0; i < qtdemux->n_streams; i++)
1430 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1432 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1433 qtdemux->sinkpad, NULL);
1435 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1442 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1448 qtdemux_ensure_index (GstQTDemux * qtdemux)
1452 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1454 /* Build complete index */
1455 for (i = 0; i < qtdemux->n_streams; i++) {
1456 QtDemuxStream *stream = qtdemux->streams[i];
1458 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1466 GST_LOG_OBJECT (qtdemux,
1467 "Building complete index of stream %u for seeking failed!", i);
1473 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1476 gboolean res = TRUE;
1477 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1479 switch (GST_EVENT_TYPE (event)) {
1480 case GST_EVENT_SEEK:
1482 #ifndef GST_DISABLE_GST_DEBUG
1483 GstClockTime ts = gst_util_get_timestamp ();
1485 /* Build complete index for seeking;
1486 * if not a fragmented file at least */
1487 if (!qtdemux->fragmented)
1488 if (!qtdemux_ensure_index (qtdemux))
1490 #ifndef GST_DISABLE_GST_DEBUG
1491 ts = gst_util_get_timestamp () - ts;
1492 GST_INFO_OBJECT (qtdemux,
1493 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1496 if (qtdemux->pullbased) {
1497 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1498 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1499 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1501 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1502 && !qtdemux->fragmented) {
1503 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1505 GST_DEBUG_OBJECT (qtdemux,
1506 "ignoring seek in push mode in current state");
1509 gst_event_unref (event);
1512 case GST_EVENT_NAVIGATION:
1514 gst_event_unref (event);
1517 res = gst_pad_event_default (pad, parent, event);
1527 GST_ERROR_OBJECT (qtdemux, "Index failed");
1528 gst_event_unref (event);
1534 /* stream/index return sample that is min/max w.r.t. byte position,
1535 * time is min/max w.r.t. time of samples,
1536 * the latter need not be time of the former sample */
1538 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1539 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1542 gint64 time, min_time;
1543 QtDemuxStream *stream;
1549 for (n = 0; n < qtdemux->n_streams; ++n) {
1552 gboolean set_sample;
1554 str = qtdemux->streams[n];
1561 i = str->n_samples - 1;
1564 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1565 if (str->samples[i].size &&
1566 ((fw && (str->samples[i].offset >= byte_pos)) ||
1568 (str->samples[i].offset + str->samples[i].size <=
1570 /* move stream to first available sample */
1572 gst_qtdemux_move_stream (qtdemux, str, i);
1575 /* determine min/max time */
1576 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1577 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1578 if (min_time == -1 || (!fw && time > min_time) ||
1579 (fw && time < min_time)) {
1582 /* determine stream with leading sample, to get its position */
1584 && (str->samples[i].offset < stream->samples[index].offset))
1586 && (str->samples[i].offset > stream->samples[index].offset))) {
1593 /* no sample for this stream, mark eos */
1595 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1607 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1610 GstQTDemux *demux = GST_QTDEMUX (parent);
1613 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1615 switch (GST_EVENT_TYPE (event)) {
1616 case GST_EVENT_SEGMENT:
1619 QtDemuxStream *stream;
1623 /* some debug output */
1624 gst_event_copy_segment (event, &segment);
1625 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1628 /* chain will send initial newsegment after pads have been added */
1629 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1630 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1634 /* we only expect a BYTE segment, e.g. following a seek */
1635 if (segment.format == GST_FORMAT_BYTES) {
1636 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1637 gint64 requested_seek_time;
1638 guint64 seek_offset;
1640 offset = segment.start;
1642 GST_OBJECT_LOCK (demux);
1643 requested_seek_time = demux->requested_seek_time;
1644 seek_offset = demux->seek_offset;
1645 demux->requested_seek_time = -1;
1646 demux->seek_offset = -1;
1647 GST_OBJECT_UNLOCK (demux);
1649 if (offset == seek_offset) {
1650 segment.start = requested_seek_time;
1652 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1653 NULL, (gint64 *) & segment.start);
1654 if ((gint64) segment.start < 0)
1658 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1659 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1660 NULL, (gint64 *) & segment.stop);
1661 /* keyframe seeking should already arrange for start >= stop,
1662 * but make sure in other rare cases */
1663 segment.stop = MAX (segment.stop, segment.start);
1666 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1670 /* accept upstream's notion of segment and distribute along */
1671 segment.format = GST_FORMAT_TIME;
1672 segment.position = segment.time = segment.start;
1673 segment.duration = demux->segment.duration;
1674 segment.base = gst_segment_to_running_time (&demux->segment,
1675 GST_FORMAT_TIME, demux->segment.position);
1677 gst_segment_copy_into (&segment, &demux->segment);
1678 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
1679 gst_qtdemux_push_event (demux, gst_event_new_segment (&segment));
1681 /* clear leftover in current segment, if any */
1682 gst_adapter_clear (demux->adapter);
1683 /* set up streaming thread */
1684 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1685 demux->offset = offset;
1687 demux->todrop = stream->samples[idx].offset - offset;
1688 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1690 /* set up for EOS */
1691 demux->neededbytes = -1;
1695 gst_event_unref (event);
1700 case GST_EVENT_FLUSH_STOP:
1705 /* clean up, force EOS if no more info follows */
1706 gst_adapter_clear (demux->adapter);
1708 demux->neededbytes = -1;
1709 /* reset flow return, e.g. following seek */
1710 for (i = 0; i < demux->n_streams; i++) {
1711 demux->streams[i]->last_ret = GST_FLOW_OK;
1712 demux->streams[i]->sent_eos = FALSE;
1714 dur = demux->segment.duration;
1715 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1716 demux->segment.duration = dur;
1720 /* If we are in push mode, and get an EOS before we've seen any streams,
1721 * then error out - we have nowhere to send the EOS */
1722 if (!demux->pullbased) {
1724 gboolean has_valid_stream = FALSE;
1725 for (i = 0; i < demux->n_streams; i++) {
1726 if (demux->streams[i]->pad != NULL) {
1727 has_valid_stream = TRUE;
1731 if (!has_valid_stream)
1732 gst_qtdemux_post_no_playable_stream_error (demux);
1739 res = gst_pad_event_default (demux->sinkpad, parent, event);
1747 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1749 GstQTDemux *demux = GST_QTDEMUX (element);
1751 GST_OBJECT_LOCK (demux);
1752 if (demux->element_index)
1753 gst_object_unref (demux->element_index);
1755 demux->element_index = gst_object_ref (index);
1757 demux->element_index = NULL;
1759 GST_OBJECT_UNLOCK (demux);
1760 /* object lock might be taken again */
1762 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1763 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
1764 demux->element_index, demux->index_id);
1768 gst_qtdemux_get_index (GstElement * element)
1770 GstIndex *result = NULL;
1771 GstQTDemux *demux = GST_QTDEMUX (element);
1773 GST_OBJECT_LOCK (demux);
1774 if (demux->element_index)
1775 result = gst_object_ref (demux->element_index);
1776 GST_OBJECT_UNLOCK (demux);
1778 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1785 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1787 g_free ((gpointer) stream->stco.data);
1788 stream->stco.data = NULL;
1789 g_free ((gpointer) stream->stsz.data);
1790 stream->stsz.data = NULL;
1791 g_free ((gpointer) stream->stsc.data);
1792 stream->stsc.data = NULL;
1793 g_free ((gpointer) stream->stts.data);
1794 stream->stts.data = NULL;
1795 g_free ((gpointer) stream->stss.data);
1796 stream->stss.data = NULL;
1797 g_free ((gpointer) stream->stps.data);
1798 stream->stps.data = NULL;
1799 g_free ((gpointer) stream->ctts.data);
1800 stream->ctts.data = NULL;
1804 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
1806 if (stream->allocator)
1807 gst_object_unref (stream->allocator);
1808 while (stream->buffers) {
1809 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1810 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1813 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
1814 g_free (stream->samples);
1816 gst_caps_unref (stream->caps);
1817 g_free (stream->segments);
1818 if (stream->pending_tags)
1819 gst_tag_list_unref (stream->pending_tags);
1820 g_free (stream->redirect_uri);
1821 /* free stbl sub-atoms */
1822 gst_qtdemux_stbl_free (stream);
1826 static GstStateChangeReturn
1827 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1829 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1830 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1832 switch (transition) {
1833 case GST_STATE_CHANGE_PAUSED_TO_READY:
1839 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1841 switch (transition) {
1842 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1845 qtdemux->state = QTDEMUX_STATE_INITIAL;
1846 qtdemux->neededbytes = 16;
1847 qtdemux->todrop = 0;
1848 qtdemux->pullbased = FALSE;
1849 qtdemux->posted_redirect = FALSE;
1850 qtdemux->offset = 0;
1851 qtdemux->first_mdat = -1;
1852 qtdemux->header_size = 0;
1853 qtdemux->got_moov = FALSE;
1854 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1855 if (qtdemux->mdatbuffer)
1856 gst_buffer_unref (qtdemux->mdatbuffer);
1857 qtdemux->mdatbuffer = NULL;
1858 if (qtdemux->comp_brands)
1859 gst_buffer_unref (qtdemux->comp_brands);
1860 qtdemux->comp_brands = NULL;
1861 if (qtdemux->tag_list)
1862 gst_tag_list_unref (qtdemux->tag_list);
1863 qtdemux->tag_list = NULL;
1865 if (qtdemux->element_index)
1866 gst_object_unref (qtdemux->element_index);
1867 qtdemux->element_index = NULL;
1869 gst_adapter_clear (qtdemux->adapter);
1870 for (n = 0; n < qtdemux->n_streams; n++) {
1871 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1872 qtdemux->streams[n] = NULL;
1874 qtdemux->major_brand = 0;
1875 qtdemux->n_streams = 0;
1876 qtdemux->n_video_streams = 0;
1877 qtdemux->n_audio_streams = 0;
1878 qtdemux->n_sub_streams = 0;
1879 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1880 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1881 qtdemux->seek_offset = 0;
1882 qtdemux->upstream_seekable = FALSE;
1883 qtdemux->upstream_size = 0;
1894 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1896 /* counts as header data */
1897 qtdemux->header_size += length;
1899 /* only consider at least a sufficiently complete ftyp atom */
1903 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1904 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1905 GST_FOURCC_ARGS (qtdemux->major_brand));
1906 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1907 _gst_buffer_copy_into_mem (buf, 0, buffer + 16, length - 16);
1912 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
1914 /* Strip out bogus fields */
1916 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
1918 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
1920 if (qtdemux->tag_list) {
1921 /* prioritize native tags using _KEEP mode */
1922 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
1923 gst_tag_list_unref (taglist);
1925 qtdemux->tag_list = taglist;
1930 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1932 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
1933 0x97, 0xA9, 0x42, 0xE8,
1934 0x9C, 0x71, 0x99, 0x94,
1935 0x91, 0xE3, 0xAF, 0xAC
1939 /* counts as header data */
1940 qtdemux->header_size += length;
1942 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
1944 if (length <= offset + 16) {
1945 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
1949 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
1951 GstTagList *taglist;
1953 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
1954 length - offset - 16, NULL);
1955 taglist = gst_tag_list_from_xmp_buffer (buf);
1956 gst_buffer_unref (buf);
1958 qtdemux_handle_xmp_taglist (qtdemux, taglist);
1961 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
1965 /* caller verifies at least 8 bytes in buf */
1967 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1968 guint64 * plength, guint32 * pfourcc)
1973 length = QT_UINT32 (data);
1974 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1975 fourcc = QT_FOURCC (data + 4);
1976 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1979 length = G_MAXUINT32;
1980 } else if (length == 1 && size >= 16) {
1981 /* this means we have an extended size, which is the 64 bit value of
1982 * the next 8 bytes */
1983 length = QT_UINT64 (data + 8);
1984 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1994 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
1996 guint32 version = 0;
1997 guint64 duration = 0;
1999 if (!gst_byte_reader_get_uint32_be (br, &version))
2004 if (!gst_byte_reader_get_uint64_be (br, &duration))
2009 if (!gst_byte_reader_get_uint32_be (br, &dur))
2014 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2015 qtdemux->duration = duration;
2021 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2027 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2028 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2030 if (!stream->parsed_trex && qtdemux->moov_node) {
2032 GstByteReader trex_data;
2034 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2036 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2039 guint32 id = 0, dur = 0, size = 0, flags = 0;
2041 /* skip version/flags */
2042 if (!gst_byte_reader_skip (&trex_data, 4))
2044 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2046 if (id != stream->track_id)
2048 /* sample description index; ignore */
2049 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2051 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2053 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2055 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2058 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2059 "duration %d, size %d, flags 0x%x", stream->track_id,
2062 stream->parsed_trex = TRUE;
2063 stream->def_sample_duration = dur;
2064 stream->def_sample_size = size;
2065 stream->def_sample_flags = flags;
2068 /* iterate all siblings */
2069 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2075 *ds_duration = stream->def_sample_duration;
2076 *ds_size = stream->def_sample_size;
2077 *ds_size = stream->def_sample_size;
2079 /* even then, above values are better than random ... */
2080 if (G_UNLIKELY (!stream->parsed_trex)) {
2081 GST_WARNING_OBJECT (qtdemux,
2082 "failed to find fragment defaults for stream %d", stream->track_id);
2090 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2091 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2092 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2093 gint64 * base_offset, gint64 * running_offset)
2096 gint32 data_offset = 0;
2097 guint32 flags = 0, first_flags = 0, samples_count = 0;
2100 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2101 QtDemuxSample *sample;
2102 gboolean ismv = FALSE;
2104 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2105 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2106 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2109 /* presence of stss or not can't really tell us much,
2110 * and flags and so on tend to be marginally reliable in these files */
2111 if (stream->subtype == FOURCC_soun) {
2112 GST_DEBUG_OBJECT (qtdemux,
2113 "sound track in fragmented file; marking all keyframes");
2114 stream->all_keyframe = TRUE;
2117 if (!gst_byte_reader_skip (trun, 1) ||
2118 !gst_byte_reader_get_uint24_be (trun, &flags))
2121 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2124 if (flags & TR_DATA_OFFSET) {
2125 /* note this is really signed */
2126 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2128 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2129 /* default base offset = first byte of moof */
2130 if (*base_offset == -1) {
2131 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2132 *base_offset = moof_offset;
2134 *running_offset = *base_offset + data_offset;
2136 /* if no offset at all, that would mean data starts at moof start,
2137 * which is a bit wrong and is ismv crappy way, so compensate
2138 * assuming data is in mdat following moof */
2139 if (*base_offset == -1) {
2140 *base_offset = moof_offset + moof_length + 8;
2141 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2144 if (*running_offset == -1)
2145 *running_offset = *base_offset;
2148 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2150 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2151 data_offset, flags, samples_count);
2153 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2154 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2155 GST_DEBUG_OBJECT (qtdemux,
2156 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2157 flags ^= TR_FIRST_SAMPLE_FLAGS;
2159 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2161 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2165 /* FIXME ? spec says other bits should also be checked to determine
2166 * entry size (and prefix size for that matter) */
2168 dur_offset = size_offset = 0;
2169 if (flags & TR_SAMPLE_DURATION) {
2170 GST_LOG_OBJECT (qtdemux, "entry duration present");
2171 dur_offset = entry_size;
2174 if (flags & TR_SAMPLE_SIZE) {
2175 GST_LOG_OBJECT (qtdemux, "entry size present");
2176 size_offset = entry_size;
2179 if (flags & TR_SAMPLE_FLAGS) {
2180 GST_LOG_OBJECT (qtdemux, "entry flags present");
2181 flags_offset = entry_size;
2184 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2185 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2186 ct_offset = entry_size;
2190 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2192 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2194 if (stream->n_samples >=
2195 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2198 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2199 stream->n_samples, (guint) sizeof (QtDemuxSample),
2200 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2202 /* create a new array of samples if it's the first sample parsed */
2203 if (stream->n_samples == 0)
2204 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2205 /* or try to reallocate it with space enough to insert the new samples */
2207 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2208 stream->n_samples + samples_count);
2209 if (stream->samples == NULL)
2212 if (G_UNLIKELY (stream->n_samples == 0)) {
2213 /* the timestamp of the first sample is also provided by the tfra entry
2214 * but we shouldn't rely on it as it is at the end of files */
2217 /* subsequent fragments extend stream */
2219 stream->samples[stream->n_samples - 1].timestamp +
2220 stream->samples[stream->n_samples - 1].duration;
2222 sample = stream->samples + stream->n_samples;
2223 for (i = 0; i < samples_count; i++) {
2224 guint32 dur, size, sflags, ct;
2226 /* first read sample data */
2227 if (flags & TR_SAMPLE_DURATION) {
2228 dur = QT_UINT32 (data + dur_offset);
2230 dur = d_sample_duration;
2232 if (flags & TR_SAMPLE_SIZE) {
2233 size = QT_UINT32 (data + size_offset);
2235 size = d_sample_size;
2237 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2239 sflags = first_flags;
2241 sflags = d_sample_flags;
2243 } else if (flags & TR_SAMPLE_FLAGS) {
2244 sflags = QT_UINT32 (data + flags_offset);
2246 sflags = d_sample_flags;
2248 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2249 ct = QT_UINT32 (data + ct_offset);
2255 /* fill the sample information */
2256 sample->offset = *running_offset;
2257 sample->pts_offset = ct;
2258 sample->size = size;
2259 sample->timestamp = timestamp;
2260 sample->duration = dur;
2261 /* sample-is-difference-sample */
2262 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2263 * now idea how it relates to bitfield other than massive LE/BE confusion */
2264 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2265 *running_offset += size;
2270 stream->n_samples += samples_count;
2276 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2281 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2287 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2288 "be larger than %uMB (broken file?)", stream->n_samples,
2289 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2294 /* find stream with @id */
2295 static inline QtDemuxStream *
2296 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2298 QtDemuxStream *stream;
2302 if (G_UNLIKELY (!id)) {
2303 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2307 /* try to get it fast and simple */
2308 if (G_LIKELY (id <= qtdemux->n_streams)) {
2309 stream = qtdemux->streams[id - 1];
2310 if (G_LIKELY (stream->track_id == id))
2314 /* linear search otherwise */
2315 for (i = 0; i < qtdemux->n_streams; i++) {
2316 stream = qtdemux->streams[i];
2317 if (stream->track_id == id)
2325 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2326 QtDemuxStream ** stream, guint32 * default_sample_duration,
2327 guint32 * default_sample_size, guint32 * default_sample_flags,
2328 gint64 * base_offset)
2331 guint32 track_id = 0;
2333 if (!gst_byte_reader_skip (tfhd, 1) ||
2334 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2337 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2340 *stream = qtdemux_find_stream (qtdemux, track_id);
2341 if (G_UNLIKELY (!*stream))
2342 goto unknown_stream;
2344 if (flags & TF_BASE_DATA_OFFSET)
2345 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2348 /* obtain stream defaults */
2349 qtdemux_parse_trex (qtdemux, *stream,
2350 default_sample_duration, default_sample_size, default_sample_flags);
2352 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2353 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2354 if (!gst_byte_reader_skip (tfhd, 4))
2357 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2358 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2361 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2362 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2365 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2366 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2373 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2378 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2384 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
2385 guint64 * decode_time)
2387 guint32 version = 0;
2389 if (!gst_byte_reader_get_uint32_be (br, &version))
2394 if (!gst_byte_reader_get_uint64_be (br, decode_time))
2397 guint32 dec_time = 0;
2398 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
2400 *decode_time = dec_time;
2403 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
2410 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
2416 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2417 guint64 moof_offset, QtDemuxStream * stream)
2419 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node;
2420 GstByteReader trun_data, tfhd_data, tfdt_data;
2421 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2422 gint64 base_offset, running_offset;
2424 /* NOTE @stream ignored */
2426 moof_node = g_node_new ((guint8 *) buffer);
2427 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2428 qtdemux_node_dump (qtdemux, moof_node);
2430 /* unknown base_offset to start with */
2431 base_offset = running_offset = -1;
2432 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2434 /* Fragment Header node */
2436 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2440 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2441 &ds_size, &ds_flags, &base_offset))
2444 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
2447 guint64 decode_time = 0;
2448 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
2449 /* If there is a new segment pending, update the time/position */
2450 if (qtdemux->pending_newsegment) {
2453 gst_segment_init (&segment, GST_FORMAT_TIME);
2454 segment.time = gst_util_uint64_scale (decode_time,
2455 GST_SECOND, stream->timescale);
2456 gst_event_replace (&qtdemux->pending_newsegment,
2457 gst_event_new_segment (&segment));
2458 /* ref added when replaced, release the original _new one */
2459 gst_event_unref (qtdemux->pending_newsegment);
2463 if (G_UNLIKELY (!stream)) {
2464 /* we lost track of offset, we'll need to regain it,
2465 * but can delay complaining until later or avoid doing so altogether */
2469 if (G_UNLIKELY (base_offset < -1))
2471 /* Track Run node */
2473 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2476 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2477 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2479 /* iterate all siblings */
2480 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2483 /* if no new base_offset provided for next traf,
2484 * base is end of current traf */
2485 base_offset = running_offset;
2486 running_offset = -1;
2488 /* iterate all siblings */
2489 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2491 g_node_destroy (moof_node);
2496 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2501 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2506 g_node_destroy (moof_node);
2507 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2508 (_("This file is corrupt and cannot be played.")), (NULL));
2513 /* might be used if some day we actually use mfra & co
2514 * for random access to fragments,
2515 * but that will require quite some modifications and much less relying
2516 * on a sample array */
2519 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2520 QtDemuxStream * stream)
2522 guint64 time = 0, moof_offset = 0;
2523 guint32 ver_flags, track_id, len, num_entries, i;
2524 guint value_size, traf_size, trun_size, sample_size;
2525 GstBuffer *buf = NULL;
2529 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2530 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2532 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2535 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2536 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2537 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2540 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2541 track_id, stream->track_id);
2542 if (track_id != stream->track_id) {
2546 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2547 sample_size = (len & 3) + 1;
2548 trun_size = ((len & 12) >> 2) + 1;
2549 traf_size = ((len & 48) >> 4) + 1;
2551 if (num_entries == 0)
2554 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2555 value_size + value_size + traf_size + trun_size + sample_size))
2558 for (i = 0; i < num_entries; i++) {
2559 qt_atom_parser_get_offset (&tfra, value_size, &time);
2560 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2561 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2562 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2563 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2565 GST_LOG_OBJECT (qtdemux,
2566 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2567 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2568 stream->timescale)), moof_offset);
2570 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2571 if (ret != GST_FLOW_OK)
2573 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2574 moof_offset, stream);
2575 gst_buffer_unref (buf);
2583 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2584 (_("This file is corrupt and cannot be played.")), (NULL));
2589 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2595 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2598 GNode *mfra_node, *tfra_node;
2601 if (!qtdemux->mfra_offset)
2604 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2605 if (ret != GST_FLOW_OK)
2608 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2609 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2610 GST_BUFFER_SIZE (buffer));
2612 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2615 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2616 /* iterate all siblings */
2617 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2619 g_node_destroy (mfra_node);
2620 gst_buffer_unref (buffer);
2626 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2627 (_("This file is corrupt and cannot be played.")), (NULL));
2632 static GstFlowReturn
2633 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2634 guint32 * mfro_size)
2636 GstFlowReturn ret = GST_FLOW_ERROR;
2637 GstBuffer *mfro = NULL;
2640 GstFormat fmt = GST_FORMAT_BYTES;
2642 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, &fmt, &len)) {
2643 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2644 "can not locate mfro");
2648 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2649 if (ret != GST_FLOW_OK)
2652 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2653 if (fourcc != FOURCC_mfro)
2656 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2657 if (GST_BUFFER_SIZE (mfro) >= 16) {
2658 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
2659 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
2660 if (*mfro_size >= len) {
2661 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
2662 ret = GST_FLOW_ERROR;
2665 *mfra_offset = len - *mfro_size;
2670 gst_buffer_unref (mfro);
2676 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
2679 guint32 mfra_size = 0;
2680 guint64 mfra_offset = 0;
2683 qtdemux->fragmented = FALSE;
2685 /* We check here if it is a fragmented mp4 container */
2686 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
2687 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
2688 qtdemux->fragmented = TRUE;
2689 GST_DEBUG_OBJECT (qtdemux,
2690 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
2691 qtdemux->mfra_offset = mfra_offset;
2696 static GstFlowReturn
2697 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
2701 GstBuffer *buf = NULL;
2702 GstFlowReturn ret = GST_FLOW_OK;
2703 guint64 cur_offset = qtdemux->offset;
2706 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
2707 if (G_UNLIKELY (ret != GST_FLOW_OK))
2709 gst_buffer_map (buf, &map, GST_MAP_READ);
2710 if (G_LIKELY (map.size >= 8))
2711 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
2712 gst_buffer_unmap (buf, &map);
2713 gst_buffer_unref (buf);
2715 /* maybe we already got most we needed, so only consider this eof */
2716 if (G_UNLIKELY (length == 0)) {
2717 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
2718 (_("Invalid atom size.")),
2719 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
2720 GST_FOURCC_ARGS (fourcc)));
2727 /* record for later parsing when needed */
2728 if (!qtdemux->moof_offset) {
2729 qtdemux->moof_offset = qtdemux->offset;
2738 GST_LOG_OBJECT (qtdemux,
2739 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
2740 GST_FOURCC_ARGS (fourcc), cur_offset);
2741 qtdemux->offset += length;
2746 GstBuffer *moov = NULL;
2748 if (qtdemux->got_moov) {
2749 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
2750 qtdemux->offset += length;
2754 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
2755 if (ret != GST_FLOW_OK)
2757 gst_buffer_map (moov, &map, GST_MAP_READ);
2759 if (length != map.size) {
2760 /* Some files have a 'moov' atom at the end of the file which contains
2761 * a terminal 'free' atom where the body of the atom is missing.
2762 * Check for, and permit, this special case.
2764 if (map.size >= 8) {
2765 guint8 *final_data = map.data + (map.size - 8);
2766 guint32 final_length = QT_UINT32 (final_data);
2767 guint32 final_fourcc = QT_FOURCC (final_data + 4);
2769 if (final_fourcc == FOURCC_free
2770 && map.size + final_length - 8 == length) {
2771 /* Ok, we've found that special case. Allocate a new buffer with
2772 * that free atom actually present. */
2773 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
2774 gst_buffer_fill (newmoov, 0, map.data, map.size);
2775 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
2776 gst_buffer_unmap (moov, &map);
2777 gst_buffer_unref (moov);
2779 gst_buffer_map (moov, &map, GST_MAP_READ);
2784 if (length != map.size) {
2785 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2786 (_("This file is incomplete and cannot be played.")),
2787 ("We got less than expected (received %" G_GSIZE_FORMAT
2788 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
2789 (guint) length, cur_offset));
2790 gst_buffer_unmap (moov, &map);
2791 gst_buffer_unref (moov);
2792 ret = GST_FLOW_ERROR;
2795 qtdemux->offset += length;
2797 qtdemux_parse_moov (qtdemux, map.data, length);
2798 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
2800 qtdemux_parse_tree (qtdemux);
2801 g_node_destroy (qtdemux->moov_node);
2802 gst_buffer_unmap (moov, &map);
2803 gst_buffer_unref (moov);
2804 qtdemux->moov_node = NULL;
2805 qtdemux->got_moov = TRUE;
2811 GstBuffer *ftyp = NULL;
2813 /* extract major brand; might come in handy for ISO vs QT issues */
2814 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
2815 if (ret != GST_FLOW_OK)
2817 qtdemux->offset += length;
2818 gst_buffer_map (ftyp, &map, GST_MAP_READ);
2819 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
2820 gst_buffer_unmap (ftyp, &map);
2821 gst_buffer_unref (ftyp);
2826 GstBuffer *uuid = NULL;
2828 /* uuid are extension atoms */
2829 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
2830 if (ret != GST_FLOW_OK)
2832 qtdemux->offset += length;
2833 gst_buffer_map (uuid, &map, GST_MAP_READ);
2834 qtdemux_parse_uuid (qtdemux, map.data, map.size);
2835 gst_buffer_unmap (uuid, &map);
2836 gst_buffer_unref (uuid);
2841 GstBuffer *unknown = NULL;
2843 GST_LOG_OBJECT (qtdemux,
2844 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
2845 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
2847 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
2848 if (ret != GST_FLOW_OK)
2850 gst_buffer_map (unknown, &map, GST_MAP_READ);
2851 GST_MEMDUMP ("Unknown tag", map.data, map.size);
2852 gst_buffer_unmap (unknown, &map);
2853 gst_buffer_unref (unknown);
2854 qtdemux->offset += length;
2860 if (ret == GST_FLOW_EOS && qtdemux->got_moov) {
2861 /* digested all data, show what we have */
2862 ret = qtdemux_expose_streams (qtdemux);
2864 qtdemux->state = QTDEMUX_STATE_MOVIE;
2865 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
2872 /* Seeks to the previous keyframe of the indexed stream and
2873 * aligns other streams with respect to the keyframe timestamp
2874 * of indexed stream. Only called in case of Reverse Playback
2876 static GstFlowReturn
2877 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
2880 guint32 seg_idx = 0, k_index = 0;
2881 guint32 ref_seg_idx, ref_k_index;
2882 guint64 k_pos = 0, last_stop = 0;
2883 QtDemuxSegment *seg = NULL;
2884 QtDemuxStream *ref_str = NULL;
2885 guint64 seg_media_start_mov; /* segment media start time in mov format */
2887 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
2888 * and finally align all the other streams on that timestamp with their
2889 * respective keyframes */
2890 for (n = 0; n < qtdemux->n_streams; n++) {
2891 QtDemuxStream *str = qtdemux->streams[n];
2893 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
2894 qtdemux->segment.position);
2896 /* segment not found, continue with normal flow */
2900 /* No candidate yet, take that one */
2906 /* So that stream has a segment, we prefer video streams */
2907 if (str->subtype == FOURCC_vide) {
2913 if (G_UNLIKELY (!ref_str)) {
2914 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
2918 if (G_UNLIKELY (!ref_str->from_sample)) {
2919 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
2923 /* So that stream has been playing from from_sample to to_sample. We will
2924 * get the timestamp of the previous sample and search for a keyframe before
2925 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
2926 if (ref_str->subtype == FOURCC_vide) {
2927 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
2928 ref_str->from_sample - 1);
2930 if (ref_str->from_sample >= 10)
2931 k_index = ref_str->from_sample - 10;
2936 /* get current segment for that stream */
2937 seg = &ref_str->segments[ref_str->segment_index];
2938 /* convert seg->media_start to mov format time for timestamp comparison */
2939 seg_media_start_mov =
2940 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
2941 /* Crawl back through segments to find the one containing this I frame */
2942 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
2943 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
2944 ref_str->segment_index);
2945 if (G_UNLIKELY (!ref_str->segment_index)) {
2946 /* Reached first segment, let's consider it's EOS */
2949 ref_str->segment_index--;
2950 seg = &ref_str->segments[ref_str->segment_index];
2951 /* convert seg->media_start to mov format time for timestamp comparison */
2952 seg_media_start_mov =
2953 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
2956 /* Calculate time position of the keyframe and where we should stop */
2958 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
2959 ref_str->timescale) - seg->media_start) + seg->time;
2961 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
2962 GST_SECOND, ref_str->timescale);
2963 last_stop = (last_stop - seg->media_start) + seg->time;
2965 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
2966 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
2967 k_index, GST_TIME_ARGS (k_pos));
2969 /* Set last_stop with the keyframe timestamp we pushed of that stream */
2970 qtdemux->segment.position = last_stop;
2971 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
2972 GST_TIME_ARGS (last_stop));
2974 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
2975 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
2979 ref_seg_idx = ref_str->segment_index;
2980 ref_k_index = k_index;
2982 /* Align them all on this */
2983 for (n = 0; n < qtdemux->n_streams; n++) {
2985 guint64 media_start = 0, seg_time = 0;
2986 QtDemuxStream *str = qtdemux->streams[n];
2988 /* aligning reference stream again might lead to backing up to yet another
2989 * keyframe (due to timestamp rounding issues),
2990 * potentially putting more load on downstream; so let's try to avoid */
2991 if (str == ref_str) {
2992 seg_idx = ref_seg_idx;
2993 seg = &str->segments[seg_idx];
2994 k_index = ref_k_index;
2995 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
2996 "sample at index %d", ref_str->segment_index, k_index);
2998 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
2999 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
3001 /* segment not found, continue with normal flow */
3005 /* get segment and time in the segment */
3006 seg = &str->segments[seg_idx];
3007 seg_time = k_pos - seg->time;
3009 /* get the media time in the segment */
3010 media_start = seg->media_start + seg_time;
3012 /* get the index of the sample with media time */
3013 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
3014 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
3015 GST_TIME_ARGS (media_start), index);
3017 /* find previous keyframe */
3018 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
3021 /* Remember until where we want to go */
3022 str->to_sample = str->from_sample - 1;
3023 /* Define our time position */
3024 str->time_position =
3025 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
3026 str->timescale) - seg->media_start) + seg->time;
3027 /* Now seek back in time */
3028 gst_qtdemux_move_stream (qtdemux, str, k_index);
3029 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
3030 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
3031 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
3037 return GST_FLOW_EOS;
3040 /* activate the given segment number @seg_idx of @stream at time @offset.
3041 * @offset is an absolute global position over all the segments.
3043 * This will push out a NEWSEGMENT event with the right values and
3044 * position the stream index to the first decodable sample before
3048 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
3049 guint32 seg_idx, guint64 offset)
3052 QtDemuxSegment *segment;
3053 guint32 index, kf_index;
3055 guint64 start, stop, time;
3058 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3061 /* update the current segment */
3062 stream->segment_index = seg_idx;
3064 /* get the segment */
3065 segment = &stream->segments[seg_idx];
3067 if (G_UNLIKELY (offset < segment->time)) {
3068 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3073 /* segment lies beyond total indicated duration */
3074 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3075 segment->time > qtdemux->segment.duration)) {
3076 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3077 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3082 /* get time in this segment */
3083 seg_time = offset - segment->time;
3085 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3086 GST_TIME_ARGS (seg_time));
3088 if (G_UNLIKELY (seg_time > segment->duration)) {
3089 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3090 GST_TIME_ARGS (segment->duration));
3094 /* qtdemux->segment.stop is in outside-time-realm, whereas
3095 * segment->media_stop is in track-time-realm.
3097 * In order to compare the two, we need to bring segment.stop
3098 * into the track-time-realm */
3100 stop = qtdemux->segment.stop;
3102 stop = qtdemux->segment.duration;
3104 stop = segment->media_stop;
3107 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3109 if (qtdemux->segment.rate >= 0) {
3110 start = MIN (segment->media_start + seg_time, stop);
3113 if (segment->media_start >= qtdemux->segment.start) {
3114 start = segment->media_start;
3115 time = segment->time;
3117 start = qtdemux->segment.start;
3118 time = segment->time + (qtdemux->segment.start - segment->media_start);
3121 start = MAX (segment->media_start, qtdemux->segment.start);
3122 stop = MIN (segment->media_start + seg_time, stop);
3125 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3126 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3127 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3129 /* combine global rate with that of the segment */
3130 rate = segment->rate * qtdemux->segment.rate;
3132 /* update the segment values used for clipping */
3133 /* accumulate previous segments */
3134 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3135 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3136 ABS (stream->segment.rate);
3137 stream->segment.rate = rate;
3138 stream->segment.start = start;
3139 stream->segment.stop = stop;
3140 stream->segment.time = time;
3141 stream->segment.position = start;
3143 /* now prepare and send the segment */
3145 event = gst_event_new_segment (&stream->segment);
3146 gst_pad_push_event (stream->pad, event);
3147 /* assume we can send more data now */
3148 stream->last_ret = GST_FLOW_OK;
3149 /* clear to send tags on this pad now */
3150 gst_qtdemux_push_tags (qtdemux, stream);
3153 /* and move to the keyframe before the indicated media time of the
3155 if (qtdemux->segment.rate >= 0) {
3156 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3157 stream->to_sample = G_MAXUINT32;
3158 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3159 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3160 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3161 GST_SECOND, stream->timescale)));
3163 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3164 stream->to_sample = index;
3165 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3166 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3167 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3168 GST_SECOND, stream->timescale)));
3171 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3172 * encountered an error and printed a message so we return appropriately */
3176 /* we're at the right spot */
3177 if (index == stream->sample_index) {
3178 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3182 /* find keyframe of the target index */
3183 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3186 /* indent does stupid stuff with stream->samples[].timestamp */
3188 /* if we move forwards, we don't have to go back to the previous
3189 * keyframe since we already sent that. We can also just jump to
3190 * the keyframe right before the target index if there is one. */
3191 if (index > stream->sample_index) {
3192 /* moving forwards check if we move past a keyframe */
3193 if (kf_index > stream->sample_index) {
3194 GST_DEBUG_OBJECT (qtdemux,
3195 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3196 GST_TIME_ARGS (gst_util_uint64_scale (
3197 stream->samples[kf_index].timestamp,
3198 GST_SECOND, stream->timescale)));
3199 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3201 GST_DEBUG_OBJECT (qtdemux,
3202 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3203 " already sent", kf_index,
3204 GST_TIME_ARGS (gst_util_uint64_scale (
3205 stream->samples[kf_index].timestamp,
3206 GST_SECOND, stream->timescale)));
3209 GST_DEBUG_OBJECT (qtdemux,
3210 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3211 GST_TIME_ARGS (gst_util_uint64_scale (
3212 stream->samples[kf_index].timestamp,
3213 GST_SECOND, stream->timescale)));
3214 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3222 /* prepare to get the current sample of @stream, getting essential values.
3224 * This function will also prepare and send the segment when needed.
3226 * Return FALSE if the stream is EOS.
3229 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3230 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * dts,
3231 guint64 * pts, guint64 * duration, gboolean * keyframe)
3233 QtDemuxSample *sample;
3234 guint64 time_position;
3237 g_return_val_if_fail (stream != NULL, FALSE);
3239 time_position = stream->time_position;
3240 if (G_UNLIKELY (time_position == -1))
3243 seg_idx = stream->segment_index;
3244 if (G_UNLIKELY (seg_idx == -1)) {
3245 /* find segment corresponding to time_position if we are looking
3247 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3249 /* nothing found, we're really eos */
3254 /* different segment, activate it, sample_index will be set. */
3255 if (G_UNLIKELY (stream->segment_index != seg_idx))
3256 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3258 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3259 stream->sample_index, stream->n_samples);
3261 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3264 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3265 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3266 stream->sample_index);
3270 /* now get the info for the sample we're at */
3271 sample = &stream->samples[stream->sample_index];
3273 *dts = QTSAMPLE_DTS (stream, sample);
3274 *pts = QTSAMPLE_PTS (stream, sample);
3275 *offset = sample->offset;
3276 *size = sample->size;
3277 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3278 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3285 stream->time_position = -1;
3290 /* move to the next sample in @stream.
3292 * Moves to the next segment when needed.
3295 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3297 QtDemuxSample *sample;
3298 QtDemuxSegment *segment;
3300 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3301 /* Mark the stream as EOS */
3302 GST_DEBUG_OBJECT (qtdemux,
3303 "reached max allowed sample %u, mark EOS", stream->to_sample);
3304 stream->time_position = -1;
3308 /* move to next sample */
3309 stream->sample_index++;
3310 stream->offset_in_sample = 0;
3312 /* get current segment */
3313 segment = &stream->segments[stream->segment_index];
3315 /* reached the last sample, we need the next segment */
3316 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3319 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3320 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3321 stream->sample_index);
3325 /* get next sample */
3326 sample = &stream->samples[stream->sample_index];
3328 /* see if we are past the segment */
3329 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3330 GST_SECOND, stream->timescale) >= segment->media_stop))
3333 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3334 stream->timescale) >= segment->media_start) {
3335 /* inside the segment, update time_position, looks very familiar to
3336 * GStreamer segments, doesn't it? */
3337 stream->time_position =
3338 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3339 stream->timescale) - segment->media_start) + segment->time;
3341 /* not yet in segment, time does not yet increment. This means
3342 * that we are still prerolling keyframes to the decoder so it can
3343 * decode the first sample of the segment. */
3344 stream->time_position = segment->time;
3348 /* move to the next segment */
3351 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3353 if (stream->segment_index == stream->n_segments - 1) {
3354 /* are we at the end of the last segment, we're EOS */
3355 stream->time_position = -1;
3357 /* else we're only at the end of the current segment */
3358 stream->time_position = segment->stop_time;
3360 /* make sure we select a new segment */
3361 stream->segment_index = -1;
3366 gst_qtdemux_sync_streams (GstQTDemux * demux)
3370 if (demux->n_streams <= 1)
3373 for (i = 0; i < demux->n_streams; i++) {
3374 QtDemuxStream *stream;
3375 GstClockTime end_time;
3377 stream = demux->streams[i];
3382 /* TODO advance time on subtitle streams here, if any some day */
3384 /* some clips/trailers may have unbalanced streams at the end,
3385 * so send EOS on shorter stream to prevent stalling others */
3387 /* do not mess with EOS if SEGMENT seeking */
3388 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3391 if (demux->pullbased) {
3392 /* loop mode is sample time based */
3393 if (stream->time_position != -1)
3396 /* push mode is byte position based */
3397 if (stream->n_samples &&
3398 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3402 if (stream->sent_eos)
3405 /* only act if some gap */
3406 end_time = stream->segments[stream->n_segments - 1].stop_time;
3407 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3408 ", stream end: %" GST_TIME_FORMAT,
3409 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3410 if (end_time + 2 * GST_SECOND < demux->segment.position) {
3411 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3412 GST_PAD_NAME (stream->pad));
3413 stream->sent_eos = TRUE;
3414 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3419 /* EOS and NOT_LINKED need to be combined. This means that we return:
3421 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3422 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
3424 static GstFlowReturn
3425 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3429 gboolean unexpected = FALSE, not_linked = TRUE;
3431 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3433 /* store the value */
3434 stream->last_ret = ret;
3436 /* any other error that is not-linked or eos can be returned right away */
3437 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3440 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3441 for (i = 0; i < demux->n_streams; i++) {
3442 QtDemuxStream *ostream = demux->streams[i];
3444 ret = ostream->last_ret;
3446 /* no unexpected or unlinked, return */
3447 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3450 /* we check to see if we have at least 1 unexpected or all unlinked */
3451 unexpected |= (ret == GST_FLOW_EOS);
3452 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3455 /* when we get here, we all have unlinked or unexpected */
3457 ret = GST_FLOW_NOT_LINKED;
3458 else if (unexpected)
3461 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3465 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3466 * completely cliped */
3468 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3471 guint64 start, stop, cstart, cstop, diff;
3472 GstClockTime pts, dts, duration;
3474 gint num_rate, denom_rate;
3479 osize = size = gst_buffer_get_size (buf);
3482 /* depending on the type, setup the clip parameters */
3483 if (stream->subtype == FOURCC_soun) {
3484 frame_size = stream->bytes_per_frame;
3485 num_rate = GST_SECOND;
3486 denom_rate = (gint) stream->rate;
3488 } else if (stream->subtype == FOURCC_vide) {
3490 num_rate = stream->fps_n;
3491 denom_rate = stream->fps_d;
3496 /* we can only clip if we have a valid pts */
3497 pts = GST_BUFFER_PTS (buf);
3498 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
3501 dts = GST_BUFFER_DTS (buf);
3502 duration = GST_BUFFER_DURATION (buf);
3504 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
3506 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3510 stop = start + duration;
3512 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3513 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3516 /* see if some clipping happened */
3517 diff = cstart - start;
3524 /* bring clipped time to samples and to bytes */
3525 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3528 GST_DEBUG_OBJECT (qtdemux,
3529 "clipping start to %" GST_TIME_FORMAT " %"
3530 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3536 diff = stop - cstop;
3541 /* bring clipped time to samples and then to bytes */
3542 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3544 GST_DEBUG_OBJECT (qtdemux,
3545 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3546 " bytes", GST_TIME_ARGS (cstop), diff);
3551 if (offset != 0 || size != osize)
3552 gst_buffer_resize (buf, offset, size);
3554 GST_BUFFER_DTS (buf) = dts;
3555 GST_BUFFER_PTS (buf) = pts;
3556 GST_BUFFER_DURATION (buf) = duration;
3560 /* dropped buffer */
3563 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3568 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
3573 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3574 gst_buffer_unref (buf);
3579 /* the input buffer metadata must be writable,
3580 * but time/duration etc not yet set and need not be preserved */
3582 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3589 /* not many cases for now */
3590 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3591 /* send a one time dvd clut event */
3592 if (stream->pending_event && stream->pad)
3593 gst_pad_push_event (stream->pad, stream->pending_event);
3594 stream->pending_event = NULL;
3595 /* no further processing needed */
3596 stream->need_process = FALSE;
3599 if (G_UNLIKELY (stream->subtype != FOURCC_text
3600 && stream->subtype != FOURCC_sbtl)) {
3604 gst_buffer_map (buf, &map, GST_MAP_READ);
3606 /* empty buffer is sent to terminate previous subtitle */
3607 if (map.size <= 2) {
3608 gst_buffer_unmap (buf, &map);
3609 gst_buffer_unref (buf);
3613 nsize = GST_READ_UINT16_BE (map.data);
3614 nsize = MIN (nsize, map.size - 2);
3616 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
3619 /* takes care of UTF-8 validation or UTF-16 recognition,
3620 * no other encoding expected */
3621 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
3622 gst_buffer_unmap (buf, &map);
3624 gst_buffer_unref (buf);
3625 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
3627 /* this should not really happen unless the subtitle is corrupted */
3628 gst_buffer_unref (buf);
3632 /* FIXME ? convert optional subsequent style info to markup */
3637 /* Sets a buffer's attributes properly and pushes it downstream.
3638 * Also checks for additional actions and custom processing that may
3639 * need to be done first.
3641 static GstFlowReturn
3642 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3643 QtDemuxStream * stream, GstBuffer * buf,
3644 guint64 dts, guint64 pts, guint64 duration, gboolean keyframe,
3645 guint64 position, guint64 byte_position)
3647 GstFlowReturn ret = GST_FLOW_OK;
3649 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
3653 gst_buffer_map (buf, &map, GST_MAP_READ);
3654 url = g_strndup ((gchar *) map.data, map.size);
3655 gst_buffer_unmap (buf, &map);
3656 if (url != NULL && strlen (url) != 0) {
3657 /* we have RTSP redirect now */
3658 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3659 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
3660 gst_structure_new ("redirect",
3661 "new-location", G_TYPE_STRING, url, NULL)));
3662 qtdemux->posted_redirect = TRUE;
3664 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
3670 /* position reporting */
3671 if (qtdemux->segment.rate >= 0) {
3672 qtdemux->segment.position = position;
3673 gst_qtdemux_sync_streams (qtdemux);
3676 if (G_UNLIKELY (!stream->pad)) {
3677 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
3678 gst_buffer_unref (buf);
3682 /* send out pending buffers */
3683 while (stream->buffers) {
3684 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
3686 if (G_UNLIKELY (stream->discont)) {
3687 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3688 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
3689 stream->discont = FALSE;
3692 gst_pad_push (stream->pad, buffer);
3694 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
3697 /* we're going to modify the metadata */
3698 buf = gst_buffer_make_writable (buf);
3700 if (G_UNLIKELY (stream->need_process))
3701 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
3707 GST_BUFFER_DTS (buf) = dts;
3708 GST_BUFFER_PTS (buf) = pts;
3709 GST_BUFFER_DURATION (buf) = duration;
3710 GST_BUFFER_OFFSET (buf) = -1;
3711 GST_BUFFER_OFFSET_END (buf) = -1;
3713 if (G_UNLIKELY (stream->padding)) {
3714 gst_buffer_resize (buf, stream->padding, -1);
3717 if (G_UNLIKELY (qtdemux->element_index)) {
3718 GstClockTime stream_time;
3721 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
3723 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
3724 GST_LOG_OBJECT (qtdemux,
3725 "adding association %" GST_TIME_FORMAT "-> %"
3726 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
3727 gst_index_add_association (qtdemux->element_index,
3729 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
3730 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
3731 GST_FORMAT_BYTES, byte_position, NULL);
3736 if (stream->need_clip)
3737 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
3739 if (G_UNLIKELY (buf == NULL))
3742 if (G_UNLIKELY (stream->discont)) {
3743 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3744 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3745 stream->discont = FALSE;
3749 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3751 GST_LOG_OBJECT (qtdemux,
3752 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
3753 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
3754 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
3755 GST_PAD_NAME (stream->pad));
3757 ret = gst_pad_push (stream->pad, buf);
3759 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
3760 /* mark position in stream, we'll need this to know when to send GAP event */
3761 stream->segment.position = pts + duration;
3768 static GstFlowReturn
3769 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
3771 GstFlowReturn ret = GST_FLOW_OK;
3772 GstBuffer *buf = NULL;
3773 QtDemuxStream *stream;
3776 guint64 dts = GST_CLOCK_TIME_NONE;
3777 guint64 pts = GST_CLOCK_TIME_NONE;
3778 guint64 duration = 0;
3779 gboolean keyframe = FALSE;
3780 guint sample_size = 0;
3785 gst_qtdemux_push_pending_newsegment (qtdemux);
3787 /* Figure out the next stream sample to output, min_time is expressed in
3788 * global time and runs over the edit list segments. */
3789 min_time = G_MAXUINT64;
3791 for (i = 0; i < qtdemux->n_streams; i++) {
3794 stream = qtdemux->streams[i];
3795 position = stream->time_position;
3797 /* position of -1 is EOS */
3798 if (position != -1 && position < min_time) {
3799 min_time = position;
3804 if (G_UNLIKELY (index == -1)) {
3805 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
3809 /* check for segment end */
3810 if (G_UNLIKELY (qtdemux->segment.stop != -1
3811 && qtdemux->segment.stop < min_time)) {
3812 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
3816 /* gap events for subtitle streams */
3817 for (i = 0; i < qtdemux->n_streams; i++) {
3818 stream = qtdemux->streams[i];
3819 if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
3820 || stream->subtype == FOURCC_sbtl) {
3821 /* send one second gap events until the stream catches up */
3822 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
3823 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
3824 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
3825 stream->segment.position + GST_SECOND < min_time) {
3827 gst_event_new_gap (stream->segment.position, GST_SECOND);
3828 gst_pad_push_event (stream->pad, gap);
3829 stream->segment.position += GST_SECOND;
3834 stream = qtdemux->streams[index];
3836 /* fetch info for the current sample of this stream */
3837 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
3838 &sample_size, &dts, &pts, &duration, &keyframe)))
3841 GST_DEBUG_OBJECT (qtdemux,
3842 "pushing from stream %d, offset %" G_GUINT64_FORMAT
3843 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
3844 ", duration %" GST_TIME_FORMAT, index, offset, sample_size,
3845 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
3847 /* hmm, empty sample, skip and move to next sample */
3848 if (G_UNLIKELY (sample_size <= 0))
3851 /* last pushed sample was out of boundary, goto next sample */
3852 if (G_UNLIKELY (stream->last_ret == GST_FLOW_EOS))
3855 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
3858 GST_DEBUG_OBJECT (qtdemux,
3859 "size %d larger than stream max_buffer_size %d, trimming",
3860 sample_size, stream->max_buffer_size);
3862 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
3865 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
3868 if (stream->use_allocator) {
3869 /* if we have a per-stream allocator, use it */
3870 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
3873 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
3875 if (G_UNLIKELY (ret != GST_FLOW_OK))
3878 if (size != sample_size) {
3879 pts += gst_util_uint64_scale_int (GST_SECOND,
3880 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
3881 dts += gst_util_uint64_scale_int (GST_SECOND,
3882 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
3883 duration = gst_util_uint64_scale_int (GST_SECOND,
3884 size / stream->bytes_per_frame, stream->timescale);
3887 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
3888 dts, pts, duration, keyframe, min_time, offset);
3890 if (size != sample_size) {
3891 QtDemuxSample *sample = &stream->samples[stream->sample_index];
3892 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
3894 GstClockTime time_position = gst_util_uint64_scale (sample->timestamp +
3895 stream->offset_in_sample / stream->bytes_per_frame, GST_SECOND,
3897 if (time_position >= segment->media_start) {
3898 /* inside the segment, update time_position, looks very familiar to
3899 * GStreamer segments, doesn't it? */
3900 stream->time_position = (time_position - segment->media_start) +
3903 /* not yet in segment, time does not yet increment. This means
3904 * that we are still prerolling keyframes to the decoder so it can
3905 * decode the first sample of the segment. */
3906 stream->time_position = segment->time;
3911 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
3912 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
3913 * we have no more data for the pad to push */
3914 if (ret == GST_FLOW_EOS)
3917 stream->offset_in_sample += size;
3918 if (stream->offset_in_sample >= sample_size) {
3919 gst_qtdemux_advance_sample (qtdemux, stream);
3924 gst_qtdemux_advance_sample (qtdemux, stream);
3932 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
3938 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
3939 /* EOS will be raised if all are EOS */
3946 gst_qtdemux_loop (GstPad * pad)
3948 GstQTDemux *qtdemux;
3952 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
3954 cur_offset = qtdemux->offset;
3955 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
3956 cur_offset, qtdemux->state);
3958 switch (qtdemux->state) {
3959 case QTDEMUX_STATE_INITIAL:
3960 case QTDEMUX_STATE_HEADER:
3961 ret = gst_qtdemux_loop_state_header (qtdemux);
3963 case QTDEMUX_STATE_MOVIE:
3964 ret = gst_qtdemux_loop_state_movie (qtdemux);
3965 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
3966 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
3974 /* if something went wrong, pause */
3975 if (ret != GST_FLOW_OK)
3979 gst_object_unref (qtdemux);
3985 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3986 (NULL), ("streaming stopped, invalid state"));
3987 gst_pad_pause_task (pad);
3988 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3993 const gchar *reason = gst_flow_get_name (ret);
3995 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
3997 gst_pad_pause_task (pad);
3999 /* fatal errors need special actions */
4001 if (ret == GST_FLOW_EOS) {
4002 if (qtdemux->n_streams == 0) {
4003 /* we have no streams, post an error */
4004 gst_qtdemux_post_no_playable_stream_error (qtdemux);
4006 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4009 if ((stop = qtdemux->segment.stop) == -1)
4010 stop = qtdemux->segment.duration;
4012 if (qtdemux->segment.rate >= 0) {
4013 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
4014 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4015 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4016 GST_FORMAT_TIME, stop));
4017 gst_qtdemux_push_event (qtdemux,
4018 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
4020 /* For Reverse Playback */
4021 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
4022 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4023 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4024 GST_FORMAT_TIME, qtdemux->segment.start));
4025 gst_qtdemux_push_event (qtdemux,
4026 gst_event_new_segment_done (GST_FORMAT_TIME,
4027 qtdemux->segment.start));
4030 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
4031 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4033 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
4034 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4035 (NULL), ("streaming stopped, reason %s", reason));
4036 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4045 * Returns the size of the first entry at the current offset.
4046 * If -1, there are none (which means EOS or empty file).
4049 next_entry_size (GstQTDemux * demux)
4051 QtDemuxStream *stream;
4054 guint64 smalloffs = (guint64) - 1;
4055 QtDemuxSample *sample;
4057 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
4060 for (i = 0; i < demux->n_streams; i++) {
4061 stream = demux->streams[i];
4063 if (stream->sample_index == -1) {
4064 stream->sample_index = 0;
4065 stream->offset_in_sample = 0;
4068 if (stream->sample_index >= stream->n_samples) {
4069 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4073 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
4074 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
4075 stream->sample_index);
4079 sample = &stream->samples[stream->sample_index];
4081 GST_LOG_OBJECT (demux,
4082 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4083 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
4084 sample->offset, sample->size);
4086 if (((smalloffs == -1)
4087 || (sample->offset < smalloffs)) && (sample->size)) {
4089 smalloffs = sample->offset;
4093 GST_LOG_OBJECT (demux,
4094 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
4095 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
4100 stream = demux->streams[smallidx];
4101 sample = &stream->samples[stream->sample_index];
4103 if (sample->offset >= demux->offset) {
4104 demux->todrop = sample->offset - demux->offset;
4105 return sample->size + demux->todrop;
4108 GST_DEBUG_OBJECT (demux,
4109 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
4114 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
4116 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
4118 gst_element_post_message (GST_ELEMENT_CAST (demux),
4119 gst_message_new_element (GST_OBJECT_CAST (demux),
4120 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
4124 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
4129 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
4132 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
4133 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
4134 GST_SEEK_TYPE_NONE, -1);
4136 res = gst_pad_push_event (demux->sinkpad, event);
4141 /* check for seekable upstream, above and beyond a mere query */
4143 gst_qtdemux_check_seekability (GstQTDemux * demux)
4146 gboolean seekable = FALSE;
4147 gint64 start = -1, stop = -1;
4149 if (demux->upstream_size)
4152 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4153 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4154 GST_DEBUG_OBJECT (demux, "seeking query failed");
4158 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4160 /* try harder to query upstream size if we didn't get it the first time */
4161 if (seekable && stop == -1) {
4162 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4163 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4166 /* if upstream doesn't know the size, it's likely that it's not seekable in
4167 * practice even if it technically may be seekable */
4168 if (seekable && (start != 0 || stop <= start)) {
4169 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4174 gst_query_unref (query);
4176 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4177 G_GUINT64_FORMAT ")", seekable, start, stop);
4178 demux->upstream_seekable = seekable;
4179 demux->upstream_size = seekable ? stop : -1;
4182 /* FIXME, unverified after edit list updates */
4183 static GstFlowReturn
4184 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4187 GstFlowReturn ret = GST_FLOW_OK;
4189 demux = GST_QTDEMUX (parent);
4191 gst_adapter_push (demux->adapter, inbuf);
4193 /* we never really mean to buffer that much */
4194 if (demux->neededbytes == -1)
4197 GST_DEBUG_OBJECT (demux,
4198 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4199 demux->neededbytes, gst_adapter_available (demux->adapter));
4201 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4202 (ret == GST_FLOW_OK)) {
4204 GST_DEBUG_OBJECT (demux,
4205 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4206 demux->state, demux->neededbytes, demux->offset);
4208 switch (demux->state) {
4209 case QTDEMUX_STATE_INITIAL:{
4214 gst_qtdemux_check_seekability (demux);
4216 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4218 /* get fourcc/length, set neededbytes */
4219 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4221 gst_adapter_unmap (demux->adapter);
4223 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4224 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4226 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4227 (_("This file is invalid and cannot be played.")),
4228 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4229 GST_FOURCC_ARGS (fourcc)));
4230 ret = GST_FLOW_ERROR;
4233 if (fourcc == FOURCC_mdat) {
4234 if (demux->n_streams > 0) {
4235 /* we have the headers, start playback */
4236 demux->state = QTDEMUX_STATE_MOVIE;
4237 demux->neededbytes = next_entry_size (demux);
4238 demux->mdatleft = size;
4240 /* no headers yet, try to get them */
4243 guint64 old, target;
4246 old = demux->offset;
4247 target = old + size;
4249 /* try to jump over the atom with a seek */
4250 /* only bother if it seems worth doing so,
4251 * and avoids possible upstream/server problems */
4252 if (demux->upstream_seekable &&
4253 demux->upstream_size > 4 * (1 << 20)) {
4254 res = qtdemux_seek_offset (demux, target);
4256 GST_DEBUG_OBJECT (demux, "skipping seek");
4261 GST_DEBUG_OBJECT (demux, "seek success");
4262 /* remember the offset fo the first mdat so we can seek back to it
4263 * after we have the headers */
4264 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4265 demux->first_mdat = old;
4266 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4269 /* seek worked, continue reading */
4270 demux->offset = target;
4271 demux->neededbytes = 16;
4272 demux->state = QTDEMUX_STATE_INITIAL;
4274 /* seek failed, need to buffer */
4275 demux->offset = old;
4276 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4277 /* there may be multiple mdat (or alike) buffers */
4279 if (demux->mdatbuffer)
4280 bs = gst_buffer_get_size (demux->mdatbuffer);
4283 if (size + bs > 10 * (1 << 20))
4285 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4286 demux->neededbytes = size;
4287 if (!demux->mdatbuffer)
4288 demux->mdatoffset = demux->offset;
4291 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4292 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4293 (_("This file is invalid and cannot be played.")),
4294 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4295 GST_FOURCC_ARGS (fourcc), size));
4296 ret = GST_FLOW_ERROR;
4299 /* this means we already started buffering and still no moov header,
4300 * let's continue buffering everything till we get moov */
4301 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
4303 demux->neededbytes = size;
4304 demux->state = QTDEMUX_STATE_HEADER;
4308 case QTDEMUX_STATE_HEADER:{
4312 GST_DEBUG_OBJECT (demux, "In header");
4314 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4316 /* parse the header */
4317 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4319 if (fourcc == FOURCC_moov) {
4320 /* in usual fragmented setup we could try to scan for more
4321 * and end up at the the moov (after mdat) again */
4322 if (demux->got_moov && demux->n_streams > 0) {
4323 GST_DEBUG_OBJECT (demux,
4324 "Skipping moov atom as we have one already");
4326 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4328 demux->got_moov = TRUE;
4330 /* prepare newsegment to send when streaming actually starts */
4331 if (!demux->pending_newsegment)
4332 demux->pending_newsegment =
4333 gst_event_new_segment (&demux->segment);
4335 qtdemux_parse_moov (demux, data, demux->neededbytes);
4336 qtdemux_node_dump (demux, demux->moov_node);
4337 qtdemux_parse_tree (demux);
4338 qtdemux_expose_streams (demux);
4340 g_node_destroy (demux->moov_node);
4341 demux->moov_node = NULL;
4342 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4344 } else if (fourcc == FOURCC_moof) {
4345 if (demux->got_moov && demux->fragmented) {
4346 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4347 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4348 demux->offset, NULL)) {
4349 gst_adapter_unmap (demux->adapter);
4350 ret = GST_FLOW_ERROR;
4354 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4356 } else if (fourcc == FOURCC_ftyp) {
4357 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4358 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4359 } else if (fourcc == FOURCC_uuid) {
4360 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4361 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4363 GST_WARNING_OBJECT (demux,
4364 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4365 GST_FOURCC_ARGS (fourcc));
4366 /* Let's jump that one and go back to initial state */
4368 gst_adapter_unmap (demux->adapter);
4371 if (demux->mdatbuffer && demux->n_streams) {
4372 /* the mdat was before the header */
4373 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4374 demux->n_streams, demux->mdatbuffer);
4375 /* restore our adapter/offset view of things with upstream;
4376 * put preceding buffered data ahead of current moov data.
4377 * This should also handle evil mdat, moov, mdat cases and alike */
4378 gst_adapter_clear (demux->adapter);
4379 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4380 demux->mdatbuffer = NULL;
4381 demux->offset = demux->mdatoffset;
4382 demux->neededbytes = next_entry_size (demux);
4383 demux->state = QTDEMUX_STATE_MOVIE;
4384 demux->mdatleft = gst_adapter_available (demux->adapter);
4386 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4387 gst_adapter_flush (demux->adapter, demux->neededbytes);
4389 if (demux->got_moov && demux->first_mdat != -1) {
4392 /* we need to seek back */
4393 res = qtdemux_seek_offset (demux, demux->first_mdat);
4395 demux->offset = demux->first_mdat;
4397 GST_DEBUG_OBJECT (demux, "Seek back failed");
4400 demux->offset += demux->neededbytes;
4402 demux->neededbytes = 16;
4403 demux->state = QTDEMUX_STATE_INITIAL;
4408 case QTDEMUX_STATE_BUFFER_MDAT:{
4412 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4414 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4415 gst_buffer_extract (buf, 0, fourcc, 4);
4416 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4417 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
4418 if (demux->mdatbuffer)
4419 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
4421 demux->mdatbuffer = buf;
4422 demux->offset += demux->neededbytes;
4423 demux->neededbytes = 16;
4424 demux->state = QTDEMUX_STATE_INITIAL;
4425 gst_qtdemux_post_progress (demux, 1, 1);
4429 case QTDEMUX_STATE_MOVIE:{
4431 QtDemuxStream *stream = NULL;
4432 QtDemuxSample *sample;
4434 guint64 dts, pts, duration;
4437 GST_DEBUG_OBJECT (demux,
4438 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4440 if (demux->fragmented) {
4441 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4443 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4444 /* if needed data starts within this atom,
4445 * then it should not exceed this atom */
4446 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4447 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4448 (_("This file is invalid and cannot be played.")),
4449 ("sample data crosses atom boundary"));
4450 ret = GST_FLOW_ERROR;
4453 demux->mdatleft -= demux->neededbytes;
4455 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4456 /* so we are dropping more than left in this atom */
4457 demux->todrop -= demux->mdatleft;
4458 demux->neededbytes -= demux->mdatleft;
4459 demux->mdatleft = 0;
4460 /* need to resume atom parsing so we do not miss any other pieces */
4461 demux->state = QTDEMUX_STATE_INITIAL;
4462 demux->neededbytes = 16;
4467 if (demux->todrop) {
4468 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4469 gst_adapter_flush (demux->adapter, demux->todrop);
4470 demux->neededbytes -= demux->todrop;
4471 demux->offset += demux->todrop;
4475 /* initial newsegment sent here after having added pads,
4476 * possible others in sink_event */
4477 if (G_UNLIKELY (demux->pending_newsegment)) {
4478 gst_qtdemux_push_event (demux, demux->pending_newsegment);
4479 demux->pending_newsegment = NULL;
4480 /* clear to send tags on all streams */
4481 for (i = 0; i < demux->n_streams; i++) {
4482 gst_qtdemux_push_tags (demux, demux->streams[i]);
4486 /* Figure out which stream this is packet belongs to */
4487 for (i = 0; i < demux->n_streams; i++) {
4488 stream = demux->streams[i];
4489 if (stream->sample_index >= stream->n_samples)
4491 GST_LOG_OBJECT (demux,
4492 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4493 " / size:%d)", i, stream->sample_index,
4494 stream->samples[stream->sample_index].offset,
4495 stream->samples[stream->sample_index].size);
4497 if (stream->samples[stream->sample_index].offset == demux->offset)
4501 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4502 goto unknown_stream;
4504 /* Put data in a buffer, set timestamps, caps, ... */
4505 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4506 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4507 GST_FOURCC_ARGS (stream->fourcc));
4509 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4511 sample = &stream->samples[stream->sample_index];
4513 dts = QTSAMPLE_DTS (stream, sample);
4514 pts = QTSAMPLE_PTS (stream, sample);
4515 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
4516 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4518 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4519 dts, pts, duration, keyframe, dts, demux->offset);
4522 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4524 stream->sample_index++;
4525 stream->offset_in_sample = 0;
4527 /* update current offset and figure out size of next buffer */
4528 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4529 demux->offset, demux->neededbytes);
4530 demux->offset += demux->neededbytes;
4531 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4534 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4535 if (demux->fragmented) {
4536 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4537 /* there may be more to follow, only finish this atom */
4538 demux->todrop = demux->mdatleft;
4539 demux->neededbytes = demux->todrop;
4551 /* when buffering movie data, at least show user something is happening */
4552 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4553 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4554 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4555 demux->neededbytes);
4564 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4565 ret = GST_FLOW_ERROR;
4570 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4576 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4577 (NULL), ("qtdemuxer invalid state %d", demux->state));
4578 ret = GST_FLOW_ERROR;
4583 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4584 (NULL), ("no 'moov' atom within the first 10 MB"));
4585 ret = GST_FLOW_ERROR;
4591 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
4596 query = gst_query_new_scheduling ();
4598 if (!gst_pad_peer_query (sinkpad, query)) {
4599 gst_query_unref (query);
4603 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
4604 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
4605 gst_query_unref (query);
4610 GST_DEBUG_OBJECT (sinkpad, "activating pull");
4611 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
4615 GST_DEBUG_OBJECT (sinkpad, "activating push");
4616 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
4621 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
4622 GstPadMode mode, gboolean active)
4625 GstQTDemux *demux = GST_QTDEMUX (parent);
4628 case GST_PAD_MODE_PUSH:
4629 demux->pullbased = FALSE;
4632 case GST_PAD_MODE_PULL:
4634 demux->pullbased = TRUE;
4635 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4638 res = gst_pad_stop_task (sinkpad);
4650 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4652 return g_malloc (items * size);
4656 qtdemux_zfree (void *opaque, void *addr)
4662 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4668 z = g_new0 (z_stream, 1);
4669 z->zalloc = qtdemux_zalloc;
4670 z->zfree = qtdemux_zfree;
4673 z->next_in = z_buffer;
4674 z->avail_in = z_length;
4676 buffer = (guint8 *) g_malloc (length);
4677 ret = inflateInit (z);
4678 while (z->avail_in > 0) {
4679 if (z->avail_out == 0) {
4681 buffer = (guint8 *) g_realloc (buffer, length);
4682 z->next_out = buffer + z->total_out;
4683 z->avail_out = 1024;
4685 ret = inflate (z, Z_SYNC_FLUSH);
4689 if (ret != Z_STREAM_END) {
4690 g_warning ("inflate() returned %d", ret);
4696 #endif /* HAVE_ZLIB */
4699 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4703 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4705 /* counts as header data */
4706 qtdemux->header_size += length;
4708 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4709 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4711 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4717 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4718 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4719 if (dcom == NULL || cmvd == NULL)
4720 goto invalid_compression;
4722 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4725 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4726 guint uncompressed_length;
4727 guint compressed_length;
4730 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4731 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4732 GST_LOG ("length = %u", uncompressed_length);
4735 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4736 compressed_length, uncompressed_length);
4738 qtdemux->moov_node_compressed = qtdemux->moov_node;
4739 qtdemux->moov_node = g_node_new (buf);
4741 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4742 uncompressed_length);
4745 #endif /* HAVE_ZLIB */
4747 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4748 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
4755 invalid_compression:
4757 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
4763 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
4766 while (G_UNLIKELY (buf < end)) {
4770 if (G_UNLIKELY (buf + 4 > end)) {
4771 GST_LOG_OBJECT (qtdemux, "buffer overrun");
4774 len = QT_UINT32 (buf);
4775 if (G_UNLIKELY (len == 0)) {
4776 GST_LOG_OBJECT (qtdemux, "empty container");
4779 if (G_UNLIKELY (len < 8)) {
4780 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
4783 if (G_UNLIKELY (len > (end - buf))) {
4784 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
4785 (gint) (end - buf));
4789 child = g_node_new ((guint8 *) buf);
4790 g_node_append (node, child);
4791 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
4792 qtdemux_parse_node (qtdemux, child, buf, len);
4800 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
4803 int len = QT_UINT32 (xdxt->data);
4804 guint8 *buf = xdxt->data;
4805 guint8 *end = buf + len;
4808 /* skip size and type */
4816 size = QT_UINT32 (buf);
4817 type = QT_FOURCC (buf + 4);
4819 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
4821 if (buf + size > end || size <= 0)
4827 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
4828 GST_FOURCC_ARGS (type));
4832 buffer = gst_buffer_new_and_alloc (size);
4833 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4834 stream->buffers = g_slist_append (stream->buffers, buffer);
4835 GST_LOG_OBJECT (qtdemux, "parsing theora header");
4838 buffer = gst_buffer_new_and_alloc (size);
4839 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4840 stream->buffers = g_slist_append (stream->buffers, buffer);
4841 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
4844 buffer = gst_buffer_new_and_alloc (size);
4845 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4846 stream->buffers = g_slist_append (stream->buffers, buffer);
4847 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
4850 GST_WARNING_OBJECT (qtdemux,
4851 "unknown theora cookie %" GST_FOURCC_FORMAT,
4852 GST_FOURCC_ARGS (type));
4861 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
4865 guint32 node_length = 0;
4866 const QtNodeType *type;
4869 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
4871 if (G_UNLIKELY (length < 8))
4872 goto not_enough_data;
4874 node_length = QT_UINT32 (buffer);
4875 fourcc = QT_FOURCC (buffer + 4);
4877 /* ignore empty nodes */
4878 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
4881 type = qtdemux_type_get (fourcc);
4883 end = buffer + length;
4885 GST_LOG_OBJECT (qtdemux,
4886 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
4887 GST_FOURCC_ARGS (fourcc), node_length, type->name);
4889 if (node_length > length)
4890 goto broken_atom_size;
4892 if (type->flags & QT_FLAG_CONTAINER) {
4893 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
4898 if (node_length < 20) {
4899 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
4902 GST_DEBUG_OBJECT (qtdemux,
4903 "parsing stsd (sample table, sample description) atom");
4904 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
4914 /* also read alac (or whatever) in stead of mp4a in the following,
4915 * since a similar layout is used in other cases as well */
4916 if (fourcc == FOURCC_mp4a)
4921 /* There are two things we might encounter here: a true mp4a atom, and
4922 an mp4a entry in an stsd atom. The latter is what we're interested
4923 in, and it looks like an atom, but isn't really one. The true mp4a
4924 atom is short, so we detect it based on length here. */
4925 if (length < min_size) {
4926 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
4927 GST_FOURCC_ARGS (fourcc));
4931 /* 'version' here is the sound sample description version. Types 0 and
4932 1 are documented in the QTFF reference, but type 2 is not: it's
4933 described in Apple header files instead (struct SoundDescriptionV2
4935 version = QT_UINT16 (buffer + 16);
4937 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
4938 GST_FOURCC_ARGS (fourcc), version);
4940 /* parse any esds descriptors */
4952 GST_WARNING_OBJECT (qtdemux,
4953 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
4954 GST_FOURCC_ARGS (fourcc), version);
4959 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4976 /* codec_data is contained inside these atoms, which all have
4977 * the same format. */
4979 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
4980 GST_FOURCC_ARGS (fourcc));
4981 version = QT_UINT32 (buffer + 16);
4982 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
4983 if (1 || version == 0x00000000) {
4984 buf = buffer + 0x32;
4986 /* FIXME Quicktime uses PASCAL string while
4987 * the iso format uses C strings. Check the file
4988 * type before attempting to parse the string here. */
4989 tlen = QT_UINT8 (buf);
4990 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
4992 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
4993 /* the string has a reserved space of 32 bytes so skip
4994 * the remaining 31 */
4996 buf += 4; /* and 4 bytes reserved */
4998 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
5000 qtdemux_parse_container (qtdemux, node, buf, end);
5006 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
5007 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5012 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
5017 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
5018 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
5026 version = QT_UINT32 (buffer + 12);
5027 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
5034 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
5039 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5044 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
5048 if (!strcmp (type->name, "unknown"))
5049 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
5053 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
5054 GST_FOURCC_ARGS (fourcc));
5060 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5061 (_("This file is corrupt and cannot be played.")),
5062 ("Not enough data for an atom header, got only %u bytes", length));
5067 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5068 (_("This file is corrupt and cannot be played.")),
5069 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
5070 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
5077 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
5081 guint32 child_fourcc;
5083 for (child = g_node_first_child (node); child;
5084 child = g_node_next_sibling (child)) {
5085 buffer = (guint8 *) child->data;
5087 child_fourcc = QT_FOURCC (buffer + 4);
5089 if (G_UNLIKELY (child_fourcc == fourcc)) {
5097 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
5098 GstByteReader * parser)
5102 guint32 child_fourcc, child_len;
5104 for (child = g_node_first_child (node); child;
5105 child = g_node_next_sibling (child)) {
5106 buffer = (guint8 *) child->data;
5108 child_len = QT_UINT32 (buffer);
5109 child_fourcc = QT_FOURCC (buffer + 4);
5111 if (G_UNLIKELY (child_fourcc == fourcc)) {
5112 if (G_UNLIKELY (child_len < (4 + 4)))
5114 /* FIXME: must verify if atom length < parent atom length */
5115 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
5123 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
5124 GstByteReader * parser)
5128 guint32 child_fourcc, child_len;
5130 for (child = g_node_next_sibling (node); child;
5131 child = g_node_next_sibling (child)) {
5132 buffer = (guint8 *) child->data;
5134 child_fourcc = QT_FOURCC (buffer + 4);
5136 if (child_fourcc == fourcc) {
5138 child_len = QT_UINT32 (buffer);
5139 if (G_UNLIKELY (child_len < (4 + 4)))
5141 /* FIXME: must verify if atom length < parent atom length */
5142 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
5151 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
5153 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
5157 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
5161 query = gst_query_new_allocation (stream->caps, FALSE);
5163 if (!gst_pad_peer_query (stream->pad, query)) {
5164 /* not a problem, just debug a little */
5165 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
5168 if (stream->allocator)
5169 gst_object_unref (stream->allocator);
5171 if (gst_query_get_n_allocation_params (query) > 0) {
5172 /* try the allocator */
5173 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
5175 stream->use_allocator = TRUE;
5177 stream->allocator = NULL;
5178 gst_allocation_params_init (&stream->params);
5179 stream->use_allocator = FALSE;
5181 gst_query_unref (query);
5185 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
5186 QtDemuxStream * stream, GstTagList * list)
5188 /* consistent default for push based mode */
5189 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
5191 if (stream->subtype == FOURCC_vide) {
5192 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5195 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5198 /* fps is calculated base on the duration of the first frames since
5199 * qt does not have a fixed framerate. */
5200 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
5205 stream->fps_n = stream->timescale;
5206 if (stream->min_duration == 0)
5209 stream->fps_d = stream->min_duration;
5214 gint depth, palette_count;
5215 const guint32 *palette_data = NULL;
5217 gst_caps_set_simple (stream->caps,
5218 "width", G_TYPE_INT, stream->width,
5219 "height", G_TYPE_INT, stream->height,
5220 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5222 /* calculate pixel-aspect-ratio using display width and height */
5223 GST_DEBUG_OBJECT (qtdemux,
5224 "video size %dx%d, target display size %dx%d", stream->width,
5225 stream->height, stream->display_width, stream->display_height);
5227 if (stream->display_width > 0 && stream->display_height > 0 &&
5228 stream->width > 0 && stream->height > 0) {
5231 /* calculate the pixel aspect ratio using the display and pixel w/h */
5232 n = stream->display_width * stream->height;
5233 d = stream->display_height * stream->width;
5236 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5237 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5238 GST_TYPE_FRACTION, n, d, NULL);
5241 /* qt file might have pasp atom */
5242 if (stream->par_w > 0 && stream->par_h > 0) {
5243 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5244 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5245 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5248 depth = stream->bits_per_sample;
5250 /* more than 32 bits means grayscale */
5251 gray = (depth > 32);
5252 /* low 32 bits specify the depth */
5255 /* different number of palette entries is determined by depth. */
5257 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
5258 palette_count = (1 << depth);
5260 switch (palette_count) {
5264 palette_data = ff_qt_default_palette_2;
5267 palette_data = ff_qt_default_palette_4;
5271 palette_data = ff_qt_grayscale_palette_16;
5273 palette_data = ff_qt_default_palette_16;
5277 palette_data = ff_qt_grayscale_palette_256;
5279 palette_data = ff_qt_default_palette_256;
5282 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5283 (_("The video in this file might not play correctly.")),
5284 ("unsupported palette depth %d", depth));
5290 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5291 * don't free any of the buffer data. */
5292 palette = _gst_buffer_new_wrapped ((gpointer) palette_data,
5293 palette_count * 4, NULL);
5295 gst_caps_set_simple (stream->caps, "palette_data",
5296 GST_TYPE_BUFFER, palette, NULL);
5297 gst_buffer_unref (palette);
5298 } else if (palette_count != 0) {
5299 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5300 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5302 gst_object_unref (stream->pad);
5306 qtdemux->n_video_streams++;
5307 } else if (stream->subtype == FOURCC_soun) {
5308 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
5311 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5314 gst_caps_set_simple (stream->caps,
5315 "rate", G_TYPE_INT, (int) stream->rate,
5316 "channels", G_TYPE_INT, stream->n_channels, NULL);
5318 if (stream->n_channels > 2) {
5319 /* FIXME: Need to parse the 'chan' atom to get channel layouts
5320 * correctly; this is just the minimum we can do - assume
5321 * we don't actually have any channel positions. */
5322 gst_caps_set_simple (stream->caps,
5323 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
5326 qtdemux->n_audio_streams++;
5327 } else if (stream->subtype == FOURCC_strm) {
5328 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5329 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
5330 || stream->subtype == FOURCC_sbtl) {
5331 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
5334 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5336 qtdemux->n_sub_streams++;
5337 } else if (stream->caps) {
5338 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5341 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5343 qtdemux->n_video_streams++;
5345 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5352 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5354 gst_pad_use_fixed_caps (stream->pad);
5355 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5356 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5357 gst_pad_set_active (stream->pad, TRUE);
5359 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5361 gst_pad_create_stream_id_printf (stream->pad,
5362 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
5363 gst_pad_push_event (stream->pad, gst_event_new_stream_start (stream_id));
5365 gst_pad_set_caps (stream->pad, stream->caps);
5367 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5368 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5369 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5371 if (stream->pending_tags)
5372 gst_tag_list_unref (stream->pending_tags);
5373 stream->pending_tags = list;
5374 /* global tags go on each pad anyway */
5375 stream->send_global_tags = TRUE;
5377 qtdemux_do_allocation (qtdemux, stream);
5383 /* find next atom with @fourcc starting at @offset */
5384 static GstFlowReturn
5385 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5386 guint64 * length, guint32 fourcc)
5392 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5393 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5399 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5400 if (G_UNLIKELY (ret != GST_FLOW_OK))
5402 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
5405 gst_buffer_unref (buf);
5408 gst_buffer_map (buf, &map, GST_MAP_READ);
5409 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
5410 gst_buffer_unmap (buf, &map);
5411 gst_buffer_unref (buf);
5413 if (G_UNLIKELY (*length == 0)) {
5414 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5415 ret = GST_FLOW_ERROR;
5419 if (lfourcc == fourcc) {
5420 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5424 GST_LOG_OBJECT (qtdemux,
5425 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5426 GST_FOURCC_ARGS (fourcc), *offset);
5435 /* might simply have had last one */
5436 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5441 /* should only do something in pull mode */
5442 /* call with OBJECT lock */
5443 static GstFlowReturn
5444 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5446 guint64 length, offset;
5447 GstBuffer *buf = NULL;
5448 GstFlowReturn ret = GST_FLOW_OK;
5449 GstFlowReturn res = GST_FLOW_OK;
5452 offset = qtdemux->moof_offset;
5453 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5456 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5457 return GST_FLOW_EOS;
5460 /* best not do pull etc with lock held */
5461 GST_OBJECT_UNLOCK (qtdemux);
5463 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5464 if (ret != GST_FLOW_OK)
5467 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5468 if (G_UNLIKELY (ret != GST_FLOW_OK))
5470 gst_buffer_map (buf, &map, GST_MAP_READ);
5471 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
5472 gst_buffer_unmap (buf, &map);
5473 gst_buffer_unref (buf);
5478 gst_buffer_unmap (buf, &map);
5479 gst_buffer_unref (buf);
5483 /* look for next moof */
5484 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5485 if (G_UNLIKELY (ret != GST_FLOW_OK))
5489 GST_OBJECT_LOCK (qtdemux);
5491 qtdemux->moof_offset = offset;
5497 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5499 res = GST_FLOW_ERROR;
5504 /* maybe upstream temporarily flushing */
5505 if (ret != GST_FLOW_FLUSHING) {
5506 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5509 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5510 /* resume at current position next time */
5517 /* initialise bytereaders for stbl sub-atoms */
5519 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5521 stream->stbl_index = -1; /* no samples have yet been parsed */
5523 /* time-to-sample atom */
5524 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5527 /* copy atom data into a new buffer for later use */
5528 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5530 /* skip version + flags */
5531 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5532 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5534 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5536 /* make sure there's enough data */
5537 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
5538 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
5539 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
5540 stream->n_sample_times);
5541 if (!stream->n_sample_times)
5545 /* sync sample atom */
5546 stream->stps_present = FALSE;
5547 if ((stream->stss_present =
5548 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5549 &stream->stss) ? TRUE : FALSE) == TRUE) {
5550 /* copy atom data into a new buffer for later use */
5551 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5553 /* skip version + flags */
5554 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5555 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5558 if (stream->n_sample_syncs) {
5559 /* make sure there's enough data */
5560 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5564 /* partial sync sample atom */
5565 if ((stream->stps_present =
5566 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5567 &stream->stps) ? TRUE : FALSE) == TRUE) {
5568 /* copy atom data into a new buffer for later use */
5569 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5571 /* skip version + flags */
5572 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5573 !gst_byte_reader_get_uint32_be (&stream->stps,
5574 &stream->n_sample_partial_syncs))
5577 /* if there are no entries, the stss table contains the real
5579 if (stream->n_sample_partial_syncs) {
5580 /* make sure there's enough data */
5581 if (!qt_atom_parser_has_chunks (&stream->stps,
5582 stream->n_sample_partial_syncs, 4))
5589 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5592 /* copy atom data into a new buffer for later use */
5593 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5595 /* skip version + flags */
5596 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5597 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5600 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5603 if (!stream->n_samples)
5606 /* sample-to-chunk atom */
5607 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5610 /* copy atom data into a new buffer for later use */
5611 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5613 /* skip version + flags */
5614 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5615 !gst_byte_reader_get_uint32_be (&stream->stsc,
5616 &stream->n_samples_per_chunk))
5619 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5620 stream->n_samples_per_chunk);
5622 /* make sure there's enough data */
5623 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5629 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5630 stream->co_size = sizeof (guint32);
5631 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5633 stream->co_size = sizeof (guint64);
5637 /* copy atom data into a new buffer for later use */
5638 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5640 /* skip version + flags */
5641 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5644 /* chunks_are_chunks == 0 means treat chunks as samples */
5645 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5646 if (stream->chunks_are_chunks) {
5647 /* skip number of entries */
5648 if (!gst_byte_reader_skip (&stream->stco, 4))
5651 /* make sure there are enough data in the stsz atom */
5652 if (!stream->sample_size) {
5653 /* different sizes for each sample */
5654 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5658 /* treat chunks as samples */
5659 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5663 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5664 stream->n_samples, (guint) sizeof (QtDemuxSample),
5665 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5667 if (stream->n_samples >=
5668 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5669 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5670 "be larger than %uMB (broken file?)", stream->n_samples,
5671 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5675 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5676 if (!stream->samples) {
5677 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5683 /* composition time-to-sample */
5684 if ((stream->ctts_present =
5685 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5686 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5687 /* copy atom data into a new buffer for later use */
5688 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5690 /* skip version + flags */
5691 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5692 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5693 &stream->n_composition_times))
5696 /* make sure there's enough data */
5697 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5706 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5707 (_("This file is corrupt and cannot be played.")), (NULL));
5712 gst_qtdemux_stbl_free (stream);
5713 if (!qtdemux->fragmented) {
5714 /* not quite good */
5715 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5718 /* may pick up samples elsewhere */
5724 /* collect samples from the next sample to be parsed up to sample @n for @stream
5725 * by reading the info from @stbl
5727 * This code can be executed from both the streaming thread and the seeking
5728 * thread so it takes the object lock to protect itself
5731 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
5734 QtDemuxSample *samples, *first, *cur, *last;
5735 guint32 n_samples_per_chunk;
5738 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
5739 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
5740 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
5742 n_samples = stream->n_samples;
5745 goto out_of_samples;
5747 GST_OBJECT_LOCK (qtdemux);
5748 if (n <= stream->stbl_index)
5749 goto already_parsed;
5751 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
5753 if (!stream->stsz.data) {
5754 /* so we already parsed and passed all the moov samples;
5755 * onto fragmented ones */
5756 g_assert (qtdemux->fragmented);
5760 /* pointer to the sample table */
5761 samples = stream->samples;
5763 /* starts from -1, moves to the next sample index to parse */
5764 stream->stbl_index++;
5766 /* keep track of the first and last sample to fill */
5767 first = &samples[stream->stbl_index];
5770 if (stream->chunks_are_chunks) {
5771 /* set the sample sizes */
5772 if (stream->sample_size == 0) {
5773 /* different sizes for each sample */
5774 for (cur = first; cur <= last; cur++) {
5775 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
5776 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
5777 (guint) (cur - samples), cur->size);
5780 /* samples have the same size */
5781 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
5782 for (cur = first; cur <= last; cur++)
5783 cur->size = stream->sample_size;
5787 n_samples_per_chunk = stream->n_samples_per_chunk;
5790 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
5793 if (stream->stsc_chunk_index >= stream->last_chunk
5794 || stream->stsc_chunk_index < stream->first_chunk) {
5795 stream->first_chunk =
5796 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5797 stream->samples_per_chunk =
5798 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5799 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
5801 /* chunk numbers are counted from 1 it seems */
5802 if (G_UNLIKELY (stream->first_chunk == 0))
5805 --stream->first_chunk;
5807 /* the last chunk of each entry is calculated by taking the first chunk
5808 * of the next entry; except if there is no next, where we fake it with
5810 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
5811 stream->last_chunk = G_MAXUINT32;
5813 stream->last_chunk =
5814 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
5815 if (G_UNLIKELY (stream->last_chunk == 0))
5818 --stream->last_chunk;
5821 GST_LOG_OBJECT (qtdemux,
5822 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
5823 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
5825 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
5828 if (stream->last_chunk != G_MAXUINT32) {
5829 if (!qt_atom_parser_peek_sub (&stream->stco,
5830 stream->first_chunk * stream->co_size,
5831 (stream->last_chunk - stream->first_chunk) * stream->co_size,
5836 stream->co_chunk = stream->stco;
5837 if (!gst_byte_reader_skip (&stream->co_chunk,
5838 stream->first_chunk * stream->co_size))
5842 stream->stsc_chunk_index = stream->first_chunk;
5845 last_chunk = stream->last_chunk;
5847 if (stream->chunks_are_chunks) {
5848 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5849 guint32 samples_per_chunk;
5850 guint64 chunk_offset;
5852 if (!stream->stsc_sample_index
5853 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
5854 &stream->chunk_offset))
5857 samples_per_chunk = stream->samples_per_chunk;
5858 chunk_offset = stream->chunk_offset;
5860 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
5861 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
5862 G_GUINT64_FORMAT "and size %d",
5863 (guint) (cur - samples), stream->chunk_offset, cur->size);
5865 cur->offset = chunk_offset;
5866 chunk_offset += cur->size;
5869 if (G_UNLIKELY (cur > last)) {
5871 stream->stsc_sample_index = k + 1;
5872 stream->chunk_offset = chunk_offset;
5873 stream->stsc_chunk_index = j;
5877 stream->stsc_sample_index = 0;
5879 stream->stsc_chunk_index = j;
5881 cur = &samples[stream->stsc_chunk_index];
5883 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5886 stream->stsc_chunk_index = j;
5891 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
5894 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
5895 "%" G_GUINT64_FORMAT, j, cur->offset);
5897 if (stream->samples_per_frame * stream->bytes_per_frame) {
5899 (stream->samples_per_chunk * stream->n_channels) /
5900 stream->samples_per_frame * stream->bytes_per_frame;
5902 cur->size = stream->samples_per_chunk;
5905 GST_DEBUG_OBJECT (qtdemux,
5906 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
5907 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
5908 GST_SECOND, stream->timescale)), cur->size);
5910 cur->timestamp = stream->stco_sample_index;
5911 cur->duration = stream->samples_per_chunk;
5912 cur->keyframe = TRUE;
5915 stream->stco_sample_index += stream->samples_per_chunk;
5917 stream->stsc_chunk_index = j;
5919 stream->stsc_index++;
5922 if (!stream->chunks_are_chunks)
5926 guint32 n_sample_times;
5928 n_sample_times = stream->n_sample_times;
5931 for (i = stream->stts_index; i < n_sample_times; i++) {
5932 guint32 stts_samples;
5933 gint32 stts_duration;
5936 if (stream->stts_sample_index >= stream->stts_samples
5937 || !stream->stts_sample_index) {
5939 stream->stts_samples =
5940 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5941 stream->stts_duration =
5942 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5944 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
5945 i, stream->stts_samples, stream->stts_duration);
5947 stream->stts_sample_index = 0;
5950 stts_samples = stream->stts_samples;
5951 stts_duration = stream->stts_duration;
5952 stts_time = stream->stts_time;
5954 for (j = stream->stts_sample_index; j < stts_samples; j++) {
5955 GST_DEBUG_OBJECT (qtdemux,
5956 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
5957 (guint) (cur - samples), j,
5958 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
5959 stream->timescale)));
5961 cur->timestamp = stts_time;
5962 cur->duration = stts_duration;
5964 /* avoid 32-bit wrap-around,
5965 * but still mind possible 'negative' duration */
5966 stts_time += (gint64) stts_duration;
5969 if (G_UNLIKELY (cur > last)) {
5971 stream->stts_time = stts_time;
5972 stream->stts_sample_index = j + 1;
5976 stream->stts_sample_index = 0;
5977 stream->stts_time = stts_time;
5978 stream->stts_index++;
5980 /* fill up empty timestamps with the last timestamp, this can happen when
5981 * the last samples do not decode and so we don't have timestamps for them.
5982 * We however look at the last timestamp to estimate the track length so we
5983 * need something in here. */
5984 for (; cur < last; cur++) {
5985 GST_DEBUG_OBJECT (qtdemux,
5986 "fill sample %d: timestamp %" GST_TIME_FORMAT,
5987 (guint) (cur - samples),
5988 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
5989 stream->timescale)));
5990 cur->timestamp = stream->stts_time;
5996 /* sample sync, can be NULL */
5997 if (stream->stss_present == TRUE) {
5998 guint32 n_sample_syncs;
6000 n_sample_syncs = stream->n_sample_syncs;
6002 if (!n_sample_syncs) {
6003 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
6004 stream->all_keyframe = TRUE;
6006 for (i = stream->stss_index; i < n_sample_syncs; i++) {
6007 /* note that the first sample is index 1, not 0 */
6010 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
6012 if (G_LIKELY (index > 0 && index <= n_samples)) {
6014 samples[index].keyframe = TRUE;
6015 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6016 /* and exit if we have enough samples */
6017 if (G_UNLIKELY (index >= n)) {
6024 stream->stss_index = i;
6027 /* stps marks partial sync frames like open GOP I-Frames */
6028 if (stream->stps_present == TRUE) {
6029 guint32 n_sample_partial_syncs;
6031 n_sample_partial_syncs = stream->n_sample_partial_syncs;
6033 /* if there are no entries, the stss table contains the real
6035 if (n_sample_partial_syncs) {
6036 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
6037 /* note that the first sample is index 1, not 0 */
6040 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
6042 if (G_LIKELY (index > 0 && index <= n_samples)) {
6044 samples[index].keyframe = TRUE;
6045 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6046 /* and exit if we have enough samples */
6047 if (G_UNLIKELY (index >= n)) {
6054 stream->stps_index = i;
6058 /* no stss, all samples are keyframes */
6059 stream->all_keyframe = TRUE;
6060 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
6065 /* composition time to sample */
6066 if (stream->ctts_present == TRUE) {
6067 guint32 n_composition_times;
6069 gint32 ctts_soffset;
6071 /* Fill in the pts_offsets */
6073 n_composition_times = stream->n_composition_times;
6075 for (i = stream->ctts_index; i < n_composition_times; i++) {
6076 if (stream->ctts_sample_index >= stream->ctts_count
6077 || !stream->ctts_sample_index) {
6078 stream->ctts_count =
6079 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
6080 stream->ctts_soffset =
6081 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
6082 stream->ctts_sample_index = 0;
6085 ctts_count = stream->ctts_count;
6086 ctts_soffset = stream->ctts_soffset;
6088 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
6089 cur->pts_offset = ctts_soffset;
6092 if (G_UNLIKELY (cur > last)) {
6094 stream->ctts_sample_index = j + 1;
6098 stream->ctts_sample_index = 0;
6099 stream->ctts_index++;
6103 stream->stbl_index = n;
6104 /* if index has been completely parsed, free data that is no-longer needed */
6105 if (n + 1 == stream->n_samples) {
6106 gst_qtdemux_stbl_free (stream);
6107 GST_DEBUG_OBJECT (qtdemux,
6108 "parsed all available samples; checking for more");
6109 while (n + 1 == stream->n_samples)
6110 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
6113 GST_OBJECT_UNLOCK (qtdemux);
6120 GST_LOG_OBJECT (qtdemux,
6121 "Tried to parse up to sample %u but this sample has already been parsed",
6123 /* if fragmented, there may be more */
6124 if (qtdemux->fragmented && n == stream->stbl_index)
6126 GST_OBJECT_UNLOCK (qtdemux);
6132 GST_LOG_OBJECT (qtdemux,
6133 "Tried to parse up to sample %u but there are only %u samples", n + 1,
6135 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6136 (_("This file is corrupt and cannot be played.")), (NULL));
6141 GST_OBJECT_UNLOCK (qtdemux);
6142 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6143 (_("This file is corrupt and cannot be played.")), (NULL));
6148 /* collect all segment info for @stream.
6151 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
6156 /* parse and prepare segment info from the edit list */
6157 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
6158 stream->n_segments = 0;
6159 stream->segments = NULL;
6160 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
6164 guint64 time, stime;
6167 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
6168 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
6171 buffer = elst->data;
6173 n_segments = QT_UINT32 (buffer + 12);
6175 /* we might allocate a bit too much, at least allocate 1 segment */
6176 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
6178 /* segments always start from 0 */
6182 for (i = 0; i < n_segments; i++) {
6185 QtDemuxSegment *segment;
6188 media_time = QT_UINT32 (buffer + 20 + i * 12);
6190 /* -1 media time is an empty segment, just ignore it */
6191 if (media_time == G_MAXUINT32)
6194 duration = QT_UINT32 (buffer + 16 + i * 12);
6196 segment = &stream->segments[count++];
6198 /* time and duration expressed in global timescale */
6199 segment->time = stime;
6200 /* add non scaled values so we don't cause roundoff errors */
6202 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
6203 segment->stop_time = stime;
6204 segment->duration = stime - segment->time;
6205 /* media_time expressed in stream timescale */
6206 segment->media_start =
6207 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
6208 segment->media_stop = segment->media_start + segment->duration;
6209 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
6211 if (rate_int <= 1) {
6212 /* 0 is not allowed, some programs write 1 instead of the floating point
6214 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
6218 segment->rate = rate_int / 65536.0;
6221 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
6222 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
6223 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
6224 GST_TIME_ARGS (segment->duration),
6225 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
6227 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
6228 stream->n_segments = count;
6232 /* push based does not handle segments, so act accordingly here,
6233 * and warn if applicable */
6234 if (!qtdemux->pullbased) {
6235 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
6236 /* remove and use default one below, we stream like it anyway */
6237 g_free (stream->segments);
6238 stream->segments = NULL;
6239 stream->n_segments = 0;
6242 /* no segments, create one to play the complete trak */
6243 if (stream->n_segments == 0) {
6244 GstClockTime stream_duration =
6245 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6247 if (stream->segments == NULL)
6248 stream->segments = g_new (QtDemuxSegment, 1);
6250 /* represent unknown our way */
6251 if (stream_duration == 0)
6252 stream_duration = -1;
6254 stream->segments[0].time = 0;
6255 stream->segments[0].stop_time = stream_duration;
6256 stream->segments[0].duration = stream_duration;
6257 stream->segments[0].media_start = 0;
6258 stream->segments[0].media_stop = stream_duration;
6259 stream->segments[0].rate = 1.0;
6261 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6262 GST_TIME_ARGS (stream_duration));
6263 stream->n_segments = 1;
6265 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6271 * Parses the stsd atom of a svq3 trak looking for
6272 * the SMI and gama atoms.
6275 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6276 guint8 ** gamma, GstBuffer ** seqh)
6278 guint8 *_gamma = NULL;
6279 GstBuffer *_seqh = NULL;
6280 guint8 *stsd_data = stsd->data;
6281 guint32 length = QT_UINT32 (stsd_data);
6285 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6291 version = QT_UINT16 (stsd_data);
6296 while (length > 8) {
6297 guint32 fourcc, size;
6299 size = QT_UINT32 (stsd_data);
6300 fourcc = QT_FOURCC (stsd_data + 4);
6301 data = stsd_data + 8;
6308 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6309 " for gama atom, expected 12", size);
6314 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6316 if (_seqh != NULL) {
6317 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6318 " found, ignoring");
6320 seqh_size = QT_UINT32 (data + 4);
6321 if (seqh_size > 0) {
6322 _seqh = gst_buffer_new_and_alloc (seqh_size);
6323 _gst_buffer_copy_into_mem (_seqh, 0, data + 8, seqh_size);
6330 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6331 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6335 if (size <= length) {
6341 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6344 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6345 G_GUINT16_FORMAT, version);
6356 gst_buffer_unref (_seqh);
6361 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6368 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6369 * atom that might contain a 'data' atom with the rtsp uri.
6370 * This case was reported in bug #597497, some info about
6371 * the hndl atom can be found in TN1195
6373 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6374 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6377 guint32 dref_num_entries = 0;
6378 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6379 gst_byte_reader_skip (&dref, 4) &&
6380 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6383 /* search dref entries for hndl atom */
6384 for (i = 0; i < dref_num_entries; i++) {
6385 guint32 size = 0, type;
6386 guint8 string_len = 0;
6387 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6388 qt_atom_parser_get_fourcc (&dref, &type)) {
6389 if (type == FOURCC_hndl) {
6390 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6392 /* skip data reference handle bytes and the
6393 * following pascal string and some extra 4
6394 * bytes I have no idea what are */
6395 if (!gst_byte_reader_skip (&dref, 4) ||
6396 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6397 !gst_byte_reader_skip (&dref, string_len + 4)) {
6398 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6402 /* iterate over the atoms to find the data atom */
6403 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6407 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6408 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6409 if (atom_type == FOURCC_data) {
6410 const guint8 *uri_aux = NULL;
6412 /* found the data atom that might contain the rtsp uri */
6413 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6414 "hndl atom, interpreting it as an URI");
6415 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6417 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6418 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6420 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6421 "didn't contain a rtsp address");
6423 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6428 /* skipping to the next entry */
6429 if (!gst_byte_reader_skip (&dref, atom_size - 8))
6432 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6439 /* skip to the next entry */
6440 if (!gst_byte_reader_skip (&dref, size - 8))
6443 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6446 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6453 less_than (gconstpointer a, gconstpointer b)
6455 const guint32 *av = a, *bv = b;
6460 #define AMR_NB_ALL_MODES 0x81ff
6461 #define AMR_WB_ALL_MODES 0x83ff
6463 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
6465 /* The 'damr' atom is of the form:
6467 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
6468 * 32 b 8 b 16 b 8 b 8 b
6470 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
6471 * represents the highest mode used in the stream (and thus the maximum
6472 * bitrate), with a couple of special cases as seen below.
6475 /* Map of frame type ID -> bitrate */
6476 static const guint nb_bitrates[] = {
6477 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
6479 static const guint wb_bitrates[] = {
6480 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
6486 gst_buffer_map (buf, &map, GST_MAP_READ);
6488 if (map.size != 0x11) {
6489 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
6493 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
6494 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
6495 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
6499 mode_set = QT_UINT16 (map.data + 13);
6501 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
6502 max_mode = 7 + (wb ? 1 : 0);
6504 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
6505 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
6507 if (max_mode == -1) {
6508 GST_DEBUG ("No mode indication was found (mode set) = %x",
6513 gst_buffer_unmap (buf, &map);
6514 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
6517 gst_buffer_unmap (buf, &map);
6522 * With each track we associate a new QtDemuxStream that contains all the info
6524 * traks that do not decode to something (like strm traks) will not have a pad.
6527 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6542 QtDemuxStream *stream;
6543 GstTagList *list = NULL;
6544 gchar *codec = NULL;
6545 const guint8 *stsd_data;
6546 guint16 lang_code; /* quicktime lang code or packed iso code */
6548 guint32 tkhd_flags = 0;
6549 guint8 tkhd_version = 0;
6551 guint value_size, len;
6553 stream = g_new0 (QtDemuxStream, 1);
6554 /* new streams always need a discont */
6555 stream->discont = TRUE;
6556 /* we enable clipping for raw audio/video streams */
6557 stream->need_clip = FALSE;
6558 stream->need_process = FALSE;
6559 stream->segment_index = -1;
6560 stream->time_position = 0;
6561 stream->sample_index = -1;
6562 stream->offset_in_sample = 0;
6563 stream->last_ret = GST_FLOW_OK;
6565 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6566 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6567 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6570 if ((tkhd_flags & 1) == 0)
6571 goto track_disabled;
6573 /* pick between 64 or 32 bits */
6574 value_size = tkhd_version == 1 ? 8 : 4;
6575 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6576 !gst_byte_reader_get_uint32_be (&tkhd, &stream->track_id))
6579 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6580 tkhd_version, tkhd_flags, stream->track_id);
6582 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6585 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6586 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6587 if (qtdemux->major_brand != FOURCC_mjp2 ||
6588 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6592 len = QT_UINT32 ((guint8 *) mdhd->data);
6593 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6594 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6595 if (version == 0x01000000) {
6598 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6599 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6600 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6604 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6605 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6606 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6609 if (lang_code < 0x800) {
6610 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6612 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6613 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6614 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6615 stream->lang_id[3] = 0;
6618 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6620 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6622 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6623 lang_code, stream->lang_id);
6625 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6628 /* fragmented files may have bogus duration in moov */
6629 if (!qtdemux->fragmented &&
6630 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6631 guint64 tdur1, tdur2;
6633 /* don't overflow */
6634 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6635 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6638 * some of those trailers, nowadays, have prologue images that are
6639 * themselves vide tracks as well. I haven't really found a way to
6640 * identify those yet, except for just looking at their duration. */
6641 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6642 GST_WARNING_OBJECT (qtdemux,
6643 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6644 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6645 "found, assuming preview image or something; skipping track",
6646 stream->duration, stream->timescale, qtdemux->duration,
6647 qtdemux->timescale);
6653 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6656 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6657 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6659 len = QT_UINT32 ((guint8 *) hdlr->data);
6661 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6662 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6663 GST_FOURCC_ARGS (stream->subtype));
6665 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6668 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6672 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6674 stsd_data = (const guint8 *) stsd->data;
6676 /* stsd should at least have one entry */
6677 len = QT_UINT32 (stsd_data);
6681 /* and that entry should fit within stsd */
6682 len = QT_UINT32 (stsd_data + 16);
6683 if (len > QT_UINT32 (stsd_data) + 16)
6685 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6687 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6688 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6689 GST_FOURCC_ARGS (stream->fourcc));
6691 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6692 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6693 goto error_encrypted;
6695 if (stream->subtype == FOURCC_vide) {
6696 guint32 w = 0, h = 0;
6698 stream->sampled = TRUE;
6700 /* version 1 uses some 64-bit ints */
6701 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6702 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6703 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6706 stream->display_width = w >> 16;
6707 stream->display_height = h >> 16;
6713 stream->width = QT_UINT16 (stsd_data + offset + 32);
6714 stream->height = QT_UINT16 (stsd_data + offset + 34);
6715 stream->fps_n = 0; /* this is filled in later */
6716 stream->fps_d = 0; /* this is filled in later */
6717 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6718 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6720 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6721 QT_UINT16 (stsd_data + offset + 48));
6724 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6726 list = gst_tag_list_new_empty ();
6727 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6728 GST_TAG_VIDEO_CODEC, codec, NULL);
6735 /* pick 'the' stsd child */
6736 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
6738 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
6739 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
6743 const guint8 *pasp_data = (const guint8 *) pasp->data;
6745 stream->par_w = QT_UINT32 (pasp_data + 8);
6746 stream->par_h = QT_UINT32 (pasp_data + 12);
6753 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
6758 gint len = QT_UINT32 (stsd_data) - 0x66;
6759 const guint8 *avc_data = stsd_data + 0x66;
6762 while (len >= 0x8) {
6765 if (QT_UINT32 (avc_data) <= len)
6766 size = QT_UINT32 (avc_data) - 0x8;
6771 /* No real data, so break out */
6774 switch (QT_FOURCC (avc_data + 0x4)) {
6777 /* parse, if found */
6780 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
6782 /* First 4 bytes are the length of the atom, the next 4 bytes
6783 * are the fourcc, the next 1 byte is the version, and the
6784 * subsequent bytes are sequence parameter set like data. */
6785 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
6786 avc_data + 8 + 1, size - 1);
6788 buf = gst_buffer_new_and_alloc (size);
6789 _gst_buffer_copy_into_mem (buf, 0, avc_data + 0x8, size);
6790 gst_caps_set_simple (stream->caps,
6791 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6792 gst_buffer_unref (buf);
6798 guint avg_bitrate, max_bitrate;
6800 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
6804 max_bitrate = QT_UINT32 (avc_data + 0xc);
6805 avg_bitrate = QT_UINT32 (avc_data + 0x10);
6807 if (!max_bitrate && !avg_bitrate)
6810 /* Some muxers seem to swap the average and maximum bitrates
6811 * (I'm looking at you, YouTube), so we swap for sanity. */
6812 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
6813 guint temp = avg_bitrate;
6815 avg_bitrate = max_bitrate;
6820 list = gst_tag_list_new_empty ();
6822 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6823 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6824 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6826 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6827 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6828 GST_TAG_BITRATE, avg_bitrate, NULL);
6839 avc_data += size + 8;
6851 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
6852 GST_FOURCC_ARGS (fourcc));
6854 /* codec data might be in glbl extension atom */
6856 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
6862 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
6864 len = QT_UINT32 (data);
6867 buf = gst_buffer_new_and_alloc (len);
6868 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
6869 gst_caps_set_simple (stream->caps,
6870 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6871 gst_buffer_unref (buf);
6878 /* see annex I of the jpeg2000 spec */
6879 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
6881 const gchar *colorspace = NULL;
6883 guint32 ncomp_map = 0;
6884 gint32 *comp_map = NULL;
6885 guint32 nchan_def = 0;
6886 gint32 *chan_def = NULL;
6888 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
6889 /* some required atoms */
6890 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
6893 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
6897 /* number of components; redundant with info in codestream, but useful
6899 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
6900 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
6902 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
6904 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
6907 GST_DEBUG_OBJECT (qtdemux, "found colr");
6908 /* extract colour space info */
6909 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
6910 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
6912 colorspace = "sRGB";
6915 colorspace = "GRAY";
6918 colorspace = "sYUV";
6926 /* colr is required, and only values 16, 17, and 18 are specified,
6927 so error if we have no colorspace */
6930 /* extract component mapping */
6931 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
6933 guint32 cmap_len = 0;
6935 cmap_len = QT_UINT32 (cmap->data);
6936 if (cmap_len >= 8) {
6937 /* normal box, subtract off header */
6939 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
6940 if (cmap_len % 4 == 0) {
6941 ncomp_map = (cmap_len / 4);
6942 comp_map = g_new0 (gint32, ncomp_map);
6943 for (i = 0; i < ncomp_map; i++) {
6946 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
6947 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
6948 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
6949 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
6954 /* extract channel definitions */
6955 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
6957 guint32 cdef_len = 0;
6959 cdef_len = QT_UINT32 (cdef->data);
6960 if (cdef_len >= 10) {
6961 /* normal box, subtract off header and len */
6963 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
6964 if (cdef_len % 6 == 0) {
6965 nchan_def = (cdef_len / 6);
6966 chan_def = g_new0 (gint32, nchan_def);
6967 for (i = 0; i < nchan_def; i++)
6969 for (i = 0; i < nchan_def; i++) {
6970 guint16 cn, typ, asoc;
6971 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
6972 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
6973 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
6974 if (cn < nchan_def) {
6977 chan_def[cn] = asoc;
6980 chan_def[cn] = 0; /* alpha */
6983 chan_def[cn] = -typ;
6991 gst_caps_set_simple (stream->caps,
6992 "num-components", G_TYPE_INT, ncomp, NULL);
6993 gst_caps_set_simple (stream->caps,
6994 "colorspace", G_TYPE_STRING, colorspace, NULL);
6997 GValue arr = { 0, };
6998 GValue elt = { 0, };
7000 g_value_init (&arr, GST_TYPE_ARRAY);
7001 g_value_init (&elt, G_TYPE_INT);
7002 for (i = 0; i < ncomp_map; i++) {
7003 g_value_set_int (&elt, comp_map[i]);
7004 gst_value_array_append_value (&arr, &elt);
7006 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
7007 "component-map", &arr);
7008 g_value_unset (&elt);
7009 g_value_unset (&arr);
7014 GValue arr = { 0, };
7015 GValue elt = { 0, };
7017 g_value_init (&arr, GST_TYPE_ARRAY);
7018 g_value_init (&elt, G_TYPE_INT);
7019 for (i = 0; i < nchan_def; i++) {
7020 g_value_set_int (&elt, chan_def[i]);
7021 gst_value_array_append_value (&arr, &elt);
7023 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
7024 "channel-definitions", &arr);
7025 g_value_unset (&elt);
7026 g_value_unset (&arr);
7030 /* some optional atoms */
7031 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
7032 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
7034 /* indicate possible fields in caps */
7036 data = (guint8 *) field->data + 8;
7038 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
7039 (gint) * data, NULL);
7041 /* add codec_data if provided */
7046 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
7047 data = prefix->data;
7048 len = QT_UINT32 (data);
7051 buf = gst_buffer_new_and_alloc (len);
7052 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
7053 gst_caps_set_simple (stream->caps,
7054 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7055 gst_buffer_unref (buf);
7064 GstBuffer *seqh = NULL;
7065 guint8 *gamma_data = NULL;
7066 gint len = QT_UINT32 (stsd_data);
7068 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
7070 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
7071 QT_FP32 (gamma_data), NULL);
7074 /* sorry for the bad name, but we don't know what this is, other
7075 * than its own fourcc */
7076 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
7080 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
7081 buf = gst_buffer_new_and_alloc (len);
7082 _gst_buffer_copy_into_mem (buf, 0, stsd_data, len);
7083 gst_caps_set_simple (stream->caps,
7084 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7085 gst_buffer_unref (buf);
7090 gst_caps_set_simple (stream->caps,
7091 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
7098 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
7099 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
7103 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
7107 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
7108 /* collect the headers and store them in a stream list so that we can
7109 * send them out first */
7110 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
7120 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
7121 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
7124 ovc1_data = ovc1->data;
7125 ovc1_len = QT_UINT32 (ovc1_data);
7126 if (ovc1_len <= 198) {
7127 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
7130 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
7131 _gst_buffer_copy_into_mem (buf, 0, ovc1_data + 198, ovc1_len - 198);
7132 gst_caps_set_simple (stream->caps,
7133 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7134 gst_buffer_unref (buf);
7142 GST_INFO_OBJECT (qtdemux,
7143 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7144 GST_FOURCC_ARGS (fourcc), stream->caps);
7146 } else if (stream->subtype == FOURCC_soun) {
7147 int version, samplesize;
7148 guint16 compression_id;
7149 gboolean amrwb = FALSE;
7152 /* sample description entry (16) + sound sample description v0 (20) */
7156 version = QT_UINT32 (stsd_data + offset);
7157 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
7158 samplesize = QT_UINT16 (stsd_data + offset + 10);
7159 compression_id = QT_UINT16 (stsd_data + offset + 12);
7160 stream->rate = QT_FP32 (stsd_data + offset + 16);
7162 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
7163 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
7164 QT_UINT32 (stsd_data + offset + 4));
7165 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7166 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
7167 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
7168 GST_LOG_OBJECT (qtdemux, "packet size: %d",
7169 QT_UINT16 (stsd_data + offset + 14));
7170 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7172 if (compression_id == 0xfffe)
7173 stream->sampled = TRUE;
7175 /* first assume uncompressed audio */
7176 stream->bytes_per_sample = samplesize / 8;
7177 stream->samples_per_frame = stream->n_channels;
7178 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
7179 stream->samples_per_packet = stream->samples_per_frame;
7180 stream->bytes_per_packet = stream->bytes_per_sample;
7184 /* Yes, these have to be hard-coded */
7187 stream->samples_per_packet = 6;
7188 stream->bytes_per_packet = 1;
7189 stream->bytes_per_frame = 1 * stream->n_channels;
7190 stream->bytes_per_sample = 1;
7191 stream->samples_per_frame = 6 * stream->n_channels;
7196 stream->samples_per_packet = 3;
7197 stream->bytes_per_packet = 1;
7198 stream->bytes_per_frame = 1 * stream->n_channels;
7199 stream->bytes_per_sample = 1;
7200 stream->samples_per_frame = 3 * stream->n_channels;
7205 stream->samples_per_packet = 64;
7206 stream->bytes_per_packet = 34;
7207 stream->bytes_per_frame = 34 * stream->n_channels;
7208 stream->bytes_per_sample = 2;
7209 stream->samples_per_frame = 64 * stream->n_channels;
7215 stream->samples_per_packet = 1;
7216 stream->bytes_per_packet = 1;
7217 stream->bytes_per_frame = 1 * stream->n_channels;
7218 stream->bytes_per_sample = 1;
7219 stream->samples_per_frame = 1 * stream->n_channels;
7224 stream->samples_per_packet = 160;
7225 stream->bytes_per_packet = 33;
7226 stream->bytes_per_frame = 33 * stream->n_channels;
7227 stream->bytes_per_sample = 2;
7228 stream->samples_per_frame = 160 * stream->n_channels;
7235 if (version == 0x00010000) {
7236 /* sample description entry (16) + sound sample description v1 (20+16) */
7247 /* only parse extra decoding config for non-pcm audio */
7248 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7249 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
7250 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
7251 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
7253 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7254 stream->samples_per_packet);
7255 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7256 stream->bytes_per_packet);
7257 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
7258 stream->bytes_per_frame);
7259 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
7260 stream->bytes_per_sample);
7262 if (!stream->sampled && stream->bytes_per_packet) {
7263 stream->samples_per_frame = (stream->bytes_per_frame /
7264 stream->bytes_per_packet) * stream->samples_per_packet;
7265 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
7266 stream->samples_per_frame);
7271 } else if (version == 0x00020000) {
7278 /* sample description entry (16) + sound sample description v2 (56) */
7282 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
7283 stream->rate = qtfp.fp;
7284 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
7286 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
7287 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7288 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7289 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
7290 QT_UINT32 (stsd_data + offset + 20));
7291 GST_LOG_OBJECT (qtdemux, "format flags: %X",
7292 QT_UINT32 (stsd_data + offset + 24));
7293 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7294 QT_UINT32 (stsd_data + offset + 28));
7295 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
7296 QT_UINT32 (stsd_data + offset + 32));
7298 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
7301 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
7302 stsd_data + 32, len - 16, &codec);
7310 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
7312 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
7314 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
7316 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
7319 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
7320 gst_caps_set_simple (stream->caps,
7321 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
7328 const guint8 *owma_data;
7329 const gchar *codec_name = NULL;
7333 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
7334 /* FIXME this should also be gst_riff_strf_auds,
7335 * but the latter one is actually missing bits-per-sample :( */
7340 gint32 nSamplesPerSec;
7341 gint32 nAvgBytesPerSec;
7343 gint16 wBitsPerSample;
7348 GST_DEBUG_OBJECT (qtdemux, "parse owma");
7349 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
7352 owma_data = owma->data;
7353 owma_len = QT_UINT32 (owma_data);
7354 if (owma_len <= 54) {
7355 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
7358 wfex = (WAVEFORMATEX *) (owma_data + 36);
7359 buf = gst_buffer_new_and_alloc (owma_len - 54);
7360 _gst_buffer_copy_into_mem (buf, 0, owma_data + 54, owma_len - 54);
7361 if (wfex->wFormatTag == 0x0161) {
7362 codec_name = "Windows Media Audio";
7364 } else if (wfex->wFormatTag == 0x0162) {
7365 codec_name = "Windows Media Audio 9 Pro";
7367 } else if (wfex->wFormatTag == 0x0163) {
7368 codec_name = "Windows Media Audio 9 Lossless";
7369 /* is that correct? gstffmpegcodecmap.c is missing it, but
7370 * fluendo codec seems to support it */
7374 gst_caps_set_simple (stream->caps,
7375 "codec_data", GST_TYPE_BUFFER, buf,
7376 "wmaversion", G_TYPE_INT, version,
7377 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
7378 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
7379 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7380 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7382 gst_buffer_unref (buf);
7386 codec = g_strdup (codec_name);
7398 list = gst_tag_list_new_empty ();
7399 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7400 GST_TAG_AUDIO_CODEC, codec, NULL);
7404 /* some bitrate info may have ended up in caps */
7405 s = gst_caps_get_structure (stream->caps, 0);
7406 gst_structure_get_int (s, "bitrate", &bitrate);
7408 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7412 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7416 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7418 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7420 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7424 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7425 16 bits is a byte-swapped wave-style codec identifier,
7426 and we can find a WAVE header internally to a 'wave' atom here.
7427 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7428 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7431 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7432 if (len < offset + 20) {
7433 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7435 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7436 const guint8 *data = stsd_data + offset + 16;
7438 GNode *waveheadernode;
7440 wavenode = g_node_new ((guint8 *) data);
7441 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7442 const guint8 *waveheader;
7445 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7446 if (waveheadernode) {
7447 waveheader = (const guint8 *) waveheadernode->data;
7448 headerlen = QT_UINT32 (waveheader);
7450 if (headerlen > 8) {
7451 gst_riff_strf_auds *header = NULL;
7452 GstBuffer *headerbuf;
7458 headerbuf = gst_buffer_new_and_alloc (headerlen);
7459 _gst_buffer_copy_into_mem (headerbuf, 0, waveheader, headerlen);
7461 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7462 headerbuf, &header, &extra)) {
7463 gst_caps_unref (stream->caps);
7464 /* FIXME: Need to do something with the channel reorder map */
7465 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7466 header, extra, NULL, NULL, NULL);
7469 gst_buffer_unref (extra);
7474 GST_DEBUG ("Didn't find waveheadernode for this codec");
7476 g_node_destroy (wavenode);
7479 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7483 /* FIXME: what is in the chunk? */
7486 gint len = QT_UINT32 (stsd_data);
7488 /* seems to be always = 116 = 0x74 */
7494 gint len = QT_UINT32 (stsd_data);
7497 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7499 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x4C, len - 0x4C);
7500 gst_caps_set_simple (stream->caps,
7501 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7502 gst_buffer_unref (buf);
7504 gst_caps_set_simple (stream->caps,
7505 "samplesize", G_TYPE_INT, samplesize, NULL);
7510 GNode *alac, *wave = NULL;
7512 /* apparently, m4a has this atom appended directly in the stsd entry,
7513 * while mov has it in a wave atom */
7514 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7516 /* alac now refers to stsd entry atom */
7517 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7519 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7521 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7524 gint len = QT_UINT32 (alac->data);
7528 GST_DEBUG_OBJECT (qtdemux,
7529 "discarding alac atom with unexpected len %d", len);
7531 /* codec-data contains alac atom size and prefix,
7532 * ffmpeg likes it that way, not quite gst-ish though ...*/
7533 buf = gst_buffer_new_and_alloc (len);
7534 _gst_buffer_copy_into_mem (buf, 0, alac->data, len);
7535 gst_caps_set_simple (stream->caps,
7536 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7537 gst_buffer_unref (buf);
7540 gst_caps_set_simple (stream->caps,
7541 "samplesize", G_TYPE_INT, samplesize, NULL);
7549 gint len = QT_UINT32 (stsd_data);
7552 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7555 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x34, len - 0x34);
7557 /* If we have enough data, let's try to get the 'damr' atom. See
7558 * the 3GPP container spec (26.244) for more details. */
7559 if ((len - 0x34) > 8 &&
7560 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
7562 list = gst_tag_list_new_empty ();
7563 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7564 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
7567 gst_caps_set_simple (stream->caps,
7568 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7569 gst_buffer_unref (buf);
7577 GST_INFO_OBJECT (qtdemux,
7578 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7579 GST_FOURCC_ARGS (fourcc), stream->caps);
7581 } else if (stream->subtype == FOURCC_strm) {
7582 if (fourcc == FOURCC_rtsp) {
7583 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7585 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7586 GST_FOURCC_ARGS (fourcc));
7587 goto unknown_stream;
7589 stream->sampled = TRUE;
7590 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7591 || stream->subtype == FOURCC_sbtl) {
7593 stream->sampled = TRUE;
7598 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7600 list = gst_tag_list_new_empty ();
7601 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7602 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7607 /* hunt for sort-of codec data */
7614 /* look for palette */
7615 /* target mp4s atom */
7616 len = QT_UINT32 (stsd_data + offset);
7617 data = stsd_data + offset;
7618 /* verify sufficient length,
7619 * and esds present with decConfigDescr of expected size and position */
7620 if ((len >= 106 + 8)
7621 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7622 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7627 /* move to decConfigDescr data */
7628 data = data + 8 + 42;
7629 for (i = 0; i < 16; i++) {
7630 clut[i] = QT_UINT32 (data);
7634 s = gst_structure_new ("application/x-gst-dvd", "event",
7635 G_TYPE_STRING, "dvd-spu-clut-change",
7636 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7637 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7638 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7639 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7640 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7641 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7642 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7643 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7646 /* store event and trigger custom processing */
7647 stream->pending_event =
7648 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7649 stream->need_process = TRUE;
7657 /* everything in 1 sample */
7658 stream->sampled = TRUE;
7661 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7663 if (stream->caps == NULL)
7664 goto unknown_stream;
7667 list = gst_tag_list_new_empty ();
7668 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7669 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7675 /* promote to sampled format */
7676 if (stream->fourcc == FOURCC_samr) {
7677 /* force mono 8000 Hz for AMR */
7678 stream->sampled = TRUE;
7679 stream->n_channels = 1;
7680 stream->rate = 8000;
7681 } else if (stream->fourcc == FOURCC_sawb) {
7682 /* force mono 16000 Hz for AMR-WB */
7683 stream->sampled = TRUE;
7684 stream->n_channels = 1;
7685 stream->rate = 16000;
7686 } else if (stream->fourcc == FOURCC_mp4a) {
7687 stream->sampled = TRUE;
7690 /* collect sample information */
7691 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7692 goto samples_failed;
7694 if (qtdemux->fragmented) {
7698 /* need all moov samples as basis; probably not many if any at all */
7699 /* prevent moof parsing taking of at this time */
7700 offset = qtdemux->moof_offset;
7701 qtdemux->moof_offset = 0;
7702 if (stream->n_samples &&
7703 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7704 qtdemux->moof_offset = offset;
7705 goto samples_failed;
7707 qtdemux->moof_offset = 0;
7708 /* movie duration more reliable in this case (e.g. mehd) */
7709 if (qtdemux->segment.duration &&
7710 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7711 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7712 stream->timescale, GST_SECOND);
7713 /* need defaults for fragments */
7714 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7717 /* configure segments */
7718 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7719 goto segments_failed;
7721 /* add some language tag, if useful */
7722 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7723 strcmp (stream->lang_id, "und")) {
7724 const gchar *lang_code;
7727 list = gst_tag_list_new_empty ();
7729 /* convert ISO 639-2 code to ISO 639-1 */
7730 lang_code = gst_tag_get_language_code (stream->lang_id);
7731 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7732 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7735 /* now we are ready to add the stream */
7736 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7737 goto too_many_streams;
7739 stream->pending_tags = list;
7740 qtdemux->streams[qtdemux->n_streams] = stream;
7741 qtdemux->n_streams++;
7742 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7749 GST_INFO_OBJECT (qtdemux, "skip disabled track");
7755 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7756 (_("This file is corrupt and cannot be played.")), (NULL));
7762 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7769 /* we posted an error already */
7770 /* free stbl sub-atoms */
7771 gst_qtdemux_stbl_free (stream);
7777 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7778 GST_FOURCC_ARGS (stream->subtype));
7784 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7785 (_("This file contains too many streams. Only playing first %d"),
7786 GST_QTDEMUX_MAX_STREAMS), (NULL));
7791 /* If we can estimate the overall bitrate, and don't have information about the
7792 * stream bitrate for exactly one stream, this guesses the stream bitrate as
7793 * the overall bitrate minus the sum of the bitrates of all other streams. This
7794 * should be useful for the common case where we have one audio and one video
7795 * stream and can estimate the bitrate of one, but not the other. */
7797 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
7799 QtDemuxStream *stream = NULL;
7800 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
7804 if (qtdemux->fragmented)
7807 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
7809 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
7811 GST_DEBUG_OBJECT (qtdemux,
7812 "Size in bytes of the stream not known - bailing");
7816 /* Subtract the header size */
7817 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
7818 size, qtdemux->header_size);
7820 if (size < qtdemux->header_size)
7823 size = size - qtdemux->header_size;
7825 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
7826 duration == GST_CLOCK_TIME_NONE) {
7827 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
7831 for (i = 0; i < qtdemux->n_streams; i++) {
7832 switch (qtdemux->streams[i]->subtype) {
7835 /* retrieve bitrate, prefer avg then max */
7837 if (qtdemux->streams[i]->pending_tags) {
7838 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7839 GST_TAG_MAXIMUM_BITRATE, &bitrate);
7840 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7841 GST_TAG_BITRATE, &bitrate);
7844 sum_bitrate += bitrate;
7847 GST_DEBUG_OBJECT (qtdemux,
7848 ">1 stream with unknown bitrate - bailing");
7851 stream = qtdemux->streams[i];
7855 /* For other subtypes, we assume no significant impact on bitrate */
7861 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
7865 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
7867 if (sys_bitrate < sum_bitrate) {
7868 /* This can happen, since sum_bitrate might be derived from maximum
7869 * bitrates and not average bitrates */
7870 GST_DEBUG_OBJECT (qtdemux,
7871 "System bitrate less than sum bitrate - bailing");
7875 bitrate = sys_bitrate - sum_bitrate;
7876 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
7877 ", Stream bitrate = %u", sys_bitrate, bitrate);
7879 if (!stream->pending_tags)
7880 stream->pending_tags = gst_tag_list_new_empty ();
7882 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
7883 GST_TAG_BITRATE, bitrate, NULL);
7886 static GstFlowReturn
7887 qtdemux_expose_streams (GstQTDemux * qtdemux)
7890 GstFlowReturn ret = GST_FLOW_OK;
7892 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7894 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7895 QtDemuxStream *stream = qtdemux->streams[i];
7896 guint32 sample_num = 0;
7901 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7902 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7904 if (qtdemux->fragmented) {
7905 /* need all moov samples first */
7906 GST_OBJECT_LOCK (qtdemux);
7907 while (stream->n_samples == 0)
7908 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7910 GST_OBJECT_UNLOCK (qtdemux);
7912 /* discard any stray moof */
7913 qtdemux->moof_offset = 0;
7916 /* prepare braking */
7917 if (ret != GST_FLOW_ERROR)
7920 /* in pull mode, we should have parsed some sample info by now;
7921 * and quite some code will not handle no samples.
7922 * in push mode, we'll just have to deal with it */
7923 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7924 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7925 gst_qtdemux_stream_free (qtdemux, stream);
7926 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7927 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7928 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7929 qtdemux->n_streams--;
7934 /* parse number of initial sample to set frame rate cap */
7935 while (sample_num < stream->n_samples && sample_num < samples) {
7936 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7940 /* collect and sort durations */
7941 samples = MIN (stream->stbl_index + 1, samples);
7942 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7944 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7946 while (sample_num < samples) {
7947 g_array_append_val (durations, stream->samples[sample_num].duration);
7950 g_array_sort (durations, less_than);
7951 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7952 g_array_free (durations, TRUE);
7955 /* now we have all info and can expose */
7956 list = stream->pending_tags;
7957 stream->pending_tags = NULL;
7958 gst_qtdemux_add_stream (qtdemux, stream, list);
7961 gst_qtdemux_guess_bitrate (qtdemux);
7963 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7965 /* check if we should post a redirect in case there is a single trak
7966 * and it is a redirecting trak */
7967 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7970 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7971 "an external content");
7972 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7973 gst_structure_new ("redirect",
7974 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7976 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7977 qtdemux->posted_redirect = TRUE;
7983 /* check if major or compatible brand is 3GP */
7984 static inline gboolean
7985 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7988 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7989 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7990 } else if (qtdemux->comp_brands != NULL) {
7994 gboolean res = FALSE;
7996 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
8000 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
8001 GST_MAKE_FOURCC ('3', 'g', 0, 0));
8005 gst_buffer_unmap (qtdemux->comp_brands, &map);
8012 /* check if tag is a spec'ed 3GP tag keyword storing a string */
8013 static inline gboolean
8014 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
8016 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
8017 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
8018 || fourcc == FOURCC_albm;
8022 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
8023 const char *dummy, GNode * node)
8025 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8029 gdouble longitude, latitude, altitude;
8032 len = QT_UINT32 (node->data);
8039 /* TODO: language code skipped */
8041 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
8044 /* do not alarm in trivial case, but bail out otherwise */
8045 if (*(data + offset) != 0) {
8046 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
8050 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8051 GST_TAG_GEO_LOCATION_NAME, name, NULL);
8052 offset += strlen (name);
8056 if (len < offset + 2 + 4 + 4 + 4)
8059 /* +1 +1 = skip null-terminator and location role byte */
8061 /* table in spec says unsigned, semantics say negative has meaning ... */
8062 longitude = QT_SFP32 (data + offset);
8065 latitude = QT_SFP32 (data + offset);
8068 altitude = QT_SFP32 (data + offset);
8070 /* one invalid means all are invalid */
8071 if (longitude >= -180.0 && longitude <= 180.0 &&
8072 latitude >= -90.0 && latitude <= 90.0) {
8073 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8074 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
8075 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
8076 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
8079 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
8086 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
8093 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8100 len = QT_UINT32 (node->data);
8104 y = QT_UINT16 ((guint8 *) node->data + 12);
8106 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
8109 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
8111 date = g_date_new_dmy (1, 1, y);
8112 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
8117 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
8118 const char *dummy, GNode * node)
8121 char *tag_str = NULL;
8126 len = QT_UINT32 (node->data);
8131 entity = (guint8 *) node->data + offset;
8132 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
8133 GST_DEBUG_OBJECT (qtdemux,
8134 "classification info: %c%c%c%c invalid classification entity",
8135 entity[0], entity[1], entity[2], entity[3]);
8140 table = QT_UINT16 ((guint8 *) node->data + offset);
8142 /* Language code skipped */
8146 /* Tag format: "XXXX://Y[YYYY]/classification info string"
8147 * XXXX: classification entity, fixed length 4 chars.
8148 * Y[YYYY]: classification table, max 5 chars.
8150 tag_str = g_strdup_printf ("----://%u/%s",
8151 table, (char *) node->data + offset);
8153 /* memcpy To be sure we're preserving byte order */
8154 memcpy (tag_str, entity, 4);
8155 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
8157 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
8167 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
8173 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
8174 const char *dummy, GNode * node)
8176 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8182 gboolean ret = TRUE;
8184 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8186 len = QT_UINT32 (data->data);
8187 type = QT_UINT32 ((guint8 *) data->data + 8);
8188 if (type == 0x00000001 && len > 16) {
8189 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
8192 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
8193 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
8197 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
8201 len = QT_UINT32 (node->data);
8202 type = QT_UINT32 ((guint8 *) node->data + 4);
8203 if ((type >> 24) == 0xa9) {
8204 /* Type starts with the (C) symbol, so the next 32 bits are
8205 * the language code, which we ignore */
8207 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
8208 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
8209 QT_FOURCC ((guint8 *) node->data + 4))) {
8210 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
8212 /* we go for 3GP style encoding if major brands claims so,
8213 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
8214 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8215 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
8216 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
8218 /* 16-bit Language code is ignored here as well */
8219 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
8226 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
8227 ret = FALSE; /* may have to fallback */
8229 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8230 len - offset, env_vars);
8232 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
8233 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
8237 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
8244 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
8245 const char *dummy, GNode * node)
8247 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
8251 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
8252 const char *dummy, GNode * node)
8254 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8256 char *s, *t, *k = NULL;
8261 /* first try normal string tag if major brand not 3GP */
8262 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
8263 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
8264 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
8265 * let's try it 3gpp way after minor safety check */
8267 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
8273 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
8277 len = QT_UINT32 (data);
8281 count = QT_UINT8 (data + 14);
8283 for (; count; count--) {
8286 if (offset + 1 > len)
8288 slen = QT_UINT8 (data + offset);
8290 if (offset + slen > len)
8292 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8295 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
8297 t = g_strjoin (",", k, s, NULL);
8305 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
8312 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
8313 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
8322 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
8328 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
8329 const char *tag2, GNode * node)
8336 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8338 len = QT_UINT32 (data->data);
8339 type = QT_UINT32 ((guint8 *) data->data + 8);
8340 if (type == 0x00000000 && len >= 22) {
8341 n1 = QT_UINT16 ((guint8 *) data->data + 18);
8342 n2 = QT_UINT16 ((guint8 *) data->data + 20);
8344 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
8345 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8349 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
8350 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8358 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8366 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8368 len = QT_UINT32 (data->data);
8369 type = QT_UINT32 ((guint8 *) data->data + 8);
8370 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
8371 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8372 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
8373 n1 = QT_UINT16 ((guint8 *) data->data + 16);
8375 /* do not add bpm=0 */
8376 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
8377 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8378 tag1, (gdouble) n1, NULL);
8385 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
8386 const char *dummy, GNode * node)
8393 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8395 len = QT_UINT32 (data->data);
8396 type = QT_UINT32 ((guint8 *) data->data + 8);
8397 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
8398 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8399 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
8400 num = QT_UINT32 ((guint8 *) data->data + 16);
8402 /* do not add num=0 */
8403 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
8404 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8412 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8420 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8422 len = QT_UINT32 (data->data);
8423 type = QT_UINT32 ((guint8 *) data->data + 8);
8424 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
8425 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
8427 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
8428 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
8429 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
8430 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8431 tag1, sample, NULL);
8432 gst_sample_unref (sample);
8439 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8447 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8449 len = QT_UINT32 (data->data);
8450 type = QT_UINT32 ((guint8 *) data->data + 8);
8451 if (type == 0x00000001 && len > 16) {
8452 guint y, m = 1, d = 1;
8455 s = g_strndup ((char *) data->data + 16, len - 16);
8456 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
8457 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
8458 if (ret >= 1 && y > 1500 && y < 3000) {
8461 date = g_date_new_dmy (d, m, y);
8462 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
8466 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
8474 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8479 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8481 /* re-route to normal string tag if major brand says so
8482 * or no data atom and compatible brand suggests so */
8483 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8484 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
8485 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
8492 len = QT_UINT32 (data->data);
8493 type = QT_UINT32 ((guint8 *) data->data + 8);
8494 if (type == 0x00000000 && len >= 18) {
8495 n = QT_UINT16 ((guint8 *) data->data + 16);
8499 genre = gst_tag_id3_genre_get (n - 1);
8500 if (genre != NULL) {
8501 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
8502 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8511 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
8512 guint8 * data, guint32 datasize)
8517 /* make a copy to have \0 at the end */
8518 datacopy = g_strndup ((gchar *) data, datasize);
8520 /* convert the str to double */
8521 if (sscanf (datacopy, "%lf", &value) == 1) {
8522 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
8523 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
8525 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
8533 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
8534 const char *tag_bis, GNode * node)
8543 const gchar *meanstr;
8544 const gchar *namestr;
8546 /* checking the whole ---- atom size for consistency */
8547 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8548 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8552 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8554 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8558 meansize = QT_UINT32 (mean->data);
8559 if (meansize <= 12) {
8560 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8563 meanstr = ((gchar *) mean->data) + 12;
8565 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8567 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8571 namesize = QT_UINT32 (name->data);
8572 if (namesize <= 12) {
8573 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8576 namestr = ((gchar *) name->data) + 12;
8583 * uint24 - data type
8587 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8589 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8592 datasize = QT_UINT32 (data->data);
8593 if (datasize <= 16) {
8594 GST_WARNING_OBJECT (demux, "Data atom too small");
8597 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8599 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8602 const gchar name[28];
8603 const gchar tag[28];
8606 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8607 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8608 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8609 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8610 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8611 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8612 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8613 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8617 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8618 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8619 switch (gst_tag_get_type (tags[i].tag)) {
8621 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8622 ((guint8 *) data->data) + 16, datasize - 16);
8625 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8634 if (i == G_N_ELEMENTS (tags))
8648 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8649 namestr_dbg = g_strndup (namestr, namesize - 12);
8651 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8652 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8654 g_free (namestr_dbg);
8655 g_free (meanstr_dbg);
8661 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
8662 const char *tag_bis, GNode * node)
8667 GstTagList *taglist = NULL;
8669 GST_LOG_OBJECT (demux, "parsing ID32");
8672 len = GST_READ_UINT32_BE (data);
8674 /* need at least full box and language tag */
8678 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
8679 gst_buffer_fill (buf, 0, data + 14, len - 14);
8681 taglist = gst_tag_list_from_id3v2_tag (buf);
8683 GST_LOG_OBJECT (demux, "parsing ok");
8684 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
8686 GST_LOG_OBJECT (demux, "parsing failed");
8690 gst_tag_list_unref (taglist);
8692 gst_buffer_unref (buf);
8695 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8696 const char *tag, const char *tag_bis, GNode * node);
8699 FOURCC_pcst -> if media is a podcast -> bool
8700 FOURCC_cpil -> if media is part of a compilation -> bool
8701 FOURCC_pgap -> if media is part of a gapless context -> bool
8702 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8708 const gchar *gst_tag;
8709 const gchar *gst_tag_bis;
8710 const GstQTDemuxAddTagFunc func;
8713 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8714 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8715 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8716 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8717 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8718 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8719 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8720 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8721 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8722 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8723 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8724 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8725 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8726 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8727 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8728 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8729 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8730 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8731 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8732 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8733 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8734 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8735 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8736 qtdemux_tag_add_num}, {
8737 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8738 qtdemux_tag_add_num}, {
8739 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8740 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8741 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8742 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8743 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8744 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8745 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8746 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8747 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8748 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8749 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8750 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8751 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8752 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8753 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8754 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8755 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8756 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8757 qtdemux_tag_add_classification}, {
8759 /* This is a special case, some tags are stored in this
8760 * 'reverse dns naming', according to:
8761 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8764 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
8765 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
8766 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
8770 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8783 len = QT_UINT32 (data);
8784 buf = gst_buffer_new_and_alloc (len);
8785 _gst_buffer_copy_into_mem (buf, 0, data, len);
8787 /* heuristic to determine style of tag */
8788 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8789 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8791 else if (demux->major_brand == FOURCC_qt__)
8792 style = "quicktime";
8793 /* fall back to assuming iso/3gp tag style */
8797 /* santize the name for the caps. */
8798 for (i = 0; i < 4; i++) {
8799 guint8 d = data[4 + i];
8800 if (g_ascii_isalnum (d))
8801 ndata[i] = g_ascii_tolower (d);
8806 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8807 ndata[0], ndata[1], ndata[2], ndata[3]);
8808 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8810 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
8811 sample = gst_sample_new (buf, NULL, NULL, s);
8812 gst_buffer_unref (buf);
8813 g_free (media_type);
8815 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
8818 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8819 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
8821 gst_sample_unref (sample);
8825 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8833 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8835 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8837 GST_LOG_OBJECT (qtdemux, "no ilst");
8842 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8845 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8846 if (!qtdemux->tag_list) {
8847 qtdemux->tag_list = gst_tag_list_new_empty ();
8848 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
8852 while (i < G_N_ELEMENTS (add_funcs)) {
8853 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8857 len = QT_UINT32 (node->data);
8859 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8860 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8862 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8863 add_funcs[i].gst_tag_bis, node);
8865 g_node_destroy (node);
8871 /* parsed nodes have been removed, pass along remainder as blob */
8872 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8873 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8875 /* parse up XMP_ node if existing */
8876 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8879 GstTagList *taglist;
8881 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
8882 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
8883 taglist = gst_tag_list_from_xmp_buffer (buf);
8884 gst_buffer_unref (buf);
8886 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8888 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8895 GstStructure *structure; /* helper for sort function */
8897 guint min_req_bitrate;
8898 guint min_req_qt_version;
8902 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8904 GstQtReference *ref_a = (GstQtReference *) a;
8905 GstQtReference *ref_b = (GstQtReference *) b;
8907 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8908 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8910 /* known bitrates go before unknown; higher bitrates go first */
8911 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8914 /* sort the redirects and post a message for the application.
8917 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8919 GstQtReference *best;
8922 GValue list_val = { 0, };
8925 g_assert (references != NULL);
8927 references = g_list_sort (references, qtdemux_redirects_sort_func);
8929 best = (GstQtReference *) references->data;
8931 g_value_init (&list_val, GST_TYPE_LIST);
8933 for (l = references; l != NULL; l = l->next) {
8934 GstQtReference *ref = (GstQtReference *) l->data;
8935 GValue struct_val = { 0, };
8937 ref->structure = gst_structure_new ("redirect",
8938 "new-location", G_TYPE_STRING, ref->location, NULL);
8940 if (ref->min_req_bitrate > 0) {
8941 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8942 ref->min_req_bitrate, NULL);
8945 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8946 g_value_set_boxed (&struct_val, ref->structure);
8947 gst_value_list_append_value (&list_val, &struct_val);
8948 g_value_unset (&struct_val);
8949 /* don't free anything here yet, since we need best->structure below */
8952 g_assert (best != NULL);
8953 s = gst_structure_copy (best->structure);
8955 if (g_list_length (references) > 1) {
8956 gst_structure_set_value (s, "locations", &list_val);
8959 g_value_unset (&list_val);
8961 for (l = references; l != NULL; l = l->next) {
8962 GstQtReference *ref = (GstQtReference *) l->data;
8964 gst_structure_free (ref->structure);
8965 g_free (ref->location);
8968 g_list_free (references);
8970 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8971 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8972 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8973 qtdemux->posted_redirect = TRUE;
8976 /* look for redirect nodes, collect all redirect information and
8980 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8982 GNode *rmra, *rmda, *rdrf;
8984 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8986 GList *redirects = NULL;
8988 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8990 GstQtReference ref = { NULL, NULL, 0, 0 };
8993 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8994 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8995 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8996 ref.min_req_bitrate);
8999 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
9000 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
9001 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
9003 #ifndef GST_DISABLE_GST_DEBUG
9004 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
9006 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
9008 GST_LOG_OBJECT (qtdemux,
9009 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
9010 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
9011 bitmask, check_type);
9012 if (package == FOURCC_qtim && check_type == 0) {
9013 ref.min_req_qt_version = version;
9017 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
9022 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
9023 ref_data = (guint8 *) rdrf->data + 20;
9024 if (ref_type == FOURCC_alis) {
9025 guint record_len, record_version, fn_len;
9027 /* MacOSX alias record, google for alias-layout.txt */
9028 record_len = QT_UINT16 (ref_data + 4);
9029 record_version = QT_UINT16 (ref_data + 4 + 2);
9030 fn_len = QT_UINT8 (ref_data + 50);
9031 if (record_len > 50 && record_version == 2 && fn_len > 0) {
9032 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
9034 } else if (ref_type == FOURCC_url_) {
9035 ref.location = g_strdup ((gchar *) ref_data);
9037 GST_DEBUG_OBJECT (qtdemux,
9038 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
9039 GST_FOURCC_ARGS (ref_type));
9041 if (ref.location != NULL) {
9042 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
9043 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
9045 GST_WARNING_OBJECT (qtdemux,
9046 "Failed to extract redirect location from rdrf atom");
9050 /* look for others */
9051 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
9054 if (redirects != NULL) {
9055 qtdemux_process_redirects (qtdemux, redirects);
9062 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
9067 tags = gst_tag_list_new_empty ();
9068 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
9071 if (qtdemux->major_brand == FOURCC_mjp2)
9072 fmt = "Motion JPEG 2000";
9073 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
9075 else if (qtdemux->major_brand == FOURCC_qt__)
9077 else if (qtdemux->fragmented)
9080 fmt = "ISO MP4/M4A";
9082 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
9083 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
9085 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
9091 /* we have read th complete moov node now.
9092 * This function parses all of the relevant info, creates the traks and
9093 * prepares all data structures for playback
9096 qtdemux_parse_tree (GstQTDemux * qtdemux)
9103 guint64 creation_time;
9104 GstDateTime *datetime = NULL;
9107 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
9109 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
9110 return qtdemux_parse_redirects (qtdemux);
9113 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
9115 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
9116 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
9117 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
9118 } else if (version == 0) {
9119 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
9120 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
9121 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
9123 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
9127 /* Moving qt creation time (secs since 1904) to unix time */
9128 if (creation_time != 0) {
9129 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
9132 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
9133 /* some data cleansing sanity */
9134 g_get_current_time (&now);
9135 if (now.tv_sec + 24 * 3600 < creation_time) {
9136 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
9138 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
9141 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
9142 "please file a bug at http://bugzilla.gnome.org");
9146 if (!qtdemux->tag_list) {
9147 qtdemux->tag_list = gst_tag_list_new_empty ();
9148 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
9151 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
9152 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
9154 gst_date_time_unref (datetime);
9157 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
9158 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
9160 /* check for fragmented file and get some (default) data */
9161 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
9164 GstByteReader mehd_data;
9166 /* let track parsing or anyone know weird stuff might happen ... */
9167 qtdemux->fragmented = TRUE;
9169 /* compensate for total duration */
9170 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
9172 qtdemux_parse_mehd (qtdemux, &mehd_data);
9175 /* set duration in the segment info */
9176 gst_qtdemux_get_duration (qtdemux, &duration);
9178 qtdemux->segment.duration = duration;
9179 /* also do not exceed duration; stop is set that way post seek anyway,
9180 * and segment activation falls back to duration,
9181 * whereas loop only checks stop, so let's align this here as well */
9182 qtdemux->segment.stop = duration;
9185 /* parse all traks */
9186 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
9188 qtdemux_parse_trak (qtdemux, trak);
9189 /* iterate all siblings */
9190 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
9194 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
9196 qtdemux_parse_udta (qtdemux, udta);
9198 GST_LOG_OBJECT (qtdemux, "No udta node found.");
9201 /* maybe also some tags in meta box */
9202 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
9204 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
9205 qtdemux_parse_udta (qtdemux, udta);
9207 GST_LOG_OBJECT (qtdemux, "No meta node found.");
9210 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
9215 /* taken from ffmpeg */
9217 get_size (guint8 * ptr, guint8 ** end)
9226 len = (len << 7) | (c & 0x7f);
9235 /* this can change the codec originally present in @list */
9237 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
9238 GNode * esds, GstTagList * list)
9240 int len = QT_UINT32 (esds->data);
9241 guint8 *ptr = esds->data;
9242 guint8 *end = ptr + len;
9244 guint8 *data_ptr = NULL;
9246 guint8 object_type_id = 0;
9247 const char *codec_name = NULL;
9248 GstCaps *caps = NULL;
9250 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
9252 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
9255 tag = QT_UINT8 (ptr);
9256 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
9258 len = get_size (ptr, &ptr);
9259 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
9263 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
9264 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
9268 guint max_bitrate, avg_bitrate;
9270 object_type_id = QT_UINT8 (ptr);
9271 max_bitrate = QT_UINT32 (ptr + 5);
9272 avg_bitrate = QT_UINT32 (ptr + 9);
9273 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
9274 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
9275 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
9276 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
9277 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
9278 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9279 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9280 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9282 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9283 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
9290 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
9296 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
9300 GST_ERROR_OBJECT (qtdemux, "parse error");
9305 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
9306 * in use, and should also be used to override some other parameters for some
9308 switch (object_type_id) {
9309 case 0x20: /* MPEG-4 */
9310 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
9311 * profile_and_level_indication */
9312 if (data_ptr != NULL && data_len >= 5 &&
9313 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
9314 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
9315 data_ptr + 4, data_len - 4);
9317 break; /* Nothing special needed here */
9318 case 0x21: /* H.264 */
9319 codec_name = "H.264 / AVC";
9320 caps = gst_caps_new_simple ("video/x-h264",
9321 "stream-format", G_TYPE_STRING, "avc",
9322 "alignment", G_TYPE_STRING, "au", NULL);
9324 case 0x40: /* AAC (any) */
9325 case 0x66: /* AAC Main */
9326 case 0x67: /* AAC LC */
9327 case 0x68: /* AAC SSR */
9328 /* Override channels and rate based on the codec_data, as it's often
9330 /* Only do so for basic setup without HE-AAC extension */
9331 if (data_ptr && data_len == 2) {
9332 guint channels, rateindex, rate;
9334 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
9335 channels = (data_ptr[1] & 0x7f) >> 3;
9336 if (channels > 0 && channels < 7) {
9337 stream->n_channels = channels;
9338 } else if (channels == 7) {
9339 stream->n_channels = 8;
9342 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
9343 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
9345 stream->rate = rate;
9348 /* Set level and profile if possible */
9349 if (data_ptr != NULL && data_len >= 2) {
9350 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
9351 data_ptr, data_len);
9354 case 0x60: /* MPEG-2, various profiles */
9360 codec_name = "MPEG-2 video";
9362 gst_caps_unref (stream->caps);
9363 stream->caps = gst_caps_new_simple ("video/mpeg",
9364 "mpegversion", G_TYPE_INT, 2,
9365 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9367 case 0x69: /* MP3 has two different values, accept either */
9369 /* change to mpeg1 layer 3 audio */
9370 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
9371 "mpegversion", G_TYPE_INT, 1, NULL);
9372 codec_name = "MPEG-1 layer 3";
9374 case 0x6A: /* MPEG-1 */
9375 codec_name = "MPEG-1 video";
9377 gst_caps_unref (stream->caps);
9378 stream->caps = gst_caps_new_simple ("video/mpeg",
9379 "mpegversion", G_TYPE_INT, 1,
9380 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9382 case 0x6C: /* MJPEG */
9383 caps = gst_caps_new_empty_simple ("image/jpeg");
9384 codec_name = "Motion-JPEG";
9386 case 0x6D: /* PNG */
9387 caps = gst_caps_new_empty_simple ("image/png");
9388 codec_name = "PNG still images";
9390 case 0x6E: /* JPEG2000 */
9391 codec_name = "JPEG-2000";
9392 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9394 case 0xA4: /* Dirac */
9395 codec_name = "Dirac";
9396 caps = gst_caps_new_empty_simple ("video/x-dirac");
9398 case 0xA5: /* AC3 */
9399 codec_name = "AC-3 audio";
9400 caps = gst_caps_new_simple ("audio/x-ac3",
9401 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9403 case 0xE1: /* QCELP */
9404 /* QCELP, the codec_data is a riff tag (little endian) with
9405 * 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). */
9406 caps = gst_caps_new_empty_simple ("audio/qcelp");
9407 codec_name = "QCELP";
9413 /* If we have a replacement caps, then change our caps for this stream */
9415 gst_caps_unref (stream->caps);
9416 stream->caps = caps;
9419 if (codec_name && list)
9420 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9421 GST_TAG_AUDIO_CODEC, codec_name, NULL);
9423 /* Add the codec_data attribute to caps, if we have it */
9427 buffer = gst_buffer_new_and_alloc (data_len);
9428 _gst_buffer_copy_into_mem (buffer, 0, data_ptr, data_len);
9430 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
9431 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
9433 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
9435 gst_buffer_unref (buffer);
9440 #define _codec(name) \
9443 *codec_name = g_strdup (name); \
9448 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9449 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9452 const GstStructure *s;
9456 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
9457 _codec ("PNG still images");
9458 caps = gst_caps_new_empty_simple ("image/png");
9460 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
9461 _codec ("JPEG still images");
9462 caps = gst_caps_new_empty_simple ("image/jpeg");
9464 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
9465 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
9466 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
9467 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
9468 _codec ("Motion-JPEG");
9469 caps = gst_caps_new_empty_simple ("image/jpeg");
9471 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
9472 _codec ("Motion-JPEG format B");
9473 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
9475 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
9476 _codec ("JPEG-2000");
9477 /* override to what it should be according to spec, avoid palette_data */
9478 stream->bits_per_sample = 24;
9479 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9481 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
9482 _codec ("Sorensen video v.3");
9483 caps = gst_caps_new_simple ("video/x-svq",
9484 "svqversion", G_TYPE_INT, 3, NULL);
9486 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
9487 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
9488 _codec ("Sorensen video v.1");
9489 caps = gst_caps_new_simple ("video/x-svq",
9490 "svqversion", G_TYPE_INT, 1, NULL);
9492 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9496 _codec ("Raw RGB video");
9497 bps = QT_UINT16 (stsd_data + 98);
9498 /* set common stuff */
9499 caps = gst_caps_new_empty_simple ("video/x-raw");
9503 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB15", NULL);
9506 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB16", NULL);
9509 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB", NULL);
9512 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "ARGB", NULL);
9520 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
9521 _codec ("Raw planar YUV 4:2:0");
9522 caps = gst_caps_new_simple ("video/x-raw",
9523 "format", G_TYPE_STRING, "I420", NULL);
9525 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
9526 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
9527 _codec ("Raw packed YUV 4:2:2");
9528 caps = gst_caps_new_simple ("video/x-raw",
9529 "format", G_TYPE_STRING, "YUY2", NULL);
9531 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
9532 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
9533 _codec ("Raw packed YUV 4:2:2");
9534 caps = gst_caps_new_simple ("video/x-raw",
9535 "format", G_TYPE_STRING, "UYVY", NULL);
9537 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
9538 _codec ("Raw packed YUV 10-bit 4:2:2");
9539 caps = gst_caps_new_simple ("video/x-raw",
9540 "format", G_TYPE_STRING, "v210", NULL);
9542 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
9543 _codec ("Raw packed RGB 10-bit 4:4:4");
9544 caps = gst_caps_new_simple ("video/x-raw",
9545 "format", G_TYPE_STRING, "r210", NULL);
9547 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
9548 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
9549 _codec ("MPEG-1 video");
9550 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9551 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9553 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
9554 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
9555 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
9556 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
9557 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
9558 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
9559 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
9560 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
9561 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
9562 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
9563 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
9564 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
9565 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
9566 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
9567 _codec ("MPEG-2 video");
9568 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
9569 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9571 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
9572 _codec ("GIF still images");
9573 caps = gst_caps_new_empty_simple ("image/gif");
9575 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
9576 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
9577 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
9578 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9580 /* ffmpeg uses the height/width props, don't know why */
9581 caps = gst_caps_new_simple ("video/x-h263",
9582 "variant", G_TYPE_STRING, "itu", NULL);
9584 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9585 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9586 _codec ("MPEG-4 video");
9587 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9588 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9590 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9591 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9592 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9593 caps = gst_caps_new_simple ("video/x-msmpeg",
9594 "msmpegversion", G_TYPE_INT, 43, NULL);
9596 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9598 caps = gst_caps_new_simple ("video/x-divx",
9599 "divxversion", G_TYPE_INT, 3, NULL);
9601 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9602 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9604 caps = gst_caps_new_simple ("video/x-divx",
9605 "divxversion", G_TYPE_INT, 4, NULL);
9607 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9609 caps = gst_caps_new_simple ("video/x-divx",
9610 "divxversion", G_TYPE_INT, 5, NULL);
9613 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9614 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9615 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9616 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9617 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9618 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9619 caps = gst_caps_new_simple ("video/mpeg",
9620 "mpegversion", G_TYPE_INT, 4, NULL);
9622 *codec_name = g_strdup ("MPEG-4");
9625 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9627 caps = gst_caps_new_empty_simple ("video/x-cinepak");
9629 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9630 _codec ("Apple QuickDraw");
9631 caps = gst_caps_new_empty_simple ("video/x-qdrw");
9633 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9634 _codec ("Apple video");
9635 caps = gst_caps_new_empty_simple ("video/x-apple-video");
9637 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9638 _codec ("H.264 / AVC");
9639 caps = gst_caps_new_simple ("video/x-h264",
9640 "stream-format", G_TYPE_STRING, "avc",
9641 "alignment", G_TYPE_STRING, "au", NULL);
9643 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9644 _codec ("Run-length encoding");
9645 caps = gst_caps_new_simple ("video/x-rle",
9646 "layout", G_TYPE_STRING, "quicktime", NULL);
9648 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9649 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9650 _codec ("Indeo Video 3");
9651 caps = gst_caps_new_simple ("video/x-indeo",
9652 "indeoversion", G_TYPE_INT, 3, NULL);
9654 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9655 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9656 _codec ("Intel Video 4");
9657 caps = gst_caps_new_simple ("video/x-indeo",
9658 "indeoversion", G_TYPE_INT, 4, NULL);
9660 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9661 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9662 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9663 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9664 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9665 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9666 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9667 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9668 _codec ("DV Video");
9669 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9670 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9672 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9673 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9674 _codec ("DVCPro50 Video");
9675 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9676 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9678 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9679 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9680 _codec ("DVCProHD Video");
9681 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9682 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9684 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9685 _codec ("Apple Graphics (SMC)");
9686 caps = gst_caps_new_empty_simple ("video/x-smc");
9688 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9690 caps = gst_caps_new_empty_simple ("video/x-vp3");
9692 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9694 caps = gst_caps_new_empty_simple ("video/x-theora");
9695 /* theora uses one byte of padding in the data stream because it does not
9696 * allow 0 sized packets while theora does */
9697 stream->padding = 1;
9699 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9701 caps = gst_caps_new_empty_simple ("video/x-dirac");
9703 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9704 _codec ("TIFF still images");
9705 caps = gst_caps_new_empty_simple ("image/tiff");
9707 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9708 _codec ("Apple Intermediate Codec");
9709 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9711 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9712 _codec ("AVID DNxHD");
9713 caps = gst_caps_from_string ("video/x-dnxhd");
9715 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9717 caps = gst_caps_from_string ("video/x-vp8");
9719 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
9720 _codec ("Apple ProRes LT");
9722 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
9725 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
9726 _codec ("Apple ProRes HQ");
9728 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
9731 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
9732 _codec ("Apple ProRes");
9734 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
9737 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
9738 _codec ("Apple ProRes Proxy");
9740 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
9743 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
9744 _codec ("Apple ProRes 4444");
9746 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
9751 caps = gst_caps_new_simple ("video/x-wmv",
9752 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
9754 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9757 char *s, fourstr[5];
9759 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9760 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
9761 caps = gst_caps_new_empty_simple (s);
9766 /* enable clipping for raw video streams */
9767 s = gst_caps_get_structure (caps, 0);
9768 name = gst_structure_get_name (s);
9769 if (g_str_has_prefix (name, "video/x-raw")) {
9770 stream->need_clip = TRUE;
9776 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9777 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9780 const GstStructure *s;
9784 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9787 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9788 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9789 _codec ("Raw 8-bit PCM audio");
9790 caps = gst_caps_new_simple ("audio/x-raw",
9791 "format", G_TYPE_STRING, "U8",
9792 "layout", G_TYPE_STRING, "interleaved", NULL);
9794 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9795 endian = G_BIG_ENDIAN;
9797 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9801 GstAudioFormat format;
9804 endian = G_LITTLE_ENDIAN;
9806 depth = stream->bytes_per_packet * 8;
9807 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
9809 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9813 caps = gst_caps_new_simple ("audio/x-raw",
9814 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
9815 "layout", G_TYPE_STRING, "interleaved", NULL);
9818 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9819 _codec ("Raw 64-bit floating-point audio");
9820 caps = gst_caps_new_simple ("audio/x-raw",
9821 "format", G_TYPE_STRING, "F64BE",
9822 "layout", G_TYPE_STRING, "interleaved", NULL);
9824 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9825 _codec ("Raw 32-bit floating-point audio");
9826 caps = gst_caps_new_simple ("audio/x-raw",
9827 "format", G_TYPE_STRING, "F32BE",
9828 "layout", G_TYPE_STRING, "interleaved", NULL);
9831 _codec ("Raw 24-bit PCM audio");
9832 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9834 caps = gst_caps_new_simple ("audio/x-raw",
9835 "format", G_TYPE_STRING, "S24BE",
9836 "layout", G_TYPE_STRING, "interleaved", NULL);
9838 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9839 _codec ("Raw 32-bit PCM audio");
9840 caps = gst_caps_new_simple ("audio/x-raw",
9841 "format", G_TYPE_STRING, "S32BE",
9842 "layout", G_TYPE_STRING, "interleaved", NULL);
9844 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9845 _codec ("Mu-law audio");
9846 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
9848 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9849 _codec ("A-law audio");
9850 caps = gst_caps_new_empty_simple ("audio/x-alaw");
9854 _codec ("Microsoft ADPCM");
9855 /* Microsoft ADPCM-ACM code 2 */
9856 caps = gst_caps_new_simple ("audio/x-adpcm",
9857 "layout", G_TYPE_STRING, "microsoft", NULL);
9861 _codec ("DVI/IMA ADPCM");
9862 caps = gst_caps_new_simple ("audio/x-adpcm",
9863 "layout", G_TYPE_STRING, "dvi", NULL);
9867 _codec ("DVI/Intel IMA ADPCM");
9868 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9869 caps = gst_caps_new_simple ("audio/x-adpcm",
9870 "layout", G_TYPE_STRING, "quicktime", NULL);
9874 /* MPEG layer 3, CBR only (pre QT4.1) */
9875 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9876 _codec ("MPEG-1 layer 3");
9877 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9878 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9879 "mpegversion", G_TYPE_INT, 1, NULL);
9882 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9883 _codec ("EAC-3 audio");
9884 caps = gst_caps_new_simple ("audio/x-eac3",
9885 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9886 stream->sampled = TRUE;
9888 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9889 _codec ("AC-3 audio");
9890 caps = gst_caps_new_simple ("audio/x-ac3",
9891 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9892 stream->sampled = TRUE;
9894 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9896 caps = gst_caps_new_simple ("audio/x-mace",
9897 "maceversion", G_TYPE_INT, 3, NULL);
9899 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9901 caps = gst_caps_new_simple ("audio/x-mace",
9902 "maceversion", G_TYPE_INT, 6, NULL);
9904 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9906 caps = gst_caps_new_empty_simple ("application/ogg");
9908 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9909 _codec ("DV audio");
9910 caps = gst_caps_new_empty_simple ("audio/x-dv");
9912 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9913 _codec ("MPEG-4 AAC audio");
9914 caps = gst_caps_new_simple ("audio/mpeg",
9915 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9916 "stream-format", G_TYPE_STRING, "raw", NULL);
9918 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9919 _codec ("QDesign Music");
9920 caps = gst_caps_new_empty_simple ("audio/x-qdm");
9922 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9923 _codec ("QDesign Music v.2");
9924 /* FIXME: QDesign music version 2 (no constant) */
9925 if (FALSE && data) {
9926 caps = gst_caps_new_simple ("audio/x-qdm2",
9927 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9928 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9929 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9931 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
9934 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9935 _codec ("GSM audio");
9936 caps = gst_caps_new_empty_simple ("audio/x-gsm");
9938 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9939 _codec ("AMR audio");
9940 caps = gst_caps_new_empty_simple ("audio/AMR");
9942 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9943 _codec ("AMR-WB audio");
9944 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
9946 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9947 _codec ("Quicktime IMA ADPCM");
9948 caps = gst_caps_new_simple ("audio/x-adpcm",
9949 "layout", G_TYPE_STRING, "quicktime", NULL);
9951 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9952 _codec ("Apple lossless audio");
9953 caps = gst_caps_new_empty_simple ("audio/x-alac");
9955 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9956 _codec ("QualComm PureVoice");
9957 caps = gst_caps_from_string ("audio/qcelp");
9961 caps = gst_caps_new_empty_simple ("audio/x-wma");
9963 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
9968 GstAudioFormat format;
9971 FLAG_IS_FLOAT = 0x1,
9972 FLAG_IS_BIG_ENDIAN = 0x2,
9973 FLAG_IS_SIGNED = 0x4,
9974 FLAG_IS_PACKED = 0x8,
9975 FLAG_IS_ALIGNED_HIGH = 0x10,
9976 FLAG_IS_NON_INTERLEAVED = 0x20
9978 _codec ("Raw LPCM audio");
9980 if (data && len >= 56) {
9981 depth = QT_UINT32 (data + 40);
9982 flags = QT_UINT32 (data + 44);
9983 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
9985 if ((flags & FLAG_IS_FLOAT) == 0) {
9990 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
9991 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
9992 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
9993 caps = gst_caps_new_simple ("audio/x-raw",
9994 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
9995 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
9996 "non-interleaved" : "interleaved", NULL);
10003 if (flags & FLAG_IS_BIG_ENDIAN)
10004 format = GST_AUDIO_FORMAT_F64BE;
10006 format = GST_AUDIO_FORMAT_F64LE;
10008 if (flags & FLAG_IS_BIG_ENDIAN)
10009 format = GST_AUDIO_FORMAT_F32BE;
10011 format = GST_AUDIO_FORMAT_F32LE;
10013 caps = gst_caps_new_simple ("audio/x-raw",
10014 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
10015 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
10016 "non-interleaved" : "interleaved", NULL);
10020 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
10024 char *s, fourstr[5];
10026 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10027 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
10028 caps = gst_caps_new_empty_simple (s);
10034 GstCaps *templ_caps =
10035 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
10036 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
10037 gst_caps_unref (caps);
10038 gst_caps_unref (templ_caps);
10039 caps = intersection;
10042 /* enable clipping for raw audio streams */
10043 s = gst_caps_get_structure (caps, 0);
10044 name = gst_structure_get_name (s);
10045 if (g_str_has_prefix (name, "audio/x-raw")) {
10046 stream->need_clip = TRUE;
10047 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
10048 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
10054 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10055 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
10059 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
10062 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
10063 _codec ("DVD subtitle");
10064 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
10066 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
10067 _codec ("Quicktime timed text");
10069 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
10070 _codec ("3GPP timed text");
10072 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
10074 /* actual text piece needs to be extracted */
10075 stream->need_process = TRUE;
10079 char *s, fourstr[5];
10081 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10082 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
10083 caps = gst_caps_new_empty_simple (s);
10091 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10092 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
10097 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
10098 _codec ("MPEG 1 video");
10099 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
10100 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);