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>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Coroporation
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
27 * SECTION:element-qtdemux
29 * Demuxes a .mov file into raw or compressed audio and/or video streams.
31 * This element supports both push and pull-based scheduling, depending on the
32 * capabilities of the upstream elements.
35 * <title>Example launch line</title>
37 * 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
38 * ]| Play (parse and decode) a .mov file and try to output it to
39 * an automatically detected soundcard and videosink. If the MOV file contains
40 * compressed audio or video data, this will only work if you have the
41 * right decoder elements/plugins installed.
44 * Last reviewed on 2006-12-29 (0.10.5)
51 #include "gst/gst-i18n-plugin.h"
53 #include <glib/gprintf.h>
54 #include <gst/tag/tag.h>
55 #include <gst/audio/audio.h>
56 #include <gst/video/video.h>
58 #include "qtatomparser.h"
59 #include "qtdemux_types.h"
60 #include "qtdemux_dump.h"
62 #include "descriptors.h"
63 #include "qtdemux_lang.h"
65 #include "qtpalette.h"
67 #include "gst/riff/riff-media.h"
68 #include "gst/riff/riff-read.h"
70 #include <gst/pbutils/pbutils.h>
77 #include <gst/math-compat.h>
83 /* max. size considered 'sane' for non-mdat atoms */
84 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
86 /* if the sample index is larger than this, something is likely wrong */
87 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
89 /* For converting qt creation times to unix epoch times */
90 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
91 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
92 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
93 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
95 #define STREAM_IS_EOS(s) (s->time_position == -1)
97 GST_DEBUG_CATEGORY (qtdemux_debug);
99 /*typedef struct _QtNode QtNode; */
100 typedef struct _QtDemuxSegment QtDemuxSegment;
101 typedef struct _QtDemuxSample QtDemuxSample;
110 struct _QtDemuxSample
113 gint32 pts_offset; /* Add this value to timestamp to get the pts */
115 guint64 timestamp; /* DTS In mov time */
116 guint32 duration; /* In mov time */
117 gboolean keyframe; /* TRUE when this packet is a keyframe */
120 /* timestamp is the DTS */
121 #define QTSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
122 GST_SECOND, (stream)->timescale)
123 /* timestamp + offset is the PTS */
124 #define QTSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
125 (sample)->pts_offset, GST_SECOND, (stream)->timescale)
126 /* timestamp + duration - dts is the duration */
127 #define QTSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
128 (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
130 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
133 * Quicktime has tracks and segments. A track is a continuous piece of
134 * multimedia content. The track is not always played from start to finish but
135 * instead, pieces of the track are 'cut out' and played in sequence. This is
136 * what the segments do.
138 * Inside the track we have keyframes (K) and delta frames. The track has its
139 * own timing, which starts from 0 and extends to end. The position in the track
140 * is called the media_time.
142 * The segments now describe the pieces that should be played from this track
143 * and are basically tuples of media_time/duration/rate entries. We can have
144 * multiple segments and they are all played after one another. An example:
146 * segment 1: media_time: 1 second, duration: 1 second, rate 1
147 * segment 2: media_time: 3 second, duration: 2 second, rate 2
149 * To correctly play back this track, one must play: 1 second of media starting
150 * from media_time 1 followed by 2 seconds of media starting from media_time 3
153 * Each of the segments will be played at a specific time, the first segment at
154 * time 0, the second one after the duration of the first one, etc.. Note that
155 * the time in resulting playback is not identical to the media_time of the
158 * Visually, assuming the track has 4 second of media_time:
161 * .-----------------------------------------------------------.
162 * track: | K.....K.........K........K.......K.......K...........K... |
163 * '-----------------------------------------------------------'
165 * .------------^ ^ .----------^ ^
166 * / .-------------' / .------------------'
168 * .--------------. .--------------.
169 * | segment 1 | | segment 2 |
170 * '--------------' '--------------'
172 * The challenge here is to cut out the right pieces of the track for each of
173 * the playback segments. This fortunately can easily be done with the SEGMENT
174 * events of GStreamer.
176 * For playback of segment 1, we need to provide the decoder with the keyframe
177 * (a), in the above figure, but we must instruct it only to output the decoded
178 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
179 * position set to the time of the segment: 0.
181 * We then proceed to push data from keyframe (a) to frame (b). The decoder
182 * decodes but clips all before media_time 1.
184 * After finishing a segment, we push out a new SEGMENT event with the clipping
185 * boundaries of the new data.
187 * This is a good usecase for the GStreamer accumulated SEGMENT events.
190 struct _QtDemuxSegment
192 /* global time and duration, all gst time */
196 /* media time of trak, all gst time */
202 struct _QtDemuxStream
213 gboolean new_stream; /* signals that a stream_start is required */
214 gboolean on_keyframe; /* if this stream last pushed buffer was a
215 * keyframe. This is important to identify
216 * where to stop pushing buffers after a
217 * segment stop time */
219 /* if the stream has a redirect URI in its headers, we store it here */
226 guint64 duration; /* in timescale */
230 gchar lang_id[4]; /* ISO 639-2T language code */
234 QtDemuxSample *samples;
235 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
236 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
237 the framerate, in timescale units */
238 guint32 offset_in_sample;
239 guint32 max_buffer_size;
241 /* if we use chunks or samples */
253 /* Numerator/denominator framerate */
256 guint16 bits_per_sample;
257 guint16 color_table_id;
258 GstMemory *rgb8_palette;
263 guint samples_per_packet;
264 guint samples_per_frame;
265 guint bytes_per_packet;
266 guint bytes_per_sample;
267 guint bytes_per_frame;
271 gboolean use_allocator;
272 GstAllocator *allocator;
273 GstAllocationParams params;
275 /* when a discontinuity is pending */
278 /* list of buffers to push first */
281 /* if we need to clip this buffer. This is only needed for uncompressed
285 /* buffer needs some custom processing, e.g. subtitles */
286 gboolean need_process;
288 /* current position */
289 guint32 segment_index;
290 guint32 sample_index;
291 guint64 time_position; /* in gst time */
293 /* the Gst segment we are processing out, used for clipping */
295 guint32 segment_seqnum; /* segment event seqnum obtained from seek */
297 /* last GstFlowReturn */
298 GstFlowReturn last_ret;
300 /* quicktime segments */
302 QtDemuxSegment *segments;
307 GstTagList *pending_tags;
308 gboolean send_global_tags;
310 GstEvent *pending_event;
320 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
324 GstByteReader co_chunk;
326 guint32 current_chunk;
328 guint32 samples_per_chunk;
329 guint32 stco_sample_index;
331 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
334 guint32 n_samples_per_chunk;
335 guint32 stsc_chunk_index;
336 guint32 stsc_sample_index;
337 guint64 chunk_offset;
340 guint32 stts_samples;
341 guint32 n_sample_times;
342 guint32 stts_sample_index;
344 guint32 stts_duration;
346 gboolean stss_present;
347 guint32 n_sample_syncs;
350 gboolean stps_present;
351 guint32 n_sample_partial_syncs;
354 gboolean ctts_present;
355 guint32 n_composition_times;
357 guint32 ctts_sample_index;
362 gboolean parsed_trex;
363 guint32 def_sample_duration;
364 guint32 def_sample_size;
365 guint32 def_sample_flags;
369 GstClockTime elst_offset; /* sample offset from edit list */
374 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
375 QTDEMUX_STATE_HEADER, /* Parsing the header */
376 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
377 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
380 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
381 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
382 guint32 fourcc, GstByteReader * parser);
383 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
384 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
385 guint32 fourcc, GstByteReader * parser);
387 static GstStaticPadTemplate gst_qtdemux_sink_template =
388 GST_STATIC_PAD_TEMPLATE ("sink",
391 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
395 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
396 GST_STATIC_PAD_TEMPLATE ("video_%u",
399 GST_STATIC_CAPS_ANY);
401 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
402 GST_STATIC_PAD_TEMPLATE ("audio_%u",
405 GST_STATIC_CAPS_ANY);
407 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
408 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
411 GST_STATIC_CAPS_ANY);
413 #define gst_qtdemux_parent_class parent_class
414 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
416 static void gst_qtdemux_dispose (GObject * object);
419 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
422 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
423 QtDemuxStream * str, gint64 media_offset);
426 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
427 static GstIndex *gst_qtdemux_get_index (GstElement * element);
429 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
430 GstStateChange transition);
431 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
432 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
433 GstObject * parent, GstPadMode mode, gboolean active);
435 static void gst_qtdemux_loop (GstPad * pad);
436 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
438 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
440 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
441 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
442 QtDemuxStream * stream);
444 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
445 const guint8 * buffer, guint length);
446 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
447 const guint8 * buffer, guint length);
448 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
450 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
451 QtDemuxStream * stream, GNode * esds, GstTagList * list);
452 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
453 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
454 gchar ** codec_name);
455 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
456 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
457 gchar ** codec_name);
458 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
459 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
460 gchar ** codec_name);
461 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
462 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
463 gchar ** codec_name);
465 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
466 QtDemuxStream * stream, guint32 n);
467 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
468 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
469 QtDemuxStream * stream);
470 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
471 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
472 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
473 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
474 QtDemuxStream * stream);
477 gst_qtdemux_class_init (GstQTDemuxClass * klass)
479 GObjectClass *gobject_class;
480 GstElementClass *gstelement_class;
482 gobject_class = (GObjectClass *) klass;
483 gstelement_class = (GstElementClass *) klass;
485 parent_class = g_type_class_peek_parent (klass);
487 gobject_class->dispose = gst_qtdemux_dispose;
489 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
491 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
492 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
495 gst_tag_register_musicbrainz_tags ();
497 gst_element_class_add_pad_template (gstelement_class,
498 gst_static_pad_template_get (&gst_qtdemux_sink_template));
499 gst_element_class_add_pad_template (gstelement_class,
500 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
501 gst_element_class_add_pad_template (gstelement_class,
502 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
503 gst_element_class_add_pad_template (gstelement_class,
504 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
505 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
507 "Demultiplex a QuickTime file into audio and video streams",
508 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
510 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
515 gst_qtdemux_init (GstQTDemux * qtdemux)
518 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
519 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
520 gst_pad_set_activatemode_function (qtdemux->sinkpad,
521 qtdemux_sink_activate_mode);
522 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
523 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
524 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
526 qtdemux->state = QTDEMUX_STATE_INITIAL;
527 qtdemux->pullbased = FALSE;
528 qtdemux->posted_redirect = FALSE;
529 qtdemux->neededbytes = 16;
531 qtdemux->adapter = gst_adapter_new ();
533 qtdemux->first_mdat = -1;
534 qtdemux->got_moov = FALSE;
535 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
536 qtdemux->mdatbuffer = NULL;
537 qtdemux->restoredata_buffer = NULL;
538 qtdemux->restoredata_offset = GST_CLOCK_TIME_NONE;
539 qtdemux->fragment_start = -1;
540 qtdemux->media_caps = NULL;
541 qtdemux->exposed = FALSE;
542 qtdemux->mss_mode = FALSE;
543 qtdemux->pending_newsegment = NULL;
544 qtdemux->upstream_newsegment = FALSE;
545 qtdemux->have_group_id = FALSE;
546 qtdemux->group_id = G_MAXUINT;
547 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
549 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
553 gst_qtdemux_dispose (GObject * object)
555 GstQTDemux *qtdemux = GST_QTDEMUX (object);
557 if (qtdemux->adapter) {
558 g_object_unref (G_OBJECT (qtdemux->adapter));
559 qtdemux->adapter = NULL;
562 G_OBJECT_CLASS (parent_class)->dispose (object);
566 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
568 if (qtdemux->posted_redirect) {
569 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
570 (_("This file contains no playable streams.")),
571 ("no known streams found, a redirect message has been posted"));
573 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
574 (_("This file contains no playable streams.")),
575 ("no known streams found"));
580 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
582 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
583 mem, size, 0, size, mem, free_func);
587 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
594 if (G_UNLIKELY (size == 0)) {
596 GstBuffer *tmp = NULL;
598 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
599 if (ret != GST_FLOW_OK)
602 gst_buffer_map (tmp, &map, GST_MAP_READ);
603 size = QT_UINT32 (map.data);
604 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
606 gst_buffer_unmap (tmp, &map);
607 gst_buffer_unref (tmp);
610 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
611 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
612 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
613 /* we're pulling header but already got most interesting bits,
614 * so never mind the rest (e.g. tags) (that much) */
615 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
619 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
620 (_("This file is invalid and cannot be played.")),
621 ("atom has bogus size %" G_GUINT64_FORMAT, size));
622 return GST_FLOW_ERROR;
626 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
628 if (G_UNLIKELY (flow != GST_FLOW_OK))
631 bsize = gst_buffer_get_size (*buf);
632 /* Catch short reads - we don't want any partial atoms */
633 if (G_UNLIKELY (bsize < size)) {
634 GST_WARNING_OBJECT (qtdemux,
635 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
636 gst_buffer_unref (*buf);
646 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
647 GstFormat dest_format, gint64 * dest_value)
650 QtDemuxStream *stream = gst_pad_get_element_private (pad);
651 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
654 if (stream->subtype != FOURCC_vide) {
659 switch (src_format) {
660 case GST_FORMAT_TIME:
661 switch (dest_format) {
662 case GST_FORMAT_BYTES:{
663 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
667 *dest_value = stream->samples[index].offset;
669 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
670 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
671 GST_TIME_ARGS (src_value), *dest_value);
679 case GST_FORMAT_BYTES:
680 switch (dest_format) {
681 case GST_FORMAT_TIME:{
683 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
690 gst_util_uint64_scale (stream->samples[index].timestamp,
691 GST_SECOND, stream->timescale);
692 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
693 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
694 src_value, GST_TIME_ARGS (*dest_value));
707 gst_object_unref (qtdemux);
714 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
718 *duration = GST_CLOCK_TIME_NONE;
720 if (qtdemux->duration != 0) {
721 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
722 *duration = gst_util_uint64_scale (qtdemux->duration,
723 GST_SECOND, qtdemux->timescale) - qtdemux->min_elst_offset;
730 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
733 gboolean res = FALSE;
734 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
736 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
738 switch (GST_QUERY_TYPE (query)) {
739 case GST_QUERY_POSITION:
740 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
741 gst_query_set_position (query, GST_FORMAT_TIME,
742 qtdemux->segment.position);
746 case GST_QUERY_DURATION:{
749 gst_query_parse_duration (query, &fmt, NULL);
750 if (fmt == GST_FORMAT_TIME) {
751 /* First try to query upstream */
752 res = gst_pad_query_default (pad, parent, query);
754 gint64 duration = -1;
755 gst_qtdemux_get_duration (qtdemux, &duration);
757 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
764 case GST_QUERY_CONVERT:{
765 GstFormat src_fmt, dest_fmt;
766 gint64 src_value, dest_value = 0;
768 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
770 res = gst_qtdemux_src_convert (pad,
771 src_fmt, src_value, dest_fmt, &dest_value);
773 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
778 case GST_QUERY_FORMATS:
779 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
782 case GST_QUERY_SEEKING:{
786 /* try upstream first */
787 res = gst_pad_query_default (pad, parent, query);
790 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
791 if (fmt == GST_FORMAT_TIME) {
792 gint64 duration = -1;
794 gst_qtdemux_get_duration (qtdemux, &duration);
796 if (!qtdemux->pullbased) {
799 /* we might be able with help from upstream */
801 q = gst_query_new_seeking (GST_FORMAT_BYTES);
802 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
803 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
804 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
808 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
814 case GST_QUERY_SEGMENT:
819 format = qtdemux->segment.format;
822 gst_segment_to_stream_time (&qtdemux->segment, format,
823 qtdemux->segment.start);
824 if ((stop = qtdemux->segment.stop) == -1)
825 stop = qtdemux->segment.duration;
827 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
829 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
834 res = gst_pad_query_default (pad, parent, query);
842 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
844 if (G_LIKELY (stream->pad)) {
845 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
846 GST_DEBUG_PAD_NAME (stream->pad));
848 if (G_UNLIKELY (stream->pending_tags)) {
849 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
850 stream->pending_tags);
851 gst_pad_push_event (stream->pad,
852 gst_event_new_tag (stream->pending_tags));
853 stream->pending_tags = NULL;
856 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
857 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
859 gst_pad_push_event (stream->pad,
860 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
861 stream->send_global_tags = FALSE;
866 /* push event on all source pads; takes ownership of the event */
868 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
871 gboolean has_valid_stream = FALSE;
872 GstEventType etype = GST_EVENT_TYPE (event);
874 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
875 GST_EVENT_TYPE_NAME (event));
877 for (n = 0; n < qtdemux->n_streams; n++) {
879 QtDemuxStream *stream = qtdemux->streams[n];
880 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
882 if ((pad = stream->pad)) {
883 has_valid_stream = TRUE;
885 if (etype == GST_EVENT_EOS) {
886 /* let's not send twice */
887 if (stream->sent_eos)
889 stream->sent_eos = TRUE;
892 gst_pad_push_event (pad, gst_event_ref (event));
896 gst_event_unref (event);
898 /* if it is EOS and there are no pads, post an error */
899 if (!has_valid_stream && etype == GST_EVENT_EOS) {
900 gst_qtdemux_post_no_playable_stream_error (qtdemux);
904 /* push a pending newsegment event, if any from the streaming thread */
906 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
908 if (qtdemux->pending_newsegment) {
909 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
910 qtdemux->pending_newsegment = NULL;
911 qtdemux->upstream_newsegment = FALSE;
921 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
923 if (s1->timestamp > *media_time)
929 /* find the index of the sample that includes the data for @media_time using a
930 * binary search. Only to be called in optimized cases of linear search below.
932 * Returns the index of the sample.
935 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
938 QtDemuxSample *result;
941 /* convert media_time to mov format */
943 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
945 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
946 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
947 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
949 if (G_LIKELY (result))
950 index = result - str->samples;
959 /* find the index of the sample that includes the data for @media_offset using a
962 * Returns the index of the sample.
965 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
966 QtDemuxStream * str, gint64 media_offset)
968 QtDemuxSample *result = str->samples;
971 if (result == NULL || str->n_samples == 0)
974 if (media_offset == result->offset)
978 while (index < str->n_samples - 1) {
979 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
982 if (media_offset < result->offset)
993 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
998 /* find the index of the sample that includes the data for @media_time using a
999 * linear search, and keeping in mind that not all samples may have been parsed
1000 * yet. If possible, it will delegate to binary search.
1002 * Returns the index of the sample.
1005 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1011 /* convert media_time to mov format */
1013 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1015 if (mov_time == str->samples[0].timestamp)
1018 /* use faster search if requested time in already parsed range */
1019 if (str->stbl_index >= 0 &&
1020 mov_time <= str->samples[str->stbl_index].timestamp)
1021 return gst_qtdemux_find_index (qtdemux, str, media_time);
1023 while (index < str->n_samples - 1) {
1024 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1027 if (mov_time < str->samples[index + 1].timestamp)
1037 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1042 /* find the index of the keyframe needed to decode the sample at @index
1045 * Returns the index of the keyframe.
1048 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1051 guint32 new_index = index;
1053 if (index >= str->n_samples) {
1054 new_index = str->n_samples;
1058 /* all keyframes, return index */
1059 if (str->all_keyframe) {
1064 /* else go back until we have a keyframe */
1066 if (str->samples[new_index].keyframe)
1076 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1077 "gave %u", index, new_index);
1082 /* find the segment for @time_position for @stream
1084 * Returns -1 if the segment cannot be found.
1087 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1088 guint64 time_position)
1093 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1094 GST_TIME_ARGS (time_position));
1096 /* find segment corresponding to time_position if we are looking
1099 for (i = 0; i < stream->n_segments; i++) {
1100 QtDemuxSegment *segment = &stream->segments[i];
1102 GST_LOG_OBJECT (qtdemux,
1103 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1104 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1106 /* For the last segment we include stop_time in the last segment */
1107 if (i < stream->n_segments - 1) {
1108 if (segment->time <= time_position && time_position < segment->stop_time) {
1109 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1114 if (segment->time <= time_position && time_position <= segment->stop_time) {
1115 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1124 /* move the stream @str to the sample position @index.
1126 * Updates @str->sample_index and marks discontinuity if needed.
1129 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1132 /* no change needed */
1133 if (index == str->sample_index)
1136 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1139 /* position changed, we have a discont */
1140 str->sample_index = index;
1141 str->offset_in_sample = 0;
1142 /* Each time we move in the stream we store the position where we are
1144 str->from_sample = index;
1145 str->discont = TRUE;
1149 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1150 gint64 * key_time, gint64 * key_offset)
1153 gint64 min_byte_offset = -1;
1156 min_offset = desired_time;
1158 /* for each stream, find the index of the sample in the segment
1159 * and move back to the previous keyframe. */
1160 for (n = 0; n < qtdemux->n_streams; n++) {
1162 guint32 index, kindex;
1164 guint64 media_start;
1167 QtDemuxSegment *seg;
1169 str = qtdemux->streams[n];
1171 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1172 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1174 /* segment not found, continue with normal flow */
1178 /* get segment and time in the segment */
1179 seg = &str->segments[seg_idx];
1180 seg_time = desired_time - seg->time;
1182 /* get the media time in the segment */
1183 media_start = seg->media_start + seg_time;
1185 /* get the index of the sample with media time */
1186 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1187 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1188 " at offset %" G_GUINT64_FORMAT,
1189 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1191 /* find previous keyframe */
1192 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1194 /* if the keyframe is at a different position, we need to update the
1195 * requested seek time */
1196 if (index != kindex) {
1199 /* get timestamp of keyframe */
1201 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1203 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT
1204 " at offset %" G_GUINT64_FORMAT,
1205 kindex, GST_TIME_ARGS (media_time), str->samples[kindex].offset);
1207 /* keyframes in the segment get a chance to change the
1208 * desired_offset. keyframes out of the segment are
1210 if (media_time >= seg->media_start) {
1213 /* this keyframe is inside the segment, convert back to
1215 seg_time = (media_time - seg->media_start) + seg->time;
1216 if (seg_time < min_offset)
1217 min_offset = seg_time;
1221 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1222 min_byte_offset = str->samples[index].offset;
1226 *key_time = min_offset;
1228 *key_offset = min_byte_offset;
1232 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1233 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1237 g_return_val_if_fail (format != NULL, FALSE);
1238 g_return_val_if_fail (cur != NULL, FALSE);
1239 g_return_val_if_fail (stop != NULL, FALSE);
1241 if (*format == GST_FORMAT_TIME)
1245 if (cur_type != GST_SEEK_TYPE_NONE)
1246 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1247 if (res && stop_type != GST_SEEK_TYPE_NONE)
1248 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1251 *format = GST_FORMAT_TIME;
1256 /* perform seek in push based mode:
1257 find BYTE position to move to based on time and delegate to upstream
1260 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1265 GstSeekType cur_type, stop_type;
1266 gint64 cur, stop, key_cur;
1269 gint64 original_stop;
1272 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1274 gst_event_parse_seek (event, &rate, &format, &flags,
1275 &cur_type, &cur, &stop_type, &stop);
1276 seqnum = gst_event_get_seqnum (event);
1278 /* only forward streaming and seeking is possible */
1280 goto unsupported_seek;
1282 /* convert to TIME if needed and possible */
1283 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1287 /* Upstrea seek in bytes will have undefined stop, but qtdemux stores
1288 * the original stop position to use when upstream pushes the new segment
1290 original_stop = stop;
1293 /* find reasonable corresponding BYTE position,
1294 * also try to mind about keyframes, since we can not go back a bit for them
1296 gst_qtdemux_adjust_seek (qtdemux, cur, &key_cur, &byte_cur);
1301 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1302 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1305 GST_OBJECT_LOCK (qtdemux);
1306 qtdemux->seek_offset = byte_cur;
1307 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1308 qtdemux->push_seek_start = cur;
1310 qtdemux->push_seek_start = key_cur;
1313 if (stop_type == GST_SEEK_TYPE_NONE) {
1314 qtdemux->push_seek_stop = qtdemux->segment.stop;
1316 qtdemux->push_seek_stop = original_stop;
1318 GST_OBJECT_UNLOCK (qtdemux);
1320 /* BYTE seek event */
1321 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1323 gst_event_set_seqnum (event, seqnum);
1324 res = gst_pad_push_event (qtdemux->sinkpad, event);
1331 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1337 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1342 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1347 /* perform the seek.
1349 * We set all segment_indexes in the streams to unknown and
1350 * adjust the time_position to the desired position. this is enough
1351 * to trigger a segment switch in the streaming thread to start
1352 * streaming from the desired position.
1354 * Keyframe seeking is a little more complicated when dealing with
1355 * segments. Ideally we want to move to the previous keyframe in
1356 * the segment but there might not be a keyframe in the segment. In
1357 * fact, none of the segments could contain a keyframe. We take a
1358 * practical approach: seek to the previous keyframe in the segment,
1359 * if there is none, seek to the beginning of the segment.
1361 * Called with STREAM_LOCK
1364 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1367 gint64 desired_offset;
1370 desired_offset = segment->position;
1372 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1373 GST_TIME_ARGS (desired_offset));
1375 /* may not have enough fragmented info to do this adjustment,
1376 * and we can't scan (and probably should not) at this time with
1377 * possibly flushing upstream */
1378 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1381 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1382 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1383 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1384 desired_offset = min_offset;
1387 /* and set all streams to the final position */
1388 for (n = 0; n < qtdemux->n_streams; n++) {
1389 QtDemuxStream *stream = qtdemux->streams[n];
1391 stream->time_position = desired_offset;
1392 stream->sample_index = -1;
1393 stream->offset_in_sample = 0;
1394 stream->segment_index = -1;
1395 stream->last_ret = GST_FLOW_OK;
1396 stream->sent_eos = FALSE;
1397 stream->segment_seqnum = seqnum;
1399 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1400 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1402 segment->position = desired_offset;
1403 segment->time = desired_offset;
1405 /* we stop at the end */
1406 if (segment->stop == -1)
1407 segment->stop = segment->duration;
1412 /* do a seek in pull based mode */
1414 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1419 GstSeekType cur_type, stop_type;
1423 GstSegment seeksegment;
1426 GstEvent *flush_event;
1429 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1431 gst_event_parse_seek (event, &rate, &format, &flags,
1432 &cur_type, &cur, &stop_type, &stop);
1433 seqnum = gst_event_get_seqnum (event);
1435 /* we have to have a format as the segment format. Try to convert
1437 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1441 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1443 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1447 flush = flags & GST_SEEK_FLAG_FLUSH;
1449 /* stop streaming, either by flushing or by pausing the task */
1451 flush_event = gst_event_new_flush_start ();
1453 gst_event_set_seqnum (flush_event, seqnum);
1454 /* unlock upstream pull_range */
1455 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1456 /* make sure out loop function exits */
1457 gst_qtdemux_push_event (qtdemux, flush_event);
1459 /* non flushing seek, pause the task */
1460 gst_pad_pause_task (qtdemux->sinkpad);
1463 /* wait for streaming to finish */
1464 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1466 /* copy segment, we need this because we still need the old
1467 * segment when we close the current segment. */
1468 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1471 /* configure the segment with the seek variables */
1472 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1473 gst_segment_do_seek (&seeksegment, rate, format, flags,
1474 cur_type, cur, stop_type, stop, &update);
1477 /* now do the seek, this actually never returns FALSE */
1478 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum);
1480 /* prepare for streaming again */
1482 flush_event = gst_event_new_flush_stop (TRUE);
1484 gst_event_set_seqnum (flush_event, seqnum);
1486 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1487 gst_qtdemux_push_event (qtdemux, flush_event);
1490 /* commit the new segment */
1491 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1493 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1494 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1495 qtdemux->segment.format, qtdemux->segment.position);
1497 gst_message_set_seqnum (msg, seqnum);
1498 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1501 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1502 for (i = 0; i < qtdemux->n_streams; i++)
1503 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1505 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1506 qtdemux->sinkpad, NULL);
1508 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1515 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1521 qtdemux_ensure_index (GstQTDemux * qtdemux)
1525 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1527 /* Build complete index */
1528 for (i = 0; i < qtdemux->n_streams; i++) {
1529 QtDemuxStream *stream = qtdemux->streams[i];
1531 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1539 GST_LOG_OBJECT (qtdemux,
1540 "Building complete index of stream %u for seeking failed!", i);
1546 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1549 gboolean res = TRUE;
1550 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1552 switch (GST_EVENT_TYPE (event)) {
1553 case GST_EVENT_SEEK:
1555 #ifndef GST_DISABLE_GST_DEBUG
1556 GstClockTime ts = gst_util_get_timestamp ();
1559 if (qtdemux->mss_mode || qtdemux->fragmented) {
1560 /* seek should be handled by upstream, we might need to re-download fragments */
1561 GST_DEBUG_OBJECT (qtdemux,
1562 "leting upstream handle seek for smoothstreaming");
1566 /* Build complete index for seeking;
1567 * if not a fragmented file at least */
1568 if (!qtdemux->fragmented)
1569 if (!qtdemux_ensure_index (qtdemux))
1571 #ifndef GST_DISABLE_GST_DEBUG
1572 ts = gst_util_get_timestamp () - ts;
1573 GST_INFO_OBJECT (qtdemux,
1574 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1577 if (qtdemux->pullbased) {
1578 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1579 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1580 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1582 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1583 && !qtdemux->fragmented) {
1584 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1586 GST_DEBUG_OBJECT (qtdemux,
1587 "ignoring seek in push mode in current state");
1590 gst_event_unref (event);
1593 case GST_EVENT_NAVIGATION:
1595 gst_event_unref (event);
1599 res = gst_pad_event_default (pad, parent, event);
1609 GST_ERROR_OBJECT (qtdemux, "Index failed");
1610 gst_event_unref (event);
1616 /* stream/index return sample that is min/max w.r.t. byte position,
1617 * time is min/max w.r.t. time of samples,
1618 * the latter need not be time of the former sample */
1620 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1621 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1624 gint64 time, min_time;
1625 QtDemuxStream *stream;
1631 for (n = 0; n < qtdemux->n_streams; ++n) {
1634 gboolean set_sample;
1636 str = qtdemux->streams[n];
1643 i = str->n_samples - 1;
1647 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1648 if (str->samples[i].size == 0)
1651 if (fw && (str->samples[i].offset < byte_pos))
1654 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1657 /* move stream to first available sample */
1659 gst_qtdemux_move_stream (qtdemux, str, i);
1663 /* avoid index from sparse streams since they might be far away */
1665 /* determine min/max time */
1666 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1667 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1668 if (min_time == -1 || (!fw && time > min_time) ||
1669 (fw && time < min_time)) {
1673 /* determine stream with leading sample, to get its position */
1675 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1676 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1684 /* no sample for this stream, mark eos */
1686 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1697 static QtDemuxStream *
1698 _create_stream (void)
1700 QtDemuxStream *stream;
1702 stream = g_new0 (QtDemuxStream, 1);
1703 /* new streams always need a discont */
1704 stream->discont = TRUE;
1705 /* we enable clipping for raw audio/video streams */
1706 stream->need_clip = FALSE;
1707 stream->need_process = FALSE;
1708 stream->segment_index = -1;
1709 stream->time_position = 0;
1710 stream->sample_index = -1;
1711 stream->offset_in_sample = 0;
1712 stream->last_ret = GST_FLOW_OK;
1713 stream->new_stream = TRUE;
1718 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1720 GstStructure *structure;
1721 const gchar *variant;
1722 const GstCaps *mediacaps = NULL;
1724 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1726 structure = gst_caps_get_structure (caps, 0);
1727 variant = gst_structure_get_string (structure, "variant");
1729 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1730 QtDemuxStream *stream;
1731 const GValue *value;
1733 demux->fragmented = TRUE;
1734 demux->mss_mode = TRUE;
1736 if (demux->n_streams > 1) {
1737 /* can't do this, we can only renegotiate for another mss format */
1741 value = gst_structure_get_value (structure, "media-caps");
1744 const GValue *timescale_v;
1746 /* TODO update when stream changes during playback */
1748 if (demux->n_streams == 0) {
1749 stream = _create_stream ();
1750 demux->streams[demux->n_streams] = stream;
1751 demux->n_streams = 1;
1753 stream = demux->streams[0];
1756 timescale_v = gst_structure_get_value (structure, "timescale");
1758 stream->timescale = g_value_get_uint64 (timescale_v);
1760 /* default mss timescale */
1761 stream->timescale = 10000000;
1763 demux->timescale = stream->timescale;
1765 mediacaps = gst_value_get_caps (value);
1766 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1767 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1769 stream->new_caps = TRUE;
1771 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1772 structure = gst_caps_get_structure (mediacaps, 0);
1773 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1774 stream->subtype = FOURCC_vide;
1776 gst_structure_get_int (structure, "width", &stream->width);
1777 gst_structure_get_int (structure, "height", &stream->height);
1778 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1780 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1782 stream->subtype = FOURCC_soun;
1783 gst_structure_get_int (structure, "channels", &stream->n_channels);
1784 gst_structure_get_int (structure, "rate", &rate);
1785 stream->rate = rate;
1788 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1795 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1799 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1800 gst_pad_stop_task (qtdemux->sinkpad);
1802 if (hard || qtdemux->mss_mode) {
1803 qtdemux->state = QTDEMUX_STATE_INITIAL;
1804 qtdemux->neededbytes = 16;
1805 qtdemux->todrop = 0;
1806 qtdemux->pullbased = FALSE;
1807 qtdemux->posted_redirect = FALSE;
1808 qtdemux->first_mdat = -1;
1809 qtdemux->header_size = 0;
1810 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1811 qtdemux->restoredata_offset = GST_CLOCK_TIME_NONE;
1812 if (qtdemux->mdatbuffer)
1813 gst_buffer_unref (qtdemux->mdatbuffer);
1814 if (qtdemux->restoredata_buffer)
1815 gst_buffer_unref (qtdemux->restoredata_buffer);
1816 qtdemux->mdatbuffer = NULL;
1817 qtdemux->restoredata_buffer = NULL;
1818 qtdemux->mdatleft = 0;
1819 if (qtdemux->comp_brands)
1820 gst_buffer_unref (qtdemux->comp_brands);
1821 qtdemux->comp_brands = NULL;
1822 if (qtdemux->moov_node)
1823 g_node_destroy (qtdemux->moov_node);
1824 qtdemux->moov_node = NULL;
1825 qtdemux->moov_node_compressed = NULL;
1826 if (qtdemux->tag_list)
1827 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1828 qtdemux->tag_list = NULL;
1830 if (qtdemux->element_index)
1831 gst_object_unref (qtdemux->element_index);
1832 qtdemux->element_index = NULL;
1834 qtdemux->major_brand = 0;
1835 if (qtdemux->pending_newsegment)
1836 gst_event_unref (qtdemux->pending_newsegment);
1837 qtdemux->pending_newsegment = NULL;
1838 qtdemux->upstream_newsegment = TRUE;
1839 qtdemux->upstream_seekable = FALSE;
1840 qtdemux->upstream_size = 0;
1842 qtdemux->fragment_start = -1;
1843 qtdemux->duration = 0;
1844 qtdemux->mfra_offset = 0;
1845 qtdemux->moof_offset = 0;
1846 qtdemux->chapters_track_id = 0;
1847 qtdemux->have_group_id = FALSE;
1848 qtdemux->group_id = G_MAXUINT;
1850 qtdemux->offset = 0;
1851 gst_adapter_clear (qtdemux->adapter);
1852 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1855 for (n = 0; n < qtdemux->n_streams; n++) {
1856 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1857 qtdemux->streams[n] = NULL;
1859 qtdemux->n_streams = 0;
1860 qtdemux->n_video_streams = 0;
1861 qtdemux->n_audio_streams = 0;
1862 qtdemux->n_sub_streams = 0;
1863 qtdemux->exposed = FALSE;
1864 qtdemux->fragmented = FALSE;
1865 qtdemux->mss_mode = FALSE;
1866 gst_caps_replace (&qtdemux->media_caps, NULL);
1867 qtdemux->timescale = 0;
1868 qtdemux->got_moov = FALSE;
1869 } else if (qtdemux->mss_mode) {
1870 for (n = 0; n < qtdemux->n_streams; n++)
1871 gst_qtdemux_stream_clear (qtdemux->streams[n]);
1873 for (n = 0; n < qtdemux->n_streams; n++) {
1874 qtdemux->streams[n]->last_ret = GST_FLOW_OK;
1875 qtdemux->streams[n]->sent_eos = FALSE;
1876 qtdemux->streams[n]->segment_seqnum = 0;
1877 qtdemux->streams[n]->time_position = 0;
1883 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1886 GstQTDemux *demux = GST_QTDEMUX (parent);
1889 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1891 switch (GST_EVENT_TYPE (event)) {
1892 case GST_EVENT_SEGMENT:
1895 QtDemuxStream *stream;
1898 GstEvent *segment_event;
1900 /* some debug output */
1901 gst_event_copy_segment (event, &segment);
1902 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1905 if (segment.format == GST_FORMAT_TIME) {
1906 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
1907 gst_event_replace (&demux->pending_newsegment, event);
1908 demux->upstream_newsegment = TRUE;
1910 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
1911 "not in time format");
1914 /* chain will send initial newsegment after pads have been added */
1915 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1916 if (!demux->mss_mode) {
1917 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1922 /* check if this matches a time seek we received previously
1923 * FIXME for backwards compatibility reasons we use the
1924 * seek_offset here to compare. In the future we might want to
1925 * change this to use the seqnum as it uniquely should identify
1926 * the segment that corresponds to the seek. */
1927 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
1928 ", received segment offset %" G_GINT64_FORMAT,
1929 demux->seek_offset, segment.start);
1930 if (segment.format == GST_FORMAT_BYTES
1931 && demux->seek_offset == segment.start) {
1932 GST_OBJECT_LOCK (demux);
1933 offset = segment.start;
1935 segment.format = GST_FORMAT_TIME;
1936 segment.start = demux->push_seek_start;
1937 segment.stop = demux->push_seek_stop;
1938 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
1939 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1940 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
1941 GST_OBJECT_UNLOCK (demux);
1944 /* we only expect a BYTE segment, e.g. following a seek */
1945 if (segment.format == GST_FORMAT_BYTES) {
1946 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1947 offset = segment.start;
1949 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1950 NULL, (gint64 *) & segment.start);
1951 if ((gint64) segment.start < 0)
1954 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1955 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1956 NULL, (gint64 *) & segment.stop);
1957 /* keyframe seeking should already arrange for start >= stop,
1958 * but make sure in other rare cases */
1959 segment.stop = MAX (segment.stop, segment.start);
1961 } else if (segment.format == GST_FORMAT_TIME) {
1964 gst_qtdemux_push_event (demux, gst_event_ref (event));
1965 gst_event_new_new_segment_full (segment.update, segment.rate,
1966 segment.arate, GST_FORMAT_TIME, segment.start, segment.stop,
1968 gst_adapter_clear (demux->adapter);
1969 demux->neededbytes = 16;
1973 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1977 /* accept upstream's notion of segment and distribute along */
1978 segment.format = GST_FORMAT_TIME;
1979 segment.position = segment.time = segment.start;
1980 segment.duration = demux->segment.duration;
1981 segment.base = gst_segment_to_running_time (&demux->segment,
1982 GST_FORMAT_TIME, demux->segment.position);
1984 gst_segment_copy_into (&segment, &demux->segment);
1985 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
1986 segment_event = gst_event_new_segment (&segment);
1987 gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
1988 gst_qtdemux_push_event (demux, segment_event);
1990 /* clear leftover in current segment, if any */
1991 gst_adapter_clear (demux->adapter);
1992 /* set up streaming thread */
1993 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1994 demux->offset = offset;
1996 demux->todrop = stream->samples[idx].offset - offset;
1997 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1999 /* set up for EOS */
2000 if (demux->mss_mode) {
2001 demux->neededbytes = 16;
2003 demux->neededbytes = -1;
2008 gst_event_unref (event);
2013 case GST_EVENT_FLUSH_STOP:
2017 dur = demux->segment.duration;
2018 gst_qtdemux_reset (demux, FALSE);
2019 demux->segment.duration = dur;
2023 /* If we are in push mode, and get an EOS before we've seen any streams,
2024 * then error out - we have nowhere to send the EOS */
2025 if (!demux->pullbased) {
2027 gboolean has_valid_stream = FALSE;
2028 for (i = 0; i < demux->n_streams; i++) {
2029 if (demux->streams[i]->pad != NULL) {
2030 has_valid_stream = TRUE;
2034 if (!has_valid_stream)
2035 gst_qtdemux_post_no_playable_stream_error (demux);
2038 case GST_EVENT_CAPS:{
2039 GstCaps *caps = NULL;
2041 gst_event_parse_caps (event, &caps);
2042 gst_qtdemux_setcaps (demux, caps);
2044 gst_event_unref (event);
2052 res = gst_pad_event_default (demux->sinkpad, parent, event);
2060 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2062 GstQTDemux *demux = GST_QTDEMUX (element);
2064 GST_OBJECT_LOCK (demux);
2065 if (demux->element_index)
2066 gst_object_unref (demux->element_index);
2068 demux->element_index = gst_object_ref (index);
2070 demux->element_index = NULL;
2072 GST_OBJECT_UNLOCK (demux);
2073 /* object lock might be taken again */
2075 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2076 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2077 demux->element_index, demux->index_id);
2081 gst_qtdemux_get_index (GstElement * element)
2083 GstIndex *result = NULL;
2084 GstQTDemux *demux = GST_QTDEMUX (element);
2086 GST_OBJECT_LOCK (demux);
2087 if (demux->element_index)
2088 result = gst_object_ref (demux->element_index);
2089 GST_OBJECT_UNLOCK (demux);
2091 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2098 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2100 g_free ((gpointer) stream->stco.data);
2101 stream->stco.data = NULL;
2102 g_free ((gpointer) stream->stsz.data);
2103 stream->stsz.data = NULL;
2104 g_free ((gpointer) stream->stsc.data);
2105 stream->stsc.data = NULL;
2106 g_free ((gpointer) stream->stts.data);
2107 stream->stts.data = NULL;
2108 g_free ((gpointer) stream->stss.data);
2109 stream->stss.data = NULL;
2110 g_free ((gpointer) stream->stps.data);
2111 stream->stps.data = NULL;
2112 g_free ((gpointer) stream->ctts.data);
2113 stream->ctts.data = NULL;
2117 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2119 if (stream->allocator)
2120 gst_object_unref (stream->allocator);
2121 while (stream->buffers) {
2122 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2123 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2125 if (stream->rgb8_palette) {
2126 gst_memory_unref (stream->rgb8_palette);
2127 stream->rgb8_palette = NULL;
2129 g_free (stream->samples);
2130 stream->samples = NULL;
2131 g_free (stream->segments);
2132 stream->segments = NULL;
2133 if (stream->pending_tags)
2134 gst_tag_list_unref (stream->pending_tags);
2135 stream->pending_tags = NULL;
2136 g_free (stream->redirect_uri);
2137 stream->redirect_uri = NULL;
2138 /* free stbl sub-atoms */
2139 gst_qtdemux_stbl_free (stream);
2141 stream->last_ret = GST_FLOW_OK;
2142 stream->sent_eos = FALSE;
2143 stream->segment_index = -1;
2144 stream->time_position = 0;
2145 stream->sample_index = -1;
2146 stream->stbl_index = -1;
2147 stream->n_samples = 0;
2148 stream->sparse = FALSE;
2152 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2154 gst_qtdemux_stream_clear (stream);
2156 gst_caps_unref (stream->caps);
2157 stream->caps = NULL;
2159 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2164 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2166 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2168 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2169 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2170 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2171 qtdemux->n_streams--;
2174 static GstStateChangeReturn
2175 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2177 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2178 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2180 switch (transition) {
2181 case GST_STATE_CHANGE_PAUSED_TO_READY:
2187 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2189 switch (transition) {
2190 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2191 gst_qtdemux_reset (qtdemux, TRUE);
2202 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2204 /* counts as header data */
2205 qtdemux->header_size += length;
2207 /* only consider at least a sufficiently complete ftyp atom */
2211 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2212 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2213 GST_FOURCC_ARGS (qtdemux->major_brand));
2214 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2215 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2220 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
2222 /* Strip out bogus fields */
2224 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
2226 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
2228 if (qtdemux->tag_list) {
2229 /* prioritize native tags using _KEEP mode */
2230 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
2231 gst_tag_list_unref (taglist);
2233 qtdemux->tag_list = taglist;
2238 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2240 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2241 0x97, 0xA9, 0x42, 0xE8,
2242 0x9C, 0x71, 0x99, 0x94,
2243 0x91, 0xE3, 0xAF, 0xAC
2245 static guint8 playready_uuid[] = {
2246 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2247 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2251 /* counts as header data */
2252 qtdemux->header_size += length;
2254 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2256 if (length <= offset + 16) {
2257 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2261 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2263 GstTagList *taglist;
2265 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2266 length - offset - 16, NULL);
2267 taglist = gst_tag_list_from_xmp_buffer (buf);
2268 gst_buffer_unref (buf);
2270 qtdemux_handle_xmp_taglist (qtdemux, taglist);
2272 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2274 const gunichar2 *s_utf16;
2277 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2278 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2279 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2280 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2284 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2285 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2288 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2289 GST_READ_UINT32_LE (buffer + offset),
2290 GST_READ_UINT32_LE (buffer + offset + 4),
2291 GST_READ_UINT32_LE (buffer + offset + 8),
2292 GST_READ_UINT32_LE (buffer + offset + 12));
2296 /* caller verifies at least 8 bytes in buf */
2298 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2299 guint64 * plength, guint32 * pfourcc)
2304 length = QT_UINT32 (data);
2305 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2306 fourcc = QT_FOURCC (data + 4);
2307 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2310 length = G_MAXUINT32;
2311 } else if (length == 1 && size >= 16) {
2312 /* this means we have an extended size, which is the 64 bit value of
2313 * the next 8 bytes */
2314 length = QT_UINT64 (data + 8);
2315 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2325 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2327 guint32 version = 0;
2328 guint64 duration = 0;
2330 if (!gst_byte_reader_get_uint32_be (br, &version))
2335 if (!gst_byte_reader_get_uint64_be (br, &duration))
2340 if (!gst_byte_reader_get_uint32_be (br, &dur))
2345 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2346 qtdemux->duration = duration;
2352 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2358 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2359 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2361 if (!stream->parsed_trex && qtdemux->moov_node) {
2363 GstByteReader trex_data;
2365 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2367 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2370 guint32 id = 0, dur = 0, size = 0, flags = 0;
2372 /* skip version/flags */
2373 if (!gst_byte_reader_skip (&trex_data, 4))
2375 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2377 if (id != stream->track_id)
2379 /* sample description index; ignore */
2380 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2382 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2384 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2386 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2389 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2390 "duration %d, size %d, flags 0x%x", stream->track_id,
2393 stream->parsed_trex = TRUE;
2394 stream->def_sample_duration = dur;
2395 stream->def_sample_size = size;
2396 stream->def_sample_flags = flags;
2399 /* iterate all siblings */
2400 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2406 *ds_duration = stream->def_sample_duration;
2407 *ds_size = stream->def_sample_size;
2408 *ds_size = stream->def_sample_size;
2410 /* even then, above values are better than random ... */
2411 if (G_UNLIKELY (!stream->parsed_trex)) {
2412 GST_WARNING_OBJECT (qtdemux,
2413 "failed to find fragment defaults for stream %d", stream->track_id);
2421 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2422 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2423 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2424 gint64 * base_offset, gint64 * running_offset)
2426 guint64 timestamp, elst_timestamp;
2427 gint32 data_offset = 0;
2428 guint32 flags = 0, first_flags = 0, samples_count = 0;
2431 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2432 QtDemuxSample *sample;
2433 gboolean ismv = FALSE;
2435 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2436 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2437 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2440 /* presence of stss or not can't really tell us much,
2441 * and flags and so on tend to be marginally reliable in these files */
2442 if (stream->subtype == FOURCC_soun) {
2443 GST_DEBUG_OBJECT (qtdemux,
2444 "sound track in fragmented file; marking all keyframes");
2445 stream->all_keyframe = TRUE;
2448 if (!gst_byte_reader_skip (trun, 1) ||
2449 !gst_byte_reader_get_uint24_be (trun, &flags))
2452 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2455 if (flags & TR_DATA_OFFSET) {
2456 /* note this is really signed */
2457 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2459 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2460 /* default base offset = first byte of moof */
2461 if (*base_offset == -1) {
2462 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2463 *base_offset = moof_offset;
2465 *running_offset = *base_offset + data_offset;
2467 /* if no offset at all, that would mean data starts at moof start,
2468 * which is a bit wrong and is ismv crappy way, so compensate
2469 * assuming data is in mdat following moof */
2470 if (*base_offset == -1) {
2471 *base_offset = moof_offset + moof_length + 8;
2472 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2475 if (*running_offset == -1)
2476 *running_offset = *base_offset;
2479 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2481 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2482 data_offset, flags, samples_count);
2484 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2485 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2486 GST_DEBUG_OBJECT (qtdemux,
2487 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2488 flags ^= TR_FIRST_SAMPLE_FLAGS;
2490 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2492 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2496 /* FIXME ? spec says other bits should also be checked to determine
2497 * entry size (and prefix size for that matter) */
2499 dur_offset = size_offset = 0;
2500 if (flags & TR_SAMPLE_DURATION) {
2501 GST_LOG_OBJECT (qtdemux, "entry duration present");
2502 dur_offset = entry_size;
2505 if (flags & TR_SAMPLE_SIZE) {
2506 GST_LOG_OBJECT (qtdemux, "entry size present");
2507 size_offset = entry_size;
2510 if (flags & TR_SAMPLE_FLAGS) {
2511 GST_LOG_OBJECT (qtdemux, "entry flags present");
2512 flags_offset = entry_size;
2515 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2516 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2517 ct_offset = entry_size;
2521 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2523 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2525 if (stream->n_samples >=
2526 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2529 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2530 stream->n_samples, (guint) sizeof (QtDemuxSample),
2531 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2533 /* create a new array of samples if it's the first sample parsed */
2534 if (stream->n_samples == 0)
2535 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2536 /* or try to reallocate it with space enough to insert the new samples */
2538 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2539 stream->n_samples + samples_count);
2540 if (stream->samples == NULL)
2543 if (qtdemux->fragment_start != -1) {
2544 timestamp = gst_util_uint64_scale_int (qtdemux->fragment_start,
2545 stream->timescale, GST_SECOND);
2546 qtdemux->fragment_start = -1;
2548 if (G_UNLIKELY (stream->n_samples == 0)) {
2549 /* the timestamp of the first sample is also provided by the tfra entry
2550 * but we shouldn't rely on it as it is at the end of files */
2553 /* subsequent fragments extend stream */
2555 stream->samples[stream->n_samples - 1].timestamp +
2556 stream->samples[stream->n_samples - 1].duration;
2559 sample = stream->samples + stream->n_samples;
2560 elst_timestamp = gst_util_uint64_scale (stream->elst_offset,
2561 stream->timescale, GST_SECOND);
2562 for (i = 0; i < samples_count; i++) {
2563 guint32 dur, size, sflags, ct;
2565 /* first read sample data */
2566 if (flags & TR_SAMPLE_DURATION) {
2567 dur = QT_UINT32 (data + dur_offset);
2569 dur = d_sample_duration;
2571 if (flags & TR_SAMPLE_SIZE) {
2572 size = QT_UINT32 (data + size_offset);
2574 size = d_sample_size;
2576 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2578 sflags = first_flags;
2580 sflags = d_sample_flags;
2582 } else if (flags & TR_SAMPLE_FLAGS) {
2583 sflags = QT_UINT32 (data + flags_offset);
2585 sflags = d_sample_flags;
2587 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2588 ct = QT_UINT32 (data + ct_offset);
2594 /* fill the sample information */
2595 sample->offset = *running_offset;
2596 sample->pts_offset = ct;
2597 sample->size = size;
2598 sample->timestamp = timestamp + elst_timestamp;
2599 sample->duration = dur;
2600 /* sample-is-difference-sample */
2601 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2602 * now idea how it relates to bitfield other than massive LE/BE confusion */
2603 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2604 *running_offset += size;
2609 stream->n_samples += samples_count;
2615 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2620 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2626 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2627 "be larger than %uMB (broken file?)", stream->n_samples,
2628 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2633 /* find stream with @id */
2634 static inline QtDemuxStream *
2635 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2637 QtDemuxStream *stream;
2641 if (G_UNLIKELY (!id)) {
2642 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2646 /* try to get it fast and simple */
2647 if (G_LIKELY (id <= qtdemux->n_streams)) {
2648 stream = qtdemux->streams[id - 1];
2649 if (G_LIKELY (stream->track_id == id))
2653 /* linear search otherwise */
2654 for (i = 0; i < qtdemux->n_streams; i++) {
2655 stream = qtdemux->streams[i];
2656 if (stream->track_id == id)
2659 if (qtdemux->mss_mode) {
2660 /* mss should have only 1 stream anyway */
2661 return qtdemux->streams[0];
2668 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2669 QtDemuxStream ** stream, guint32 * default_sample_duration,
2670 guint32 * default_sample_size, guint32 * default_sample_flags,
2671 gint64 * base_offset)
2674 guint32 track_id = 0;
2676 if (!gst_byte_reader_skip (tfhd, 1) ||
2677 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2680 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2683 *stream = qtdemux_find_stream (qtdemux, track_id);
2684 if (G_UNLIKELY (!*stream))
2685 goto unknown_stream;
2687 if (flags & TF_BASE_DATA_OFFSET)
2688 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2691 /* obtain stream defaults */
2692 qtdemux_parse_trex (qtdemux, *stream,
2693 default_sample_duration, default_sample_size, default_sample_flags);
2695 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2696 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2697 if (!gst_byte_reader_skip (tfhd, 4))
2700 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2701 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2704 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2705 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2708 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2709 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2716 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2721 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2727 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
2728 guint64 * decode_time)
2730 guint32 version = 0;
2732 if (!gst_byte_reader_get_uint32_be (br, &version))
2737 if (!gst_byte_reader_get_uint64_be (br, decode_time))
2740 guint32 dec_time = 0;
2741 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
2743 *decode_time = dec_time;
2746 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
2753 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
2759 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2760 guint64 moof_offset, QtDemuxStream * stream)
2762 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node;
2763 GstByteReader trun_data, tfhd_data, tfdt_data;
2764 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2765 gint64 base_offset, running_offset;
2767 /* NOTE @stream ignored */
2769 moof_node = g_node_new ((guint8 *) buffer);
2770 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2771 qtdemux_node_dump (qtdemux, moof_node);
2773 /* unknown base_offset to start with */
2774 base_offset = running_offset = -1;
2775 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2777 /* Fragment Header node */
2779 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2783 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2784 &ds_size, &ds_flags, &base_offset))
2787 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
2790 guint64 decode_time = 0;
2791 GstClockTime decode_time_ts;
2793 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
2795 /* FIXME, we can use decode_time to interpolate timestamps
2796 * in case the input timestamps are missing */
2797 decode_time_ts = gst_util_uint64_scale (decode_time, GST_SECOND,
2800 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GUINT64_FORMAT
2801 " (%" GST_TIME_FORMAT ")", decode_time,
2802 GST_TIME_ARGS (decode_time_ts));
2805 if (G_UNLIKELY (!stream)) {
2806 /* we lost track of offset, we'll need to regain it,
2807 * but can delay complaining until later or avoid doing so altogether */
2811 if (G_UNLIKELY (base_offset < -1))
2813 /* Track Run node */
2815 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2818 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2819 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2821 /* iterate all siblings */
2822 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2825 /* if no new base_offset provided for next traf,
2826 * base is end of current traf */
2827 base_offset = running_offset;
2828 running_offset = -1;
2830 /* iterate all siblings */
2831 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2833 g_node_destroy (moof_node);
2838 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2843 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2848 g_node_destroy (moof_node);
2849 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2850 (_("This file is corrupt and cannot be played.")), (NULL));
2855 /* might be used if some day we actually use mfra & co
2856 * for random access to fragments,
2857 * but that will require quite some modifications and much less relying
2858 * on a sample array */
2861 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2862 QtDemuxStream * stream)
2864 guint64 time = 0, moof_offset = 0;
2865 guint32 ver_flags, track_id, len, num_entries, i;
2866 guint value_size, traf_size, trun_size, sample_size;
2867 GstBuffer *buf = NULL;
2871 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2872 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2874 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2877 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2878 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2879 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2882 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2883 track_id, stream->track_id);
2884 if (track_id != stream->track_id) {
2888 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2889 sample_size = (len & 3) + 1;
2890 trun_size = ((len & 12) >> 2) + 1;
2891 traf_size = ((len & 48) >> 4) + 1;
2893 if (num_entries == 0)
2896 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2897 value_size + value_size + traf_size + trun_size + sample_size))
2900 for (i = 0; i < num_entries; i++) {
2901 qt_atom_parser_get_offset (&tfra, value_size, &time);
2902 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2903 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2904 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2905 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2907 GST_LOG_OBJECT (qtdemux,
2908 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2909 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2910 stream->timescale)), moof_offset);
2912 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2913 if (ret != GST_FLOW_OK)
2915 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2916 moof_offset, stream);
2917 gst_buffer_unref (buf);
2925 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2926 (_("This file is corrupt and cannot be played.")), (NULL));
2931 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2937 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2940 GNode *mfra_node, *tfra_node;
2943 if (!qtdemux->mfra_offset)
2946 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2947 if (ret != GST_FLOW_OK)
2950 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2951 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2952 GST_BUFFER_SIZE (buffer));
2954 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2957 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2958 /* iterate all siblings */
2959 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2961 g_node_destroy (mfra_node);
2962 gst_buffer_unref (buffer);
2968 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2969 (_("This file is corrupt and cannot be played.")), (NULL));
2974 static GstFlowReturn
2975 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2976 guint32 * mfro_size)
2978 GstFlowReturn ret = GST_FLOW_ERROR;
2979 GstBuffer *mfro = NULL;
2982 GstFormat fmt = GST_FORMAT_BYTES;
2984 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, &fmt, &len)) {
2985 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2986 "can not locate mfro");
2990 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2991 if (ret != GST_FLOW_OK)
2994 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2995 if (fourcc != FOURCC_mfro)
2998 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2999 if (GST_BUFFER_SIZE (mfro) >= 16) {
3000 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
3001 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
3002 if (*mfro_size >= len) {
3003 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
3004 ret = GST_FLOW_ERROR;
3007 *mfra_offset = len - *mfro_size;
3012 gst_buffer_unref (mfro);
3018 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
3021 guint32 mfra_size = 0;
3022 guint64 mfra_offset = 0;
3025 qtdemux->fragmented = FALSE;
3027 /* We check here if it is a fragmented mp4 container */
3028 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
3029 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
3030 qtdemux->fragmented = TRUE;
3031 GST_DEBUG_OBJECT (qtdemux,
3032 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
3033 qtdemux->mfra_offset = mfra_offset;
3038 static GstFlowReturn
3039 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
3043 GstBuffer *buf = NULL;
3044 GstFlowReturn ret = GST_FLOW_OK;
3045 guint64 cur_offset = qtdemux->offset;
3048 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
3049 if (G_UNLIKELY (ret != GST_FLOW_OK))
3051 gst_buffer_map (buf, &map, GST_MAP_READ);
3052 if (G_LIKELY (map.size >= 8))
3053 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
3054 gst_buffer_unmap (buf, &map);
3055 gst_buffer_unref (buf);
3057 /* maybe we already got most we needed, so only consider this eof */
3058 if (G_UNLIKELY (length == 0)) {
3059 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
3060 (_("Invalid atom size.")),
3061 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
3062 GST_FOURCC_ARGS (fourcc)));
3069 /* record for later parsing when needed */
3070 if (!qtdemux->moof_offset) {
3071 qtdemux->moof_offset = qtdemux->offset;
3080 GST_LOG_OBJECT (qtdemux,
3081 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
3082 GST_FOURCC_ARGS (fourcc), cur_offset);
3083 qtdemux->offset += length;
3088 GstBuffer *moov = NULL;
3090 if (qtdemux->got_moov) {
3091 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
3092 qtdemux->offset += length;
3096 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
3097 if (ret != GST_FLOW_OK)
3099 gst_buffer_map (moov, &map, GST_MAP_READ);
3101 if (length != map.size) {
3102 /* Some files have a 'moov' atom at the end of the file which contains
3103 * a terminal 'free' atom where the body of the atom is missing.
3104 * Check for, and permit, this special case.
3106 if (map.size >= 8) {
3107 guint8 *final_data = map.data + (map.size - 8);
3108 guint32 final_length = QT_UINT32 (final_data);
3109 guint32 final_fourcc = QT_FOURCC (final_data + 4);
3111 if (final_fourcc == FOURCC_free
3112 && map.size + final_length - 8 == length) {
3113 /* Ok, we've found that special case. Allocate a new buffer with
3114 * that free atom actually present. */
3115 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
3116 gst_buffer_fill (newmoov, 0, map.data, map.size);
3117 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
3118 gst_buffer_unmap (moov, &map);
3119 gst_buffer_unref (moov);
3121 gst_buffer_map (moov, &map, GST_MAP_READ);
3126 if (length != map.size) {
3127 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3128 (_("This file is incomplete and cannot be played.")),
3129 ("We got less than expected (received %" G_GSIZE_FORMAT
3130 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3131 (guint) length, cur_offset));
3132 gst_buffer_unmap (moov, &map);
3133 gst_buffer_unref (moov);
3134 ret = GST_FLOW_ERROR;
3137 qtdemux->offset += length;
3139 qtdemux_parse_moov (qtdemux, map.data, length);
3140 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3142 qtdemux_parse_tree (qtdemux);
3143 g_node_destroy (qtdemux->moov_node);
3144 gst_buffer_unmap (moov, &map);
3145 gst_buffer_unref (moov);
3146 qtdemux->moov_node = NULL;
3147 qtdemux->got_moov = TRUE;
3153 GstBuffer *ftyp = NULL;
3155 /* extract major brand; might come in handy for ISO vs QT issues */
3156 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3157 if (ret != GST_FLOW_OK)
3159 qtdemux->offset += length;
3160 gst_buffer_map (ftyp, &map, GST_MAP_READ);
3161 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3162 gst_buffer_unmap (ftyp, &map);
3163 gst_buffer_unref (ftyp);
3168 GstBuffer *uuid = NULL;
3170 /* uuid are extension atoms */
3171 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3172 if (ret != GST_FLOW_OK)
3174 qtdemux->offset += length;
3175 gst_buffer_map (uuid, &map, GST_MAP_READ);
3176 qtdemux_parse_uuid (qtdemux, map.data, map.size);
3177 gst_buffer_unmap (uuid, &map);
3178 gst_buffer_unref (uuid);
3183 GstBuffer *unknown = NULL;
3185 GST_LOG_OBJECT (qtdemux,
3186 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3187 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3189 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3190 if (ret != GST_FLOW_OK)
3192 gst_buffer_map (unknown, &map, GST_MAP_READ);
3193 GST_MEMDUMP ("Unknown tag", map.data, map.size);
3194 gst_buffer_unmap (unknown, &map);
3195 gst_buffer_unref (unknown);
3196 qtdemux->offset += length;
3202 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3203 /* digested all data, show what we have */
3204 qtdemux_prepare_streams (qtdemux);
3205 ret = qtdemux_expose_streams (qtdemux);
3207 qtdemux->state = QTDEMUX_STATE_MOVIE;
3208 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3215 /* Seeks to the previous keyframe of the indexed stream and
3216 * aligns other streams with respect to the keyframe timestamp
3217 * of indexed stream. Only called in case of Reverse Playback
3219 static GstFlowReturn
3220 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
3223 guint32 seg_idx = 0, k_index = 0;
3224 guint32 ref_seg_idx, ref_k_index;
3225 guint64 k_pos = 0, last_stop = 0;
3226 QtDemuxSegment *seg = NULL;
3227 QtDemuxStream *ref_str = NULL;
3228 guint64 seg_media_start_mov; /* segment media start time in mov format */
3230 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
3231 * and finally align all the other streams on that timestamp with their
3232 * respective keyframes */
3233 for (n = 0; n < qtdemux->n_streams; n++) {
3234 QtDemuxStream *str = qtdemux->streams[n];
3236 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
3237 qtdemux->segment.position);
3239 /* segment not found, continue with normal flow */
3243 /* No candidate yet, take that one */
3249 /* So that stream has a segment, we prefer video streams */
3250 if (str->subtype == FOURCC_vide) {
3256 if (G_UNLIKELY (!ref_str)) {
3257 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
3261 if (G_UNLIKELY (!ref_str->from_sample)) {
3262 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
3266 /* So that stream has been playing from from_sample to to_sample. We will
3267 * get the timestamp of the previous sample and search for a keyframe before
3268 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
3269 if (ref_str->subtype == FOURCC_vide) {
3270 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
3271 ref_str->from_sample - 1);
3273 if (ref_str->from_sample >= 10)
3274 k_index = ref_str->from_sample - 10;
3279 /* get current segment for that stream */
3280 seg = &ref_str->segments[ref_str->segment_index];
3281 /* convert seg->media_start to mov format time for timestamp comparison */
3282 seg_media_start_mov =
3283 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
3284 /* Crawl back through segments to find the one containing this I frame */
3285 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
3286 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
3287 ref_str->segment_index);
3288 if (G_UNLIKELY (!ref_str->segment_index)) {
3289 /* Reached first segment, let's consider it's EOS */
3292 ref_str->segment_index--;
3293 seg = &ref_str->segments[ref_str->segment_index];
3294 /* convert seg->media_start to mov format time for timestamp comparison */
3295 seg_media_start_mov =
3296 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
3299 /* Calculate time position of the keyframe and where we should stop */
3301 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
3302 ref_str->timescale) - seg->media_start) + seg->time;
3304 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
3305 GST_SECOND, ref_str->timescale);
3306 last_stop = (last_stop - seg->media_start) + seg->time;
3308 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
3309 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
3310 k_index, GST_TIME_ARGS (k_pos));
3312 /* Set last_stop with the keyframe timestamp we pushed of that stream */
3313 qtdemux->segment.position = last_stop;
3314 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
3315 GST_TIME_ARGS (last_stop));
3317 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
3318 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
3322 ref_seg_idx = ref_str->segment_index;
3323 ref_k_index = k_index;
3325 /* Align them all on this */
3326 for (n = 0; n < qtdemux->n_streams; n++) {
3328 guint64 media_start = 0, seg_time = 0;
3329 QtDemuxStream *str = qtdemux->streams[n];
3331 /* aligning reference stream again might lead to backing up to yet another
3332 * keyframe (due to timestamp rounding issues),
3333 * potentially putting more load on downstream; so let's try to avoid */
3334 if (str == ref_str) {
3335 seg_idx = ref_seg_idx;
3336 seg = &str->segments[seg_idx];
3337 k_index = ref_k_index;
3338 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
3339 "sample at index %d", ref_str->segment_index, k_index);
3341 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
3342 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
3344 /* segment not found, continue with normal flow */
3348 /* get segment and time in the segment */
3349 seg = &str->segments[seg_idx];
3350 seg_time = k_pos - seg->time;
3352 /* get the media time in the segment */
3353 media_start = seg->media_start + seg_time;
3355 /* get the index of the sample with media time */
3356 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
3357 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
3358 GST_TIME_ARGS (media_start), index);
3360 /* find previous keyframe */
3361 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
3364 /* Remember until where we want to go */
3365 str->to_sample = str->from_sample - 1;
3366 /* Define our time position */
3367 str->time_position =
3368 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
3369 str->timescale) - seg->media_start) + seg->time;
3370 /* Now seek back in time */
3371 gst_qtdemux_move_stream (qtdemux, str, k_index);
3372 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
3373 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
3374 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
3380 return GST_FLOW_EOS;
3383 /* activate the given segment number @seg_idx of @stream at time @offset.
3384 * @offset is an absolute global position over all the segments.
3386 * This will push out a NEWSEGMENT event with the right values and
3387 * position the stream index to the first decodable sample before
3391 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
3392 guint32 seg_idx, guint64 offset)
3395 QtDemuxSegment *segment;
3396 guint32 index, kf_index;
3398 guint64 start, stop, time;
3401 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3404 /* update the current segment */
3405 stream->segment_index = seg_idx;
3407 /* get the segment */
3408 segment = &stream->segments[seg_idx];
3410 if (G_UNLIKELY (offset < segment->time)) {
3411 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3416 /* segment lies beyond total indicated duration */
3417 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3418 segment->time > qtdemux->segment.duration)) {
3419 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3420 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3425 /* get time in this segment */
3426 seg_time = offset - segment->time;
3428 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3429 GST_TIME_ARGS (seg_time));
3431 if (G_UNLIKELY (seg_time > segment->duration)) {
3432 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3433 GST_TIME_ARGS (segment->duration));
3437 /* qtdemux->segment.stop is in outside-time-realm, whereas
3438 * segment->media_stop is in track-time-realm.
3440 * In order to compare the two, we need to bring segment.stop
3441 * into the track-time-realm */
3443 stop = qtdemux->segment.stop;
3445 stop = qtdemux->segment.duration;
3447 stop = segment->media_stop;
3450 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3452 if (qtdemux->segment.rate >= 0) {
3453 start = MIN (segment->media_start + seg_time, stop);
3456 if (segment->media_start >= qtdemux->segment.start) {
3457 start = segment->media_start;
3458 time = segment->time;
3460 start = qtdemux->segment.start;
3461 time = segment->time + (qtdemux->segment.start - segment->media_start);
3464 start = MAX (segment->media_start, qtdemux->segment.start);
3465 stop = MIN (segment->media_start + seg_time, stop);
3468 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3469 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3470 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3472 /* combine global rate with that of the segment */
3473 rate = segment->rate * qtdemux->segment.rate;
3475 /* update the segment values used for clipping */
3476 /* accumulate previous segments */
3477 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3478 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3479 ABS (stream->segment.rate);
3480 stream->segment.rate = rate;
3481 stream->segment.start = start;
3482 stream->segment.stop = stop;
3483 stream->segment.time = time;
3484 stream->segment.position = start;
3486 /* now prepare and send the segment */
3488 event = gst_event_new_segment (&stream->segment);
3489 if (stream->segment_seqnum) {
3490 gst_event_set_seqnum (event, stream->segment_seqnum);
3491 stream->segment_seqnum = 0;
3493 gst_pad_push_event (stream->pad, event);
3494 /* assume we can send more data now */
3495 stream->last_ret = GST_FLOW_OK;
3496 /* clear to send tags on this pad now */
3497 gst_qtdemux_push_tags (qtdemux, stream);
3500 /* and move to the keyframe before the indicated media time of the
3502 if (qtdemux->segment.rate >= 0) {
3503 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3504 stream->to_sample = G_MAXUINT32;
3505 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3506 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3507 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3508 GST_SECOND, stream->timescale)));
3510 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3511 stream->to_sample = index;
3512 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3513 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3514 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3515 GST_SECOND, stream->timescale)));
3518 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3519 * encountered an error and printed a message so we return appropriately */
3523 /* we're at the right spot */
3524 if (index == stream->sample_index) {
3525 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3529 /* find keyframe of the target index */
3530 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3533 /* indent does stupid stuff with stream->samples[].timestamp */
3535 /* if we move forwards, we don't have to go back to the previous
3536 * keyframe since we already sent that. We can also just jump to
3537 * the keyframe right before the target index if there is one. */
3538 if (index > stream->sample_index) {
3539 /* moving forwards check if we move past a keyframe */
3540 if (kf_index > stream->sample_index) {
3541 GST_DEBUG_OBJECT (qtdemux,
3542 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3543 GST_TIME_ARGS (gst_util_uint64_scale (
3544 stream->samples[kf_index].timestamp,
3545 GST_SECOND, stream->timescale)));
3546 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3548 GST_DEBUG_OBJECT (qtdemux,
3549 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3550 " already sent", kf_index,
3551 GST_TIME_ARGS (gst_util_uint64_scale (
3552 stream->samples[kf_index].timestamp,
3553 GST_SECOND, stream->timescale)));
3556 GST_DEBUG_OBJECT (qtdemux,
3557 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3558 GST_TIME_ARGS (gst_util_uint64_scale (
3559 stream->samples[kf_index].timestamp,
3560 GST_SECOND, stream->timescale)));
3561 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3569 /* prepare to get the current sample of @stream, getting essential values.
3571 * This function will also prepare and send the segment when needed.
3573 * Return FALSE if the stream is EOS.
3576 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3577 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * dts,
3578 guint64 * pts, guint64 * duration, gboolean * keyframe)
3580 QtDemuxSample *sample;
3581 guint64 time_position;
3584 g_return_val_if_fail (stream != NULL, FALSE);
3586 time_position = stream->time_position;
3587 if (G_UNLIKELY (time_position == -1))
3590 seg_idx = stream->segment_index;
3591 if (G_UNLIKELY (seg_idx == -1)) {
3592 /* find segment corresponding to time_position if we are looking
3594 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3596 /* nothing found, we're really eos */
3601 /* different segment, activate it, sample_index will be set. */
3602 if (G_UNLIKELY (stream->segment_index != seg_idx))
3603 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3605 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3606 stream->sample_index, stream->n_samples);
3608 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3611 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3612 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3613 stream->sample_index);
3617 /* now get the info for the sample we're at */
3618 sample = &stream->samples[stream->sample_index];
3620 *dts = QTSAMPLE_DTS (stream, sample);
3621 *pts = QTSAMPLE_PTS (stream, sample);
3622 *offset = sample->offset;
3623 *size = sample->size;
3624 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3625 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3632 stream->time_position = -1;
3637 /* move to the next sample in @stream.
3639 * Moves to the next segment when needed.
3642 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3644 QtDemuxSample *sample;
3645 QtDemuxSegment *segment;
3647 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3648 /* Mark the stream as EOS */
3649 GST_DEBUG_OBJECT (qtdemux,
3650 "reached max allowed sample %u, mark EOS", stream->to_sample);
3651 stream->time_position = -1;
3655 /* move to next sample */
3656 stream->sample_index++;
3657 stream->offset_in_sample = 0;
3659 /* get current segment */
3660 segment = &stream->segments[stream->segment_index];
3662 /* reached the last sample, we need the next segment */
3663 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3666 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3667 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3668 stream->sample_index);
3672 /* get next sample */
3673 sample = &stream->samples[stream->sample_index];
3675 /* see if we are past the segment */
3676 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3677 GST_SECOND, stream->timescale) >= segment->media_stop))
3680 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3681 stream->timescale) >= segment->media_start) {
3682 /* inside the segment, update time_position, looks very familiar to
3683 * GStreamer segments, doesn't it? */
3684 stream->time_position =
3685 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3686 stream->timescale) - segment->media_start) + segment->time;
3688 /* not yet in segment, time does not yet increment. This means
3689 * that we are still prerolling keyframes to the decoder so it can
3690 * decode the first sample of the segment. */
3691 stream->time_position = segment->time;
3695 /* move to the next segment */
3698 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3700 if (stream->segment_index == stream->n_segments - 1) {
3701 /* are we at the end of the last segment, we're EOS */
3702 stream->time_position = -1;
3704 /* else we're only at the end of the current segment */
3705 stream->time_position = segment->stop_time;
3707 /* make sure we select a new segment */
3708 stream->segment_index = -1;
3713 gst_qtdemux_sync_streams (GstQTDemux * demux)
3717 if (demux->n_streams <= 1)
3720 for (i = 0; i < demux->n_streams; i++) {
3721 QtDemuxStream *stream;
3722 GstClockTime end_time;
3724 stream = demux->streams[i];
3729 /* TODO advance time on subtitle streams here, if any some day */
3731 /* some clips/trailers may have unbalanced streams at the end,
3732 * so send EOS on shorter stream to prevent stalling others */
3734 /* do not mess with EOS if SEGMENT seeking */
3735 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3738 if (demux->pullbased) {
3739 /* loop mode is sample time based */
3740 if (!STREAM_IS_EOS (stream))
3743 /* push mode is byte position based */
3744 if (stream->n_samples &&
3745 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3749 if (stream->sent_eos)
3752 /* only act if some gap */
3753 end_time = stream->segments[stream->n_segments - 1].stop_time;
3754 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3755 ", stream end: %" GST_TIME_FORMAT,
3756 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3757 if (GST_CLOCK_TIME_IS_VALID (end_time)
3758 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
3759 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3760 GST_PAD_NAME (stream->pad));
3761 stream->sent_eos = TRUE;
3762 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3767 /* EOS and NOT_LINKED need to be combined. This means that we return:
3769 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3770 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
3772 static GstFlowReturn
3773 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3777 gboolean unexpected = FALSE, not_linked = TRUE;
3779 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3781 /* store the value */
3782 stream->last_ret = ret;
3784 /* any other error that is not-linked or eos can be returned right away */
3785 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3788 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3789 for (i = 0; i < demux->n_streams; i++) {
3790 QtDemuxStream *ostream = demux->streams[i];
3792 ret = ostream->last_ret;
3794 /* no unexpected or unlinked, return */
3795 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3798 /* we check to see if we have at least 1 unexpected or all unlinked */
3799 unexpected |= (ret == GST_FLOW_EOS);
3800 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3803 /* when we get here, we all have unlinked or unexpected */
3805 ret = GST_FLOW_NOT_LINKED;
3806 else if (unexpected)
3809 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3813 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3816 * Should be used only with raw buffers */
3818 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3821 guint64 start, stop, cstart, cstop, diff;
3822 GstClockTime pts, duration;
3824 gint num_rate, denom_rate;
3829 osize = size = gst_buffer_get_size (buf);
3832 /* depending on the type, setup the clip parameters */
3833 if (stream->subtype == FOURCC_soun) {
3834 frame_size = stream->bytes_per_frame;
3835 num_rate = GST_SECOND;
3836 denom_rate = (gint) stream->rate;
3838 } else if (stream->subtype == FOURCC_vide) {
3840 num_rate = stream->fps_n;
3841 denom_rate = stream->fps_d;
3846 /* we can only clip if we have a valid pts */
3847 pts = GST_BUFFER_PTS (buf);
3848 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
3851 duration = GST_BUFFER_DURATION (buf);
3853 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
3855 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3859 stop = start + duration;
3861 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3862 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3865 /* see if some clipping happened */
3866 diff = cstart - start;
3872 /* bring clipped time to samples and to bytes */
3873 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3876 GST_DEBUG_OBJECT (qtdemux,
3877 "clipping start to %" GST_TIME_FORMAT " %"
3878 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3884 diff = stop - cstop;
3889 /* bring clipped time to samples and then to bytes */
3890 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3892 GST_DEBUG_OBJECT (qtdemux,
3893 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3894 " bytes", GST_TIME_ARGS (cstop), diff);
3899 if (offset != 0 || size != osize)
3900 gst_buffer_resize (buf, offset, size);
3902 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
3903 GST_BUFFER_PTS (buf) = pts;
3904 GST_BUFFER_DURATION (buf) = duration;
3908 /* dropped buffer */
3911 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3916 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
3921 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3922 gst_buffer_unref (buf);
3927 /* the input buffer metadata must be writable,
3928 * but time/duration etc not yet set and need not be preserved */
3930 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3937 /* not many cases for now */
3938 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3939 /* send a one time dvd clut event */
3940 if (stream->pending_event && stream->pad)
3941 gst_pad_push_event (stream->pad, stream->pending_event);
3942 stream->pending_event = NULL;
3943 /* no further processing needed */
3944 stream->need_process = FALSE;
3947 if (G_UNLIKELY (stream->subtype != FOURCC_text
3948 && stream->subtype != FOURCC_sbtl)) {
3952 gst_buffer_map (buf, &map, GST_MAP_READ);
3954 /* empty buffer is sent to terminate previous subtitle */
3955 if (map.size <= 2) {
3956 gst_buffer_unmap (buf, &map);
3957 gst_buffer_unref (buf);
3961 nsize = GST_READ_UINT16_BE (map.data);
3962 nsize = MIN (nsize, map.size - 2);
3964 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
3967 /* takes care of UTF-8 validation or UTF-16 recognition,
3968 * no other encoding expected */
3969 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
3970 gst_buffer_unmap (buf, &map);
3972 gst_buffer_unref (buf);
3973 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
3975 /* this should not really happen unless the subtitle is corrupted */
3976 gst_buffer_unref (buf);
3980 /* FIXME ? convert optional subsequent style info to markup */
3985 /* Sets a buffer's attributes properly and pushes it downstream.
3986 * Also checks for additional actions and custom processing that may
3987 * need to be done first.
3989 static GstFlowReturn
3990 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3991 QtDemuxStream * stream, GstBuffer * buf,
3992 guint64 dts, guint64 pts, guint64 duration, gboolean keyframe,
3993 guint64 position, guint64 byte_position)
3995 GstFlowReturn ret = GST_FLOW_OK;
3997 /* offset the timestamps according to the edit list */
3999 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
4003 gst_buffer_map (buf, &map, GST_MAP_READ);
4004 url = g_strndup ((gchar *) map.data, map.size);
4005 gst_buffer_unmap (buf, &map);
4006 if (url != NULL && strlen (url) != 0) {
4007 /* we have RTSP redirect now */
4008 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4009 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
4010 gst_structure_new ("redirect",
4011 "new-location", G_TYPE_STRING, url, NULL)));
4012 qtdemux->posted_redirect = TRUE;
4014 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
4020 /* position reporting */
4021 if (qtdemux->segment.rate >= 0) {
4022 qtdemux->segment.position = position;
4023 gst_qtdemux_sync_streams (qtdemux);
4026 if (G_UNLIKELY (!stream->pad)) {
4027 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
4028 gst_buffer_unref (buf);
4032 /* send out pending buffers */
4033 while (stream->buffers) {
4034 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
4036 if (G_UNLIKELY (stream->discont)) {
4037 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4038 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
4039 stream->discont = FALSE;
4041 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4044 gst_pad_push (stream->pad, buffer);
4046 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
4049 /* we're going to modify the metadata */
4050 buf = gst_buffer_make_writable (buf);
4052 if (G_UNLIKELY (stream->need_process))
4053 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
4059 GST_BUFFER_DTS (buf) = dts;
4060 GST_BUFFER_PTS (buf) = pts;
4061 GST_BUFFER_DURATION (buf) = duration;
4062 GST_BUFFER_OFFSET (buf) = -1;
4063 GST_BUFFER_OFFSET_END (buf) = -1;
4065 if (G_UNLIKELY (stream->rgb8_palette))
4066 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
4068 if (G_UNLIKELY (stream->padding)) {
4069 gst_buffer_resize (buf, stream->padding, -1);
4072 if (G_UNLIKELY (qtdemux->element_index)) {
4073 GstClockTime stream_time;
4076 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
4078 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
4079 GST_LOG_OBJECT (qtdemux,
4080 "adding association %" GST_TIME_FORMAT "-> %"
4081 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
4082 gst_index_add_association (qtdemux->element_index,
4084 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
4085 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
4086 GST_FORMAT_BYTES, byte_position, NULL);
4091 if (stream->need_clip)
4092 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
4094 if (G_UNLIKELY (buf == NULL))
4097 if (G_UNLIKELY (stream->discont)) {
4098 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4099 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4100 stream->discont = FALSE;
4102 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4106 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4107 stream->on_keyframe = FALSE;
4109 stream->on_keyframe = TRUE;
4113 GST_LOG_OBJECT (qtdemux,
4114 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
4115 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
4116 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
4117 GST_PAD_NAME (stream->pad));
4119 ret = gst_pad_push (stream->pad, buf);
4121 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
4122 /* mark position in stream, we'll need this to know when to send GAP event */
4123 stream->segment.position = pts + duration;
4130 static GstFlowReturn
4131 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
4133 GstFlowReturn ret = GST_FLOW_OK;
4134 GstBuffer *buf = NULL;
4135 QtDemuxStream *stream;
4138 guint64 dts = GST_CLOCK_TIME_NONE;
4139 guint64 pts = GST_CLOCK_TIME_NONE;
4140 guint64 duration = 0;
4141 gboolean keyframe = FALSE;
4142 guint sample_size = 0;
4147 gst_qtdemux_push_pending_newsegment (qtdemux);
4149 /* Figure out the next stream sample to output, min_time is expressed in
4150 * global time and runs over the edit list segments. */
4151 min_time = G_MAXUINT64;
4153 for (i = 0; i < qtdemux->n_streams; i++) {
4156 stream = qtdemux->streams[i];
4157 position = stream->time_position;
4159 /* position of -1 is EOS */
4160 if (position != -1 && position < min_time) {
4161 min_time = position;
4166 if (G_UNLIKELY (index == -1)) {
4167 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
4171 /* check for segment end */
4172 if (G_UNLIKELY (qtdemux->segment.stop != -1
4173 && qtdemux->segment.stop <= min_time
4174 && qtdemux->streams[index]->on_keyframe)) {
4175 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
4176 qtdemux->streams[index]->time_position = -1;
4180 /* gap events for subtitle streams */
4181 for (i = 0; i < qtdemux->n_streams; i++) {
4182 stream = qtdemux->streams[i];
4183 if (stream->pad && (stream->subtype == FOURCC_subp
4184 || stream->subtype == FOURCC_text
4185 || stream->subtype == FOURCC_sbtl)) {
4186 /* send one second gap events until the stream catches up */
4187 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
4188 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
4189 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
4190 stream->segment.position + GST_SECOND < min_time) {
4192 gst_event_new_gap (stream->segment.position, GST_SECOND);
4193 gst_pad_push_event (stream->pad, gap);
4194 stream->segment.position += GST_SECOND;
4199 stream = qtdemux->streams[index];
4200 if (stream->new_caps) {
4201 gst_qtdemux_configure_stream (qtdemux, stream);
4202 qtdemux_do_allocation (qtdemux, stream);
4205 /* fetch info for the current sample of this stream */
4206 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
4207 &sample_size, &dts, &pts, &duration, &keyframe)))
4210 GST_DEBUG_OBJECT (qtdemux,
4211 "pushing from stream %d, offset %" G_GUINT64_FORMAT
4212 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
4213 ", duration %" GST_TIME_FORMAT, index, offset, sample_size,
4214 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
4216 /* hmm, empty sample, skip and move to next sample */
4217 if (G_UNLIKELY (sample_size <= 0))
4220 /* last pushed sample was out of boundary, goto next sample */
4221 if (G_UNLIKELY (stream->last_ret == GST_FLOW_EOS))
4224 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
4227 GST_DEBUG_OBJECT (qtdemux,
4228 "size %d larger than stream max_buffer_size %d, trimming",
4229 sample_size, stream->max_buffer_size);
4231 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
4234 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
4237 if (stream->use_allocator) {
4238 /* if we have a per-stream allocator, use it */
4239 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
4242 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
4244 if (G_UNLIKELY (ret != GST_FLOW_OK))
4247 if (size != sample_size) {
4248 pts += gst_util_uint64_scale_int (GST_SECOND,
4249 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4250 dts += gst_util_uint64_scale_int (GST_SECOND,
4251 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4252 duration = gst_util_uint64_scale_int (GST_SECOND,
4253 size / stream->bytes_per_frame, stream->timescale);
4256 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
4257 dts, pts, duration, keyframe, min_time, offset);
4259 if (size != sample_size) {
4260 QtDemuxSample *sample = &stream->samples[stream->sample_index];
4261 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
4263 GstClockTime time_position = gst_util_uint64_scale (sample->timestamp +
4264 stream->offset_in_sample / stream->bytes_per_frame, GST_SECOND,
4266 if (time_position >= segment->media_start) {
4267 /* inside the segment, update time_position, looks very familiar to
4268 * GStreamer segments, doesn't it? */
4269 stream->time_position = (time_position - segment->media_start) +
4272 /* not yet in segment, time does not yet increment. This means
4273 * that we are still prerolling keyframes to the decoder so it can
4274 * decode the first sample of the segment. */
4275 stream->time_position = segment->time;
4280 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
4281 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
4282 * we have no more data for the pad to push */
4283 if (ret == GST_FLOW_EOS)
4286 stream->offset_in_sample += size;
4287 if (stream->offset_in_sample >= sample_size) {
4288 gst_qtdemux_advance_sample (qtdemux, stream);
4293 gst_qtdemux_advance_sample (qtdemux, stream);
4301 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
4307 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
4308 /* EOS will be raised if all are EOS */
4315 gst_qtdemux_loop (GstPad * pad)
4317 GstQTDemux *qtdemux;
4321 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
4323 cur_offset = qtdemux->offset;
4324 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
4325 cur_offset, qtdemux->state);
4327 switch (qtdemux->state) {
4328 case QTDEMUX_STATE_INITIAL:
4329 case QTDEMUX_STATE_HEADER:
4330 ret = gst_qtdemux_loop_state_header (qtdemux);
4332 case QTDEMUX_STATE_MOVIE:
4333 ret = gst_qtdemux_loop_state_movie (qtdemux);
4334 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
4335 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
4343 /* if something went wrong, pause */
4344 if (ret != GST_FLOW_OK)
4348 gst_object_unref (qtdemux);
4354 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4355 (NULL), ("streaming stopped, invalid state"));
4356 gst_pad_pause_task (pad);
4357 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4362 const gchar *reason = gst_flow_get_name (ret);
4364 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
4366 gst_pad_pause_task (pad);
4368 /* fatal errors need special actions */
4370 if (ret == GST_FLOW_EOS) {
4371 if (qtdemux->n_streams == 0) {
4372 /* we have no streams, post an error */
4373 gst_qtdemux_post_no_playable_stream_error (qtdemux);
4375 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4378 if ((stop = qtdemux->segment.stop) == -1)
4379 stop = qtdemux->segment.duration;
4381 if (qtdemux->segment.rate >= 0) {
4382 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
4383 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4384 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4385 GST_FORMAT_TIME, stop));
4386 gst_qtdemux_push_event (qtdemux,
4387 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
4389 /* For Reverse Playback */
4390 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
4391 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4392 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4393 GST_FORMAT_TIME, qtdemux->segment.start));
4394 gst_qtdemux_push_event (qtdemux,
4395 gst_event_new_segment_done (GST_FORMAT_TIME,
4396 qtdemux->segment.start));
4399 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
4400 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4402 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
4403 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4404 (NULL), ("streaming stopped, reason %s", reason));
4405 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4414 * Returns the size of the first entry at the current offset.
4415 * If -1, there are none (which means EOS or empty file).
4418 next_entry_size (GstQTDemux * demux)
4420 QtDemuxStream *stream;
4423 guint64 smalloffs = (guint64) - 1;
4424 QtDemuxSample *sample;
4426 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
4429 for (i = 0; i < demux->n_streams; i++) {
4430 stream = demux->streams[i];
4432 if (stream->sample_index == -1) {
4433 stream->sample_index = 0;
4434 stream->offset_in_sample = 0;
4437 if (stream->sample_index >= stream->n_samples) {
4438 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4442 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
4443 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
4444 stream->sample_index);
4448 sample = &stream->samples[stream->sample_index];
4450 GST_LOG_OBJECT (demux,
4451 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4452 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
4453 sample->offset, sample->size);
4455 if (((smalloffs == -1)
4456 || (sample->offset < smalloffs)) && (sample->size)) {
4458 smalloffs = sample->offset;
4462 GST_LOG_OBJECT (demux,
4463 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
4464 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
4469 stream = demux->streams[smallidx];
4470 sample = &stream->samples[stream->sample_index];
4472 if (sample->offset >= demux->offset) {
4473 demux->todrop = sample->offset - demux->offset;
4474 return sample->size + demux->todrop;
4477 GST_DEBUG_OBJECT (demux,
4478 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
4483 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
4485 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
4487 gst_element_post_message (GST_ELEMENT_CAST (demux),
4488 gst_message_new_element (GST_OBJECT_CAST (demux),
4489 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
4493 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
4498 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
4501 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
4502 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
4503 GST_SEEK_TYPE_NONE, -1);
4505 res = gst_pad_push_event (demux->sinkpad, event);
4510 /* check for seekable upstream, above and beyond a mere query */
4512 gst_qtdemux_check_seekability (GstQTDemux * demux)
4515 gboolean seekable = FALSE;
4516 gint64 start = -1, stop = -1;
4518 if (demux->upstream_size)
4521 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4522 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4523 GST_DEBUG_OBJECT (demux, "seeking query failed");
4527 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4529 /* try harder to query upstream size if we didn't get it the first time */
4530 if (seekable && stop == -1) {
4531 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4532 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4535 /* if upstream doesn't know the size, it's likely that it's not seekable in
4536 * practice even if it technically may be seekable */
4537 if (seekable && (start != 0 || stop <= start)) {
4538 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4543 gst_query_unref (query);
4545 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4546 G_GUINT64_FORMAT ")", seekable, start, stop);
4547 demux->upstream_seekable = seekable;
4548 demux->upstream_size = seekable ? stop : -1;
4551 /* FIXME, unverified after edit list updates */
4552 static GstFlowReturn
4553 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4556 GstFlowReturn ret = GST_FLOW_OK;
4557 GstClockTime timestamp;
4559 demux = GST_QTDEMUX (parent);
4561 timestamp = GST_BUFFER_TIMESTAMP (inbuf);
4563 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (timestamp))) {
4564 demux->fragment_start = timestamp;
4565 GST_DEBUG_OBJECT (demux, "got fragment_start %" GST_TIME_FORMAT,
4566 GST_TIME_ARGS (timestamp));
4569 gst_adapter_push (demux->adapter, inbuf);
4571 /* we never really mean to buffer that much */
4572 if (demux->neededbytes == -1) {
4576 GST_DEBUG_OBJECT (demux,
4577 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4578 demux->neededbytes, gst_adapter_available (demux->adapter));
4580 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4581 (ret == GST_FLOW_OK)) {
4583 GST_DEBUG_OBJECT (demux,
4584 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4585 demux->state, demux->neededbytes, demux->offset);
4587 switch (demux->state) {
4588 case QTDEMUX_STATE_INITIAL:{
4593 gst_qtdemux_check_seekability (demux);
4595 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4597 /* get fourcc/length, set neededbytes */
4598 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4600 gst_adapter_unmap (demux->adapter);
4602 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4603 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4605 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4606 (_("This file is invalid and cannot be played.")),
4607 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4608 GST_FOURCC_ARGS (fourcc)));
4609 ret = GST_FLOW_ERROR;
4612 if (fourcc == FOURCC_mdat) {
4613 gint next_entry = next_entry_size (demux);
4614 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
4615 /* we have the headers, start playback */
4616 demux->state = QTDEMUX_STATE_MOVIE;
4617 demux->neededbytes = next_entry;
4618 demux->mdatleft = size;
4620 /* no headers yet, try to get them */
4623 guint64 old, target;
4626 old = demux->offset;
4627 target = old + size;
4629 /* try to jump over the atom with a seek */
4630 /* only bother if it seems worth doing so,
4631 * and avoids possible upstream/server problems */
4632 if (demux->upstream_seekable &&
4633 demux->upstream_size > 4 * (1 << 20)) {
4634 res = qtdemux_seek_offset (demux, target);
4636 GST_DEBUG_OBJECT (demux, "skipping seek");
4641 GST_DEBUG_OBJECT (demux, "seek success");
4642 /* remember the offset fo the first mdat so we can seek back to it
4643 * after we have the headers */
4644 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4645 demux->first_mdat = old;
4646 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4649 /* seek worked, continue reading */
4650 demux->offset = target;
4651 demux->neededbytes = 16;
4652 demux->state = QTDEMUX_STATE_INITIAL;
4654 /* seek failed, need to buffer */
4655 demux->offset = old;
4656 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4657 /* there may be multiple mdat (or alike) buffers */
4659 if (demux->mdatbuffer)
4660 bs = gst_buffer_get_size (demux->mdatbuffer);
4663 if (size + bs > 10 * (1 << 20))
4665 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4666 demux->neededbytes = size;
4667 if (!demux->mdatbuffer)
4668 demux->mdatoffset = demux->offset;
4671 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4672 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4673 (_("This file is invalid and cannot be played.")),
4674 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4675 GST_FOURCC_ARGS (fourcc), size));
4676 ret = GST_FLOW_ERROR;
4679 /* this means we already started buffering and still no moov header,
4680 * let's continue buffering everything till we get moov */
4681 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
4682 || fourcc == FOURCC_moof))
4684 demux->neededbytes = size;
4685 demux->state = QTDEMUX_STATE_HEADER;
4689 case QTDEMUX_STATE_HEADER:{
4693 GST_DEBUG_OBJECT (demux, "In header");
4695 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4697 /* parse the header */
4698 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4700 if (fourcc == FOURCC_moov) {
4701 /* in usual fragmented setup we could try to scan for more
4702 * and end up at the the moov (after mdat) again */
4703 if (demux->got_moov && demux->n_streams > 0 && !demux->fragmented) {
4704 GST_DEBUG_OBJECT (demux,
4705 "Skipping moov atom as we have one already");
4707 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4709 if (demux->got_moov && demux->fragmented) {
4710 GST_DEBUG_OBJECT (demux,
4711 "Got a second moov, clean up data from old one");
4712 if (demux->moov_node)
4713 g_node_destroy (demux->moov_node);
4714 demux->moov_node = NULL;
4715 demux->moov_node_compressed = NULL;
4717 /* prepare newsegment to send when streaming actually starts */
4718 if (!demux->pending_newsegment)
4719 demux->pending_newsegment =
4720 gst_event_new_segment (&demux->segment);
4723 qtdemux_parse_moov (demux, data, demux->neededbytes);
4724 qtdemux_node_dump (demux, demux->moov_node);
4725 qtdemux_parse_tree (demux);
4726 qtdemux_prepare_streams (demux);
4727 if (!demux->got_moov)
4728 qtdemux_expose_streams (demux);
4732 for (n = 0; n < demux->n_streams; n++) {
4733 QtDemuxStream *stream = demux->streams[n];
4735 gst_qtdemux_configure_stream (demux, stream);
4739 demux->got_moov = TRUE;
4741 g_node_destroy (demux->moov_node);
4742 demux->moov_node = NULL;
4743 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4745 } else if (fourcc == FOURCC_moof) {
4746 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
4747 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4748 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4749 demux->offset, NULL)) {
4750 gst_adapter_unmap (demux->adapter);
4751 ret = GST_FLOW_ERROR;
4754 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
4755 if (demux->mss_mode && !demux->exposed) {
4756 if (!demux->pending_newsegment) {
4758 gst_segment_init (&segment, GST_FORMAT_TIME);
4759 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
4760 demux->pending_newsegment = gst_event_new_segment (&segment);
4762 qtdemux_expose_streams (demux);
4765 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4767 } else if (fourcc == FOURCC_ftyp) {
4768 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4769 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4770 } else if (fourcc == FOURCC_uuid) {
4771 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4772 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4774 GST_WARNING_OBJECT (demux,
4775 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4776 GST_FOURCC_ARGS (fourcc));
4777 /* Let's jump that one and go back to initial state */
4779 gst_adapter_unmap (demux->adapter);
4782 if (demux->mdatbuffer && demux->n_streams) {
4783 gsize remaining_data_size = 0;
4785 /* the mdat was before the header */
4786 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4787 demux->n_streams, demux->mdatbuffer);
4788 /* restore our adapter/offset view of things with upstream;
4789 * put preceding buffered data ahead of current moov data.
4790 * This should also handle evil mdat, moov, mdat cases and alike */
4791 gst_adapter_flush (demux->adapter, demux->neededbytes);
4793 /* Store any remaining data after the mdat for later usage */
4794 remaining_data_size = gst_adapter_available (demux->adapter);
4795 if (remaining_data_size > 0) {
4796 g_assert (demux->restoredata_buffer == NULL);
4797 demux->restoredata_buffer =
4798 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
4799 demux->restoredata_offset = demux->offset + demux->neededbytes;
4800 GST_DEBUG_OBJECT (demux,
4801 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
4802 G_GUINT64_FORMAT, remaining_data_size,
4803 demux->restoredata_offset);
4806 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4807 demux->mdatbuffer = NULL;
4808 demux->offset = demux->mdatoffset;
4809 demux->neededbytes = next_entry_size (demux);
4810 demux->state = QTDEMUX_STATE_MOVIE;
4811 demux->mdatleft = gst_adapter_available (demux->adapter);
4813 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4814 gst_adapter_flush (demux->adapter, demux->neededbytes);
4816 if (demux->got_moov && demux->first_mdat != -1) {
4819 /* we need to seek back */
4820 res = qtdemux_seek_offset (demux, demux->first_mdat);
4822 demux->offset = demux->first_mdat;
4824 GST_DEBUG_OBJECT (demux, "Seek back failed");
4827 demux->offset += demux->neededbytes;
4829 demux->neededbytes = 16;
4830 demux->state = QTDEMUX_STATE_INITIAL;
4835 case QTDEMUX_STATE_BUFFER_MDAT:{
4839 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4841 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4842 gst_buffer_extract (buf, 0, fourcc, 4);
4843 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4844 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
4845 if (demux->mdatbuffer)
4846 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
4848 demux->mdatbuffer = buf;
4849 demux->offset += demux->neededbytes;
4850 demux->neededbytes = 16;
4851 demux->state = QTDEMUX_STATE_INITIAL;
4852 gst_qtdemux_post_progress (demux, 1, 1);
4856 case QTDEMUX_STATE_MOVIE:{
4858 QtDemuxStream *stream = NULL;
4859 QtDemuxSample *sample;
4861 guint64 dts, pts, duration;
4864 GST_DEBUG_OBJECT (demux,
4865 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4867 if (demux->fragmented) {
4868 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4870 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4871 /* if needed data starts within this atom,
4872 * then it should not exceed this atom */
4873 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4874 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4875 (_("This file is invalid and cannot be played.")),
4876 ("sample data crosses atom boundary"));
4877 ret = GST_FLOW_ERROR;
4880 demux->mdatleft -= demux->neededbytes;
4882 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4883 /* so we are dropping more than left in this atom */
4884 demux->todrop -= demux->mdatleft;
4885 demux->neededbytes -= demux->mdatleft;
4886 demux->mdatleft = 0;
4887 /* need to resume atom parsing so we do not miss any other pieces */
4888 demux->state = QTDEMUX_STATE_INITIAL;
4889 demux->neededbytes = 16;
4891 /* check if there was any stored post mdat data from previous buffers */
4892 if (demux->restoredata_buffer) {
4893 g_assert (gst_adapter_available (demux->adapter) == 0);
4895 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
4896 demux->restoredata_buffer = NULL;
4897 demux->offset = demux->restoredata_offset;
4904 if (demux->todrop) {
4905 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4906 gst_adapter_flush (demux->adapter, demux->todrop);
4907 demux->neededbytes -= demux->todrop;
4908 demux->offset += demux->todrop;
4912 /* initial newsegment sent here after having added pads,
4913 * possible others in sink_event */
4914 if (G_UNLIKELY (demux->pending_newsegment)) {
4915 gst_qtdemux_push_pending_newsegment (demux);
4916 /* clear to send tags on all streams */
4917 for (i = 0; i < demux->n_streams; i++) {
4918 stream = demux->streams[i];
4919 gst_qtdemux_push_tags (demux, stream);
4920 if (stream->sparse) {
4921 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
4922 gst_pad_push_event (stream->pad,
4923 gst_event_new_gap (stream->segment.position,
4924 GST_CLOCK_TIME_NONE));
4929 /* Figure out which stream this packet belongs to */
4930 for (i = 0; i < demux->n_streams; i++) {
4931 stream = demux->streams[i];
4932 if (stream->sample_index >= stream->n_samples)
4934 GST_LOG_OBJECT (demux,
4935 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4936 " / size:%d)", i, stream->sample_index,
4937 stream->samples[stream->sample_index].offset,
4938 stream->samples[stream->sample_index].size);
4940 if (stream->samples[stream->sample_index].offset == demux->offset)
4944 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4945 goto unknown_stream;
4947 if (stream->new_caps) {
4948 gst_qtdemux_configure_stream (demux, stream);
4951 /* Put data in a buffer, set timestamps, caps, ... */
4952 sample = &stream->samples[stream->sample_index];
4954 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
4955 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4956 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4957 GST_FOURCC_ARGS (stream->fourcc));
4959 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4961 dts = QTSAMPLE_DTS (stream, sample);
4962 pts = QTSAMPLE_PTS (stream, sample);
4963 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
4964 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4966 /* check for segment end */
4967 if (G_UNLIKELY (demux->segment.stop != -1
4968 && demux->segment.stop <= pts && stream->on_keyframe)) {
4969 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
4970 stream->time_position = -1; /* this means EOS */
4972 /* check if all streams are eos */
4974 for (i = 0; i < demux->n_streams; i++) {
4975 if (!STREAM_IS_EOS (demux->streams[i])) {
4981 if (ret == GST_FLOW_EOS) {
4982 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
4986 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4987 dts, pts, duration, keyframe, dts, demux->offset);
4991 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4993 /* skip this data, stream is EOS */
4994 gst_adapter_flush (demux->adapter, demux->neededbytes);
4997 stream->sample_index++;
4998 stream->offset_in_sample = 0;
5000 /* update current offset and figure out size of next buffer */
5001 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
5002 demux->offset, demux->neededbytes);
5003 demux->offset += demux->neededbytes;
5004 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
5007 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
5008 if (demux->fragmented) {
5009 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
5010 /* there may be more to follow, only finish this atom */
5011 demux->todrop = demux->mdatleft;
5012 demux->neededbytes = demux->todrop;
5024 /* when buffering movie data, at least show user something is happening */
5025 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
5026 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
5027 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
5028 demux->neededbytes);
5037 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
5038 ret = GST_FLOW_ERROR;
5043 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
5049 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5050 (NULL), ("qtdemuxer invalid state %d", demux->state));
5051 ret = GST_FLOW_ERROR;
5056 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5057 (NULL), ("no 'moov' atom within the first 10 MB"));
5058 ret = GST_FLOW_ERROR;
5064 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
5069 query = gst_query_new_scheduling ();
5071 if (!gst_pad_peer_query (sinkpad, query)) {
5072 gst_query_unref (query);
5076 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
5077 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
5078 gst_query_unref (query);
5083 GST_DEBUG_OBJECT (sinkpad, "activating pull");
5084 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
5088 GST_DEBUG_OBJECT (sinkpad, "activating push");
5089 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
5094 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5095 GstPadMode mode, gboolean active)
5098 GstQTDemux *demux = GST_QTDEMUX (parent);
5101 case GST_PAD_MODE_PUSH:
5102 demux->pullbased = FALSE;
5105 case GST_PAD_MODE_PULL:
5107 demux->pullbased = TRUE;
5108 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
5111 res = gst_pad_stop_task (sinkpad);
5123 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
5125 return g_malloc (items * size);
5129 qtdemux_zfree (void *opaque, void *addr)
5135 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
5141 z = g_new0 (z_stream, 1);
5142 z->zalloc = qtdemux_zalloc;
5143 z->zfree = qtdemux_zfree;
5146 z->next_in = z_buffer;
5147 z->avail_in = z_length;
5149 buffer = (guint8 *) g_malloc (length);
5150 ret = inflateInit (z);
5151 while (z->avail_in > 0) {
5152 if (z->avail_out == 0) {
5154 buffer = (guint8 *) g_realloc (buffer, length);
5155 z->next_out = buffer + z->total_out;
5156 z->avail_out = 1024;
5158 ret = inflate (z, Z_SYNC_FLUSH);
5162 if (ret != Z_STREAM_END) {
5163 g_warning ("inflate() returned %d", ret);
5169 #endif /* HAVE_ZLIB */
5172 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
5176 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
5178 /* counts as header data */
5179 qtdemux->header_size += length;
5181 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
5182 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
5184 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
5190 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
5191 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
5192 if (dcom == NULL || cmvd == NULL)
5193 goto invalid_compression;
5195 method = QT_FOURCC ((guint8 *) dcom->data + 8);
5198 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
5199 guint uncompressed_length;
5200 guint compressed_length;
5203 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
5204 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
5205 GST_LOG ("length = %u", uncompressed_length);
5208 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
5209 compressed_length, uncompressed_length);
5211 qtdemux->moov_node_compressed = qtdemux->moov_node;
5212 qtdemux->moov_node = g_node_new (buf);
5214 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
5215 uncompressed_length);
5218 #endif /* HAVE_ZLIB */
5220 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
5221 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
5228 invalid_compression:
5230 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
5236 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
5239 while (G_UNLIKELY (buf < end)) {
5243 if (G_UNLIKELY (buf + 4 > end)) {
5244 GST_LOG_OBJECT (qtdemux, "buffer overrun");
5247 len = QT_UINT32 (buf);
5248 if (G_UNLIKELY (len == 0)) {
5249 GST_LOG_OBJECT (qtdemux, "empty container");
5252 if (G_UNLIKELY (len < 8)) {
5253 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
5256 if (G_UNLIKELY (len > (end - buf))) {
5257 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
5258 (gint) (end - buf));
5262 child = g_node_new ((guint8 *) buf);
5263 g_node_append (node, child);
5264 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
5265 qtdemux_parse_node (qtdemux, child, buf, len);
5273 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
5276 int len = QT_UINT32 (xdxt->data);
5277 guint8 *buf = xdxt->data;
5278 guint8 *end = buf + len;
5281 /* skip size and type */
5289 size = QT_UINT32 (buf);
5290 type = QT_FOURCC (buf + 4);
5292 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
5294 if (buf + size > end || size <= 0)
5300 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
5301 GST_FOURCC_ARGS (type));
5305 buffer = gst_buffer_new_and_alloc (size);
5306 gst_buffer_fill (buffer, 0, buf, size);
5307 stream->buffers = g_slist_append (stream->buffers, buffer);
5308 GST_LOG_OBJECT (qtdemux, "parsing theora header");
5311 buffer = gst_buffer_new_and_alloc (size);
5312 gst_buffer_fill (buffer, 0, buf, size);
5313 stream->buffers = g_slist_append (stream->buffers, buffer);
5314 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
5317 buffer = gst_buffer_new_and_alloc (size);
5318 gst_buffer_fill (buffer, 0, buf, size);
5319 stream->buffers = g_slist_append (stream->buffers, buffer);
5320 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
5323 GST_WARNING_OBJECT (qtdemux,
5324 "unknown theora cookie %" GST_FOURCC_FORMAT,
5325 GST_FOURCC_ARGS (type));
5334 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
5338 guint32 node_length = 0;
5339 const QtNodeType *type;
5342 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
5344 if (G_UNLIKELY (length < 8))
5345 goto not_enough_data;
5347 node_length = QT_UINT32 (buffer);
5348 fourcc = QT_FOURCC (buffer + 4);
5350 /* ignore empty nodes */
5351 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
5354 type = qtdemux_type_get (fourcc);
5356 end = buffer + length;
5358 GST_LOG_OBJECT (qtdemux,
5359 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
5360 GST_FOURCC_ARGS (fourcc), node_length, type->name);
5362 if (node_length > length)
5363 goto broken_atom_size;
5365 if (type->flags & QT_FLAG_CONTAINER) {
5366 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
5371 if (node_length < 20) {
5372 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
5375 GST_DEBUG_OBJECT (qtdemux,
5376 "parsing stsd (sample table, sample description) atom");
5377 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
5378 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5388 /* also read alac (or whatever) in stead of mp4a in the following,
5389 * since a similar layout is used in other cases as well */
5390 if (fourcc == FOURCC_mp4a)
5395 /* There are two things we might encounter here: a true mp4a atom, and
5396 an mp4a entry in an stsd atom. The latter is what we're interested
5397 in, and it looks like an atom, but isn't really one. The true mp4a
5398 atom is short, so we detect it based on length here. */
5399 if (length < min_size) {
5400 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
5401 GST_FOURCC_ARGS (fourcc));
5405 /* 'version' here is the sound sample description version. Types 0 and
5406 1 are documented in the QTFF reference, but type 2 is not: it's
5407 described in Apple header files instead (struct SoundDescriptionV2
5409 version = QT_UINT16 (buffer + 16);
5411 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
5412 GST_FOURCC_ARGS (fourcc), version);
5414 /* parse any esds descriptors */
5426 GST_WARNING_OBJECT (qtdemux,
5427 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
5428 GST_FOURCC_ARGS (fourcc), version);
5433 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5450 /* codec_data is contained inside these atoms, which all have
5451 * the same format. */
5453 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
5454 GST_FOURCC_ARGS (fourcc));
5455 version = QT_UINT32 (buffer + 16);
5456 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
5457 if (1 || version == 0x00000000) {
5458 buf = buffer + 0x32;
5460 /* FIXME Quicktime uses PASCAL string while
5461 * the iso format uses C strings. Check the file
5462 * type before attempting to parse the string here. */
5463 tlen = QT_UINT8 (buf);
5464 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
5466 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
5467 /* the string has a reserved space of 32 bytes so skip
5468 * the remaining 31 */
5470 buf += 4; /* and 4 bytes reserved */
5472 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
5474 qtdemux_parse_container (qtdemux, node, buf, end);
5480 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
5481 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5486 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
5487 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5492 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
5493 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5498 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
5499 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5504 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
5505 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5510 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
5511 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5516 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
5521 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
5522 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
5527 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
5528 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
5529 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5537 version = QT_UINT32 (buffer + 12);
5538 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
5545 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
5550 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5555 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
5560 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
5564 if (!strcmp (type->name, "unknown"))
5565 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
5569 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
5570 GST_FOURCC_ARGS (fourcc));
5576 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5577 (_("This file is corrupt and cannot be played.")),
5578 ("Not enough data for an atom header, got only %u bytes", length));
5583 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5584 (_("This file is corrupt and cannot be played.")),
5585 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
5586 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
5593 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
5597 guint32 child_fourcc;
5599 for (child = g_node_first_child (node); child;
5600 child = g_node_next_sibling (child)) {
5601 buffer = (guint8 *) child->data;
5603 child_fourcc = QT_FOURCC (buffer + 4);
5605 if (G_UNLIKELY (child_fourcc == fourcc)) {
5613 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
5614 GstByteReader * parser)
5618 guint32 child_fourcc, child_len;
5620 for (child = g_node_first_child (node); child;
5621 child = g_node_next_sibling (child)) {
5622 buffer = (guint8 *) child->data;
5624 child_len = QT_UINT32 (buffer);
5625 child_fourcc = QT_FOURCC (buffer + 4);
5627 if (G_UNLIKELY (child_fourcc == fourcc)) {
5628 if (G_UNLIKELY (child_len < (4 + 4)))
5630 /* FIXME: must verify if atom length < parent atom length */
5631 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
5639 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
5640 GstByteReader * parser)
5644 guint32 child_fourcc, child_len;
5646 for (child = g_node_next_sibling (node); child;
5647 child = g_node_next_sibling (child)) {
5648 buffer = (guint8 *) child->data;
5650 child_fourcc = QT_FOURCC (buffer + 4);
5652 if (child_fourcc == fourcc) {
5654 child_len = QT_UINT32 (buffer);
5655 if (G_UNLIKELY (child_len < (4 + 4)))
5657 /* FIXME: must verify if atom length < parent atom length */
5658 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
5667 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
5669 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
5673 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
5675 /* FIXME: This can only reliably work if demuxers have a
5676 * separate streaming thread per srcpad. This should be
5677 * done in a demuxer base class, which integrates parts
5680 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
5685 query = gst_query_new_allocation (stream->caps, FALSE);
5687 if (!gst_pad_peer_query (stream->pad, query)) {
5688 /* not a problem, just debug a little */
5689 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
5692 if (stream->allocator)
5693 gst_object_unref (stream->allocator);
5695 if (gst_query_get_n_allocation_params (query) > 0) {
5696 /* try the allocator */
5697 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
5699 stream->use_allocator = TRUE;
5701 stream->allocator = NULL;
5702 gst_allocation_params_init (&stream->params);
5703 stream->use_allocator = FALSE;
5705 gst_query_unref (query);
5710 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
5712 if (stream->subtype == FOURCC_vide) {
5713 /* fps is calculated base on the duration of the first frames since
5714 * qt does not have a fixed framerate. */
5715 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
5720 /* we might need to scale the timescale to get precise framerate */
5721 const int required_scale = rint (log (10000) / 2.303); /* divide to get log10 */
5722 int current_scale = rint (log (stream->timescale) / 2.303);
5723 int factor = pow (10.0, MAX (0, required_scale - current_scale));
5725 stream->fps_n = stream->timescale * factor;
5727 if (stream->duration == 0 || stream->n_samples == 0)
5728 stream->fps_d = factor;
5731 gst_util_uint64_scale_int_round (stream->duration, factor,
5736 stream->caps = gst_caps_make_writable (stream->caps);
5738 gst_caps_set_simple (stream->caps,
5739 "width", G_TYPE_INT, stream->width,
5740 "height", G_TYPE_INT, stream->height,
5741 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5743 /* calculate pixel-aspect-ratio using display width and height */
5744 GST_DEBUG_OBJECT (qtdemux,
5745 "video size %dx%d, target display size %dx%d", stream->width,
5746 stream->height, stream->display_width, stream->display_height);
5748 if (stream->display_width > 0 && stream->display_height > 0 &&
5749 stream->width > 0 && stream->height > 0) {
5752 /* calculate the pixel aspect ratio using the display and pixel w/h */
5753 n = stream->display_width * stream->height;
5754 d = stream->display_height * stream->width;
5757 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5758 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5759 GST_TYPE_FRACTION, n, d, NULL);
5762 /* qt file might have pasp atom */
5763 if (stream->par_w > 0 && stream->par_h > 0) {
5764 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5765 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5766 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5769 } else if (stream->subtype == FOURCC_soun) {
5771 stream->caps = gst_caps_make_writable (stream->caps);
5772 if (stream->rate > 0)
5773 gst_caps_set_simple (stream->caps,
5774 "rate", G_TYPE_INT, (int) stream->rate, NULL);
5775 if (stream->n_channels > 0)
5776 gst_caps_set_simple (stream->caps,
5777 "channels", G_TYPE_INT, stream->n_channels, NULL);
5778 if (stream->n_channels > 2) {
5779 /* FIXME: Need to parse the 'chan' atom to get channel layouts
5780 * correctly; this is just the minimum we can do - assume
5781 * we don't actually have any channel positions. */
5782 gst_caps_set_simple (stream->caps,
5783 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
5789 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5790 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5791 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5792 gst_pad_set_active (stream->pad, TRUE);
5794 gst_pad_use_fixed_caps (stream->pad);
5796 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5797 if (stream->new_stream) {
5800 GstStreamFlags stream_flags;
5803 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
5806 if (gst_event_parse_group_id (event, &qtdemux->group_id))
5807 qtdemux->have_group_id = TRUE;
5809 qtdemux->have_group_id = FALSE;
5810 gst_event_unref (event);
5811 } else if (!qtdemux->have_group_id) {
5812 qtdemux->have_group_id = TRUE;
5813 qtdemux->group_id = gst_util_group_id_next ();
5816 stream->new_stream = FALSE;
5818 gst_pad_create_stream_id_printf (stream->pad,
5819 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
5820 event = gst_event_new_stream_start (stream_id);
5821 if (qtdemux->have_group_id)
5822 gst_event_set_group_id (event, qtdemux->group_id);
5823 stream_flags = GST_STREAM_FLAG_NONE;
5824 if (stream->disabled)
5825 stream_flags |= GST_STREAM_FLAG_UNSELECT;
5827 stream_flags |= GST_STREAM_FLAG_SPARSE;
5828 gst_event_set_stream_flags (event, stream_flags);
5829 gst_pad_push_event (stream->pad, event);
5832 gst_pad_set_caps (stream->pad, stream->caps);
5833 stream->new_caps = FALSE;
5839 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
5840 QtDemuxStream * stream, GstTagList * list)
5842 /* consistent default for push based mode */
5843 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
5845 if (stream->subtype == FOURCC_vide) {
5846 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5849 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5852 gst_qtdemux_configure_stream (qtdemux, stream);
5853 qtdemux->n_video_streams++;
5854 } else if (stream->subtype == FOURCC_soun) {
5855 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
5858 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5860 gst_qtdemux_configure_stream (qtdemux, stream);
5861 qtdemux->n_audio_streams++;
5862 } else if (stream->subtype == FOURCC_strm) {
5863 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5864 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
5865 || stream->subtype == FOURCC_sbtl) {
5866 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
5869 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5871 gst_qtdemux_configure_stream (qtdemux, stream);
5872 qtdemux->n_sub_streams++;
5873 } else if (stream->caps) {
5874 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5877 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5879 gst_qtdemux_configure_stream (qtdemux, stream);
5880 qtdemux->n_video_streams++;
5882 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5887 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5888 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5889 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5891 if (stream->pending_tags)
5892 gst_tag_list_unref (stream->pending_tags);
5893 stream->pending_tags = list;
5894 /* global tags go on each pad anyway */
5895 stream->send_global_tags = TRUE;
5901 /* find next atom with @fourcc starting at @offset */
5902 static GstFlowReturn
5903 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5904 guint64 * length, guint32 fourcc)
5910 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5911 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5917 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5918 if (G_UNLIKELY (ret != GST_FLOW_OK))
5920 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
5923 gst_buffer_unref (buf);
5926 gst_buffer_map (buf, &map, GST_MAP_READ);
5927 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
5928 gst_buffer_unmap (buf, &map);
5929 gst_buffer_unref (buf);
5931 if (G_UNLIKELY (*length == 0)) {
5932 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5933 ret = GST_FLOW_ERROR;
5937 if (lfourcc == fourcc) {
5938 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5942 GST_LOG_OBJECT (qtdemux,
5943 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5944 GST_FOURCC_ARGS (fourcc), *offset);
5953 /* might simply have had last one */
5954 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5959 /* should only do something in pull mode */
5960 /* call with OBJECT lock */
5961 static GstFlowReturn
5962 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5964 guint64 length, offset;
5965 GstBuffer *buf = NULL;
5966 GstFlowReturn ret = GST_FLOW_OK;
5967 GstFlowReturn res = GST_FLOW_OK;
5970 offset = qtdemux->moof_offset;
5971 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5974 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5975 return GST_FLOW_EOS;
5978 /* best not do pull etc with lock held */
5979 GST_OBJECT_UNLOCK (qtdemux);
5981 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5982 if (ret != GST_FLOW_OK)
5985 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5986 if (G_UNLIKELY (ret != GST_FLOW_OK))
5988 gst_buffer_map (buf, &map, GST_MAP_READ);
5989 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
5990 gst_buffer_unmap (buf, &map);
5991 gst_buffer_unref (buf);
5996 gst_buffer_unmap (buf, &map);
5997 gst_buffer_unref (buf);
6001 /* look for next moof */
6002 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6003 if (G_UNLIKELY (ret != GST_FLOW_OK))
6007 GST_OBJECT_LOCK (qtdemux);
6009 qtdemux->moof_offset = offset;
6015 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
6017 res = GST_FLOW_ERROR;
6022 /* maybe upstream temporarily flushing */
6023 if (ret != GST_FLOW_FLUSHING) {
6024 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6027 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
6028 /* resume at current position next time */
6035 /* initialise bytereaders for stbl sub-atoms */
6037 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
6039 stream->stbl_index = -1; /* no samples have yet been parsed */
6040 stream->sample_index = -1;
6042 /* time-to-sample atom */
6043 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
6046 /* copy atom data into a new buffer for later use */
6047 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
6049 /* skip version + flags */
6050 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
6051 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
6053 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
6055 /* make sure there's enough data */
6056 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
6057 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
6058 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
6059 stream->n_sample_times);
6060 if (!stream->n_sample_times)
6064 /* sync sample atom */
6065 stream->stps_present = FALSE;
6066 if ((stream->stss_present =
6067 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
6068 &stream->stss) ? TRUE : FALSE) == TRUE) {
6069 /* copy atom data into a new buffer for later use */
6070 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
6072 /* skip version + flags */
6073 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
6074 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
6077 if (stream->n_sample_syncs) {
6078 /* make sure there's enough data */
6079 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
6083 /* partial sync sample atom */
6084 if ((stream->stps_present =
6085 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
6086 &stream->stps) ? TRUE : FALSE) == TRUE) {
6087 /* copy atom data into a new buffer for later use */
6088 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
6090 /* skip version + flags */
6091 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
6092 !gst_byte_reader_get_uint32_be (&stream->stps,
6093 &stream->n_sample_partial_syncs))
6096 /* if there are no entries, the stss table contains the real
6098 if (stream->n_sample_partial_syncs) {
6099 /* make sure there's enough data */
6100 if (!qt_atom_parser_has_chunks (&stream->stps,
6101 stream->n_sample_partial_syncs, 4))
6108 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
6111 /* copy atom data into a new buffer for later use */
6112 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
6114 /* skip version + flags */
6115 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
6116 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
6119 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
6122 if (!stream->n_samples)
6125 /* sample-to-chunk atom */
6126 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
6129 /* copy atom data into a new buffer for later use */
6130 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
6132 /* skip version + flags */
6133 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
6134 !gst_byte_reader_get_uint32_be (&stream->stsc,
6135 &stream->n_samples_per_chunk))
6138 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
6139 stream->n_samples_per_chunk);
6141 /* make sure there's enough data */
6142 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
6148 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
6149 stream->co_size = sizeof (guint32);
6150 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
6152 stream->co_size = sizeof (guint64);
6156 /* copy atom data into a new buffer for later use */
6157 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
6159 /* skip version + flags */
6160 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
6163 /* chunks_are_samples == TRUE means treat chunks as samples */
6164 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
6165 if (stream->chunks_are_samples) {
6166 /* treat chunks as samples */
6167 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
6170 /* skip number of entries */
6171 if (!gst_byte_reader_skip (&stream->stco, 4))
6174 /* make sure there are enough data in the stsz atom */
6175 if (!stream->sample_size) {
6176 /* different sizes for each sample */
6177 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
6182 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
6183 stream->n_samples, (guint) sizeof (QtDemuxSample),
6184 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
6186 if (stream->n_samples >=
6187 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
6188 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
6189 "be larger than %uMB (broken file?)", stream->n_samples,
6190 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
6194 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
6195 if (!stream->samples) {
6196 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
6202 /* composition time-to-sample */
6203 if ((stream->ctts_present =
6204 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
6205 &stream->ctts) ? TRUE : FALSE) == TRUE) {
6206 /* copy atom data into a new buffer for later use */
6207 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
6209 /* skip version + flags */
6210 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
6211 || !gst_byte_reader_get_uint32_be (&stream->ctts,
6212 &stream->n_composition_times))
6215 /* make sure there's enough data */
6216 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
6225 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6226 (_("This file is corrupt and cannot be played.")), (NULL));
6231 gst_qtdemux_stbl_free (stream);
6232 if (!qtdemux->fragmented) {
6233 /* not quite good */
6234 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
6237 /* may pick up samples elsewhere */
6243 /* collect samples from the next sample to be parsed up to sample @n for @stream
6244 * by reading the info from @stbl
6246 * This code can be executed from both the streaming thread and the seeking
6247 * thread so it takes the object lock to protect itself
6250 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
6253 QtDemuxSample *samples, *first, *cur, *last;
6254 guint32 n_samples_per_chunk;
6257 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
6258 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
6259 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
6261 n_samples = stream->n_samples;
6264 goto out_of_samples;
6266 GST_OBJECT_LOCK (qtdemux);
6267 if (n <= stream->stbl_index)
6268 goto already_parsed;
6270 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
6272 if (!stream->stsz.data) {
6273 /* so we already parsed and passed all the moov samples;
6274 * onto fragmented ones */
6275 g_assert (qtdemux->fragmented);
6279 /* pointer to the sample table */
6280 samples = stream->samples;
6282 /* starts from -1, moves to the next sample index to parse */
6283 stream->stbl_index++;
6285 /* keep track of the first and last sample to fill */
6286 first = &samples[stream->stbl_index];
6289 if (!stream->chunks_are_samples) {
6290 /* set the sample sizes */
6291 if (stream->sample_size == 0) {
6292 /* different sizes for each sample */
6293 for (cur = first; cur <= last; cur++) {
6294 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
6295 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
6296 (guint) (cur - samples), cur->size);
6299 /* samples have the same size */
6300 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
6301 for (cur = first; cur <= last; cur++)
6302 cur->size = stream->sample_size;
6306 n_samples_per_chunk = stream->n_samples_per_chunk;
6309 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
6312 if (stream->stsc_chunk_index >= stream->last_chunk
6313 || stream->stsc_chunk_index < stream->first_chunk) {
6314 stream->first_chunk =
6315 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6316 stream->samples_per_chunk =
6317 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6318 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
6320 /* chunk numbers are counted from 1 it seems */
6321 if (G_UNLIKELY (stream->first_chunk == 0))
6324 --stream->first_chunk;
6326 /* the last chunk of each entry is calculated by taking the first chunk
6327 * of the next entry; except if there is no next, where we fake it with
6329 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
6330 stream->last_chunk = G_MAXUINT32;
6332 stream->last_chunk =
6333 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
6334 if (G_UNLIKELY (stream->last_chunk == 0))
6337 --stream->last_chunk;
6340 GST_LOG_OBJECT (qtdemux,
6341 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
6342 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
6344 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
6347 if (stream->last_chunk != G_MAXUINT32) {
6348 if (!qt_atom_parser_peek_sub (&stream->stco,
6349 stream->first_chunk * stream->co_size,
6350 (stream->last_chunk - stream->first_chunk) * stream->co_size,
6355 stream->co_chunk = stream->stco;
6356 if (!gst_byte_reader_skip (&stream->co_chunk,
6357 stream->first_chunk * stream->co_size))
6361 stream->stsc_chunk_index = stream->first_chunk;
6364 last_chunk = stream->last_chunk;
6366 if (stream->chunks_are_samples) {
6367 guint64 elst_timestamp;
6369 cur = &samples[stream->stsc_chunk_index];
6370 elst_timestamp = gst_util_uint64_scale (stream->elst_offset,
6371 stream->timescale, GST_SECOND);
6373 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6376 stream->stsc_chunk_index = j;
6381 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
6384 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
6385 "%" G_GUINT64_FORMAT, j, cur->offset);
6387 if (stream->samples_per_frame * stream->bytes_per_frame) {
6389 (stream->samples_per_chunk * stream->n_channels) /
6390 stream->samples_per_frame * stream->bytes_per_frame;
6392 cur->size = stream->samples_per_chunk;
6395 GST_DEBUG_OBJECT (qtdemux,
6396 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
6397 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
6398 GST_SECOND, stream->timescale)), cur->size);
6400 cur->timestamp = stream->stco_sample_index + elst_timestamp;
6401 cur->duration = stream->samples_per_chunk;
6402 cur->keyframe = TRUE;
6405 stream->stco_sample_index += stream->samples_per_chunk;
6407 stream->stsc_chunk_index = j;
6409 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6410 guint32 samples_per_chunk;
6411 guint64 chunk_offset;
6413 if (!stream->stsc_sample_index
6414 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
6415 &stream->chunk_offset))
6418 samples_per_chunk = stream->samples_per_chunk;
6419 chunk_offset = stream->chunk_offset;
6421 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
6422 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
6423 G_GUINT64_FORMAT " and size %d",
6424 (guint) (cur - samples), stream->chunk_offset, cur->size);
6426 cur->offset = chunk_offset;
6427 chunk_offset += cur->size;
6430 if (G_UNLIKELY (cur > last)) {
6432 stream->stsc_sample_index = k + 1;
6433 stream->chunk_offset = chunk_offset;
6434 stream->stsc_chunk_index = j;
6438 stream->stsc_sample_index = 0;
6440 stream->stsc_chunk_index = j;
6442 stream->stsc_index++;
6445 if (stream->chunks_are_samples)
6449 guint32 n_sample_times;
6452 n_sample_times = stream->n_sample_times;
6455 gst_util_uint64_scale (stream->elst_offset, stream->timescale,
6458 for (i = stream->stts_index; i < n_sample_times; i++) {
6459 guint32 stts_samples;
6460 gint32 stts_duration;
6463 if (stream->stts_sample_index >= stream->stts_samples
6464 || !stream->stts_sample_index) {
6466 stream->stts_samples =
6467 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6468 stream->stts_duration =
6469 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6471 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
6472 i, stream->stts_samples, stream->stts_duration);
6474 stream->stts_sample_index = 0;
6477 stts_samples = stream->stts_samples;
6478 stts_duration = stream->stts_duration;
6479 stts_time = stream->stts_time;
6481 for (j = stream->stts_sample_index; j < stts_samples; j++) {
6482 GST_DEBUG_OBJECT (qtdemux,
6483 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
6484 (guint) (cur - samples), j,
6485 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
6486 stream->timescale)));
6488 cur->timestamp = stts_time + elst_offset;
6489 cur->duration = stts_duration;
6491 /* avoid 32-bit wrap-around,
6492 * but still mind possible 'negative' duration */
6493 stts_time += (gint64) stts_duration;
6496 if (G_UNLIKELY (cur > last)) {
6498 stream->stts_time = stts_time;
6499 stream->stts_sample_index = j + 1;
6503 stream->stts_sample_index = 0;
6504 stream->stts_time = stts_time;
6505 stream->stts_index++;
6507 /* fill up empty timestamps with the last timestamp, this can happen when
6508 * the last samples do not decode and so we don't have timestamps for them.
6509 * We however look at the last timestamp to estimate the track length so we
6510 * need something in here. */
6511 for (; cur < last; cur++) {
6512 GST_DEBUG_OBJECT (qtdemux,
6513 "fill sample %d: timestamp %" GST_TIME_FORMAT,
6514 (guint) (cur - samples),
6515 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
6516 stream->timescale)));
6517 cur->timestamp = stream->stts_time + elst_offset;
6523 /* sample sync, can be NULL */
6524 if (stream->stss_present == TRUE) {
6525 guint32 n_sample_syncs;
6527 n_sample_syncs = stream->n_sample_syncs;
6529 if (!n_sample_syncs) {
6530 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
6531 stream->all_keyframe = TRUE;
6533 for (i = stream->stss_index; i < n_sample_syncs; i++) {
6534 /* note that the first sample is index 1, not 0 */
6537 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
6539 if (G_LIKELY (index > 0 && index <= n_samples)) {
6541 samples[index].keyframe = TRUE;
6542 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6543 /* and exit if we have enough samples */
6544 if (G_UNLIKELY (index >= n)) {
6551 stream->stss_index = i;
6554 /* stps marks partial sync frames like open GOP I-Frames */
6555 if (stream->stps_present == TRUE) {
6556 guint32 n_sample_partial_syncs;
6558 n_sample_partial_syncs = stream->n_sample_partial_syncs;
6560 /* if there are no entries, the stss table contains the real
6562 if (n_sample_partial_syncs) {
6563 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
6564 /* note that the first sample is index 1, not 0 */
6567 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
6569 if (G_LIKELY (index > 0 && index <= n_samples)) {
6571 samples[index].keyframe = TRUE;
6572 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6573 /* and exit if we have enough samples */
6574 if (G_UNLIKELY (index >= n)) {
6581 stream->stps_index = i;
6585 /* no stss, all samples are keyframes */
6586 stream->all_keyframe = TRUE;
6587 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
6592 /* composition time to sample */
6593 if (stream->ctts_present == TRUE) {
6594 guint32 n_composition_times;
6596 gint32 ctts_soffset;
6598 /* Fill in the pts_offsets */
6600 n_composition_times = stream->n_composition_times;
6602 for (i = stream->ctts_index; i < n_composition_times; i++) {
6603 if (stream->ctts_sample_index >= stream->ctts_count
6604 || !stream->ctts_sample_index) {
6605 stream->ctts_count =
6606 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
6607 stream->ctts_soffset =
6608 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
6609 stream->ctts_sample_index = 0;
6612 ctts_count = stream->ctts_count;
6613 ctts_soffset = stream->ctts_soffset;
6615 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
6616 cur->pts_offset = ctts_soffset;
6619 if (G_UNLIKELY (cur > last)) {
6621 stream->ctts_sample_index = j + 1;
6625 stream->ctts_sample_index = 0;
6626 stream->ctts_index++;
6630 stream->stbl_index = n;
6631 /* if index has been completely parsed, free data that is no-longer needed */
6632 if (n + 1 == stream->n_samples) {
6633 gst_qtdemux_stbl_free (stream);
6634 GST_DEBUG_OBJECT (qtdemux,
6635 "parsed all available samples; checking for more");
6636 while (n + 1 == stream->n_samples)
6637 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
6640 GST_OBJECT_UNLOCK (qtdemux);
6647 GST_LOG_OBJECT (qtdemux,
6648 "Tried to parse up to sample %u but this sample has already been parsed",
6650 /* if fragmented, there may be more */
6651 if (qtdemux->fragmented && n == stream->stbl_index)
6653 GST_OBJECT_UNLOCK (qtdemux);
6659 GST_LOG_OBJECT (qtdemux,
6660 "Tried to parse up to sample %u but there are only %u samples", n + 1,
6662 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6663 (_("This file is corrupt and cannot be played.")), (NULL));
6668 GST_OBJECT_UNLOCK (qtdemux);
6669 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6670 (_("This file is corrupt and cannot be played.")), (NULL));
6675 /* collect all segment info for @stream.
6678 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
6683 /* parse and prepare segment info from the edit list */
6684 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
6685 stream->n_segments = 0;
6686 stream->segments = NULL;
6687 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
6691 guint64 time, stime;
6694 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
6695 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
6698 buffer = elst->data;
6700 n_segments = QT_UINT32 (buffer + 12);
6702 /* we might allocate a bit too much, at least allocate 1 segment */
6703 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
6705 /* segments always start from 0 */
6709 for (i = 0; i < n_segments; i++) {
6712 QtDemuxSegment *segment;
6715 media_time = QT_UINT32 (buffer + 20 + i * 12);
6716 duration = QT_UINT32 (buffer + 16 + i * 12);
6718 /* -1 media time is an empty segment, just ignore it */
6719 if (media_time == G_MAXUINT32) {
6721 /* first empty segment specifies sample offset (if movie timescale) */
6722 stream->elst_offset =
6723 gst_util_uint64_scale (duration, GST_SECOND, qtdemux->timescale);
6728 segment = &stream->segments[count++];
6730 /* time and duration expressed in global timescale */
6731 segment->time = stime;
6732 /* add non scaled values so we don't cause roundoff errors */
6734 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
6735 segment->stop_time = stime;
6736 segment->duration = stime - segment->time;
6737 /* media_time expressed in stream timescale */
6738 segment->media_start =
6739 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
6740 segment->media_stop = segment->media_start + segment->duration;
6741 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
6743 if (rate_int <= 1) {
6744 /* 0 is not allowed, some programs write 1 instead of the floating point
6746 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
6750 segment->rate = rate_int / 65536.0;
6753 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
6754 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
6755 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
6756 GST_TIME_ARGS (segment->duration),
6757 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
6759 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
6760 stream->n_segments = count;
6764 /* push based does not handle segments, so act accordingly here,
6765 * and warn if applicable */
6766 if (!qtdemux->pullbased) {
6767 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
6768 /* remove and use default one below, we stream like it anyway */
6769 g_free (stream->segments);
6770 stream->segments = NULL;
6771 stream->n_segments = 0;
6774 /* no segments, create one to play the complete trak */
6775 if (stream->n_segments == 0) {
6776 GstClockTime stream_duration =
6777 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6779 if (stream->segments == NULL)
6780 stream->segments = g_new (QtDemuxSegment, 1);
6782 /* represent unknown our way */
6783 if (stream_duration == 0)
6784 stream_duration = -1;
6786 stream->segments[0].time = 0;
6787 stream->segments[0].stop_time = stream_duration;
6788 stream->segments[0].duration = stream_duration;
6789 stream->segments[0].media_start = 0;
6790 stream->segments[0].media_stop = stream_duration;
6791 stream->segments[0].rate = 1.0;
6793 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6794 GST_TIME_ARGS (stream_duration));
6795 stream->n_segments = 1;
6797 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6803 * Parses the stsd atom of a svq3 trak looking for
6804 * the SMI and gama atoms.
6807 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6808 guint8 ** gamma, GstBuffer ** seqh)
6810 guint8 *_gamma = NULL;
6811 GstBuffer *_seqh = NULL;
6812 guint8 *stsd_data = stsd->data;
6813 guint32 length = QT_UINT32 (stsd_data);
6817 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6823 version = QT_UINT16 (stsd_data);
6828 while (length > 8) {
6829 guint32 fourcc, size;
6831 size = QT_UINT32 (stsd_data);
6832 fourcc = QT_FOURCC (stsd_data + 4);
6833 data = stsd_data + 8;
6840 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6841 " for gama atom, expected 12", size);
6846 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6848 if (_seqh != NULL) {
6849 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6850 " found, ignoring");
6852 seqh_size = QT_UINT32 (data + 4);
6853 if (seqh_size > 0) {
6854 _seqh = gst_buffer_new_and_alloc (seqh_size);
6855 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
6862 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6863 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6867 if (size <= length) {
6873 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6876 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6877 G_GUINT16_FORMAT, version);
6888 gst_buffer_unref (_seqh);
6893 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6900 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6901 * atom that might contain a 'data' atom with the rtsp uri.
6902 * This case was reported in bug #597497, some info about
6903 * the hndl atom can be found in TN1195
6905 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6906 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6909 guint32 dref_num_entries = 0;
6910 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6911 gst_byte_reader_skip (&dref, 4) &&
6912 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6915 /* search dref entries for hndl atom */
6916 for (i = 0; i < dref_num_entries; i++) {
6917 guint32 size = 0, type;
6918 guint8 string_len = 0;
6919 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6920 qt_atom_parser_get_fourcc (&dref, &type)) {
6921 if (type == FOURCC_hndl) {
6922 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6924 /* skip data reference handle bytes and the
6925 * following pascal string and some extra 4
6926 * bytes I have no idea what are */
6927 if (!gst_byte_reader_skip (&dref, 4) ||
6928 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6929 !gst_byte_reader_skip (&dref, string_len + 4)) {
6930 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6934 /* iterate over the atoms to find the data atom */
6935 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6939 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6940 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6941 if (atom_type == FOURCC_data) {
6942 const guint8 *uri_aux = NULL;
6944 /* found the data atom that might contain the rtsp uri */
6945 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6946 "hndl atom, interpreting it as an URI");
6947 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6949 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6950 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6952 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6953 "didn't contain a rtsp address");
6955 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6960 /* skipping to the next entry */
6961 if (!gst_byte_reader_skip (&dref, atom_size - 8))
6964 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6971 /* skip to the next entry */
6972 if (!gst_byte_reader_skip (&dref, size - 8))
6975 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6978 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6985 less_than (gconstpointer a, gconstpointer b)
6987 const guint32 *av = a, *bv = b;
6992 #define AMR_NB_ALL_MODES 0x81ff
6993 #define AMR_WB_ALL_MODES 0x83ff
6995 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
6997 /* The 'damr' atom is of the form:
6999 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
7000 * 32 b 8 b 16 b 8 b 8 b
7002 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
7003 * represents the highest mode used in the stream (and thus the maximum
7004 * bitrate), with a couple of special cases as seen below.
7007 /* Map of frame type ID -> bitrate */
7008 static const guint nb_bitrates[] = {
7009 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
7011 static const guint wb_bitrates[] = {
7012 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
7018 gst_buffer_map (buf, &map, GST_MAP_READ);
7020 if (map.size != 0x11) {
7021 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
7025 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
7026 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
7027 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
7031 mode_set = QT_UINT16 (map.data + 13);
7033 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
7034 max_mode = 7 + (wb ? 1 : 0);
7036 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
7037 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
7039 if (max_mode == -1) {
7040 GST_DEBUG ("No mode indication was found (mode set) = %x",
7045 gst_buffer_unmap (buf, &map);
7046 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
7049 gst_buffer_unmap (buf, &map);
7054 * With each track we associate a new QtDemuxStream that contains all the info
7056 * traks that do not decode to something (like strm traks) will not have a pad.
7059 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
7076 QtDemuxStream *stream = NULL;
7077 GstTagList *list = NULL;
7078 gchar *codec = NULL;
7079 const guint8 *stsd_data;
7080 guint16 lang_code; /* quicktime lang code or packed iso code */
7082 guint32 tkhd_flags = 0;
7083 guint8 tkhd_version = 0;
7085 guint value_size, stsd_len, len;
7088 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
7090 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
7091 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
7092 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
7095 /* pick between 64 or 32 bits */
7096 value_size = tkhd_version == 1 ? 8 : 4;
7097 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
7098 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
7101 if (!qtdemux->got_moov) {
7102 if (qtdemux_find_stream (qtdemux, track_id))
7103 goto existing_stream;
7104 stream = _create_stream ();
7105 stream->track_id = track_id;
7107 stream = qtdemux_find_stream (qtdemux, track_id);
7109 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
7114 if ((tkhd_flags & 1) == 0)
7115 stream->disabled = TRUE;
7117 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
7118 tkhd_version, tkhd_flags, stream->track_id);
7120 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
7123 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
7124 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
7125 if (qtdemux->major_brand != FOURCC_mjp2 ||
7126 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
7130 len = QT_UINT32 ((guint8 *) mdhd->data);
7131 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
7132 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
7133 if (version == 0x01000000) {
7136 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
7137 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
7138 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
7142 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
7143 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
7144 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
7147 if (lang_code < 0x800) {
7148 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
7150 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
7151 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
7152 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
7153 stream->lang_id[3] = 0;
7156 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
7158 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
7160 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
7161 lang_code, stream->lang_id);
7163 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
7166 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
7167 /* chapters track reference */
7168 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
7170 gsize length = GST_READ_UINT32_BE (chap->data);
7171 if (qtdemux->chapters_track_id)
7172 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
7175 qtdemux->chapters_track_id =
7176 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
7181 /* fragmented files may have bogus duration in moov */
7182 if (!qtdemux->fragmented &&
7183 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
7184 guint64 tdur1, tdur2;
7186 /* don't overflow */
7187 tdur1 = stream->timescale * (guint64) qtdemux->duration;
7188 tdur2 = qtdemux->timescale * (guint64) stream->duration;
7191 * some of those trailers, nowadays, have prologue images that are
7192 * themselves vide tracks as well. I haven't really found a way to
7193 * identify those yet, except for just looking at their duration. */
7194 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
7195 GST_WARNING_OBJECT (qtdemux,
7196 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
7197 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
7198 "found, assuming preview image or something; skipping track",
7199 stream->duration, stream->timescale, qtdemux->duration,
7200 qtdemux->timescale);
7206 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
7209 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
7210 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
7212 len = QT_UINT32 ((guint8 *) hdlr->data);
7214 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
7215 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
7216 GST_FOURCC_ARGS (stream->subtype));
7218 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
7221 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
7225 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
7227 stsd_data = (const guint8 *) stsd->data;
7229 /* stsd should at least have one entry */
7230 stsd_len = QT_UINT32 (stsd_data);
7231 if (stsd_len < 24) {
7232 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
7233 if (stream->subtype == FOURCC_vivo) {
7241 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
7243 /* and that entry should fit within stsd */
7244 len = QT_UINT32 (stsd_data + 16);
7245 if (len > stsd_len + 16)
7248 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
7249 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
7250 GST_FOURCC_ARGS (stream->fourcc));
7251 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
7253 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
7254 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
7255 goto error_encrypted;
7257 if (stream->subtype == FOURCC_vide) {
7258 guint32 w = 0, h = 0;
7260 gint depth, palette_size, palette_count;
7261 guint32 *palette_data = NULL;
7263 stream->sampled = TRUE;
7265 /* version 1 uses some 64-bit ints */
7266 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
7267 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
7268 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
7271 stream->display_width = w >> 16;
7272 stream->display_height = h >> 16;
7278 stream->width = QT_UINT16 (stsd_data + offset + 32);
7279 stream->height = QT_UINT16 (stsd_data + offset + 34);
7280 stream->fps_n = 0; /* this is filled in later */
7281 stream->fps_d = 0; /* this is filled in later */
7282 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
7283 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
7285 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
7286 stream->width, stream->height, stream->bits_per_sample,
7287 stream->color_table_id);
7289 depth = stream->bits_per_sample;
7291 /* more than 32 bits means grayscale */
7292 gray = (depth > 32);
7293 /* low 32 bits specify the depth */
7296 /* different number of palette entries is determined by depth. */
7298 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
7299 palette_count = (1 << depth);
7300 palette_size = palette_count * 4;
7302 if (stream->color_table_id) {
7303 switch (palette_count) {
7307 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
7310 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
7314 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
7316 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
7320 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
7322 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
7325 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7326 (_("The video in this file might not play correctly.")),
7327 ("unsupported palette depth %d", depth));
7331 gint i, j, start, end;
7337 start = QT_UINT32 (stsd_data + offset + 86);
7338 palette_count = QT_UINT16 (stsd_data + offset + 90);
7339 end = QT_UINT16 (stsd_data + offset + 92);
7341 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
7342 start, end, palette_count);
7349 if (len < 94 + (end - start) * 8)
7352 /* palette is always the same size */
7353 palette_data = g_malloc0 (256 * 4);
7354 palette_size = 256 * 4;
7356 for (j = 0, i = start; i <= end; j++, i++) {
7359 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
7360 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
7361 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
7362 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
7364 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
7365 (g & 0xff00) | (b >> 8);
7370 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7372 list = gst_tag_list_new_empty ();
7373 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7374 GST_TAG_VIDEO_CODEC, codec, NULL);
7383 if (stream->rgb8_palette)
7384 gst_memory_unref (stream->rgb8_palette);
7385 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
7386 palette_data, palette_size, 0, palette_size, palette_data, g_free);
7388 s = gst_caps_get_structure (stream->caps, 0);
7390 /* non-raw video has a palette_data property. raw video has the palette as
7391 * an extra plane that we append to the output buffers before we push
7393 if (!gst_structure_has_name (s, "video/x-raw")) {
7396 palette = gst_buffer_new ();
7397 gst_buffer_append_memory (palette, stream->rgb8_palette);
7398 stream->rgb8_palette = NULL;
7400 gst_caps_set_simple (stream->caps, "palette_data",
7401 GST_TYPE_BUFFER, palette, NULL);
7402 gst_buffer_unref (palette);
7404 } else if (palette_count != 0) {
7405 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
7406 (NULL), ("Unsupported palette depth %d", depth));
7409 GST_LOG_OBJECT (qtdemux, "frame count: %u",
7410 QT_UINT16 (stsd_data + offset + 48));
7414 /* pick 'the' stsd child */
7415 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
7417 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
7418 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
7422 const guint8 *pasp_data = (const guint8 *) pasp->data;
7424 stream->par_w = QT_UINT32 (pasp_data + 8);
7425 stream->par_h = QT_UINT32 (pasp_data + 12);
7432 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7439 gint len = QT_UINT32 (stsd_data) - 0x66;
7440 const guint8 *avc_data = stsd_data + 0x66;
7443 while (len >= 0x8) {
7446 if (QT_UINT32 (avc_data) <= len)
7447 size = QT_UINT32 (avc_data) - 0x8;
7452 /* No real data, so break out */
7455 switch (QT_FOURCC (avc_data + 0x4)) {
7458 /* parse, if found */
7461 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
7463 /* First 4 bytes are the length of the atom, the next 4 bytes
7464 * are the fourcc, the next 1 byte is the version, and the
7465 * subsequent bytes are profile_tier_level structure like data. */
7466 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
7467 avc_data + 8 + 1, size - 1);
7468 buf = gst_buffer_new_and_alloc (size);
7469 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
7470 gst_caps_set_simple (stream->caps,
7471 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7472 gst_buffer_unref (buf);
7480 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
7482 /* First 4 bytes are the length of the atom, the next 4 bytes
7483 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
7484 * next 1 byte is the version, and the
7485 * subsequent bytes are sequence parameter set like data. */
7487 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
7489 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
7490 avc_data + 8 + 40 + 1, size - 1);
7492 buf = gst_buffer_new_and_alloc (size);
7493 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
7494 gst_caps_set_simple (stream->caps,
7495 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7496 gst_buffer_unref (buf);
7502 guint avg_bitrate, max_bitrate;
7504 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
7508 max_bitrate = QT_UINT32 (avc_data + 0xc);
7509 avg_bitrate = QT_UINT32 (avc_data + 0x10);
7511 if (!max_bitrate && !avg_bitrate)
7514 /* Some muxers seem to swap the average and maximum bitrates
7515 * (I'm looking at you, YouTube), so we swap for sanity. */
7516 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
7517 guint temp = avg_bitrate;
7519 avg_bitrate = max_bitrate;
7524 list = gst_tag_list_new_empty ();
7526 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
7527 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7528 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
7530 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
7531 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7532 GST_TAG_BITRATE, avg_bitrate, NULL);
7543 avc_data += size + 8;
7552 gint len = QT_UINT32 (stsd_data) - 0x66;
7553 const guint8 *hevc_data = stsd_data + 0x66;
7556 while (len >= 0x8) {
7559 if (QT_UINT32 (hevc_data) <= len)
7560 size = QT_UINT32 (hevc_data) - 0x8;
7565 /* No real data, so break out */
7568 switch (QT_FOURCC (hevc_data + 0x4)) {
7571 /* parse, if found */
7574 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
7576 /* First 4 bytes are the length of the atom, the next 4 bytes
7577 * are the fourcc, the next 1 byte is the version, and the
7578 * subsequent bytes are sequence parameter set like data. */
7579 gst_codec_utils_h265_caps_set_level_tier_and_profile
7580 (stream->caps, hevc_data + 8 + 1, size - 1);
7582 buf = gst_buffer_new_and_alloc (size);
7583 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
7584 gst_caps_set_simple (stream->caps,
7585 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7586 gst_buffer_unref (buf);
7593 hevc_data += size + 8;
7604 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
7605 GST_FOURCC_ARGS (fourcc));
7607 /* codec data might be in glbl extension atom */
7609 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
7615 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
7617 len = QT_UINT32 (data);
7620 buf = gst_buffer_new_and_alloc (len);
7621 gst_buffer_fill (buf, 0, data + 8, len);
7622 gst_caps_set_simple (stream->caps,
7623 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7624 gst_buffer_unref (buf);
7631 /* see annex I of the jpeg2000 spec */
7632 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
7634 const gchar *colorspace = NULL;
7636 guint32 ncomp_map = 0;
7637 gint32 *comp_map = NULL;
7638 guint32 nchan_def = 0;
7639 gint32 *chan_def = NULL;
7641 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
7642 /* some required atoms */
7643 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
7646 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
7650 /* number of components; redundant with info in codestream, but useful
7652 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
7653 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
7655 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
7657 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
7660 GST_DEBUG_OBJECT (qtdemux, "found colr");
7661 /* extract colour space info */
7662 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
7663 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
7665 colorspace = "sRGB";
7668 colorspace = "GRAY";
7671 colorspace = "sYUV";
7679 /* colr is required, and only values 16, 17, and 18 are specified,
7680 so error if we have no colorspace */
7683 /* extract component mapping */
7684 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
7686 guint32 cmap_len = 0;
7688 cmap_len = QT_UINT32 (cmap->data);
7689 if (cmap_len >= 8) {
7690 /* normal box, subtract off header */
7692 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
7693 if (cmap_len % 4 == 0) {
7694 ncomp_map = (cmap_len / 4);
7695 comp_map = g_new0 (gint32, ncomp_map);
7696 for (i = 0; i < ncomp_map; i++) {
7699 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
7700 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
7701 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
7702 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
7707 /* extract channel definitions */
7708 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
7710 guint32 cdef_len = 0;
7712 cdef_len = QT_UINT32 (cdef->data);
7713 if (cdef_len >= 10) {
7714 /* normal box, subtract off header and len */
7716 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
7717 if (cdef_len % 6 == 0) {
7718 nchan_def = (cdef_len / 6);
7719 chan_def = g_new0 (gint32, nchan_def);
7720 for (i = 0; i < nchan_def; i++)
7722 for (i = 0; i < nchan_def; i++) {
7723 guint16 cn, typ, asoc;
7724 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
7725 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
7726 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
7727 if (cn < nchan_def) {
7730 chan_def[cn] = asoc;
7733 chan_def[cn] = 0; /* alpha */
7736 chan_def[cn] = -typ;
7744 gst_caps_set_simple (stream->caps,
7745 "num-components", G_TYPE_INT, ncomp, NULL);
7746 gst_caps_set_simple (stream->caps,
7747 "colorspace", G_TYPE_STRING, colorspace, NULL);
7750 GValue arr = { 0, };
7751 GValue elt = { 0, };
7753 g_value_init (&arr, GST_TYPE_ARRAY);
7754 g_value_init (&elt, G_TYPE_INT);
7755 for (i = 0; i < ncomp_map; i++) {
7756 g_value_set_int (&elt, comp_map[i]);
7757 gst_value_array_append_value (&arr, &elt);
7759 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
7760 "component-map", &arr);
7761 g_value_unset (&elt);
7762 g_value_unset (&arr);
7767 GValue arr = { 0, };
7768 GValue elt = { 0, };
7770 g_value_init (&arr, GST_TYPE_ARRAY);
7771 g_value_init (&elt, G_TYPE_INT);
7772 for (i = 0; i < nchan_def; i++) {
7773 g_value_set_int (&elt, chan_def[i]);
7774 gst_value_array_append_value (&arr, &elt);
7776 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
7777 "channel-definitions", &arr);
7778 g_value_unset (&elt);
7779 g_value_unset (&arr);
7783 /* some optional atoms */
7784 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
7785 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
7787 /* indicate possible fields in caps */
7789 data = (guint8 *) field->data + 8;
7791 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
7792 (gint) * data, NULL);
7794 /* add codec_data if provided */
7799 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
7800 data = prefix->data;
7801 len = QT_UINT32 (data);
7804 buf = gst_buffer_new_and_alloc (len);
7805 gst_buffer_fill (buf, 0, data + 8, len);
7806 gst_caps_set_simple (stream->caps,
7807 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7808 gst_buffer_unref (buf);
7817 GstBuffer *seqh = NULL;
7818 guint8 *gamma_data = NULL;
7819 gint len = QT_UINT32 (stsd_data);
7821 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
7823 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
7824 QT_FP32 (gamma_data), NULL);
7827 /* sorry for the bad name, but we don't know what this is, other
7828 * than its own fourcc */
7829 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
7833 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
7834 buf = gst_buffer_new_and_alloc (len);
7835 gst_buffer_fill (buf, 0, stsd_data, len);
7836 gst_caps_set_simple (stream->caps,
7837 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7838 gst_buffer_unref (buf);
7844 gst_caps_set_simple (stream->caps,
7845 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
7852 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
7853 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
7857 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
7861 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
7862 /* collect the headers and store them in a stream list so that we can
7863 * send them out first */
7864 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
7874 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
7875 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
7878 ovc1_data = ovc1->data;
7879 ovc1_len = QT_UINT32 (ovc1_data);
7880 if (ovc1_len <= 198) {
7881 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
7884 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
7885 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
7886 gst_caps_set_simple (stream->caps,
7887 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7888 gst_buffer_unref (buf);
7896 GST_INFO_OBJECT (qtdemux,
7897 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7898 GST_FOURCC_ARGS (fourcc), stream->caps);
7900 } else if (stream->subtype == FOURCC_soun) {
7901 int version, samplesize;
7902 guint16 compression_id;
7903 gboolean amrwb = FALSE;
7906 /* sample description entry (16) + sound sample description v0 (20) */
7910 version = QT_UINT32 (stsd_data + offset);
7911 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
7912 samplesize = QT_UINT16 (stsd_data + offset + 10);
7913 compression_id = QT_UINT16 (stsd_data + offset + 12);
7914 stream->rate = QT_FP32 (stsd_data + offset + 16);
7916 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
7917 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
7918 QT_UINT32 (stsd_data + offset + 4));
7919 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7920 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
7921 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
7922 GST_LOG_OBJECT (qtdemux, "packet size: %d",
7923 QT_UINT16 (stsd_data + offset + 14));
7924 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7926 if (compression_id == 0xfffe)
7927 stream->sampled = TRUE;
7929 /* first assume uncompressed audio */
7930 stream->bytes_per_sample = samplesize / 8;
7931 stream->samples_per_frame = stream->n_channels;
7932 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
7933 stream->samples_per_packet = stream->samples_per_frame;
7934 stream->bytes_per_packet = stream->bytes_per_sample;
7938 /* Yes, these have to be hard-coded */
7941 stream->samples_per_packet = 6;
7942 stream->bytes_per_packet = 1;
7943 stream->bytes_per_frame = 1 * stream->n_channels;
7944 stream->bytes_per_sample = 1;
7945 stream->samples_per_frame = 6 * stream->n_channels;
7950 stream->samples_per_packet = 3;
7951 stream->bytes_per_packet = 1;
7952 stream->bytes_per_frame = 1 * stream->n_channels;
7953 stream->bytes_per_sample = 1;
7954 stream->samples_per_frame = 3 * stream->n_channels;
7959 stream->samples_per_packet = 64;
7960 stream->bytes_per_packet = 34;
7961 stream->bytes_per_frame = 34 * stream->n_channels;
7962 stream->bytes_per_sample = 2;
7963 stream->samples_per_frame = 64 * stream->n_channels;
7969 stream->samples_per_packet = 1;
7970 stream->bytes_per_packet = 1;
7971 stream->bytes_per_frame = 1 * stream->n_channels;
7972 stream->bytes_per_sample = 1;
7973 stream->samples_per_frame = 1 * stream->n_channels;
7978 stream->samples_per_packet = 160;
7979 stream->bytes_per_packet = 33;
7980 stream->bytes_per_frame = 33 * stream->n_channels;
7981 stream->bytes_per_sample = 2;
7982 stream->samples_per_frame = 160 * stream->n_channels;
7989 if (version == 0x00010000) {
7990 /* sample description entry (16) + sound sample description v1 (20+16) */
8001 /* only parse extra decoding config for non-pcm audio */
8002 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
8003 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
8004 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
8005 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
8007 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
8008 stream->samples_per_packet);
8009 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8010 stream->bytes_per_packet);
8011 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
8012 stream->bytes_per_frame);
8013 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
8014 stream->bytes_per_sample);
8016 if (!stream->sampled && stream->bytes_per_packet) {
8017 stream->samples_per_frame = (stream->bytes_per_frame /
8018 stream->bytes_per_packet) * stream->samples_per_packet;
8019 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
8020 stream->samples_per_frame);
8025 } else if (version == 0x00020000) {
8032 /* sample description entry (16) + sound sample description v2 (56) */
8036 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
8037 stream->rate = qtfp.fp;
8038 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
8040 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
8041 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8042 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8043 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
8044 QT_UINT32 (stsd_data + offset + 20));
8045 GST_LOG_OBJECT (qtdemux, "format flags: %X",
8046 QT_UINT32 (stsd_data + offset + 24));
8047 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8048 QT_UINT32 (stsd_data + offset + 28));
8049 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
8050 QT_UINT32 (stsd_data + offset + 32));
8052 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
8055 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
8056 stsd_data + 32, len - 16, &codec);
8064 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
8066 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
8068 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
8070 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
8073 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
8074 gst_caps_set_simple (stream->caps,
8075 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
8082 const guint8 *owma_data;
8083 const gchar *codec_name = NULL;
8087 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8088 /* FIXME this should also be gst_riff_strf_auds,
8089 * but the latter one is actually missing bits-per-sample :( */
8094 gint32 nSamplesPerSec;
8095 gint32 nAvgBytesPerSec;
8097 gint16 wBitsPerSample;
8102 GST_DEBUG_OBJECT (qtdemux, "parse owma");
8103 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
8106 owma_data = owma->data;
8107 owma_len = QT_UINT32 (owma_data);
8108 if (owma_len <= 54) {
8109 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
8112 wfex = (WAVEFORMATEX *) (owma_data + 36);
8113 buf = gst_buffer_new_and_alloc (owma_len - 54);
8114 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
8115 if (wfex->wFormatTag == 0x0161) {
8116 codec_name = "Windows Media Audio";
8118 } else if (wfex->wFormatTag == 0x0162) {
8119 codec_name = "Windows Media Audio 9 Pro";
8121 } else if (wfex->wFormatTag == 0x0163) {
8122 codec_name = "Windows Media Audio 9 Lossless";
8123 /* is that correct? gstffmpegcodecmap.c is missing it, but
8124 * fluendo codec seems to support it */
8128 gst_caps_set_simple (stream->caps,
8129 "codec_data", GST_TYPE_BUFFER, buf,
8130 "wmaversion", G_TYPE_INT, version,
8131 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
8132 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
8133 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8134 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8136 gst_buffer_unref (buf);
8140 codec = g_strdup (codec_name);
8152 list = gst_tag_list_new_empty ();
8153 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8154 GST_TAG_AUDIO_CODEC, codec, NULL);
8158 /* some bitrate info may have ended up in caps */
8159 s = gst_caps_get_structure (stream->caps, 0);
8160 gst_structure_get_int (s, "bitrate", &bitrate);
8162 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
8166 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
8170 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
8172 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
8174 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
8178 /* If the fourcc's bottom 16 bits gives 'sm', then the top
8179 16 bits is a byte-swapped wave-style codec identifier,
8180 and we can find a WAVE header internally to a 'wave' atom here.
8181 This can more clearly be thought of as 'ms' as the top 16 bits, and a
8182 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
8185 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
8186 if (len < offset + 20) {
8187 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
8189 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
8190 const guint8 *data = stsd_data + offset + 16;
8192 GNode *waveheadernode;
8194 wavenode = g_node_new ((guint8 *) data);
8195 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
8196 const guint8 *waveheader;
8199 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
8200 if (waveheadernode) {
8201 waveheader = (const guint8 *) waveheadernode->data;
8202 headerlen = QT_UINT32 (waveheader);
8204 if (headerlen > 8) {
8205 gst_riff_strf_auds *header = NULL;
8206 GstBuffer *headerbuf;
8212 headerbuf = gst_buffer_new_and_alloc (headerlen);
8213 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
8215 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
8216 headerbuf, &header, &extra)) {
8217 gst_caps_unref (stream->caps);
8218 /* FIXME: Need to do something with the channel reorder map */
8219 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
8220 header, extra, NULL, NULL, NULL);
8223 gst_buffer_unref (extra);
8228 GST_DEBUG ("Didn't find waveheadernode for this codec");
8230 g_node_destroy (wavenode);
8233 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
8237 /* FIXME: what is in the chunk? */
8240 gint len = QT_UINT32 (stsd_data);
8242 /* seems to be always = 116 = 0x74 */
8248 gint len = QT_UINT32 (stsd_data);
8251 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
8253 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
8254 gst_caps_set_simple (stream->caps,
8255 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8256 gst_buffer_unref (buf);
8258 gst_caps_set_simple (stream->caps,
8259 "samplesize", G_TYPE_INT, samplesize, NULL);
8264 GNode *alac, *wave = NULL;
8266 /* apparently, m4a has this atom appended directly in the stsd entry,
8267 * while mov has it in a wave atom */
8268 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
8270 /* alac now refers to stsd entry atom */
8271 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
8273 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
8275 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
8278 const guint8 *alac_data = alac->data;
8279 gint len = QT_UINT32 (alac->data);
8283 GST_DEBUG_OBJECT (qtdemux,
8284 "discarding alac atom with unexpected len %d", len);
8286 /* codec-data contains alac atom size and prefix,
8287 * ffmpeg likes it that way, not quite gst-ish though ...*/
8288 buf = gst_buffer_new_and_alloc (len);
8289 gst_buffer_fill (buf, 0, alac->data, len);
8290 gst_caps_set_simple (stream->caps,
8291 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8292 gst_buffer_unref (buf);
8294 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
8295 stream->n_channels = QT_UINT8 (alac_data + 21);
8296 stream->rate = QT_UINT32 (alac_data + 32);
8299 gst_caps_set_simple (stream->caps,
8300 "samplesize", G_TYPE_INT, samplesize, NULL);
8308 gint len = QT_UINT32 (stsd_data);
8311 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
8314 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
8316 /* If we have enough data, let's try to get the 'damr' atom. See
8317 * the 3GPP container spec (26.244) for more details. */
8318 if ((len - 0x34) > 8 &&
8319 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
8321 list = gst_tag_list_new_empty ();
8322 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8323 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
8326 gst_caps_set_simple (stream->caps,
8327 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8328 gst_buffer_unref (buf);
8333 GST_INFO_OBJECT (qtdemux,
8334 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
8338 GST_INFO_OBJECT (qtdemux,
8339 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8340 GST_FOURCC_ARGS (fourcc), stream->caps);
8342 } else if (stream->subtype == FOURCC_strm) {
8343 if (fourcc == FOURCC_rtsp) {
8344 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
8346 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
8347 GST_FOURCC_ARGS (fourcc));
8348 goto unknown_stream;
8350 stream->sampled = TRUE;
8351 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8352 || stream->subtype == FOURCC_sbtl) {
8354 stream->sampled = TRUE;
8355 stream->sparse = TRUE;
8360 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
8362 list = gst_tag_list_new_empty ();
8363 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8364 GST_TAG_SUBTITLE_CODEC, codec, NULL);
8369 /* hunt for sort-of codec data */
8376 /* look for palette in a stsd->mp4s->esds sub-atom */
8377 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
8379 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
8382 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
8386 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
8390 GST_INFO_OBJECT (qtdemux,
8391 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
8394 GST_INFO_OBJECT (qtdemux,
8395 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8396 GST_FOURCC_ARGS (fourcc), stream->caps);
8398 /* everything in 1 sample */
8399 stream->sampled = TRUE;
8402 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
8404 if (stream->caps == NULL)
8405 goto unknown_stream;
8408 list = gst_tag_list_new_empty ();
8409 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8410 GST_TAG_SUBTITLE_CODEC, codec, NULL);
8416 /* promote to sampled format */
8417 if (stream->fourcc == FOURCC_samr) {
8418 /* force mono 8000 Hz for AMR */
8419 stream->sampled = TRUE;
8420 stream->n_channels = 1;
8421 stream->rate = 8000;
8422 } else if (stream->fourcc == FOURCC_sawb) {
8423 /* force mono 16000 Hz for AMR-WB */
8424 stream->sampled = TRUE;
8425 stream->n_channels = 1;
8426 stream->rate = 16000;
8427 } else if (stream->fourcc == FOURCC_mp4a) {
8428 stream->sampled = TRUE;
8431 /* collect sample information */
8432 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
8433 goto samples_failed;
8435 if (qtdemux->fragmented) {
8439 /* need all moov samples as basis; probably not many if any at all */
8440 /* prevent moof parsing taking of at this time */
8441 offset = qtdemux->moof_offset;
8442 qtdemux->moof_offset = 0;
8443 if (stream->n_samples &&
8444 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
8445 qtdemux->moof_offset = offset;
8446 goto samples_failed;
8448 qtdemux->moof_offset = 0;
8449 /* movie duration more reliable in this case (e.g. mehd) */
8450 if (qtdemux->segment.duration &&
8451 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
8452 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
8453 stream->timescale, GST_SECOND);
8454 /* need defaults for fragments */
8455 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
8458 /* configure segments */
8459 if (!qtdemux_parse_segments (qtdemux, stream, trak))
8460 goto segments_failed;
8462 /* add some language tag, if useful */
8463 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
8464 strcmp (stream->lang_id, "und")) {
8465 const gchar *lang_code;
8468 list = gst_tag_list_new_empty ();
8470 /* convert ISO 639-2 code to ISO 639-1 */
8471 lang_code = gst_tag_get_language_code (stream->lang_id);
8472 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8473 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
8476 /* now we are ready to add the stream */
8477 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
8478 goto too_many_streams;
8480 if (!qtdemux->got_moov) {
8481 stream->pending_tags = list;
8482 qtdemux->streams[qtdemux->n_streams] = stream;
8483 qtdemux->n_streams++;
8484 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
8492 GST_INFO_OBJECT (qtdemux, "skip disabled track");
8498 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8499 (_("This file is corrupt and cannot be played.")), (NULL));
8505 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
8512 /* we posted an error already */
8513 /* free stbl sub-atoms */
8514 gst_qtdemux_stbl_free (stream);
8520 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
8528 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
8529 GST_FOURCC_ARGS (stream->subtype));
8535 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
8536 (_("This file contains too many streams. Only playing first %d"),
8537 GST_QTDEMUX_MAX_STREAMS), (NULL));
8542 /* If we can estimate the overall bitrate, and don't have information about the
8543 * stream bitrate for exactly one stream, this guesses the stream bitrate as
8544 * the overall bitrate minus the sum of the bitrates of all other streams. This
8545 * should be useful for the common case where we have one audio and one video
8546 * stream and can estimate the bitrate of one, but not the other. */
8548 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
8550 QtDemuxStream *stream = NULL;
8551 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
8555 if (qtdemux->fragmented)
8558 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
8560 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
8562 GST_DEBUG_OBJECT (qtdemux,
8563 "Size in bytes of the stream not known - bailing");
8567 /* Subtract the header size */
8568 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
8569 size, qtdemux->header_size);
8571 if (size < qtdemux->header_size)
8574 size = size - qtdemux->header_size;
8576 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
8577 duration == GST_CLOCK_TIME_NONE) {
8578 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
8582 for (i = 0; i < qtdemux->n_streams; i++) {
8583 switch (qtdemux->streams[i]->subtype) {
8586 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
8587 qtdemux->streams[i]->caps);
8588 /* retrieve bitrate, prefer avg then max */
8590 if (qtdemux->streams[i]->pending_tags) {
8591 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8592 GST_TAG_MAXIMUM_BITRATE, &bitrate);
8593 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
8594 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8595 GST_TAG_NOMINAL_BITRATE, &bitrate);
8596 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
8597 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8598 GST_TAG_BITRATE, &bitrate);
8599 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
8602 sum_bitrate += bitrate;
8605 GST_DEBUG_OBJECT (qtdemux,
8606 ">1 stream with unknown bitrate - bailing");
8609 stream = qtdemux->streams[i];
8613 /* For other subtypes, we assume no significant impact on bitrate */
8619 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
8623 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
8625 if (sys_bitrate < sum_bitrate) {
8626 /* This can happen, since sum_bitrate might be derived from maximum
8627 * bitrates and not average bitrates */
8628 GST_DEBUG_OBJECT (qtdemux,
8629 "System bitrate less than sum bitrate - bailing");
8633 bitrate = sys_bitrate - sum_bitrate;
8634 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
8635 ", Stream bitrate = %u", sys_bitrate, bitrate);
8637 if (!stream->pending_tags)
8638 stream->pending_tags = gst_tag_list_new_empty ();
8640 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8641 GST_TAG_BITRATE, bitrate, NULL);
8644 static GstFlowReturn
8645 qtdemux_prepare_streams (GstQTDemux * qtdemux)
8648 GstFlowReturn ret = GST_FLOW_OK;
8650 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
8652 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
8653 QtDemuxStream *stream = qtdemux->streams[i];
8654 guint32 sample_num = 0;
8658 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
8659 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
8661 if (qtdemux->fragmented) {
8662 /* need all moov samples first */
8663 GST_OBJECT_LOCK (qtdemux);
8664 while (stream->n_samples == 0)
8665 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
8667 GST_OBJECT_UNLOCK (qtdemux);
8669 /* discard any stray moof */
8670 qtdemux->moof_offset = 0;
8673 /* prepare braking */
8674 if (ret != GST_FLOW_ERROR)
8677 /* in pull mode, we should have parsed some sample info by now;
8678 * and quite some code will not handle no samples.
8679 * in push mode, we'll just have to deal with it */
8680 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
8681 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
8682 gst_qtdemux_remove_stream (qtdemux, i);
8687 /* parse number of initial sample to set frame rate cap */
8688 while (sample_num < stream->n_samples && sample_num < samples) {
8689 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
8693 /* collect and sort durations */
8694 samples = MIN (stream->stbl_index + 1, samples);
8695 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
8697 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
8699 while (sample_num < samples) {
8700 g_array_append_val (durations, stream->samples[sample_num].duration);
8703 g_array_sort (durations, less_than);
8704 stream->min_duration = g_array_index (durations, guint32, samples / 2);
8705 g_array_free (durations, TRUE);
8712 static GstFlowReturn
8713 qtdemux_expose_streams (GstQTDemux * qtdemux)
8716 GstFlowReturn ret = GST_FLOW_OK;
8717 GSList *oldpads = NULL;
8720 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
8722 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
8723 QtDemuxStream *stream = qtdemux->streams[i];
8724 GstPad *oldpad = stream->pad;
8727 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
8728 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
8730 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
8731 stream->track_id == qtdemux->chapters_track_id) {
8732 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
8733 so that it doesn't look like a subtitle track */
8734 gst_qtdemux_remove_stream (qtdemux, i);
8739 /* now we have all info and can expose */
8740 list = stream->pending_tags;
8741 stream->pending_tags = NULL;
8743 oldpads = g_slist_prepend (oldpads, oldpad);
8744 gst_qtdemux_add_stream (qtdemux, stream, list);
8747 gst_qtdemux_guess_bitrate (qtdemux);
8749 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
8751 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
8752 GstPad *oldpad = iter->data;
8754 gst_pad_push_event (oldpad, gst_event_new_eos ());
8755 gst_pad_set_active (oldpad, FALSE);
8756 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
8757 gst_object_unref (oldpad);
8760 /* check if we should post a redirect in case there is a single trak
8761 * and it is a redirecting trak */
8762 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
8765 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
8766 "an external content");
8767 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
8768 gst_structure_new ("redirect",
8769 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
8771 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
8772 qtdemux->posted_redirect = TRUE;
8775 for (i = 0; i < qtdemux->n_streams; i++) {
8776 QtDemuxStream *stream = qtdemux->streams[i];
8778 qtdemux_do_allocation (qtdemux, stream);
8781 qtdemux->exposed = TRUE;
8785 /* check if major or compatible brand is 3GP */
8786 static inline gboolean
8787 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
8790 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
8791 GST_MAKE_FOURCC ('3', 'g', 0, 0));
8792 } else if (qtdemux->comp_brands != NULL) {
8796 gboolean res = FALSE;
8798 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
8802 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
8803 GST_MAKE_FOURCC ('3', 'g', 0, 0));
8807 gst_buffer_unmap (qtdemux->comp_brands, &map);
8814 /* check if tag is a spec'ed 3GP tag keyword storing a string */
8815 static inline gboolean
8816 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
8818 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
8819 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
8820 || fourcc == FOURCC_albm;
8824 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
8825 const char *dummy, GNode * node)
8827 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8831 gdouble longitude, latitude, altitude;
8834 len = QT_UINT32 (node->data);
8841 /* TODO: language code skipped */
8843 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
8846 /* do not alarm in trivial case, but bail out otherwise */
8847 if (*(data + offset) != 0) {
8848 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
8852 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8853 GST_TAG_GEO_LOCATION_NAME, name, NULL);
8854 offset += strlen (name);
8858 if (len < offset + 2 + 4 + 4 + 4)
8861 /* +1 +1 = skip null-terminator and location role byte */
8863 /* table in spec says unsigned, semantics say negative has meaning ... */
8864 longitude = QT_SFP32 (data + offset);
8867 latitude = QT_SFP32 (data + offset);
8870 altitude = QT_SFP32 (data + offset);
8872 /* one invalid means all are invalid */
8873 if (longitude >= -180.0 && longitude <= 180.0 &&
8874 latitude >= -90.0 && latitude <= 90.0) {
8875 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8876 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
8877 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
8878 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
8881 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
8888 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
8895 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8902 len = QT_UINT32 (node->data);
8906 y = QT_UINT16 ((guint8 *) node->data + 12);
8908 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
8911 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
8913 date = g_date_new_dmy (1, 1, y);
8914 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
8919 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
8920 const char *dummy, GNode * node)
8923 char *tag_str = NULL;
8928 len = QT_UINT32 (node->data);
8933 entity = (guint8 *) node->data + offset;
8934 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
8935 GST_DEBUG_OBJECT (qtdemux,
8936 "classification info: %c%c%c%c invalid classification entity",
8937 entity[0], entity[1], entity[2], entity[3]);
8942 table = QT_UINT16 ((guint8 *) node->data + offset);
8944 /* Language code skipped */
8948 /* Tag format: "XXXX://Y[YYYY]/classification info string"
8949 * XXXX: classification entity, fixed length 4 chars.
8950 * Y[YYYY]: classification table, max 5 chars.
8952 tag_str = g_strdup_printf ("----://%u/%s",
8953 table, (char *) node->data + offset);
8955 /* memcpy To be sure we're preserving byte order */
8956 memcpy (tag_str, entity, 4);
8957 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
8959 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
8969 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
8975 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
8976 const char *dummy, GNode * node)
8978 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8984 gboolean ret = TRUE;
8986 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8988 len = QT_UINT32 (data->data);
8989 type = QT_UINT32 ((guint8 *) data->data + 8);
8990 if (type == 0x00000001 && len > 16) {
8991 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
8994 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
8995 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
8999 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9003 len = QT_UINT32 (node->data);
9004 type = QT_UINT32 ((guint8 *) node->data + 4);
9005 if ((type >> 24) == 0xa9) {
9006 /* Type starts with the (C) symbol, so the next 32 bits are
9007 * the language code, which we ignore */
9009 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
9010 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
9011 QT_FOURCC ((guint8 *) node->data + 4))) {
9012 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
9014 /* we go for 3GP style encoding if major brands claims so,
9015 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
9016 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9017 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
9018 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
9020 /* 16-bit Language code is ignored here as well */
9021 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
9028 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
9029 ret = FALSE; /* may have to fallback */
9031 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9032 len - offset, env_vars);
9034 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9035 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
9039 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9046 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
9047 const char *dummy, GNode * node)
9049 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
9053 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
9054 const char *dummy, GNode * node)
9056 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9058 char *s, *t, *k = NULL;
9063 /* first try normal string tag if major brand not 3GP */
9064 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
9065 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
9066 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
9067 * let's try it 3gpp way after minor safety check */
9069 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
9075 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
9079 len = QT_UINT32 (data);
9083 count = QT_UINT8 (data + 14);
9085 for (; count; count--) {
9088 if (offset + 1 > len)
9090 slen = QT_UINT8 (data + offset);
9092 if (offset + slen > len)
9094 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9097 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
9099 t = g_strjoin (",", k, s, NULL);
9107 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
9114 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
9115 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
9124 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
9130 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
9131 const char *tag2, GNode * node)
9138 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9140 len = QT_UINT32 (data->data);
9141 type = QT_UINT32 ((guint8 *) data->data + 8);
9142 if (type == 0x00000000 && len >= 22) {
9143 n1 = QT_UINT16 ((guint8 *) data->data + 18);
9144 n2 = QT_UINT16 ((guint8 *) data->data + 20);
9146 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
9147 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9151 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
9152 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9160 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9168 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9170 len = QT_UINT32 (data->data);
9171 type = QT_UINT32 ((guint8 *) data->data + 8);
9172 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
9173 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9174 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
9175 n1 = QT_UINT16 ((guint8 *) data->data + 16);
9177 /* do not add bpm=0 */
9178 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
9179 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9180 tag1, (gdouble) n1, NULL);
9187 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
9188 const char *dummy, GNode * node)
9195 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9197 len = QT_UINT32 (data->data);
9198 type = QT_UINT32 ((guint8 *) data->data + 8);
9199 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
9200 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9201 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
9202 num = QT_UINT32 ((guint8 *) data->data + 16);
9204 /* do not add num=0 */
9205 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
9206 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9214 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9222 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9224 len = QT_UINT32 (data->data);
9225 type = QT_UINT32 ((guint8 *) data->data + 8);
9226 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
9227 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
9229 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
9230 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
9231 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
9232 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9233 tag1, sample, NULL);
9234 gst_sample_unref (sample);
9241 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9249 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9251 len = QT_UINT32 (data->data);
9252 type = QT_UINT32 ((guint8 *) data->data + 8);
9253 if (type == 0x00000001 && len > 16) {
9254 guint y, m = 1, d = 1;
9257 s = g_strndup ((char *) data->data + 16, len - 16);
9258 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
9259 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
9260 if (ret >= 1 && y > 1500 && y < 3000) {
9263 date = g_date_new_dmy (d, m, y);
9264 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
9268 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
9276 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9281 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9283 /* re-route to normal string tag if major brand says so
9284 * or no data atom and compatible brand suggests so */
9285 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9286 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
9287 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
9294 len = QT_UINT32 (data->data);
9295 type = QT_UINT32 ((guint8 *) data->data + 8);
9296 if (type == 0x00000000 && len >= 18) {
9297 n = QT_UINT16 ((guint8 *) data->data + 16);
9301 genre = gst_tag_id3_genre_get (n - 1);
9302 if (genre != NULL) {
9303 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
9304 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9313 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
9314 guint8 * data, guint32 datasize)
9319 /* make a copy to have \0 at the end */
9320 datacopy = g_strndup ((gchar *) data, datasize);
9322 /* convert the str to double */
9323 if (sscanf (datacopy, "%lf", &value) == 1) {
9324 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
9325 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
9327 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
9335 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
9336 const char *tag_bis, GNode * node)
9345 const gchar *meanstr;
9346 const gchar *namestr;
9348 /* checking the whole ---- atom size for consistency */
9349 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
9350 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
9354 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
9356 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
9360 meansize = QT_UINT32 (mean->data);
9361 if (meansize <= 12) {
9362 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
9365 meanstr = ((gchar *) mean->data) + 12;
9367 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
9369 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
9373 namesize = QT_UINT32 (name->data);
9374 if (namesize <= 12) {
9375 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
9378 namestr = ((gchar *) name->data) + 12;
9385 * uint24 - data type
9389 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9391 GST_WARNING_OBJECT (demux, "No data atom in this tag");
9394 datasize = QT_UINT32 (data->data);
9395 if (datasize <= 16) {
9396 GST_WARNING_OBJECT (demux, "Data atom too small");
9399 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
9401 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
9404 const gchar name[28];
9405 const gchar tag[28];
9408 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
9409 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
9410 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
9411 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
9412 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
9413 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
9414 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
9415 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
9419 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
9420 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
9421 switch (gst_tag_get_type (tags[i].tag)) {
9423 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
9424 ((guint8 *) data->data) + 16, datasize - 16);
9427 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
9436 if (i == G_N_ELEMENTS (tags))
9450 meanstr_dbg = g_strndup (meanstr, meansize - 12);
9451 namestr_dbg = g_strndup (namestr, namesize - 12);
9453 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
9454 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
9456 g_free (namestr_dbg);
9457 g_free (meanstr_dbg);
9463 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
9464 const char *tag_bis, GNode * node)
9469 GstTagList *taglist = NULL;
9471 GST_LOG_OBJECT (demux, "parsing ID32");
9474 len = GST_READ_UINT32_BE (data);
9476 /* need at least full box and language tag */
9480 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
9481 gst_buffer_fill (buf, 0, data + 14, len - 14);
9483 taglist = gst_tag_list_from_id3v2_tag (buf);
9485 GST_LOG_OBJECT (demux, "parsing ok");
9486 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
9488 GST_LOG_OBJECT (demux, "parsing failed");
9492 gst_tag_list_unref (taglist);
9494 gst_buffer_unref (buf);
9497 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
9498 const char *tag, const char *tag_bis, GNode * node);
9501 FOURCC_pcst -> if media is a podcast -> bool
9502 FOURCC_cpil -> if media is part of a compilation -> bool
9503 FOURCC_pgap -> if media is part of a gapless context -> bool
9504 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
9510 const gchar *gst_tag;
9511 const gchar *gst_tag_bis;
9512 const GstQTDemuxAddTagFunc func;
9515 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
9516 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
9517 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
9518 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
9519 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
9520 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
9521 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
9522 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
9523 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
9524 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
9525 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
9526 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
9527 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
9528 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9529 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9530 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9531 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
9532 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
9533 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
9534 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
9535 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
9536 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
9537 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
9538 qtdemux_tag_add_num}, {
9539 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
9540 qtdemux_tag_add_num}, {
9541 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
9542 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
9543 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
9544 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
9545 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
9546 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
9547 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
9548 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
9549 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
9550 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
9551 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
9552 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
9553 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
9554 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
9555 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
9556 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
9557 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
9558 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
9559 qtdemux_tag_add_classification}, {
9561 /* This is a special case, some tags are stored in this
9562 * 'reverse dns naming', according to:
9563 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
9566 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
9567 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
9568 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
9572 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
9585 len = QT_UINT32 (data);
9586 buf = gst_buffer_new_and_alloc (len);
9587 gst_buffer_fill (buf, 0, data, len);
9589 /* heuristic to determine style of tag */
9590 if (QT_FOURCC (data + 4) == FOURCC_____ ||
9591 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
9593 else if (demux->major_brand == FOURCC_qt__)
9594 style = "quicktime";
9595 /* fall back to assuming iso/3gp tag style */
9599 /* santize the name for the caps. */
9600 for (i = 0; i < 4; i++) {
9601 guint8 d = data[4 + i];
9602 if (g_ascii_isalnum (d))
9603 ndata[i] = g_ascii_tolower (d);
9608 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
9609 ndata[0], ndata[1], ndata[2], ndata[3]);
9610 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
9612 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
9613 sample = gst_sample_new (buf, NULL, NULL, s);
9614 gst_buffer_unref (buf);
9615 g_free (media_type);
9617 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
9620 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
9621 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
9623 gst_sample_unref (sample);
9627 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
9635 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
9637 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
9639 GST_LOG_OBJECT (qtdemux, "no ilst");
9644 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
9647 GST_DEBUG_OBJECT (qtdemux, "new tag list");
9648 if (!qtdemux->tag_list) {
9649 qtdemux->tag_list = gst_tag_list_new_empty ();
9650 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
9652 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
9656 while (i < G_N_ELEMENTS (add_funcs)) {
9657 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
9661 len = QT_UINT32 (node->data);
9663 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
9664 GST_FOURCC_ARGS (add_funcs[i].fourcc));
9666 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
9667 add_funcs[i].gst_tag_bis, node);
9669 g_node_destroy (node);
9675 /* parsed nodes have been removed, pass along remainder as blob */
9676 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
9677 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
9679 /* parse up XMP_ node if existing */
9680 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
9683 GstTagList *taglist;
9685 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
9686 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
9687 taglist = gst_tag_list_from_xmp_buffer (buf);
9688 gst_buffer_unref (buf);
9690 qtdemux_handle_xmp_taglist (qtdemux, taglist);
9692 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
9699 GstStructure *structure; /* helper for sort function */
9701 guint min_req_bitrate;
9702 guint min_req_qt_version;
9706 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
9708 GstQtReference *ref_a = (GstQtReference *) a;
9709 GstQtReference *ref_b = (GstQtReference *) b;
9711 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
9712 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
9714 /* known bitrates go before unknown; higher bitrates go first */
9715 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
9718 /* sort the redirects and post a message for the application.
9721 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
9723 GstQtReference *best;
9726 GValue list_val = { 0, };
9729 g_assert (references != NULL);
9731 references = g_list_sort (references, qtdemux_redirects_sort_func);
9733 best = (GstQtReference *) references->data;
9735 g_value_init (&list_val, GST_TYPE_LIST);
9737 for (l = references; l != NULL; l = l->next) {
9738 GstQtReference *ref = (GstQtReference *) l->data;
9739 GValue struct_val = { 0, };
9741 ref->structure = gst_structure_new ("redirect",
9742 "new-location", G_TYPE_STRING, ref->location, NULL);
9744 if (ref->min_req_bitrate > 0) {
9745 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
9746 ref->min_req_bitrate, NULL);
9749 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
9750 g_value_set_boxed (&struct_val, ref->structure);
9751 gst_value_list_append_value (&list_val, &struct_val);
9752 g_value_unset (&struct_val);
9753 /* don't free anything here yet, since we need best->structure below */
9756 g_assert (best != NULL);
9757 s = gst_structure_copy (best->structure);
9759 if (g_list_length (references) > 1) {
9760 gst_structure_set_value (s, "locations", &list_val);
9763 g_value_unset (&list_val);
9765 for (l = references; l != NULL; l = l->next) {
9766 GstQtReference *ref = (GstQtReference *) l->data;
9768 gst_structure_free (ref->structure);
9769 g_free (ref->location);
9772 g_list_free (references);
9774 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
9775 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
9776 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
9777 qtdemux->posted_redirect = TRUE;
9780 /* look for redirect nodes, collect all redirect information and
9784 qtdemux_parse_redirects (GstQTDemux * qtdemux)
9786 GNode *rmra, *rmda, *rdrf;
9788 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
9790 GList *redirects = NULL;
9792 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
9794 GstQtReference ref = { NULL, NULL, 0, 0 };
9797 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
9798 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
9799 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
9800 ref.min_req_bitrate);
9803 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
9804 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
9805 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
9807 #ifndef GST_DISABLE_GST_DEBUG
9808 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
9810 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
9812 GST_LOG_OBJECT (qtdemux,
9813 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
9814 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
9815 bitmask, check_type);
9816 if (package == FOURCC_qtim && check_type == 0) {
9817 ref.min_req_qt_version = version;
9821 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
9826 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
9827 ref_data = (guint8 *) rdrf->data + 20;
9828 if (ref_type == FOURCC_alis) {
9829 guint record_len, record_version, fn_len;
9831 /* MacOSX alias record, google for alias-layout.txt */
9832 record_len = QT_UINT16 (ref_data + 4);
9833 record_version = QT_UINT16 (ref_data + 4 + 2);
9834 fn_len = QT_UINT8 (ref_data + 50);
9835 if (record_len > 50 && record_version == 2 && fn_len > 0) {
9836 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
9838 } else if (ref_type == FOURCC_url_) {
9839 ref.location = g_strdup ((gchar *) ref_data);
9841 GST_DEBUG_OBJECT (qtdemux,
9842 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
9843 GST_FOURCC_ARGS (ref_type));
9845 if (ref.location != NULL) {
9846 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
9847 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
9849 GST_WARNING_OBJECT (qtdemux,
9850 "Failed to extract redirect location from rdrf atom");
9854 /* look for others */
9855 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
9858 if (redirects != NULL) {
9859 qtdemux_process_redirects (qtdemux, redirects);
9866 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
9871 tags = gst_tag_list_new_empty ();
9872 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
9875 if (qtdemux->major_brand == FOURCC_mjp2)
9876 fmt = "Motion JPEG 2000";
9877 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
9879 else if (qtdemux->major_brand == FOURCC_qt__)
9881 else if (qtdemux->fragmented)
9884 fmt = "ISO MP4/M4A";
9886 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
9887 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
9889 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
9895 /* we have read th complete moov node now.
9896 * This function parses all of the relevant info, creates the traks and
9897 * prepares all data structures for playback
9900 qtdemux_parse_tree (GstQTDemux * qtdemux)
9907 guint64 creation_time;
9908 GstDateTime *datetime = NULL;
9912 /* make sure we have a usable taglist */
9913 if (!qtdemux->tag_list) {
9914 qtdemux->tag_list = gst_tag_list_new_empty ();
9915 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
9917 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
9920 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
9922 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
9923 return qtdemux_parse_redirects (qtdemux);
9926 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
9928 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
9929 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
9930 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
9931 } else if (version == 0) {
9932 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
9933 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
9934 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
9936 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
9940 /* Moving qt creation time (secs since 1904) to unix time */
9941 if (creation_time != 0) {
9942 /* Try to use epoch first as it should be faster and more commonly found */
9943 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
9946 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
9947 /* some data cleansing sanity */
9948 g_get_current_time (&now);
9949 if (now.tv_sec + 24 * 3600 < creation_time) {
9950 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
9952 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
9955 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
9956 GDateTime *dt, *dt_local;
9958 dt = g_date_time_add_seconds (base_dt, creation_time);
9959 dt_local = g_date_time_to_local (dt);
9960 datetime = gst_date_time_new_from_g_date_time (dt_local);
9962 g_date_time_unref (base_dt);
9963 g_date_time_unref (dt);
9967 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
9968 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
9970 gst_date_time_unref (datetime);
9973 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
9974 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
9976 /* check for fragmented file and get some (default) data */
9977 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
9980 GstByteReader mehd_data;
9982 /* let track parsing or anyone know weird stuff might happen ... */
9983 qtdemux->fragmented = TRUE;
9985 /* compensate for total duration */
9986 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
9988 qtdemux_parse_mehd (qtdemux, &mehd_data);
9991 /* parse all traks */
9992 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
9994 qtdemux_parse_trak (qtdemux, trak);
9995 /* iterate all siblings */
9996 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
9999 /* make sure we don't offset samples more than we have to */
10000 qtdemux->min_elst_offset = GST_CLOCK_TIME_NONE;
10001 for (i = 0; i < qtdemux->n_streams; ++i) {
10002 QtDemuxStream *stream = qtdemux->streams[i];
10003 if (!GST_CLOCK_TIME_IS_VALID (qtdemux->min_elst_offset)
10004 || stream->elst_offset < qtdemux->min_elst_offset) {
10005 qtdemux->min_elst_offset = stream->elst_offset;
10008 if (!GST_CLOCK_TIME_IS_VALID (qtdemux->min_elst_offset)) {
10009 qtdemux->min_elst_offset = 0;
10011 for (i = 0; i < qtdemux->n_streams; ++i) {
10012 QtDemuxStream *stream = qtdemux->streams[i];
10013 stream->elst_offset -= qtdemux->min_elst_offset;
10016 /* set duration in the segment info */
10017 gst_qtdemux_get_duration (qtdemux, &duration);
10019 qtdemux->segment.duration = duration;
10020 /* also do not exceed duration; stop is set that way post seek anyway,
10021 * and segment activation falls back to duration,
10022 * whereas loop only checks stop, so let's align this here as well */
10023 qtdemux->segment.stop = duration;
10027 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
10029 qtdemux_parse_udta (qtdemux, udta);
10031 GST_LOG_OBJECT (qtdemux, "No udta node found.");
10034 /* maybe also some tags in meta box */
10035 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
10037 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
10038 qtdemux_parse_udta (qtdemux, udta);
10040 GST_LOG_OBJECT (qtdemux, "No meta node found.");
10043 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
10048 /* taken from ffmpeg */
10050 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
10062 len = (len << 7) | (c & 0x7f);
10070 /* this can change the codec originally present in @list */
10072 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
10073 GNode * esds, GstTagList * list)
10075 int len = QT_UINT32 (esds->data);
10076 guint8 *ptr = esds->data;
10077 guint8 *end = ptr + len;
10079 guint8 *data_ptr = NULL;
10081 guint8 object_type_id = 0;
10082 const char *codec_name = NULL;
10083 GstCaps *caps = NULL;
10085 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
10087 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
10089 while (ptr + 1 < end) {
10090 tag = QT_UINT8 (ptr);
10091 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
10093 len = read_descr_size (ptr, end, &ptr);
10094 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
10096 /* Check the stated amount of data is available for reading */
10097 if (len < 0 || ptr + len > end)
10101 case ES_DESCRIPTOR_TAG:
10102 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
10103 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
10106 case DECODER_CONFIG_DESC_TAG:{
10107 guint max_bitrate, avg_bitrate;
10109 object_type_id = QT_UINT8 (ptr);
10110 max_bitrate = QT_UINT32 (ptr + 5);
10111 avg_bitrate = QT_UINT32 (ptr + 9);
10112 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
10113 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
10114 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
10115 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
10116 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
10117 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10118 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
10119 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
10121 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10122 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
10123 avg_bitrate, NULL);
10128 case DECODER_SPECIFIC_INFO_TAG:
10129 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
10130 if (object_type_id == 0xe0 && len == 0x40) {
10136 GST_DEBUG_OBJECT (qtdemux,
10137 "Have VOBSUB palette. Creating palette event");
10138 /* move to decConfigDescr data and read palette */
10140 for (i = 0; i < 16; i++) {
10141 clut[i] = QT_UINT32 (data);
10145 s = gst_structure_new ("application/x-gst-dvd", "event",
10146 G_TYPE_STRING, "dvd-spu-clut-change",
10147 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
10148 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
10149 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
10150 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
10151 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
10152 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
10153 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
10154 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
10157 /* store event and trigger custom processing */
10158 stream->pending_event =
10159 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
10160 stream->need_process = TRUE;
10162 /* Generic codec_data handler puts it on the caps */
10169 case SL_CONFIG_DESC_TAG:
10170 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
10174 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
10176 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
10182 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
10183 * in use, and should also be used to override some other parameters for some
10185 switch (object_type_id) {
10186 case 0x20: /* MPEG-4 */
10187 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
10188 * profile_and_level_indication */
10189 if (data_ptr != NULL && data_len >= 5 &&
10190 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
10191 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
10192 data_ptr + 4, data_len - 4);
10194 break; /* Nothing special needed here */
10195 case 0x21: /* H.264 */
10196 codec_name = "H.264 / AVC";
10197 caps = gst_caps_new_simple ("video/x-h264",
10198 "stream-format", G_TYPE_STRING, "avc",
10199 "alignment", G_TYPE_STRING, "au", NULL);
10201 case 0x40: /* AAC (any) */
10202 case 0x66: /* AAC Main */
10203 case 0x67: /* AAC LC */
10204 case 0x68: /* AAC SSR */
10205 /* Override channels and rate based on the codec_data, as it's often
10207 /* Only do so for basic setup without HE-AAC extension */
10208 if (data_ptr && data_len == 2) {
10209 guint channels, rateindex, rate;
10211 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
10212 channels = (data_ptr[1] & 0x7f) >> 3;
10213 if (channels > 0 && channels < 7) {
10214 stream->n_channels = channels;
10215 } else if (channels == 7) {
10216 stream->n_channels = 8;
10219 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
10220 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
10222 stream->rate = rate;
10225 /* Set level and profile if possible */
10226 if (data_ptr != NULL && data_len >= 2) {
10227 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
10228 data_ptr, data_len);
10231 case 0x60: /* MPEG-2, various profiles */
10237 codec_name = "MPEG-2 video";
10238 caps = gst_caps_new_simple ("video/mpeg",
10239 "mpegversion", G_TYPE_INT, 2,
10240 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10242 case 0x69: /* MPEG-2 BC audio */
10243 case 0x6B: /* MPEG-1 audio */
10244 caps = gst_caps_new_simple ("audio/mpeg",
10245 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
10246 codec_name = "MPEG-1 audio";
10248 case 0x6A: /* MPEG-1 */
10249 codec_name = "MPEG-1 video";
10250 caps = gst_caps_new_simple ("video/mpeg",
10251 "mpegversion", G_TYPE_INT, 1,
10252 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10254 case 0x6C: /* MJPEG */
10255 caps = gst_caps_new_empty_simple ("image/jpeg");
10256 codec_name = "Motion-JPEG";
10258 case 0x6D: /* PNG */
10259 caps = gst_caps_new_empty_simple ("image/png");
10260 codec_name = "PNG still images";
10262 case 0x6E: /* JPEG2000 */
10263 codec_name = "JPEG-2000";
10264 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
10266 case 0xA4: /* Dirac */
10267 codec_name = "Dirac";
10268 caps = gst_caps_new_empty_simple ("video/x-dirac");
10270 case 0xA5: /* AC3 */
10271 codec_name = "AC-3 audio";
10272 caps = gst_caps_new_simple ("audio/x-ac3",
10273 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10275 case 0xE1: /* QCELP */
10276 /* QCELP, the codec_data is a riff tag (little endian) with
10277 * 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). */
10278 caps = gst_caps_new_empty_simple ("audio/qcelp");
10279 codec_name = "QCELP";
10285 /* If we have a replacement caps, then change our caps for this stream */
10287 gst_caps_unref (stream->caps);
10288 stream->caps = caps;
10291 if (codec_name && list)
10292 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
10293 GST_TAG_AUDIO_CODEC, codec_name, NULL);
10295 /* Add the codec_data attribute to caps, if we have it */
10299 buffer = gst_buffer_new_and_alloc (data_len);
10300 gst_buffer_fill (buffer, 0, data_ptr, data_len);
10302 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
10303 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
10305 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
10307 gst_buffer_unref (buffer);
10312 #define _codec(name) \
10314 if (codec_name) { \
10315 *codec_name = g_strdup (name); \
10320 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10321 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
10324 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
10327 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
10328 _codec ("PNG still images");
10329 caps = gst_caps_new_empty_simple ("image/png");
10331 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
10332 _codec ("JPEG still images");
10333 caps = gst_caps_new_empty_simple ("image/jpeg");
10335 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
10336 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
10337 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
10338 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
10339 _codec ("Motion-JPEG");
10340 caps = gst_caps_new_empty_simple ("image/jpeg");
10342 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
10343 _codec ("Motion-JPEG format B");
10344 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
10346 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
10347 _codec ("JPEG-2000");
10348 /* override to what it should be according to spec, avoid palette_data */
10349 stream->bits_per_sample = 24;
10350 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
10352 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
10353 _codec ("Sorensen video v.3");
10354 caps = gst_caps_new_simple ("video/x-svq",
10355 "svqversion", G_TYPE_INT, 3, NULL);
10357 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
10358 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
10359 _codec ("Sorensen video v.1");
10360 caps = gst_caps_new_simple ("video/x-svq",
10361 "svqversion", G_TYPE_INT, 1, NULL);
10363 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
10364 caps = gst_caps_new_empty_simple ("video/x-raw");
10365 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
10366 _codec ("Windows Raw RGB");
10368 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
10372 bps = QT_UINT16 (stsd_data + 98);
10375 format = GST_VIDEO_FORMAT_RGB15;
10378 format = GST_VIDEO_FORMAT_RGB16;
10381 format = GST_VIDEO_FORMAT_RGB;
10384 format = GST_VIDEO_FORMAT_ARGB;
10392 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
10393 format = GST_VIDEO_FORMAT_I420;
10395 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
10396 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
10397 format = GST_VIDEO_FORMAT_I420;
10399 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
10400 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
10401 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
10402 format = GST_VIDEO_FORMAT_UYVY;
10404 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
10405 format = GST_VIDEO_FORMAT_r210;
10407 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
10408 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
10409 _codec ("MPEG-1 video");
10410 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
10411 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10413 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
10414 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
10415 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
10416 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
10417 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
10418 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
10419 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
10420 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
10421 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
10422 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
10423 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
10424 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
10425 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
10426 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
10427 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
10428 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
10429 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
10430 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
10431 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
10432 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
10433 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
10434 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
10435 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
10436 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
10437 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
10438 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
10439 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
10440 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
10441 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
10442 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
10443 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
10444 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
10445 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
10446 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
10447 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
10448 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
10449 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
10450 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
10451 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
10452 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
10453 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
10454 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
10455 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
10456 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
10457 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
10458 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
10459 _codec ("MPEG-2 video");
10460 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
10461 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10463 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
10464 _codec ("GIF still images");
10465 caps = gst_caps_new_empty_simple ("image/gif");
10467 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
10468 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
10469 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
10470 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
10472 /* ffmpeg uses the height/width props, don't know why */
10473 caps = gst_caps_new_simple ("video/x-h263",
10474 "variant", G_TYPE_STRING, "itu", NULL);
10476 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
10477 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
10478 _codec ("MPEG-4 video");
10479 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
10480 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10482 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
10483 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
10484 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
10485 caps = gst_caps_new_simple ("video/x-msmpeg",
10486 "msmpegversion", G_TYPE_INT, 43, NULL);
10488 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
10490 caps = gst_caps_new_simple ("video/x-divx",
10491 "divxversion", G_TYPE_INT, 3, NULL);
10493 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
10494 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
10496 caps = gst_caps_new_simple ("video/x-divx",
10497 "divxversion", G_TYPE_INT, 4, NULL);
10499 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
10501 caps = gst_caps_new_simple ("video/x-divx",
10502 "divxversion", G_TYPE_INT, 5, NULL);
10505 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
10506 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
10507 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
10508 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
10509 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
10510 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
10511 caps = gst_caps_new_simple ("video/mpeg",
10512 "mpegversion", G_TYPE_INT, 4, NULL);
10514 *codec_name = g_strdup ("MPEG-4");
10517 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
10518 _codec ("Cinepak");
10519 caps = gst_caps_new_empty_simple ("video/x-cinepak");
10521 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
10522 _codec ("Apple QuickDraw");
10523 caps = gst_caps_new_empty_simple ("video/x-qdrw");
10525 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
10526 _codec ("Apple video");
10527 caps = gst_caps_new_empty_simple ("video/x-apple-video");
10529 case GST_MAKE_FOURCC ('H', '2', '6', '4'):
10530 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
10531 _codec ("H.264 / AVC");
10532 caps = gst_caps_new_simple ("video/x-h264",
10533 "stream-format", G_TYPE_STRING, "avc",
10534 "alignment", G_TYPE_STRING, "au", NULL);
10536 case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
10537 _codec ("H.264 / AVC");
10538 caps = gst_caps_new_simple ("video/x-h264",
10539 "stream-format", G_TYPE_STRING, "avc3",
10540 "alignment", G_TYPE_STRING, "au", NULL);
10542 case GST_MAKE_FOURCC ('H', '2', '6', '5'):
10543 case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
10544 _codec ("H.265 / HEVC");
10545 caps = gst_caps_new_simple ("video/x-h265",
10546 "stream-format", G_TYPE_STRING, "hvc1",
10547 "alignment", G_TYPE_STRING, "au", NULL);
10549 case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
10550 _codec ("H.265 / HEVC");
10551 caps = gst_caps_new_simple ("video/x-h265",
10552 "stream-format", G_TYPE_STRING, "hev1",
10553 "alignment", G_TYPE_STRING, "au", NULL);
10555 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
10556 _codec ("Run-length encoding");
10557 caps = gst_caps_new_simple ("video/x-rle",
10558 "layout", G_TYPE_STRING, "quicktime", NULL);
10560 case GST_MAKE_FOURCC ('W', 'R', 'L', 'E'):
10561 _codec ("Run-length encoding");
10562 caps = gst_caps_new_simple ("video/x-rle",
10563 "layout", G_TYPE_STRING, "microsoft", NULL);
10565 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
10566 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
10567 _codec ("Indeo Video 3");
10568 caps = gst_caps_new_simple ("video/x-indeo",
10569 "indeoversion", G_TYPE_INT, 3, NULL);
10571 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
10572 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
10573 _codec ("Intel Video 4");
10574 caps = gst_caps_new_simple ("video/x-indeo",
10575 "indeoversion", G_TYPE_INT, 4, NULL);
10577 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
10578 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
10579 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
10580 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
10581 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
10582 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
10583 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
10584 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
10585 _codec ("DV Video");
10586 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
10587 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10589 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
10590 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
10591 _codec ("DVCPro50 Video");
10592 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
10593 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10595 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
10596 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
10597 _codec ("DVCProHD Video");
10598 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
10599 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10601 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
10602 _codec ("Apple Graphics (SMC)");
10603 caps = gst_caps_new_empty_simple ("video/x-smc");
10605 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
10607 caps = gst_caps_new_empty_simple ("video/x-vp3");
10609 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
10610 _codec ("VP6 Flash");
10611 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
10613 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
10615 caps = gst_caps_new_empty_simple ("video/x-theora");
10616 /* theora uses one byte of padding in the data stream because it does not
10617 * allow 0 sized packets while theora does */
10618 stream->padding = 1;
10620 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
10622 caps = gst_caps_new_empty_simple ("video/x-dirac");
10624 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
10625 _codec ("TIFF still images");
10626 caps = gst_caps_new_empty_simple ("image/tiff");
10628 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
10629 _codec ("Apple Intermediate Codec");
10630 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
10632 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
10633 _codec ("AVID DNxHD");
10634 caps = gst_caps_from_string ("video/x-dnxhd");
10636 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
10637 _codec ("On2 VP8");
10638 caps = gst_caps_from_string ("video/x-vp8");
10640 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
10641 _codec ("Apple ProRes LT");
10643 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
10646 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
10647 _codec ("Apple ProRes HQ");
10649 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
10652 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
10653 _codec ("Apple ProRes");
10655 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10658 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
10659 _codec ("Apple ProRes Proxy");
10661 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10664 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
10665 _codec ("Apple ProRes 4444");
10667 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10672 caps = gst_caps_new_simple ("video/x-wmv",
10673 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
10675 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
10678 char *s, fourstr[5];
10680 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10681 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
10682 caps = gst_caps_new_empty_simple (s);
10687 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
10690 gst_video_info_init (&info);
10691 gst_video_info_set_format (&info, format, stream->width, stream->height);
10692 caps = gst_video_info_to_caps (&info);
10693 *codec_name = gst_pb_utils_get_codec_description (caps);
10695 /* enable clipping for raw video streams */
10696 stream->need_clip = TRUE;
10703 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10704 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
10707 const GstStructure *s;
10711 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
10714 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
10715 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
10716 _codec ("Raw 8-bit PCM audio");
10717 caps = gst_caps_new_simple ("audio/x-raw",
10718 "format", G_TYPE_STRING, "U8",
10719 "layout", G_TYPE_STRING, "interleaved", NULL);
10721 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
10722 endian = G_BIG_ENDIAN;
10724 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
10728 GstAudioFormat format;
10731 endian = G_LITTLE_ENDIAN;
10733 depth = stream->bytes_per_packet * 8;
10734 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
10736 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
10740 caps = gst_caps_new_simple ("audio/x-raw",
10741 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
10742 "layout", G_TYPE_STRING, "interleaved", NULL);
10745 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
10746 _codec ("Raw 64-bit floating-point audio");
10747 caps = gst_caps_new_simple ("audio/x-raw",
10748 "format", G_TYPE_STRING, "F64BE",
10749 "layout", G_TYPE_STRING, "interleaved", NULL);
10751 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
10752 _codec ("Raw 32-bit floating-point audio");
10753 caps = gst_caps_new_simple ("audio/x-raw",
10754 "format", G_TYPE_STRING, "F32BE",
10755 "layout", G_TYPE_STRING, "interleaved", NULL);
10758 _codec ("Raw 24-bit PCM audio");
10759 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
10761 caps = gst_caps_new_simple ("audio/x-raw",
10762 "format", G_TYPE_STRING, "S24BE",
10763 "layout", G_TYPE_STRING, "interleaved", NULL);
10765 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
10766 _codec ("Raw 32-bit PCM audio");
10767 caps = gst_caps_new_simple ("audio/x-raw",
10768 "format", G_TYPE_STRING, "S32BE",
10769 "layout", G_TYPE_STRING, "interleaved", NULL);
10771 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
10772 _codec ("Mu-law audio");
10773 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
10775 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
10776 _codec ("A-law audio");
10777 caps = gst_caps_new_empty_simple ("audio/x-alaw");
10781 _codec ("Microsoft ADPCM");
10782 /* Microsoft ADPCM-ACM code 2 */
10783 caps = gst_caps_new_simple ("audio/x-adpcm",
10784 "layout", G_TYPE_STRING, "microsoft", NULL);
10788 _codec ("DVI/IMA ADPCM");
10789 caps = gst_caps_new_simple ("audio/x-adpcm",
10790 "layout", G_TYPE_STRING, "dvi", NULL);
10794 _codec ("DVI/Intel IMA ADPCM");
10795 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
10796 caps = gst_caps_new_simple ("audio/x-adpcm",
10797 "layout", G_TYPE_STRING, "quicktime", NULL);
10801 /* MPEG layer 3, CBR only (pre QT4.1) */
10802 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
10803 _codec ("MPEG-1 layer 3");
10804 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
10805 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
10806 "mpegversion", G_TYPE_INT, 1, NULL);
10809 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
10810 _codec ("EAC-3 audio");
10811 caps = gst_caps_new_simple ("audio/x-eac3",
10812 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10813 stream->sampled = TRUE;
10815 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
10816 _codec ("AC-3 audio");
10817 caps = gst_caps_new_simple ("audio/x-ac3",
10818 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10819 stream->sampled = TRUE;
10821 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
10823 caps = gst_caps_new_simple ("audio/x-mace",
10824 "maceversion", G_TYPE_INT, 3, NULL);
10826 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
10828 caps = gst_caps_new_simple ("audio/x-mace",
10829 "maceversion", G_TYPE_INT, 6, NULL);
10831 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
10833 caps = gst_caps_new_empty_simple ("application/ogg");
10835 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
10836 _codec ("DV audio");
10837 caps = gst_caps_new_empty_simple ("audio/x-dv");
10839 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
10840 _codec ("MPEG-4 AAC audio");
10841 caps = gst_caps_new_simple ("audio/mpeg",
10842 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
10843 "stream-format", G_TYPE_STRING, "raw", NULL);
10845 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
10846 _codec ("QDesign Music");
10847 caps = gst_caps_new_empty_simple ("audio/x-qdm");
10849 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
10850 _codec ("QDesign Music v.2");
10851 /* FIXME: QDesign music version 2 (no constant) */
10852 if (FALSE && data) {
10853 caps = gst_caps_new_simple ("audio/x-qdm2",
10854 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
10855 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
10856 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
10858 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
10861 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
10862 _codec ("GSM audio");
10863 caps = gst_caps_new_empty_simple ("audio/x-gsm");
10865 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
10866 _codec ("AMR audio");
10867 caps = gst_caps_new_empty_simple ("audio/AMR");
10869 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
10870 _codec ("AMR-WB audio");
10871 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
10873 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
10874 _codec ("Quicktime IMA ADPCM");
10875 caps = gst_caps_new_simple ("audio/x-adpcm",
10876 "layout", G_TYPE_STRING, "quicktime", NULL);
10878 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
10879 _codec ("Apple lossless audio");
10880 caps = gst_caps_new_empty_simple ("audio/x-alac");
10882 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
10883 _codec ("QualComm PureVoice");
10884 caps = gst_caps_from_string ("audio/qcelp");
10888 caps = gst_caps_new_empty_simple ("audio/x-wma");
10890 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
10895 GstAudioFormat format;
10898 FLAG_IS_FLOAT = 0x1,
10899 FLAG_IS_BIG_ENDIAN = 0x2,
10900 FLAG_IS_SIGNED = 0x4,
10901 FLAG_IS_PACKED = 0x8,
10902 FLAG_IS_ALIGNED_HIGH = 0x10,
10903 FLAG_IS_NON_INTERLEAVED = 0x20
10905 _codec ("Raw LPCM audio");
10907 if (data && len >= 56) {
10908 depth = QT_UINT32 (data + 40);
10909 flags = QT_UINT32 (data + 44);
10910 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
10912 if ((flags & FLAG_IS_FLOAT) == 0) {
10917 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
10918 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
10919 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
10920 caps = gst_caps_new_simple ("audio/x-raw",
10921 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
10922 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
10923 "non-interleaved" : "interleaved", NULL);
10930 if (flags & FLAG_IS_BIG_ENDIAN)
10931 format = GST_AUDIO_FORMAT_F64BE;
10933 format = GST_AUDIO_FORMAT_F64LE;
10935 if (flags & FLAG_IS_BIG_ENDIAN)
10936 format = GST_AUDIO_FORMAT_F32BE;
10938 format = GST_AUDIO_FORMAT_F32LE;
10940 caps = gst_caps_new_simple ("audio/x-raw",
10941 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
10942 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
10943 "non-interleaved" : "interleaved", NULL);
10947 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
10951 char *s, fourstr[5];
10953 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10954 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
10955 caps = gst_caps_new_empty_simple (s);
10961 GstCaps *templ_caps =
10962 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
10963 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
10964 gst_caps_unref (caps);
10965 gst_caps_unref (templ_caps);
10966 caps = intersection;
10969 /* enable clipping for raw audio streams */
10970 s = gst_caps_get_structure (caps, 0);
10971 name = gst_structure_get_name (s);
10972 if (g_str_has_prefix (name, "audio/x-raw")) {
10973 stream->need_clip = TRUE;
10974 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
10975 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
10981 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10982 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
10986 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
10989 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
10990 _codec ("DVD subtitle");
10991 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
10993 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
10994 _codec ("Quicktime timed text");
10996 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
10997 _codec ("3GPP timed text");
10999 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
11001 /* actual text piece needs to be extracted */
11002 stream->need_process = TRUE;
11006 char *s, fourstr[5];
11008 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11009 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
11010 caps = gst_caps_new_empty_simple (s);
11018 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11019 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11024 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
11025 _codec ("MPEG 1 video");
11026 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11027 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);