2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 * SECTION:element-qtdemux
28 * Demuxes a .mov file into raw or compressed audio and/or video streams.
30 * This element supports both push and pull-based scheduling, depending on the
31 * capabilities of the upstream elements.
34 * <title>Example launch line</title>
36 * gst-launch filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
37 * ]| Play (parse and decode) a .mov file and try to output it to
38 * an automatically detected soundcard and videosink. If the MOV file contains
39 * compressed audio or video data, this will only work if you have the
40 * right decoder elements/plugins installed.
43 * Last reviewed on 2006-12-29 (0.10.5)
50 #include "gst/gst-i18n-plugin.h"
52 #include <glib/gprintf.h>
53 #include <gst/tag/tag.h>
54 #include <gst/audio/audio.h>
56 #include "qtatomparser.h"
57 #include "qtdemux_types.h"
58 #include "qtdemux_dump.h"
59 #include "qtdemux_fourcc.h"
60 #include "qtdemux_lang.h"
62 #include "qtpalette.h"
64 #include "gst/riff/riff-media.h"
65 #include "gst/riff/riff-read.h"
67 #include <gst/pbutils/pbutils.h>
77 /* max. size considered 'sane' for non-mdat atoms */
78 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
80 /* if the sample index is larger than this, something is likely wrong */
81 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
83 /* For converting qt creation times to unix epoch times */
84 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
85 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
86 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
87 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
89 GST_DEBUG_CATEGORY (qtdemux_debug);
91 /*typedef struct _QtNode QtNode; */
92 typedef struct _QtDemuxSegment QtDemuxSegment;
93 typedef struct _QtDemuxSample QtDemuxSample;
102 struct _QtDemuxSample
105 gint32 pts_offset; /* Add this value to timestamp to get the pts */
107 guint64 timestamp; /* DTS In mov time */
108 guint32 duration; /* In mov time */
109 gboolean keyframe; /* TRUE when this packet is a keyframe */
112 /* timestamp is the DTS */
113 #define QTSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
114 GST_SECOND, (stream)->timescale)
115 /* timestamp + offset is the PTS */
116 #define QTSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
117 (sample)->pts_offset, GST_SECOND, (stream)->timescale)
118 /* timestamp + duration - dts is the duration */
119 #define QTSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
120 (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
122 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
125 * Quicktime has tracks and segments. A track is a continuous piece of
126 * multimedia content. The track is not always played from start to finish but
127 * instead, pieces of the track are 'cut out' and played in sequence. This is
128 * what the segments do.
130 * Inside the track we have keyframes (K) and delta frames. The track has its
131 * own timing, which starts from 0 and extends to end. The position in the track
132 * is called the media_time.
134 * The segments now describe the pieces that should be played from this track
135 * and are basically tupples of media_time/duration/rate entries. We can have
136 * multiple segments and they are all played after one another. An example:
138 * segment 1: media_time: 1 second, duration: 1 second, rate 1
139 * segment 2: media_time: 3 second, duration: 2 second, rate 2
141 * To correctly play back this track, one must play: 1 second of media starting
142 * from media_time 1 followed by 2 seconds of media starting from media_time 3
145 * Each of the segments will be played at a specific time, the first segment at
146 * time 0, the second one after the duration of the first one, etc.. Note that
147 * the time in resulting playback is not identical to the media_time of the
150 * Visually, assuming the track has 4 second of media_time:
153 * .-----------------------------------------------------------.
154 * track: | K.....K.........K........K.......K.......K...........K... |
155 * '-----------------------------------------------------------'
157 * .------------^ ^ .----------^ ^
158 * / .-------------' / .------------------'
160 * .--------------. .--------------.
161 * | segment 1 | | segment 2 |
162 * '--------------' '--------------'
164 * The challenge here is to cut out the right pieces of the track for each of
165 * the playback segments. This fortunatly can easily be done with the SEGMENT
166 * events of gstreamer.
168 * For playback of segment 1, we need to provide the decoder with the keyframe
169 * (a), in the above figure, but we must instruct it only to output the decoded
170 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
171 * position set to the time of the segment: 0.
173 * We then proceed to push data from keyframe (a) to frame (b). The decoder
174 * decodes but clips all before media_time 1.
176 * After finishing a segment, we push out a new SEGMENT event with the clipping
177 * boundaries of the new data.
179 * This is a good usecase for the GStreamer accumulated SEGMENT events.
182 struct _QtDemuxSegment
184 /* global time and duration, all gst time */
188 /* media time of trak, all gst time */
194 struct _QtDemuxStream
203 /* if the stream has a redirect URI in its headers, we store it here */
210 guint64 duration; /* in timescale */
214 gchar lang_id[4]; /* ISO 639-2T language code */
218 QtDemuxSample *samples;
219 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
220 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
221 the framerate, in timescale units */
223 /* if we use chunks or samples */
235 /* Numerator/denominator framerate */
238 guint16 bits_per_sample;
239 guint16 color_table_id;
244 guint samples_per_packet;
245 guint samples_per_frame;
246 guint bytes_per_packet;
247 guint bytes_per_sample;
248 guint bytes_per_frame;
252 gboolean use_allocator;
253 GstAllocator *allocator;
254 GstAllocationParams params;
256 /* when a discontinuity is pending */
259 /* list of buffers to push first */
262 /* if we need to clip this buffer. This is only needed for uncompressed
266 /* buffer needs some custom processing, e.g. subtitles */
267 gboolean need_process;
269 /* current position */
270 guint32 segment_index;
271 guint32 sample_index;
272 guint64 time_position; /* in gst time */
274 /* the Gst segment we are processing out, used for clipping */
277 /* last GstFlowReturn */
278 GstFlowReturn last_ret;
280 /* quicktime segments */
282 QtDemuxSegment *segments;
287 GstTagList *pending_tags;
288 gboolean send_global_tags;
290 GstEvent *pending_event;
300 gboolean chunks_are_chunks;
304 GstByteReader co_chunk;
306 guint32 current_chunk;
308 guint32 samples_per_chunk;
309 guint32 stco_sample_index;
311 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
314 guint32 n_samples_per_chunk;
315 guint32 stsc_chunk_index;
316 guint32 stsc_sample_index;
317 guint64 chunk_offset;
320 guint32 stts_samples;
321 guint32 n_sample_times;
322 guint32 stts_sample_index;
324 guint32 stts_duration;
326 gboolean stss_present;
327 guint32 n_sample_syncs;
330 gboolean stps_present;
331 guint32 n_sample_partial_syncs;
334 gboolean ctts_present;
335 guint32 n_composition_times;
337 guint32 ctts_sample_index;
342 gboolean parsed_trex;
343 guint32 def_sample_duration;
344 guint32 def_sample_size;
345 guint32 def_sample_flags;
350 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
351 QTDEMUX_STATE_HEADER, /* Parsing the header */
352 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
353 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
356 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
357 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
358 guint32 fourcc, GstByteReader * parser);
359 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
360 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
361 guint32 fourcc, GstByteReader * parser);
363 static GstStaticPadTemplate gst_qtdemux_sink_template =
364 GST_STATIC_PAD_TEMPLATE ("sink",
367 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
371 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
372 GST_STATIC_PAD_TEMPLATE ("video_%u",
375 GST_STATIC_CAPS_ANY);
377 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
378 GST_STATIC_PAD_TEMPLATE ("audio_%u",
381 GST_STATIC_CAPS_ANY);
383 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
384 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
387 GST_STATIC_CAPS_ANY);
389 #define gst_qtdemux_parent_class parent_class
390 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
392 static void gst_qtdemux_dispose (GObject * object);
395 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
398 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
399 QtDemuxStream * str, gint64 media_offset);
402 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
403 static GstIndex *gst_qtdemux_get_index (GstElement * element);
405 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
406 GstStateChange transition);
407 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
408 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
409 GstObject * parent, GstPadMode mode, gboolean active);
411 static void gst_qtdemux_loop (GstPad * pad);
412 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
414 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
417 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
418 const guint8 * buffer, guint length);
419 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
420 const guint8 * buffer, guint length);
421 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
423 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
424 QtDemuxStream * stream, GNode * esds, GstTagList * list);
425 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
426 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
427 gchar ** codec_name);
428 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
429 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
430 gchar ** codec_name);
431 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
432 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
433 gchar ** codec_name);
434 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
435 QtDemuxStream * stream, guint32 n);
436 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
439 gst_qtdemux_class_init (GstQTDemuxClass * klass)
441 GObjectClass *gobject_class;
442 GstElementClass *gstelement_class;
444 gobject_class = (GObjectClass *) klass;
445 gstelement_class = (GstElementClass *) klass;
447 parent_class = g_type_class_peek_parent (klass);
449 gobject_class->dispose = gst_qtdemux_dispose;
451 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
453 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
454 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
457 gst_tag_register_musicbrainz_tags ();
459 gst_element_class_add_pad_template (gstelement_class,
460 gst_static_pad_template_get (&gst_qtdemux_sink_template));
461 gst_element_class_add_pad_template (gstelement_class,
462 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
463 gst_element_class_add_pad_template (gstelement_class,
464 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
465 gst_element_class_add_pad_template (gstelement_class,
466 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
467 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
469 "Demultiplex a QuickTime file into audio and video streams",
470 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
472 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
477 gst_qtdemux_init (GstQTDemux * qtdemux)
480 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
481 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
482 gst_pad_set_activatemode_function (qtdemux->sinkpad,
483 qtdemux_sink_activate_mode);
484 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
485 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
486 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
488 qtdemux->state = QTDEMUX_STATE_INITIAL;
489 qtdemux->pullbased = FALSE;
490 qtdemux->posted_redirect = FALSE;
491 qtdemux->neededbytes = 16;
493 qtdemux->adapter = gst_adapter_new ();
495 qtdemux->first_mdat = -1;
496 qtdemux->got_moov = FALSE;
497 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
498 qtdemux->mdatbuffer = NULL;
499 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
501 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
505 gst_qtdemux_dispose (GObject * object)
507 GstQTDemux *qtdemux = GST_QTDEMUX (object);
509 if (qtdemux->adapter) {
510 g_object_unref (G_OBJECT (qtdemux->adapter));
511 qtdemux->adapter = NULL;
514 G_OBJECT_CLASS (parent_class)->dispose (object);
518 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
520 if (qtdemux->posted_redirect) {
521 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
522 (_("This file contains no playable streams.")),
523 ("no known streams found, a redirect message has been posted"));
525 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
526 (_("This file contains no playable streams.")),
527 ("no known streams found"));
532 _gst_buffer_copy_into_mem (GstBuffer * dest, gsize offset, const guint8 * src,
537 g_return_if_fail (gst_buffer_is_writable (dest));
539 bsize = gst_buffer_get_size (dest);
540 g_return_if_fail (bsize >= offset + size);
542 gst_buffer_fill (dest, offset, src, size);
546 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
550 buf = gst_buffer_new ();
551 gst_buffer_append_memory (buf,
552 gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
553 mem, size, 0, size, mem, free_func));
559 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
566 if (G_UNLIKELY (size == 0)) {
568 GstBuffer *tmp = NULL;
570 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
571 if (ret != GST_FLOW_OK)
574 gst_buffer_map (tmp, &map, GST_MAP_READ);
575 size = QT_UINT32 (map.data);
576 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
578 gst_buffer_unmap (tmp, &map);
579 gst_buffer_unref (tmp);
582 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
583 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
584 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
585 /* we're pulling header but already got most interesting bits,
586 * so never mind the rest (e.g. tags) (that much) */
587 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
591 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
592 (_("This file is invalid and cannot be played.")),
593 ("atom has bogus size %" G_GUINT64_FORMAT, size));
594 return GST_FLOW_ERROR;
598 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
600 if (G_UNLIKELY (flow != GST_FLOW_OK))
603 bsize = gst_buffer_get_size (*buf);
604 /* Catch short reads - we don't want any partial atoms */
605 if (G_UNLIKELY (bsize < size)) {
606 GST_WARNING_OBJECT (qtdemux,
607 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
608 gst_buffer_unref (*buf);
618 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
619 GstFormat dest_format, gint64 * dest_value)
622 QtDemuxStream *stream = gst_pad_get_element_private (pad);
623 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
626 if (stream->subtype != FOURCC_vide) {
631 switch (src_format) {
632 case GST_FORMAT_TIME:
633 switch (dest_format) {
634 case GST_FORMAT_BYTES:{
635 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
639 *dest_value = stream->samples[index].offset;
641 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
642 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
643 GST_TIME_ARGS (src_value), *dest_value);
651 case GST_FORMAT_BYTES:
652 switch (dest_format) {
653 case GST_FORMAT_TIME:{
655 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
662 gst_util_uint64_scale (stream->samples[index].timestamp,
663 GST_SECOND, stream->timescale);
664 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
665 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
666 src_value, GST_TIME_ARGS (*dest_value));
679 gst_object_unref (qtdemux);
686 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
690 *duration = GST_CLOCK_TIME_NONE;
692 if (qtdemux->duration != 0) {
693 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
694 *duration = gst_util_uint64_scale (qtdemux->duration,
695 GST_SECOND, qtdemux->timescale);
702 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
705 gboolean res = FALSE;
706 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
708 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
710 switch (GST_QUERY_TYPE (query)) {
711 case GST_QUERY_POSITION:
712 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
713 gst_query_set_position (query, GST_FORMAT_TIME,
714 qtdemux->segment.position);
718 case GST_QUERY_DURATION:{
721 gst_query_parse_duration (query, &fmt, NULL);
722 if (fmt == GST_FORMAT_TIME) {
723 /* First try to query upstream */
724 res = gst_pad_query_default (pad, parent, query);
726 gint64 duration = -1;
728 gst_qtdemux_get_duration (qtdemux, &duration);
730 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
737 case GST_QUERY_CONVERT:{
738 GstFormat src_fmt, dest_fmt;
739 gint64 src_value, dest_value = 0;
741 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
743 res = gst_qtdemux_src_convert (pad,
744 src_fmt, src_value, dest_fmt, &dest_value);
746 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
751 case GST_QUERY_FORMATS:
752 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
755 case GST_QUERY_SEEKING:{
759 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
760 if (fmt == GST_FORMAT_TIME) {
761 gint64 duration = -1;
763 gst_qtdemux_get_duration (qtdemux, &duration);
765 if (!qtdemux->pullbased) {
768 /* we might be able with help from upstream */
770 q = gst_query_new_seeking (GST_FORMAT_BYTES);
771 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
772 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
773 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
777 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
783 res = gst_pad_query_default (pad, parent, query);
791 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
793 if (G_LIKELY (stream->pad)) {
794 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
795 GST_DEBUG_PAD_NAME (stream->pad));
797 if (G_UNLIKELY (stream->pending_tags)) {
798 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
799 stream->pending_tags);
800 gst_pad_push_event (stream->pad,
801 gst_event_new_tag ("GstDemuxer", stream->pending_tags));
802 stream->pending_tags = NULL;
805 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
806 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
808 gst_pad_push_event (stream->pad,
809 gst_event_new_tag ("GstDemuxer",
810 gst_tag_list_copy (qtdemux->tag_list)));
811 stream->send_global_tags = FALSE;
816 /* push event on all source pads; takes ownership of the event */
818 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
821 gboolean has_valid_stream = FALSE;
822 GstEventType etype = GST_EVENT_TYPE (event);
824 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
825 GST_EVENT_TYPE_NAME (event));
827 for (n = 0; n < qtdemux->n_streams; n++) {
829 QtDemuxStream *stream = qtdemux->streams[n];
831 if ((pad = stream->pad)) {
832 has_valid_stream = TRUE;
834 if (etype == GST_EVENT_EOS) {
835 /* let's not send twice */
836 if (stream->sent_eos)
838 stream->sent_eos = TRUE;
841 gst_pad_push_event (pad, gst_event_ref (event));
845 gst_event_unref (event);
847 /* if it is EOS and there are no pads, post an error */
848 if (!has_valid_stream && etype == GST_EVENT_EOS) {
849 gst_qtdemux_post_no_playable_stream_error (qtdemux);
853 /* push a pending newsegment event, if any from the streaming thread */
855 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
857 if (qtdemux->pending_newsegment) {
858 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
859 qtdemux->pending_newsegment = NULL;
869 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
871 if (s1->timestamp > *media_time)
877 /* find the index of the sample that includes the data for @media_time using a
878 * binary search. Only to be called in optimized cases of linear search below.
880 * Returns the index of the sample.
883 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
886 QtDemuxSample *result;
889 /* convert media_time to mov format */
891 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
893 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
894 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
895 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
897 if (G_LIKELY (result))
898 index = result - str->samples;
907 /* find the index of the sample that includes the data for @media_offset using a
910 * Returns the index of the sample.
913 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
914 QtDemuxStream * str, gint64 media_offset)
916 QtDemuxSample *result = str->samples;
919 if (result == NULL || str->n_samples == 0)
922 if (media_offset == result->offset)
926 while (index < str->n_samples - 1) {
927 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
930 if (media_offset < result->offset)
941 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
946 /* find the index of the sample that includes the data for @media_time using a
947 * linear search, and keeping in mind that not all samples may have been parsed
948 * yet. If possible, it will delegate to binary search.
950 * Returns the index of the sample.
953 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
959 /* convert media_time to mov format */
961 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
963 if (mov_time == str->samples[0].timestamp)
966 /* use faster search if requested time in already parsed range */
967 if (str->stbl_index >= 0 &&
968 mov_time <= str->samples[str->stbl_index].timestamp)
969 return gst_qtdemux_find_index (qtdemux, str, media_time);
971 while (index < str->n_samples - 1) {
972 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
975 if (mov_time < str->samples[index + 1].timestamp)
985 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
990 /* find the index of the keyframe needed to decode the sample at @index
993 * Returns the index of the keyframe.
996 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
999 guint32 new_index = index;
1001 if (index >= str->n_samples) {
1002 new_index = str->n_samples;
1006 /* all keyframes, return index */
1007 if (str->all_keyframe) {
1012 /* else go back until we have a keyframe */
1014 if (str->samples[new_index].keyframe)
1024 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1025 "gave %u", index, new_index);
1030 /* find the segment for @time_position for @stream
1032 * Returns -1 if the segment cannot be found.
1035 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1036 guint64 time_position)
1041 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1042 GST_TIME_ARGS (time_position));
1044 /* find segment corresponding to time_position if we are looking
1047 for (i = 0; i < stream->n_segments; i++) {
1048 QtDemuxSegment *segment = &stream->segments[i];
1050 GST_LOG_OBJECT (qtdemux,
1051 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1052 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1054 /* For the last segment we include stop_time in the last segment */
1055 if (i < stream->n_segments - 1) {
1056 if (segment->time <= time_position && time_position < segment->stop_time) {
1057 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1062 if (segment->time <= time_position && time_position <= segment->stop_time) {
1063 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1072 /* move the stream @str to the sample position @index.
1074 * Updates @str->sample_index and marks discontinuity if needed.
1077 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1080 /* no change needed */
1081 if (index == str->sample_index)
1084 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1087 /* position changed, we have a discont */
1088 str->sample_index = index;
1089 /* Each time we move in the stream we store the position where we are
1091 str->from_sample = index;
1092 str->discont = TRUE;
1096 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1097 gint64 * key_time, gint64 * key_offset)
1100 gint64 min_byte_offset = -1;
1103 min_offset = desired_time;
1105 /* for each stream, find the index of the sample in the segment
1106 * and move back to the previous keyframe. */
1107 for (n = 0; n < qtdemux->n_streams; n++) {
1109 guint32 index, kindex;
1111 guint64 media_start;
1114 QtDemuxSegment *seg;
1116 str = qtdemux->streams[n];
1118 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1119 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1121 /* segment not found, continue with normal flow */
1125 /* get segment and time in the segment */
1126 seg = &str->segments[seg_idx];
1127 seg_time = desired_time - seg->time;
1129 /* get the media time in the segment */
1130 media_start = seg->media_start + seg_time;
1132 /* get the index of the sample with media time */
1133 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1134 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1135 " at offset %" G_GUINT64_FORMAT,
1136 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1138 /* find previous keyframe */
1139 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1141 /* if the keyframe is at a different position, we need to update the
1142 * requested seek time */
1143 if (index != kindex) {
1146 /* get timestamp of keyframe */
1148 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1150 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT
1151 " at offset %" G_GUINT64_FORMAT,
1152 kindex, GST_TIME_ARGS (media_time), str->samples[kindex].offset);
1154 /* keyframes in the segment get a chance to change the
1155 * desired_offset. keyframes out of the segment are
1157 if (media_time >= seg->media_start) {
1160 /* this keyframe is inside the segment, convert back to
1162 seg_time = (media_time - seg->media_start) + seg->time;
1163 if (seg_time < min_offset)
1164 min_offset = seg_time;
1168 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1169 min_byte_offset = str->samples[index].offset;
1173 *key_time = min_offset;
1175 *key_offset = min_byte_offset;
1179 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1180 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1184 g_return_val_if_fail (format != NULL, FALSE);
1185 g_return_val_if_fail (cur != NULL, FALSE);
1186 g_return_val_if_fail (stop != NULL, FALSE);
1188 if (*format == GST_FORMAT_TIME)
1192 if (cur_type != GST_SEEK_TYPE_NONE)
1193 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1194 if (res && stop_type != GST_SEEK_TYPE_NONE)
1195 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1198 *format = GST_FORMAT_TIME;
1203 /* perform seek in push based mode:
1204 find BYTE position to move to based on time and delegate to upstream
1207 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1212 GstSeekType cur_type, stop_type;
1217 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1219 gst_event_parse_seek (event, &rate, &format, &flags,
1220 &cur_type, &cur, &stop_type, &stop);
1222 /* FIXME, always play to the end */
1225 /* only forward streaming and seeking is possible */
1227 goto unsupported_seek;
1229 /* convert to TIME if needed and possible */
1230 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1234 /* find reasonable corresponding BYTE position,
1235 * also try to mind about keyframes, since we can not go back a bit for them
1237 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1242 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1243 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1246 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1247 GST_DEBUG_OBJECT (qtdemux,
1248 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1249 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1250 GST_OBJECT_LOCK (qtdemux);
1251 qtdemux->requested_seek_time = cur;
1252 qtdemux->seek_offset = byte_cur;
1253 GST_OBJECT_UNLOCK (qtdemux);
1256 /* BYTE seek event */
1257 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1259 res = gst_pad_push_event (qtdemux->sinkpad, event);
1266 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1272 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1277 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1282 /* perform the seek.
1284 * We set all segment_indexes in the streams to unknown and
1285 * adjust the time_position to the desired position. this is enough
1286 * to trigger a segment switch in the streaming thread to start
1287 * streaming from the desired position.
1289 * Keyframe seeking is a little more complicated when dealing with
1290 * segments. Ideally we want to move to the previous keyframe in
1291 * the segment but there might not be a keyframe in the segment. In
1292 * fact, none of the segments could contain a keyframe. We take a
1293 * practical approach: seek to the previous keyframe in the segment,
1294 * if there is none, seek to the beginning of the segment.
1296 * Called with STREAM_LOCK
1299 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1301 gint64 desired_offset;
1304 desired_offset = segment->position;
1306 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1307 GST_TIME_ARGS (desired_offset));
1309 /* may not have enough fragmented info to do this adjustment,
1310 * and we can't scan (and probably should not) at this time with
1311 * possibly flushing upstream */
1312 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1315 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1316 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1317 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1318 desired_offset = min_offset;
1321 /* and set all streams to the final position */
1322 for (n = 0; n < qtdemux->n_streams; n++) {
1323 QtDemuxStream *stream = qtdemux->streams[n];
1325 stream->time_position = desired_offset;
1326 stream->sample_index = -1;
1327 stream->segment_index = -1;
1328 stream->last_ret = GST_FLOW_OK;
1329 stream->sent_eos = FALSE;
1331 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1332 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1334 segment->position = desired_offset;
1335 segment->time = desired_offset;
1337 /* we stop at the end */
1338 if (segment->stop == -1)
1339 segment->stop = segment->duration;
1344 /* do a seek in pull based mode */
1346 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1351 GstSeekType cur_type, stop_type;
1355 GstSegment seeksegment;
1359 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1361 gst_event_parse_seek (event, &rate, &format, &flags,
1362 &cur_type, &cur, &stop_type, &stop);
1364 /* we have to have a format as the segment format. Try to convert
1366 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1370 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1372 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1376 flush = flags & GST_SEEK_FLAG_FLUSH;
1378 /* stop streaming, either by flushing or by pausing the task */
1380 /* unlock upstream pull_range */
1381 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1382 /* make sure out loop function exits */
1383 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1385 /* non flushing seek, pause the task */
1386 gst_pad_pause_task (qtdemux->sinkpad);
1389 /* wait for streaming to finish */
1390 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1392 /* copy segment, we need this because we still need the old
1393 * segment when we close the current segment. */
1394 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1397 /* configure the segment with the seek variables */
1398 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1399 gst_segment_do_seek (&seeksegment, rate, format, flags,
1400 cur_type, cur, stop_type, stop, &update);
1403 /* now do the seek, this actually never returns FALSE */
1404 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1406 /* prepare for streaming again */
1408 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop (TRUE));
1409 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop (TRUE));
1412 /* commit the new segment */
1413 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1415 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1416 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1417 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1418 qtdemux->segment.format, qtdemux->segment.position));
1421 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1422 for (i = 0; i < qtdemux->n_streams; i++)
1423 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1425 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1426 qtdemux->sinkpad, NULL);
1428 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1435 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1441 qtdemux_ensure_index (GstQTDemux * qtdemux)
1445 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1447 /* Build complete index */
1448 for (i = 0; i < qtdemux->n_streams; i++) {
1449 QtDemuxStream *stream = qtdemux->streams[i];
1451 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1459 GST_LOG_OBJECT (qtdemux,
1460 "Building complete index of stream %u for seeking failed!", i);
1466 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1469 gboolean res = TRUE;
1470 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1472 switch (GST_EVENT_TYPE (event)) {
1473 case GST_EVENT_SEEK:
1475 #ifndef GST_DISABLE_GST_DEBUG
1476 GstClockTime ts = gst_util_get_timestamp ();
1478 /* Build complete index for seeking;
1479 * if not a fragmented file at least */
1480 if (!qtdemux->fragmented)
1481 if (!qtdemux_ensure_index (qtdemux))
1483 #ifndef GST_DISABLE_GST_DEBUG
1484 ts = gst_util_get_timestamp () - ts;
1485 GST_INFO_OBJECT (qtdemux,
1486 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1489 if (qtdemux->pullbased) {
1490 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1491 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1492 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1494 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1495 && !qtdemux->fragmented) {
1496 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1498 GST_DEBUG_OBJECT (qtdemux,
1499 "ignoring seek in push mode in current state");
1502 gst_event_unref (event);
1505 case GST_EVENT_NAVIGATION:
1507 gst_event_unref (event);
1510 res = gst_pad_event_default (pad, parent, event);
1520 GST_ERROR_OBJECT (qtdemux, "Index failed");
1521 gst_event_unref (event);
1527 /* stream/index return sample that is min/max w.r.t. byte position,
1528 * time is min/max w.r.t. time of samples,
1529 * the latter need not be time of the former sample */
1531 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1532 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1535 gint64 time, min_time;
1536 QtDemuxStream *stream;
1542 for (n = 0; n < qtdemux->n_streams; ++n) {
1545 gboolean set_sample;
1547 str = qtdemux->streams[n];
1554 i = str->n_samples - 1;
1557 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1558 if (str->samples[i].size &&
1559 ((fw && (str->samples[i].offset >= byte_pos)) ||
1561 (str->samples[i].offset + str->samples[i].size <=
1563 /* move stream to first available sample */
1565 gst_qtdemux_move_stream (qtdemux, str, i);
1568 /* determine min/max time */
1569 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1570 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1571 if (min_time == -1 || (!fw && time > min_time) ||
1572 (fw && time < min_time)) {
1575 /* determine stream with leading sample, to get its position */
1577 && (str->samples[i].offset < stream->samples[index].offset))
1579 && (str->samples[i].offset > stream->samples[index].offset))) {
1586 /* no sample for this stream, mark eos */
1588 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1600 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1603 GstQTDemux *demux = GST_QTDEMUX (parent);
1606 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1608 switch (GST_EVENT_TYPE (event)) {
1609 case GST_EVENT_SEGMENT:
1612 QtDemuxStream *stream;
1616 /* some debug output */
1617 gst_event_copy_segment (event, &segment);
1618 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1621 /* chain will send initial newsegment after pads have been added */
1622 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1623 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1627 /* we only expect a BYTE segment, e.g. following a seek */
1628 if (segment.format == GST_FORMAT_BYTES) {
1629 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1630 gint64 requested_seek_time;
1631 guint64 seek_offset;
1633 offset = segment.start;
1635 GST_OBJECT_LOCK (demux);
1636 requested_seek_time = demux->requested_seek_time;
1637 seek_offset = demux->seek_offset;
1638 demux->requested_seek_time = -1;
1639 demux->seek_offset = -1;
1640 GST_OBJECT_UNLOCK (demux);
1642 if (offset == seek_offset) {
1643 segment.start = requested_seek_time;
1645 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1646 NULL, (gint64 *) & segment.start);
1647 if ((gint64) segment.start < 0)
1651 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1652 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1653 NULL, (gint64 *) & segment.stop);
1654 /* keyframe seeking should already arrange for start >= stop,
1655 * but make sure in other rare cases */
1656 segment.stop = MAX (segment.stop, segment.start);
1659 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1663 /* accept upstream's notion of segment and distribute along */
1664 segment.time = segment.start;
1665 segment.duration = demux->segment.duration;
1666 segment.base = gst_segment_to_running_time (&demux->segment,
1667 GST_FORMAT_TIME, demux->segment.position);
1669 gst_segment_copy_into (&segment, &demux->segment);
1670 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
1671 gst_qtdemux_push_event (demux, gst_event_new_segment (&segment));
1673 /* clear leftover in current segment, if any */
1674 gst_adapter_clear (demux->adapter);
1675 /* set up streaming thread */
1676 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1677 demux->offset = offset;
1679 demux->todrop = stream->samples[idx].offset - offset;
1680 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1682 /* set up for EOS */
1683 demux->neededbytes = -1;
1687 gst_event_unref (event);
1692 case GST_EVENT_FLUSH_STOP:
1697 /* clean up, force EOS if no more info follows */
1698 gst_adapter_clear (demux->adapter);
1700 demux->neededbytes = -1;
1701 /* reset flow return, e.g. following seek */
1702 for (i = 0; i < demux->n_streams; i++) {
1703 demux->streams[i]->last_ret = GST_FLOW_OK;
1704 demux->streams[i]->sent_eos = FALSE;
1706 dur = demux->segment.duration;
1707 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1708 demux->segment.duration = dur;
1712 /* If we are in push mode, and get an EOS before we've seen any streams,
1713 * then error out - we have nowhere to send the EOS */
1714 if (!demux->pullbased) {
1716 gboolean has_valid_stream = FALSE;
1717 for (i = 0; i < demux->n_streams; i++) {
1718 if (demux->streams[i]->pad != NULL) {
1719 has_valid_stream = TRUE;
1723 if (!has_valid_stream)
1724 gst_qtdemux_post_no_playable_stream_error (demux);
1731 res = gst_pad_event_default (demux->sinkpad, parent, event);
1739 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1741 GstQTDemux *demux = GST_QTDEMUX (element);
1743 GST_OBJECT_LOCK (demux);
1744 if (demux->element_index)
1745 gst_object_unref (demux->element_index);
1747 demux->element_index = gst_object_ref (index);
1749 demux->element_index = NULL;
1751 GST_OBJECT_UNLOCK (demux);
1752 /* object lock might be taken again */
1754 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1755 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
1756 demux->element_index, demux->index_id);
1760 gst_qtdemux_get_index (GstElement * element)
1762 GstIndex *result = NULL;
1763 GstQTDemux *demux = GST_QTDEMUX (element);
1765 GST_OBJECT_LOCK (demux);
1766 if (demux->element_index)
1767 result = gst_object_ref (demux->element_index);
1768 GST_OBJECT_UNLOCK (demux);
1770 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1777 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1779 g_free ((gpointer) stream->stco.data);
1780 stream->stco.data = NULL;
1781 g_free ((gpointer) stream->stsz.data);
1782 stream->stsz.data = NULL;
1783 g_free ((gpointer) stream->stsc.data);
1784 stream->stsc.data = NULL;
1785 g_free ((gpointer) stream->stts.data);
1786 stream->stts.data = NULL;
1787 g_free ((gpointer) stream->stss.data);
1788 stream->stss.data = NULL;
1789 g_free ((gpointer) stream->stps.data);
1790 stream->stps.data = NULL;
1791 g_free ((gpointer) stream->ctts.data);
1792 stream->ctts.data = NULL;
1796 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
1798 if (stream->allocator)
1799 gst_object_unref (stream->allocator);
1800 while (stream->buffers) {
1801 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1802 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1805 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
1806 g_free (stream->samples);
1808 gst_caps_unref (stream->caps);
1809 g_free (stream->segments);
1810 if (stream->pending_tags)
1811 gst_tag_list_free (stream->pending_tags);
1812 g_free (stream->redirect_uri);
1813 /* free stbl sub-atoms */
1814 gst_qtdemux_stbl_free (stream);
1818 static GstStateChangeReturn
1819 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1821 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1822 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1824 switch (transition) {
1825 case GST_STATE_CHANGE_PAUSED_TO_READY:
1831 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1833 switch (transition) {
1834 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1837 qtdemux->state = QTDEMUX_STATE_INITIAL;
1838 qtdemux->neededbytes = 16;
1839 qtdemux->todrop = 0;
1840 qtdemux->pullbased = FALSE;
1841 qtdemux->posted_redirect = FALSE;
1842 qtdemux->offset = 0;
1843 qtdemux->first_mdat = -1;
1844 qtdemux->header_size = 0;
1845 qtdemux->got_moov = FALSE;
1846 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1847 if (qtdemux->mdatbuffer)
1848 gst_buffer_unref (qtdemux->mdatbuffer);
1849 qtdemux->mdatbuffer = NULL;
1850 if (qtdemux->comp_brands)
1851 gst_buffer_unref (qtdemux->comp_brands);
1852 qtdemux->comp_brands = NULL;
1853 if (qtdemux->tag_list)
1854 gst_tag_list_free (qtdemux->tag_list);
1855 qtdemux->tag_list = NULL;
1857 if (qtdemux->element_index)
1858 gst_object_unref (qtdemux->element_index);
1859 qtdemux->element_index = NULL;
1861 gst_adapter_clear (qtdemux->adapter);
1862 for (n = 0; n < qtdemux->n_streams; n++) {
1863 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1864 qtdemux->streams[n] = NULL;
1866 qtdemux->major_brand = 0;
1867 qtdemux->n_streams = 0;
1868 qtdemux->n_video_streams = 0;
1869 qtdemux->n_audio_streams = 0;
1870 qtdemux->n_sub_streams = 0;
1871 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1872 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1873 qtdemux->seek_offset = 0;
1874 qtdemux->upstream_seekable = FALSE;
1875 qtdemux->upstream_size = 0;
1886 qtdemux_post_global_tags (GstQTDemux * qtdemux)
1888 if (qtdemux->tag_list) {
1889 /* all header tags ready and parsed, push them */
1890 GST_INFO_OBJECT (qtdemux, "posting global tags: %" GST_PTR_FORMAT,
1892 /* post now, send event on pads later */
1893 gst_element_post_message (GST_ELEMENT (qtdemux),
1894 gst_message_new_tag (GST_OBJECT (qtdemux),
1895 gst_tag_list_copy (qtdemux->tag_list)));
1900 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1902 /* counts as header data */
1903 qtdemux->header_size += length;
1905 /* only consider at least a sufficiently complete ftyp atom */
1909 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1910 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1911 GST_FOURCC_ARGS (qtdemux->major_brand));
1912 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1913 _gst_buffer_copy_into_mem (buf, 0, buffer + 16, length - 16);
1918 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
1920 /* Strip out bogus fields */
1922 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
1924 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
1926 if (qtdemux->tag_list) {
1927 /* prioritize native tags using _KEEP mode */
1928 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
1929 gst_tag_list_free (taglist);
1931 qtdemux->tag_list = taglist;
1936 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1938 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
1939 0x97, 0xA9, 0x42, 0xE8,
1940 0x9C, 0x71, 0x99, 0x94,
1941 0x91, 0xE3, 0xAF, 0xAC
1945 /* counts as header data */
1946 qtdemux->header_size += length;
1948 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
1950 if (length <= offset + 16) {
1951 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
1955 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
1957 GstTagList *taglist;
1959 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
1960 length - offset - 16, NULL);
1961 taglist = gst_tag_list_from_xmp_buffer (buf);
1962 gst_buffer_unref (buf);
1964 qtdemux_handle_xmp_taglist (qtdemux, taglist);
1967 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
1971 /* caller verifies at least 8 bytes in buf */
1973 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1974 guint64 * plength, guint32 * pfourcc)
1979 length = QT_UINT32 (data);
1980 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1981 fourcc = QT_FOURCC (data + 4);
1982 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1985 length = G_MAXUINT32;
1986 } else if (length == 1 && size >= 16) {
1987 /* this means we have an extended size, which is the 64 bit value of
1988 * the next 8 bytes */
1989 length = QT_UINT64 (data + 8);
1990 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2000 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2002 guint32 version = 0;
2003 guint64 duration = 0;
2005 if (!gst_byte_reader_get_uint32_be (br, &version))
2010 if (!gst_byte_reader_get_uint64_be (br, &duration))
2015 if (!gst_byte_reader_get_uint32_be (br, &dur))
2020 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2021 qtdemux->duration = duration;
2027 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2033 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2034 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2036 if (!stream->parsed_trex && qtdemux->moov_node) {
2038 GstByteReader trex_data;
2040 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2042 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2045 guint32 id = 0, dur = 0, size = 0, flags = 0;
2047 /* skip version/flags */
2048 if (!gst_byte_reader_skip (&trex_data, 4))
2050 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2052 if (id != stream->track_id)
2054 /* sample description index; ignore */
2055 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2057 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2059 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2061 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2064 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2065 "duration %d, size %d, flags 0x%x", stream->track_id,
2068 stream->parsed_trex = TRUE;
2069 stream->def_sample_duration = dur;
2070 stream->def_sample_size = size;
2071 stream->def_sample_flags = flags;
2074 /* iterate all siblings */
2075 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2081 *ds_duration = stream->def_sample_duration;
2082 *ds_size = stream->def_sample_size;
2083 *ds_size = stream->def_sample_size;
2085 /* even then, above values are better than random ... */
2086 if (G_UNLIKELY (!stream->parsed_trex)) {
2087 GST_WARNING_OBJECT (qtdemux,
2088 "failed to find fragment defaults for stream %d", stream->track_id);
2096 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2097 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2098 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2099 gint64 * base_offset, gint64 * running_offset)
2102 gint32 data_offset = 0;
2103 guint32 flags = 0, first_flags = 0, samples_count = 0;
2106 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2107 QtDemuxSample *sample;
2108 gboolean ismv = FALSE;
2110 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2111 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2112 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2115 /* presence of stss or not can't really tell us much,
2116 * and flags and so on tend to be marginally reliable in these files */
2117 if (stream->subtype == FOURCC_soun) {
2118 GST_DEBUG_OBJECT (qtdemux,
2119 "sound track in fragmented file; marking all keyframes");
2120 stream->all_keyframe = TRUE;
2123 if (!gst_byte_reader_skip (trun, 1) ||
2124 !gst_byte_reader_get_uint24_be (trun, &flags))
2127 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2130 if (flags & TR_DATA_OFFSET) {
2131 /* note this is really signed */
2132 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2134 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2135 /* default base offset = first byte of moof */
2136 if (*base_offset == -1) {
2137 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2138 *base_offset = moof_offset;
2140 *running_offset = *base_offset + data_offset;
2142 /* if no offset at all, that would mean data starts at moof start,
2143 * which is a bit wrong and is ismv crappy way, so compensate
2144 * assuming data is in mdat following moof */
2145 if (*base_offset == -1) {
2146 *base_offset = moof_offset + moof_length + 8;
2147 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2150 if (*running_offset == -1)
2151 *running_offset = *base_offset;
2154 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2156 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2157 data_offset, flags, samples_count);
2159 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2160 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2161 GST_DEBUG_OBJECT (qtdemux,
2162 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2163 flags ^= TR_FIRST_SAMPLE_FLAGS;
2165 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2167 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2171 /* FIXME ? spec says other bits should also be checked to determine
2172 * entry size (and prefix size for that matter) */
2174 dur_offset = size_offset = 0;
2175 if (flags & TR_SAMPLE_DURATION) {
2176 GST_LOG_OBJECT (qtdemux, "entry duration present");
2177 dur_offset = entry_size;
2180 if (flags & TR_SAMPLE_SIZE) {
2181 GST_LOG_OBJECT (qtdemux, "entry size present");
2182 size_offset = entry_size;
2185 if (flags & TR_SAMPLE_FLAGS) {
2186 GST_LOG_OBJECT (qtdemux, "entry flags present");
2187 flags_offset = entry_size;
2190 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2191 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2192 ct_offset = entry_size;
2196 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2198 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2200 if (stream->n_samples >=
2201 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2204 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2205 stream->n_samples, (guint) sizeof (QtDemuxSample),
2206 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2208 /* create a new array of samples if it's the first sample parsed */
2209 if (stream->n_samples == 0)
2210 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2211 /* or try to reallocate it with space enough to insert the new samples */
2213 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2214 stream->n_samples + samples_count);
2215 if (stream->samples == NULL)
2218 if (G_UNLIKELY (stream->n_samples == 0)) {
2219 /* the timestamp of the first sample is also provided by the tfra entry
2220 * but we shouldn't rely on it as it is at the end of files */
2223 /* subsequent fragments extend stream */
2225 stream->samples[stream->n_samples - 1].timestamp +
2226 stream->samples[stream->n_samples - 1].duration;
2228 sample = stream->samples + stream->n_samples;
2229 for (i = 0; i < samples_count; i++) {
2230 guint32 dur, size, sflags, ct;
2232 /* first read sample data */
2233 if (flags & TR_SAMPLE_DURATION) {
2234 dur = QT_UINT32 (data + dur_offset);
2236 dur = d_sample_duration;
2238 if (flags & TR_SAMPLE_SIZE) {
2239 size = QT_UINT32 (data + size_offset);
2241 size = d_sample_size;
2243 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2245 sflags = first_flags;
2247 sflags = d_sample_flags;
2249 } else if (flags & TR_SAMPLE_FLAGS) {
2250 sflags = QT_UINT32 (data + flags_offset);
2252 sflags = d_sample_flags;
2254 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2255 ct = QT_UINT32 (data + ct_offset);
2261 /* fill the sample information */
2262 sample->offset = *running_offset;
2263 sample->pts_offset = ct;
2264 sample->size = size;
2265 sample->timestamp = timestamp;
2266 sample->duration = dur;
2267 /* sample-is-difference-sample */
2268 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2269 * now idea how it relates to bitfield other than massive LE/BE confusion */
2270 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2271 *running_offset += size;
2276 stream->n_samples += samples_count;
2282 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2287 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2293 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2294 "be larger than %uMB (broken file?)", stream->n_samples,
2295 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2300 /* find stream with @id */
2301 static inline QtDemuxStream *
2302 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2304 QtDemuxStream *stream;
2308 if (G_UNLIKELY (!id)) {
2309 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2313 /* try to get it fast and simple */
2314 if (G_LIKELY (id <= qtdemux->n_streams)) {
2315 stream = qtdemux->streams[id - 1];
2316 if (G_LIKELY (stream->track_id == id))
2320 /* linear search otherwise */
2321 for (i = 0; i < qtdemux->n_streams; i++) {
2322 stream = qtdemux->streams[i];
2323 if (stream->track_id == id)
2331 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2332 QtDemuxStream ** stream, guint32 * default_sample_duration,
2333 guint32 * default_sample_size, guint32 * default_sample_flags,
2334 gint64 * base_offset)
2337 guint32 track_id = 0;
2339 if (!gst_byte_reader_skip (tfhd, 1) ||
2340 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2343 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2346 *stream = qtdemux_find_stream (qtdemux, track_id);
2347 if (G_UNLIKELY (!*stream))
2348 goto unknown_stream;
2350 if (flags & TF_BASE_DATA_OFFSET)
2351 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2354 /* obtain stream defaults */
2355 qtdemux_parse_trex (qtdemux, *stream,
2356 default_sample_duration, default_sample_size, default_sample_flags);
2358 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2359 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2360 if (!gst_byte_reader_skip (tfhd, 4))
2363 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2364 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2367 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2368 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2371 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2372 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2379 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2384 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2390 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2391 guint64 moof_offset, QtDemuxStream * stream)
2393 GNode *moof_node, *traf_node, *tfhd_node, *trun_node;
2394 GstByteReader trun_data, tfhd_data;
2395 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2396 gint64 base_offset, running_offset;
2398 /* NOTE @stream ignored */
2400 moof_node = g_node_new ((guint8 *) buffer);
2401 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2402 qtdemux_node_dump (qtdemux, moof_node);
2404 /* unknown base_offset to start with */
2405 base_offset = running_offset = -1;
2406 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2408 /* Fragment Header node */
2410 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2414 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2415 &ds_size, &ds_flags, &base_offset))
2417 if (G_UNLIKELY (!stream)) {
2418 /* we lost track of offset, we'll need to regain it,
2419 * but can delay complaining until later or avoid doing so altogether */
2423 if (G_UNLIKELY (base_offset < -1))
2425 /* Track Run node */
2427 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2430 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2431 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2433 /* iterate all siblings */
2434 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2437 /* if no new base_offset provided for next traf,
2438 * base is end of current traf */
2439 base_offset = running_offset;
2440 running_offset = -1;
2442 /* iterate all siblings */
2443 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2445 g_node_destroy (moof_node);
2450 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2455 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2460 g_node_destroy (moof_node);
2461 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2462 (_("This file is corrupt and cannot be played.")), (NULL));
2467 /* might be used if some day we actually use mfra & co
2468 * for random access to fragments,
2469 * but that will require quite some modifications and much less relying
2470 * on a sample array */
2473 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2474 QtDemuxStream * stream)
2476 guint64 time = 0, moof_offset = 0;
2477 guint32 ver_flags, track_id, len, num_entries, i;
2478 guint value_size, traf_size, trun_size, sample_size;
2479 GstBuffer *buf = NULL;
2483 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2484 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2486 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2489 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2490 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2491 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2494 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2495 track_id, stream->track_id);
2496 if (track_id != stream->track_id) {
2500 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2501 sample_size = (len & 3) + 1;
2502 trun_size = ((len & 12) >> 2) + 1;
2503 traf_size = ((len & 48) >> 4) + 1;
2505 if (num_entries == 0)
2508 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2509 value_size + value_size + traf_size + trun_size + sample_size))
2512 for (i = 0; i < num_entries; i++) {
2513 qt_atom_parser_get_offset (&tfra, value_size, &time);
2514 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2515 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2516 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2517 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2519 GST_LOG_OBJECT (qtdemux,
2520 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2521 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2522 stream->timescale)), moof_offset);
2524 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2525 if (ret != GST_FLOW_OK)
2527 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2528 moof_offset, stream);
2529 gst_buffer_unref (buf);
2537 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2538 (_("This file is corrupt and cannot be played.")), (NULL));
2543 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2549 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2552 GNode *mfra_node, *tfra_node;
2555 if (!qtdemux->mfra_offset)
2558 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2559 if (ret != GST_FLOW_OK)
2562 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2563 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2564 GST_BUFFER_SIZE (buffer));
2566 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2569 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2570 /* iterate all siblings */
2571 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2573 g_node_destroy (mfra_node);
2574 gst_buffer_unref (buffer);
2580 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2581 (_("This file is corrupt and cannot be played.")), (NULL));
2586 static GstFlowReturn
2587 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2588 guint32 * mfro_size)
2590 GstFlowReturn ret = GST_FLOW_ERROR;
2591 GstBuffer *mfro = NULL;
2594 GstFormat fmt = GST_FORMAT_BYTES;
2596 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, &fmt, &len)) {
2597 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2598 "can not locate mfro");
2602 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2603 if (ret != GST_FLOW_OK)
2606 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2607 if (fourcc != FOURCC_mfro)
2610 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2611 if (GST_BUFFER_SIZE (mfro) >= 16) {
2612 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
2613 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
2614 if (*mfro_size >= len) {
2615 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
2616 ret = GST_FLOW_ERROR;
2619 *mfra_offset = len - *mfro_size;
2624 gst_buffer_unref (mfro);
2630 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
2633 guint32 mfra_size = 0;
2634 guint64 mfra_offset = 0;
2637 qtdemux->fragmented = FALSE;
2639 /* We check here if it is a fragmented mp4 container */
2640 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
2641 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
2642 qtdemux->fragmented = TRUE;
2643 GST_DEBUG_OBJECT (qtdemux,
2644 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
2645 qtdemux->mfra_offset = mfra_offset;
2650 static GstFlowReturn
2651 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
2655 GstBuffer *buf = NULL;
2656 GstFlowReturn ret = GST_FLOW_OK;
2657 guint64 cur_offset = qtdemux->offset;
2660 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
2661 if (G_UNLIKELY (ret != GST_FLOW_OK))
2663 gst_buffer_map (buf, &map, GST_MAP_READ);
2664 if (G_LIKELY (map.size >= 8))
2665 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
2666 gst_buffer_unmap (buf, &map);
2667 gst_buffer_unref (buf);
2669 /* maybe we already got most we needed, so only consider this eof */
2670 if (G_UNLIKELY (length == 0)) {
2671 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
2672 (_("Invalid atom size.")),
2673 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
2674 GST_FOURCC_ARGS (fourcc)));
2681 /* record for later parsing when needed */
2682 if (!qtdemux->moof_offset) {
2683 qtdemux->moof_offset = qtdemux->offset;
2692 GST_LOG_OBJECT (qtdemux,
2693 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
2694 GST_FOURCC_ARGS (fourcc), cur_offset);
2695 qtdemux->offset += length;
2700 GstBuffer *moov = NULL;
2702 if (qtdemux->got_moov) {
2703 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
2704 qtdemux->offset += length;
2708 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
2709 if (ret != GST_FLOW_OK)
2711 gst_buffer_map (moov, &map, GST_MAP_READ);
2712 if (length != map.size) {
2713 /* Some files have a 'moov' atom at the end of the file which contains
2714 * a terminal 'free' atom where the body of the atom is missing.
2715 * Check for, and permit, this special case.
2717 if (map.size >= 8) {
2718 guint8 *final_data = map.data + (map.size - 8);
2719 guint32 final_length = QT_UINT32 (final_data);
2720 guint32 final_fourcc = QT_FOURCC (final_data + 4);
2721 gst_buffer_unmap (moov, &map);
2722 if (final_fourcc == FOURCC_free
2723 && map.size + final_length - 8 == length) {
2724 /* Ok, we've found that special case. Allocate a new buffer with
2725 * that free atom actually present. */
2726 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
2727 gst_buffer_copy_into (newmoov, moov, 0, 0, map.size);
2728 gst_buffer_map (newmoov, &map, GST_MAP_WRITE);
2729 memset (map.data + length - final_length + 8, 0, final_length - 8);
2730 gst_buffer_unref (moov);
2736 if (length != map.size) {
2737 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2738 (_("This file is incomplete and cannot be played.")),
2739 ("We got less than expected (received %" G_GSIZE_FORMAT
2740 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
2741 (guint) length, cur_offset));
2742 gst_buffer_unmap (moov, &map);
2743 gst_buffer_unref (moov);
2744 ret = GST_FLOW_ERROR;
2747 qtdemux->offset += length;
2749 qtdemux_parse_moov (qtdemux, map.data, length);
2750 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
2752 qtdemux_parse_tree (qtdemux);
2753 g_node_destroy (qtdemux->moov_node);
2754 gst_buffer_unmap (moov, &map);
2755 gst_buffer_unref (moov);
2756 qtdemux->moov_node = NULL;
2757 qtdemux->got_moov = TRUE;
2763 GstBuffer *ftyp = NULL;
2765 /* extract major brand; might come in handy for ISO vs QT issues */
2766 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
2767 if (ret != GST_FLOW_OK)
2769 qtdemux->offset += length;
2770 gst_buffer_map (ftyp, &map, GST_MAP_READ);
2771 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
2772 gst_buffer_unmap (ftyp, &map);
2773 gst_buffer_unref (ftyp);
2778 GstBuffer *uuid = NULL;
2780 /* uuid are extension atoms */
2781 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
2782 if (ret != GST_FLOW_OK)
2784 qtdemux->offset += length;
2785 gst_buffer_map (uuid, &map, GST_MAP_READ);
2786 qtdemux_parse_uuid (qtdemux, map.data, map.size);
2787 gst_buffer_unmap (uuid, &map);
2788 gst_buffer_unref (uuid);
2793 GstBuffer *unknown = NULL;
2795 GST_LOG_OBJECT (qtdemux,
2796 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
2797 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
2799 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
2800 if (ret != GST_FLOW_OK)
2802 gst_buffer_map (unknown, &map, GST_MAP_READ);
2803 GST_MEMDUMP ("Unknown tag", map.data, map.size);
2804 gst_buffer_unmap (unknown, &map);
2805 gst_buffer_unref (unknown);
2806 qtdemux->offset += length;
2812 if (ret == GST_FLOW_EOS && qtdemux->got_moov) {
2813 /* digested all data, show what we have */
2814 ret = qtdemux_expose_streams (qtdemux);
2816 /* Only post, event on pads is done after newsegment */
2817 qtdemux_post_global_tags (qtdemux);
2819 qtdemux->state = QTDEMUX_STATE_MOVIE;
2820 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
2827 /* Seeks to the previous keyframe of the indexed stream and
2828 * aligns other streams with respect to the keyframe timestamp
2829 * of indexed stream. Only called in case of Reverse Playback
2831 static GstFlowReturn
2832 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
2835 guint32 seg_idx = 0, k_index = 0;
2836 guint32 ref_seg_idx, ref_k_index;
2837 guint64 k_pos = 0, last_stop = 0;
2838 QtDemuxSegment *seg = NULL;
2839 QtDemuxStream *ref_str = NULL;
2840 guint64 seg_media_start_mov; /* segment media start time in mov format */
2842 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
2843 * and finally align all the other streams on that timestamp with their
2844 * respective keyframes */
2845 for (n = 0; n < qtdemux->n_streams; n++) {
2846 QtDemuxStream *str = qtdemux->streams[n];
2848 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
2849 qtdemux->segment.position);
2851 /* segment not found, continue with normal flow */
2855 /* No candidate yet, take that one */
2861 /* So that stream has a segment, we prefer video streams */
2862 if (str->subtype == FOURCC_vide) {
2868 if (G_UNLIKELY (!ref_str)) {
2869 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
2873 if (G_UNLIKELY (!ref_str->from_sample)) {
2874 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
2878 /* So that stream has been playing from from_sample to to_sample. We will
2879 * get the timestamp of the previous sample and search for a keyframe before
2880 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
2881 if (ref_str->subtype == FOURCC_vide) {
2882 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
2883 ref_str->from_sample - 1);
2885 if (ref_str->from_sample >= 10)
2886 k_index = ref_str->from_sample - 10;
2891 /* get current segment for that stream */
2892 seg = &ref_str->segments[ref_str->segment_index];
2893 /* convert seg->media_start to mov format time for timestamp comparison */
2894 seg_media_start_mov =
2895 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
2896 /* Crawl back through segments to find the one containing this I frame */
2897 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
2898 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
2899 ref_str->segment_index);
2900 if (G_UNLIKELY (!ref_str->segment_index)) {
2901 /* Reached first segment, let's consider it's EOS */
2904 ref_str->segment_index--;
2905 seg = &ref_str->segments[ref_str->segment_index];
2906 /* convert seg->media_start to mov format time for timestamp comparison */
2907 seg_media_start_mov =
2908 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
2911 /* Calculate time position of the keyframe and where we should stop */
2913 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
2914 ref_str->timescale) - seg->media_start) + seg->time;
2916 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
2917 GST_SECOND, ref_str->timescale);
2918 last_stop = (last_stop - seg->media_start) + seg->time;
2920 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
2921 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
2922 k_index, GST_TIME_ARGS (k_pos));
2924 /* Set last_stop with the keyframe timestamp we pushed of that stream */
2925 qtdemux->segment.position = last_stop;
2926 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
2927 GST_TIME_ARGS (last_stop));
2929 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
2930 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
2934 ref_seg_idx = ref_str->segment_index;
2935 ref_k_index = k_index;
2937 /* Align them all on this */
2938 for (n = 0; n < qtdemux->n_streams; n++) {
2940 guint64 media_start = 0, seg_time = 0;
2941 QtDemuxStream *str = qtdemux->streams[n];
2943 /* aligning reference stream again might lead to backing up to yet another
2944 * keyframe (due to timestamp rounding issues),
2945 * potentially putting more load on downstream; so let's try to avoid */
2946 if (str == ref_str) {
2947 seg_idx = ref_seg_idx;
2948 seg = &str->segments[seg_idx];
2949 k_index = ref_k_index;
2950 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
2951 "sample at index %d", ref_str->segment_index, k_index);
2953 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
2954 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
2956 /* segment not found, continue with normal flow */
2960 /* get segment and time in the segment */
2961 seg = &str->segments[seg_idx];
2962 seg_time = k_pos - seg->time;
2964 /* get the media time in the segment */
2965 media_start = seg->media_start + seg_time;
2967 /* get the index of the sample with media time */
2968 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
2969 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
2970 GST_TIME_ARGS (media_start), index);
2972 /* find previous keyframe */
2973 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
2976 /* Remember until where we want to go */
2977 str->to_sample = str->from_sample - 1;
2978 /* Define our time position */
2979 str->time_position =
2980 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
2981 str->timescale) - seg->media_start) + seg->time;
2982 /* Now seek back in time */
2983 gst_qtdemux_move_stream (qtdemux, str, k_index);
2984 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
2985 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
2986 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
2992 return GST_FLOW_EOS;
2995 /* activate the given segment number @seg_idx of @stream at time @offset.
2996 * @offset is an absolute global position over all the segments.
2998 * This will push out a NEWSEGMENT event with the right values and
2999 * position the stream index to the first decodable sample before
3003 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
3004 guint32 seg_idx, guint64 offset)
3007 QtDemuxSegment *segment;
3008 guint32 index, kf_index;
3010 guint64 start, stop, time;
3013 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3016 /* update the current segment */
3017 stream->segment_index = seg_idx;
3019 /* get the segment */
3020 segment = &stream->segments[seg_idx];
3022 if (G_UNLIKELY (offset < segment->time)) {
3023 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3028 /* segment lies beyond total indicated duration */
3029 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3030 segment->time > qtdemux->segment.duration)) {
3031 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3032 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3037 /* get time in this segment */
3038 seg_time = offset - segment->time;
3040 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3041 GST_TIME_ARGS (seg_time));
3043 if (G_UNLIKELY (seg_time > segment->duration)) {
3044 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3045 GST_TIME_ARGS (segment->duration));
3049 /* qtdemux->segment.stop is in outside-time-realm, whereas
3050 * segment->media_stop is in track-time-realm.
3052 * In order to compare the two, we need to bring segment.stop
3053 * into the track-time-realm */
3055 stop = qtdemux->segment.stop;
3057 stop = qtdemux->segment.duration;
3059 stop = segment->media_stop;
3062 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3064 if (qtdemux->segment.rate >= 0) {
3065 start = MIN (segment->media_start + seg_time, stop);
3068 if (segment->media_start >= qtdemux->segment.start) {
3069 start = segment->media_start;
3070 time = segment->time;
3072 start = qtdemux->segment.start;
3073 time = segment->time + (qtdemux->segment.start - segment->media_start);
3076 start = MAX (segment->media_start, qtdemux->segment.start);
3077 stop = MIN (segment->media_start + seg_time, stop);
3080 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3081 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3082 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3084 /* combine global rate with that of the segment */
3085 rate = segment->rate * qtdemux->segment.rate;
3087 /* update the segment values used for clipping */
3088 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
3089 /* accumulate previous segments */
3090 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3091 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3092 ABS (stream->segment.rate);
3093 stream->segment.rate = rate;
3094 stream->segment.start = start;
3095 stream->segment.stop = stop;
3096 stream->segment.time = time;
3098 /* now prepare and send the segment */
3100 event = gst_event_new_segment (&stream->segment);
3101 gst_pad_push_event (stream->pad, event);
3102 /* assume we can send more data now */
3103 stream->last_ret = GST_FLOW_OK;
3104 /* clear to send tags on this pad now */
3105 gst_qtdemux_push_tags (qtdemux, stream);
3108 /* and move to the keyframe before the indicated media time of the
3110 if (qtdemux->segment.rate >= 0) {
3111 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3112 stream->to_sample = G_MAXUINT32;
3113 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3114 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3115 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3116 GST_SECOND, stream->timescale)));
3118 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3119 stream->to_sample = index;
3120 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3121 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3122 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3123 GST_SECOND, stream->timescale)));
3126 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3127 * encountered an error and printed a message so we return appropriately */
3131 /* we're at the right spot */
3132 if (index == stream->sample_index) {
3133 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3137 /* find keyframe of the target index */
3138 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3141 /* indent does stupid stuff with stream->samples[].timestamp */
3143 /* if we move forwards, we don't have to go back to the previous
3144 * keyframe since we already sent that. We can also just jump to
3145 * the keyframe right before the target index if there is one. */
3146 if (index > stream->sample_index) {
3147 /* moving forwards check if we move past a keyframe */
3148 if (kf_index > stream->sample_index) {
3149 GST_DEBUG_OBJECT (qtdemux,
3150 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3151 GST_TIME_ARGS (gst_util_uint64_scale (
3152 stream->samples[kf_index].timestamp,
3153 GST_SECOND, stream->timescale)));
3154 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3156 GST_DEBUG_OBJECT (qtdemux,
3157 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3158 " already sent", kf_index,
3159 GST_TIME_ARGS (gst_util_uint64_scale (
3160 stream->samples[kf_index].timestamp,
3161 GST_SECOND, stream->timescale)));
3164 GST_DEBUG_OBJECT (qtdemux,
3165 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3166 GST_TIME_ARGS (gst_util_uint64_scale (
3167 stream->samples[kf_index].timestamp,
3168 GST_SECOND, stream->timescale)));
3169 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3177 /* prepare to get the current sample of @stream, getting essential values.
3179 * This function will also prepare and send the segment when needed.
3181 * Return FALSE if the stream is EOS.
3184 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3185 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * dts,
3186 guint64 * pts, guint64 * duration, gboolean * keyframe)
3188 QtDemuxSample *sample;
3189 guint64 time_position;
3192 g_return_val_if_fail (stream != NULL, FALSE);
3194 time_position = stream->time_position;
3195 if (G_UNLIKELY (time_position == -1))
3198 seg_idx = stream->segment_index;
3199 if (G_UNLIKELY (seg_idx == -1)) {
3200 /* find segment corresponding to time_position if we are looking
3202 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3204 /* nothing found, we're really eos */
3209 /* different segment, activate it, sample_index will be set. */
3210 if (G_UNLIKELY (stream->segment_index != seg_idx))
3211 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3213 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3214 stream->sample_index, stream->n_samples);
3216 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3219 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3220 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3221 stream->sample_index);
3225 /* now get the info for the sample we're at */
3226 sample = &stream->samples[stream->sample_index];
3228 *dts = QTSAMPLE_DTS (stream, sample);
3229 *pts = QTSAMPLE_PTS (stream, sample);
3230 *offset = sample->offset;
3231 *size = sample->size;
3232 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3233 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3240 stream->time_position = -1;
3245 /* move to the next sample in @stream.
3247 * Moves to the next segment when needed.
3250 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3252 QtDemuxSample *sample;
3253 QtDemuxSegment *segment;
3255 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3256 /* Mark the stream as EOS */
3257 GST_DEBUG_OBJECT (qtdemux,
3258 "reached max allowed sample %u, mark EOS", stream->to_sample);
3259 stream->time_position = -1;
3263 /* move to next sample */
3264 stream->sample_index++;
3266 /* get current segment */
3267 segment = &stream->segments[stream->segment_index];
3269 /* reached the last sample, we need the next segment */
3270 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3273 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3274 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3275 stream->sample_index);
3279 /* get next sample */
3280 sample = &stream->samples[stream->sample_index];
3282 /* see if we are past the segment */
3283 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3284 GST_SECOND, stream->timescale) >= segment->media_stop))
3287 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3288 stream->timescale) >= segment->media_start) {
3289 /* inside the segment, update time_position, looks very familiar to
3290 * GStreamer segments, doesn't it? */
3291 stream->time_position =
3292 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3293 stream->timescale) - segment->media_start) + segment->time;
3295 /* not yet in segment, time does not yet increment. This means
3296 * that we are still prerolling keyframes to the decoder so it can
3297 * decode the first sample of the segment. */
3298 stream->time_position = segment->time;
3302 /* move to the next segment */
3305 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3307 if (stream->segment_index == stream->n_segments - 1) {
3308 /* are we at the end of the last segment, we're EOS */
3309 stream->time_position = -1;
3311 /* else we're only at the end of the current segment */
3312 stream->time_position = segment->stop_time;
3314 /* make sure we select a new segment */
3315 stream->segment_index = -1;
3320 gst_qtdemux_sync_streams (GstQTDemux * demux)
3324 if (demux->n_streams <= 1)
3327 for (i = 0; i < demux->n_streams; i++) {
3328 QtDemuxStream *stream;
3329 GstClockTime end_time;
3331 stream = demux->streams[i];
3336 /* TODO advance time on subtitle streams here, if any some day */
3338 /* some clips/trailers may have unbalanced streams at the end,
3339 * so send EOS on shorter stream to prevent stalling others */
3341 /* do not mess with EOS if SEGMENT seeking */
3342 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3345 if (demux->pullbased) {
3346 /* loop mode is sample time based */
3347 if (stream->time_position != -1)
3350 /* push mode is byte position based */
3351 if (stream->n_samples &&
3352 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3356 if (stream->sent_eos)
3359 /* only act if some gap */
3360 end_time = stream->segments[stream->n_segments - 1].stop_time;
3361 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3362 ", stream end: %" GST_TIME_FORMAT,
3363 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3364 if (end_time + 2 * GST_SECOND < demux->segment.position) {
3365 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3366 GST_PAD_NAME (stream->pad));
3367 stream->sent_eos = TRUE;
3368 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3373 /* EOS and NOT_LINKED need to be combined. This means that we return:
3375 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3376 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
3378 static GstFlowReturn
3379 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3383 gboolean unexpected = FALSE, not_linked = TRUE;
3385 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3387 /* store the value */
3388 stream->last_ret = ret;
3390 /* any other error that is not-linked or eos can be returned right away */
3391 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3394 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3395 for (i = 0; i < demux->n_streams; i++) {
3396 QtDemuxStream *ostream = demux->streams[i];
3398 ret = ostream->last_ret;
3400 /* no unexpected or unlinked, return */
3401 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3404 /* we check to see if we have at least 1 unexpected or all unlinked */
3405 unexpected |= (ret == GST_FLOW_EOS);
3406 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3409 /* when we get here, we all have unlinked or unexpected */
3411 ret = GST_FLOW_NOT_LINKED;
3412 else if (unexpected)
3415 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3419 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3420 * completely cliped */
3422 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3425 guint64 start, stop, cstart, cstop, diff;
3426 GstClockTime pts, dts, duration;
3428 gint num_rate, denom_rate;
3433 osize = size = gst_buffer_get_size (buf);
3436 /* depending on the type, setup the clip parameters */
3437 if (stream->subtype == FOURCC_soun) {
3438 frame_size = stream->bytes_per_frame;
3439 num_rate = GST_SECOND;
3440 denom_rate = (gint) stream->rate;
3442 } else if (stream->subtype == FOURCC_vide) {
3444 num_rate = stream->fps_n;
3445 denom_rate = stream->fps_d;
3450 /* we can only clip if we have a valid pts */
3451 pts = GST_BUFFER_PTS (buf);
3452 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
3455 dts = GST_BUFFER_DTS (buf);
3456 duration = GST_BUFFER_DURATION (buf);
3458 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
3460 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3464 stop = start + duration;
3466 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3467 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3470 /* see if some clipping happened */
3471 diff = cstart - start;
3478 /* bring clipped time to samples and to bytes */
3479 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3482 GST_DEBUG_OBJECT (qtdemux,
3483 "clipping start to %" GST_TIME_FORMAT " %"
3484 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3490 diff = stop - cstop;
3495 /* bring clipped time to samples and then to bytes */
3496 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3498 GST_DEBUG_OBJECT (qtdemux,
3499 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3500 " bytes", GST_TIME_ARGS (cstop), diff);
3505 if (offset != 0 || size != osize)
3506 gst_buffer_resize (buf, offset, size);
3508 GST_BUFFER_DTS (buf) = dts;
3509 GST_BUFFER_PTS (buf) = pts;
3510 GST_BUFFER_DURATION (buf) = duration;
3514 /* dropped buffer */
3517 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3522 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
3527 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3528 gst_buffer_unref (buf);
3533 /* the input buffer metadata must be writable,
3534 * but time/duration etc not yet set and need not be preserved */
3536 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3543 /* not many cases for now */
3544 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3545 /* send a one time dvd clut event */
3546 if (stream->pending_event && stream->pad)
3547 gst_pad_push_event (stream->pad, stream->pending_event);
3548 stream->pending_event = NULL;
3549 /* no further processing needed */
3550 stream->need_process = FALSE;
3553 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
3557 gst_buffer_map (buf, &map, GST_MAP_READ);
3559 if (G_LIKELY (map.size >= 2)) {
3560 nsize = GST_READ_UINT16_BE (map.data);
3561 nsize = MIN (nsize, map.size - 2);
3564 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
3567 /* takes care of UTF-8 validation or UTF-16 recognition,
3568 * no other encoding expected */
3569 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
3570 gst_buffer_unmap (buf, &map);
3572 gst_buffer_unref (buf);
3573 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
3575 /* may be 0-size subtitle, which is also sent to keep pipeline going */
3576 gst_buffer_resize (buf, 2, nsize);
3579 /* FIXME ? convert optional subsequent style info to markup */
3584 /* Sets a buffer's attributes properly and pushes it downstream.
3585 * Also checks for additional actions and custom processing that may
3586 * need to be done first.
3589 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3590 QtDemuxStream * stream, GstBuffer * buf,
3591 guint64 dts, guint64 pts, guint64 duration, gboolean keyframe,
3592 guint64 position, guint64 byte_position)
3594 GstFlowReturn ret = GST_FLOW_OK;
3596 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
3600 gst_buffer_map (buf, &map, GST_MAP_READ);
3601 url = g_strndup ((gchar *) map.data, map.size);
3602 gst_buffer_unmap (buf, &map);
3603 if (url != NULL && strlen (url) != 0) {
3604 /* we have RTSP redirect now */
3605 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3606 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
3607 gst_structure_new ("redirect",
3608 "new-location", G_TYPE_STRING, url, NULL)));
3609 qtdemux->posted_redirect = TRUE;
3611 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
3617 /* position reporting */
3618 if (qtdemux->segment.rate >= 0) {
3619 qtdemux->segment.position = position;
3620 gst_qtdemux_sync_streams (qtdemux);
3623 if (G_UNLIKELY (!stream->pad)) {
3624 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
3625 gst_buffer_unref (buf);
3629 /* send out pending buffers */
3630 while (stream->buffers) {
3631 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
3633 if (G_UNLIKELY (stream->discont)) {
3634 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3635 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
3636 stream->discont = FALSE;
3639 gst_pad_push (stream->pad, buffer);
3641 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
3644 /* we're going to modify the metadata */
3645 buf = gst_buffer_make_writable (buf);
3647 if (G_UNLIKELY (stream->need_process))
3648 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
3650 GST_BUFFER_DTS (buf) = dts;
3651 GST_BUFFER_PTS (buf) = pts;
3652 GST_BUFFER_DURATION (buf) = duration;
3653 GST_BUFFER_OFFSET (buf) = -1;
3654 GST_BUFFER_OFFSET_END (buf) = -1;
3656 if (G_UNLIKELY (stream->padding)) {
3657 gst_buffer_resize (buf, stream->padding, -1);
3660 if (G_UNLIKELY (qtdemux->element_index)) {
3661 GstClockTime stream_time;
3664 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
3666 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
3667 GST_LOG_OBJECT (qtdemux,
3668 "adding association %" GST_TIME_FORMAT "-> %"
3669 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
3670 gst_index_add_association (qtdemux->element_index,
3672 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
3673 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
3674 GST_FORMAT_BYTES, byte_position, NULL);
3679 if (stream->need_clip)
3680 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
3682 if (G_UNLIKELY (buf == NULL))
3685 if (G_UNLIKELY (stream->discont)) {
3686 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3687 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3688 stream->discont = FALSE;
3692 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3694 GST_LOG_OBJECT (qtdemux,
3695 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
3696 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
3697 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
3698 GST_PAD_NAME (stream->pad));
3700 ret = gst_pad_push (stream->pad, buf);
3706 static GstFlowReturn
3707 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
3709 GstFlowReturn ret = GST_FLOW_OK;
3710 GstBuffer *buf = NULL;
3711 QtDemuxStream *stream;
3714 guint64 dts = GST_CLOCK_TIME_NONE;
3715 guint64 pts = GST_CLOCK_TIME_NONE;
3716 guint64 duration = 0;
3717 gboolean keyframe = FALSE;
3722 gst_qtdemux_push_pending_newsegment (qtdemux);
3724 /* Figure out the next stream sample to output, min_time is expressed in
3725 * global time and runs over the edit list segments. */
3726 min_time = G_MAXUINT64;
3728 for (i = 0; i < qtdemux->n_streams; i++) {
3731 stream = qtdemux->streams[i];
3732 position = stream->time_position;
3734 /* position of -1 is EOS */
3735 if (position != -1 && position < min_time) {
3736 min_time = position;
3741 if (G_UNLIKELY (index == -1)) {
3742 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
3746 /* check for segment end */
3747 if (G_UNLIKELY (qtdemux->segment.stop != -1
3748 && qtdemux->segment.stop < min_time)) {
3749 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
3753 stream = qtdemux->streams[index];
3755 /* fetch info for the current sample of this stream */
3756 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
3757 &size, &dts, &pts, &duration, &keyframe)))
3760 GST_LOG_OBJECT (qtdemux,
3761 "pushing from stream %d, offset %" G_GUINT64_FORMAT
3762 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
3763 ", duration %" GST_TIME_FORMAT, index, offset, size,
3764 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
3766 /* hmm, empty sample, skip and move to next sample */
3767 if (G_UNLIKELY (size <= 0))
3770 /* last pushed sample was out of boundary, goto next sample */
3771 if (G_UNLIKELY (stream->last_ret == GST_FLOW_EOS))
3774 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
3777 if (stream->use_allocator) {
3778 /* if we have a per-stream allocator, use it */
3779 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
3782 ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
3783 if (G_UNLIKELY (ret != GST_FLOW_OK))
3786 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
3787 dts, pts, duration, keyframe, min_time, offset);
3790 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
3791 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
3792 * we have no more data for the pad to push */
3793 if (ret == GST_FLOW_EOS)
3797 gst_qtdemux_advance_sample (qtdemux, stream);
3805 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
3811 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
3812 /* EOS will be raised if all are EOS */
3819 gst_qtdemux_loop (GstPad * pad)
3821 GstQTDemux *qtdemux;
3825 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
3827 cur_offset = qtdemux->offset;
3828 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
3829 cur_offset, qtdemux->state);
3831 switch (qtdemux->state) {
3832 case QTDEMUX_STATE_INITIAL:
3833 case QTDEMUX_STATE_HEADER:
3834 ret = gst_qtdemux_loop_state_header (qtdemux);
3836 case QTDEMUX_STATE_MOVIE:
3837 ret = gst_qtdemux_loop_state_movie (qtdemux);
3838 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
3839 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
3847 /* if something went wrong, pause */
3848 if (ret != GST_FLOW_OK)
3852 gst_object_unref (qtdemux);
3858 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3859 (NULL), ("streaming stopped, invalid state"));
3860 gst_pad_pause_task (pad);
3861 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3866 const gchar *reason = gst_flow_get_name (ret);
3868 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
3870 gst_pad_pause_task (pad);
3872 /* fatal errors need special actions */
3874 if (ret == GST_FLOW_EOS) {
3875 if (qtdemux->n_streams == 0) {
3876 /* we have no streams, post an error */
3877 gst_qtdemux_post_no_playable_stream_error (qtdemux);
3879 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3882 if ((stop = qtdemux->segment.stop) == -1)
3883 stop = qtdemux->segment.duration;
3885 if (qtdemux->segment.rate >= 0) {
3886 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
3887 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3888 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3889 GST_FORMAT_TIME, stop));
3890 gst_qtdemux_push_event (qtdemux,
3891 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
3893 /* For Reverse Playback */
3894 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
3895 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3896 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3897 GST_FORMAT_TIME, qtdemux->segment.start));
3898 gst_qtdemux_push_event (qtdemux,
3899 gst_event_new_segment_done (GST_FORMAT_TIME,
3900 qtdemux->segment.start));
3903 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
3904 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3906 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
3907 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3908 (NULL), ("streaming stopped, reason %s", reason));
3909 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3918 * Returns the size of the first entry at the current offset.
3919 * If -1, there are none (which means EOS or empty file).
3922 next_entry_size (GstQTDemux * demux)
3924 QtDemuxStream *stream;
3927 guint64 smalloffs = (guint64) - 1;
3928 QtDemuxSample *sample;
3930 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
3933 for (i = 0; i < demux->n_streams; i++) {
3934 stream = demux->streams[i];
3936 if (stream->sample_index == -1)
3937 stream->sample_index = 0;
3939 if (stream->sample_index >= stream->n_samples) {
3940 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
3944 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
3945 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
3946 stream->sample_index);
3950 sample = &stream->samples[stream->sample_index];
3952 GST_LOG_OBJECT (demux,
3953 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3954 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
3955 sample->offset, sample->size);
3957 if (((smalloffs == -1)
3958 || (sample->offset < smalloffs)) && (sample->size)) {
3960 smalloffs = sample->offset;
3964 GST_LOG_OBJECT (demux,
3965 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
3966 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
3971 stream = demux->streams[smallidx];
3972 sample = &stream->samples[stream->sample_index];
3974 if (sample->offset >= demux->offset) {
3975 demux->todrop = sample->offset - demux->offset;
3976 return sample->size + demux->todrop;
3979 GST_DEBUG_OBJECT (demux,
3980 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
3985 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
3987 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
3989 gst_element_post_message (GST_ELEMENT_CAST (demux),
3990 gst_message_new_element (GST_OBJECT_CAST (demux),
3991 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
3995 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
4000 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
4003 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
4004 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
4005 GST_SEEK_TYPE_NONE, -1);
4007 res = gst_pad_push_event (demux->sinkpad, event);
4012 /* check for seekable upstream, above and beyond a mere query */
4014 gst_qtdemux_check_seekability (GstQTDemux * demux)
4017 gboolean seekable = FALSE;
4018 gint64 start = -1, stop = -1;
4020 if (demux->upstream_size)
4023 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4024 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4025 GST_DEBUG_OBJECT (demux, "seeking query failed");
4029 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4031 /* try harder to query upstream size if we didn't get it the first time */
4032 if (seekable && stop == -1) {
4033 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4034 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4037 /* if upstream doesn't know the size, it's likely that it's not seekable in
4038 * practice even if it technically may be seekable */
4039 if (seekable && (start != 0 || stop <= start)) {
4040 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4045 gst_query_unref (query);
4047 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4048 G_GUINT64_FORMAT ")", seekable, start, stop);
4049 demux->upstream_seekable = seekable;
4050 demux->upstream_size = seekable ? stop : -1;
4053 /* FIXME, unverified after edit list updates */
4054 static GstFlowReturn
4055 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4058 GstFlowReturn ret = GST_FLOW_OK;
4060 demux = GST_QTDEMUX (parent);
4062 gst_adapter_push (demux->adapter, inbuf);
4064 /* we never really mean to buffer that much */
4065 if (demux->neededbytes == -1)
4068 GST_DEBUG_OBJECT (demux,
4069 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4070 demux->neededbytes, gst_adapter_available (demux->adapter));
4072 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4073 (ret == GST_FLOW_OK)) {
4075 GST_DEBUG_OBJECT (demux,
4076 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4077 demux->state, demux->neededbytes, demux->offset);
4079 switch (demux->state) {
4080 case QTDEMUX_STATE_INITIAL:{
4085 gst_qtdemux_check_seekability (demux);
4087 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4089 /* get fourcc/length, set neededbytes */
4090 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4092 gst_adapter_unmap (demux->adapter);
4094 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4095 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4097 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4098 (_("This file is invalid and cannot be played.")),
4099 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4100 GST_FOURCC_ARGS (fourcc)));
4101 ret = GST_FLOW_ERROR;
4104 if (fourcc == FOURCC_mdat) {
4105 if (demux->n_streams > 0) {
4106 /* we have the headers, start playback */
4107 demux->state = QTDEMUX_STATE_MOVIE;
4108 demux->neededbytes = next_entry_size (demux);
4109 demux->mdatleft = size;
4111 /* Only post, event on pads is done after newsegment */
4112 qtdemux_post_global_tags (demux);
4115 /* no headers yet, try to get them */
4118 guint64 old, target;
4121 old = demux->offset;
4122 target = old + size;
4124 /* try to jump over the atom with a seek */
4125 /* only bother if it seems worth doing so,
4126 * and avoids possible upstream/server problems */
4127 if (demux->upstream_seekable &&
4128 demux->upstream_size > 4 * (1 << 20)) {
4129 res = qtdemux_seek_offset (demux, target);
4131 GST_DEBUG_OBJECT (demux, "skipping seek");
4136 GST_DEBUG_OBJECT (demux, "seek success");
4137 /* remember the offset fo the first mdat so we can seek back to it
4138 * after we have the headers */
4139 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4140 demux->first_mdat = old;
4141 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4144 /* seek worked, continue reading */
4145 demux->offset = target;
4146 demux->neededbytes = 16;
4147 demux->state = QTDEMUX_STATE_INITIAL;
4149 /* seek failed, need to buffer */
4150 demux->offset = old;
4151 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4152 /* there may be multiple mdat (or alike) buffers */
4154 if (demux->mdatbuffer)
4155 bs = gst_buffer_get_size (demux->mdatbuffer);
4158 if (size + bs > 10 * (1 << 20))
4160 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4161 demux->neededbytes = size;
4162 if (!demux->mdatbuffer)
4163 demux->mdatoffset = demux->offset;
4166 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4167 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4168 (_("This file is invalid and cannot be played.")),
4169 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4170 GST_FOURCC_ARGS (fourcc), size));
4171 ret = GST_FLOW_ERROR;
4174 /* this means we already started buffering and still no moov header,
4175 * let's continue buffering everything till we get moov */
4176 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
4178 demux->neededbytes = size;
4179 demux->state = QTDEMUX_STATE_HEADER;
4183 case QTDEMUX_STATE_HEADER:{
4187 GST_DEBUG_OBJECT (demux, "In header");
4189 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4191 /* parse the header */
4192 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4194 if (fourcc == FOURCC_moov) {
4195 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4197 demux->got_moov = TRUE;
4199 /* prepare newsegment to send when streaming actually starts */
4200 if (!demux->pending_newsegment)
4201 demux->pending_newsegment = gst_event_new_segment (&demux->segment);
4203 qtdemux_parse_moov (demux, data, demux->neededbytes);
4204 qtdemux_node_dump (demux, demux->moov_node);
4205 qtdemux_parse_tree (demux);
4206 qtdemux_expose_streams (demux);
4208 g_node_destroy (demux->moov_node);
4209 demux->moov_node = NULL;
4210 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4211 } else if (fourcc == FOURCC_moof) {
4212 if (demux->got_moov && demux->fragmented) {
4213 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4214 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4215 demux->offset, NULL)) {
4216 gst_adapter_unmap (demux->adapter);
4217 ret = GST_FLOW_ERROR;
4221 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4223 } else if (fourcc == FOURCC_ftyp) {
4224 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4225 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4226 } else if (fourcc == FOURCC_uuid) {
4227 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4228 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4230 GST_WARNING_OBJECT (demux,
4231 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4232 GST_FOURCC_ARGS (fourcc));
4233 /* Let's jump that one and go back to initial state */
4235 gst_adapter_unmap (demux->adapter);
4238 if (demux->mdatbuffer && demux->n_streams) {
4239 /* the mdat was before the header */
4240 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4241 demux->n_streams, demux->mdatbuffer);
4242 /* restore our adapter/offset view of things with upstream;
4243 * put preceding buffered data ahead of current moov data.
4244 * This should also handle evil mdat, moov, mdat cases and alike */
4245 gst_adapter_clear (demux->adapter);
4246 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4247 demux->mdatbuffer = NULL;
4248 demux->offset = demux->mdatoffset;
4249 demux->neededbytes = next_entry_size (demux);
4250 demux->state = QTDEMUX_STATE_MOVIE;
4251 demux->mdatleft = gst_adapter_available (demux->adapter);
4253 /* Only post, event on pads is done after newsegment */
4254 qtdemux_post_global_tags (demux);
4257 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4258 gst_adapter_flush (demux->adapter, demux->neededbytes);
4260 if (demux->got_moov && demux->first_mdat != -1) {
4263 /* we need to seek back */
4264 res = qtdemux_seek_offset (demux, demux->first_mdat);
4266 demux->offset = demux->first_mdat;
4268 GST_DEBUG_OBJECT (demux, "Seek back failed");
4271 demux->offset += demux->neededbytes;
4273 demux->neededbytes = 16;
4274 demux->state = QTDEMUX_STATE_INITIAL;
4279 case QTDEMUX_STATE_BUFFER_MDAT:{
4283 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4285 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4286 gst_buffer_extract (buf, 0, fourcc, 4);
4287 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4288 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
4289 if (demux->mdatbuffer)
4290 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
4292 demux->mdatbuffer = buf;
4293 demux->offset += demux->neededbytes;
4294 demux->neededbytes = 16;
4295 demux->state = QTDEMUX_STATE_INITIAL;
4296 gst_qtdemux_post_progress (demux, 1, 1);
4300 case QTDEMUX_STATE_MOVIE:{
4302 QtDemuxStream *stream = NULL;
4303 QtDemuxSample *sample;
4305 guint64 dts, pts, duration;
4308 GST_DEBUG_OBJECT (demux,
4309 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4311 if (demux->fragmented) {
4312 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4314 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4315 /* if needed data starts within this atom,
4316 * then it should not exceed this atom */
4317 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4318 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4319 (_("This file is invalid and cannot be played.")),
4320 ("sample data crosses atom boundary"));
4321 ret = GST_FLOW_ERROR;
4324 demux->mdatleft -= demux->neededbytes;
4326 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4327 /* so we are dropping more than left in this atom */
4328 demux->todrop -= demux->mdatleft;
4329 demux->neededbytes -= demux->mdatleft;
4330 demux->mdatleft = 0;
4331 /* need to resume atom parsing so we do not miss any other pieces */
4332 demux->state = QTDEMUX_STATE_INITIAL;
4333 demux->neededbytes = 16;
4338 if (demux->todrop) {
4339 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4340 gst_adapter_flush (demux->adapter, demux->todrop);
4341 demux->neededbytes -= demux->todrop;
4342 demux->offset += demux->todrop;
4346 /* initial newsegment sent here after having added pads,
4347 * possible others in sink_event */
4348 if (G_UNLIKELY (demux->pending_newsegment)) {
4349 gst_qtdemux_push_event (demux, demux->pending_newsegment);
4350 demux->pending_newsegment = NULL;
4351 /* clear to send tags on all streams */
4352 for (i = 0; i < demux->n_streams; i++) {
4353 gst_qtdemux_push_tags (demux, demux->streams[i]);
4357 /* Figure out which stream this is packet belongs to */
4358 for (i = 0; i < demux->n_streams; i++) {
4359 stream = demux->streams[i];
4360 if (stream->sample_index >= stream->n_samples)
4362 GST_LOG_OBJECT (demux,
4363 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4364 " / size:%d)", i, stream->sample_index,
4365 stream->samples[stream->sample_index].offset,
4366 stream->samples[stream->sample_index].size);
4368 if (stream->samples[stream->sample_index].offset == demux->offset)
4372 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4373 goto unknown_stream;
4375 /* Put data in a buffer, set timestamps, caps, ... */
4376 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4377 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4378 GST_FOURCC_ARGS (stream->fourcc));
4380 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4382 sample = &stream->samples[stream->sample_index];
4384 dts = QTSAMPLE_DTS (stream, sample);
4385 pts = QTSAMPLE_PTS (stream, sample);
4386 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
4387 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4389 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4390 dts, pts, duration, keyframe, dts, demux->offset);
4393 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4395 stream->sample_index++;
4397 /* update current offset and figure out size of next buffer */
4398 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4399 demux->offset, demux->neededbytes);
4400 demux->offset += demux->neededbytes;
4401 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4404 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4405 if (demux->fragmented) {
4406 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4407 /* there may be more to follow, only finish this atom */
4408 demux->todrop = demux->mdatleft;
4409 demux->neededbytes = demux->todrop;
4421 /* when buffering movie data, at least show user something is happening */
4422 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4423 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4424 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4425 demux->neededbytes);
4434 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4435 ret = GST_FLOW_ERROR;
4440 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4446 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4447 (NULL), ("qtdemuxer invalid state %d", demux->state));
4448 ret = GST_FLOW_ERROR;
4453 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4454 (NULL), ("no 'moov' atom within the first 10 MB"));
4455 ret = GST_FLOW_ERROR;
4461 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
4466 query = gst_query_new_scheduling ();
4468 if (!gst_pad_peer_query (sinkpad, query)) {
4469 gst_query_unref (query);
4473 pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
4474 gst_query_unref (query);
4479 GST_DEBUG_OBJECT (sinkpad, "activating pull");
4480 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
4484 GST_DEBUG_OBJECT (sinkpad, "activating push");
4485 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
4490 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
4491 GstPadMode mode, gboolean active)
4494 GstQTDemux *demux = GST_QTDEMUX (parent);
4497 case GST_PAD_MODE_PUSH:
4498 demux->pullbased = FALSE;
4501 case GST_PAD_MODE_PULL:
4503 demux->pullbased = TRUE;
4504 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4507 res = gst_pad_stop_task (sinkpad);
4519 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4521 return g_malloc (items * size);
4525 qtdemux_zfree (void *opaque, void *addr)
4531 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4537 z = g_new0 (z_stream, 1);
4538 z->zalloc = qtdemux_zalloc;
4539 z->zfree = qtdemux_zfree;
4542 z->next_in = z_buffer;
4543 z->avail_in = z_length;
4545 buffer = (guint8 *) g_malloc (length);
4546 ret = inflateInit (z);
4547 while (z->avail_in > 0) {
4548 if (z->avail_out == 0) {
4550 buffer = (guint8 *) g_realloc (buffer, length);
4551 z->next_out = buffer + z->total_out;
4552 z->avail_out = 1024;
4554 ret = inflate (z, Z_SYNC_FLUSH);
4558 if (ret != Z_STREAM_END) {
4559 g_warning ("inflate() returned %d", ret);
4565 #endif /* HAVE_ZLIB */
4568 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4572 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4574 /* counts as header data */
4575 qtdemux->header_size += length;
4577 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4578 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4580 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4586 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4587 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4588 if (dcom == NULL || cmvd == NULL)
4589 goto invalid_compression;
4591 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4594 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4595 guint uncompressed_length;
4596 guint compressed_length;
4599 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4600 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4601 GST_LOG ("length = %u", uncompressed_length);
4604 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4605 compressed_length, uncompressed_length);
4607 qtdemux->moov_node_compressed = qtdemux->moov_node;
4608 qtdemux->moov_node = g_node_new (buf);
4610 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4611 uncompressed_length);
4614 #endif /* HAVE_ZLIB */
4616 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4617 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
4624 invalid_compression:
4626 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
4632 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
4635 while (G_UNLIKELY (buf < end)) {
4639 if (G_UNLIKELY (buf + 4 > end)) {
4640 GST_LOG_OBJECT (qtdemux, "buffer overrun");
4643 len = QT_UINT32 (buf);
4644 if (G_UNLIKELY (len == 0)) {
4645 GST_LOG_OBJECT (qtdemux, "empty container");
4648 if (G_UNLIKELY (len < 8)) {
4649 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
4652 if (G_UNLIKELY (len > (end - buf))) {
4653 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
4654 (gint) (end - buf));
4658 child = g_node_new ((guint8 *) buf);
4659 g_node_append (node, child);
4660 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
4661 qtdemux_parse_node (qtdemux, child, buf, len);
4669 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
4672 int len = QT_UINT32 (xdxt->data);
4673 guint8 *buf = xdxt->data;
4674 guint8 *end = buf + len;
4677 /* skip size and type */
4685 size = QT_UINT32 (buf);
4686 type = QT_FOURCC (buf + 4);
4688 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
4690 if (buf + size > end || size <= 0)
4696 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
4697 GST_FOURCC_ARGS (type));
4701 buffer = gst_buffer_new_and_alloc (size);
4702 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4703 stream->buffers = g_slist_append (stream->buffers, buffer);
4704 GST_LOG_OBJECT (qtdemux, "parsing theora header");
4707 buffer = gst_buffer_new_and_alloc (size);
4708 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4709 stream->buffers = g_slist_append (stream->buffers, buffer);
4710 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
4713 buffer = gst_buffer_new_and_alloc (size);
4714 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4715 stream->buffers = g_slist_append (stream->buffers, buffer);
4716 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
4719 GST_WARNING_OBJECT (qtdemux,
4720 "unknown theora cookie %" GST_FOURCC_FORMAT,
4721 GST_FOURCC_ARGS (type));
4730 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
4734 guint32 node_length = 0;
4735 const QtNodeType *type;
4738 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
4740 if (G_UNLIKELY (length < 8))
4741 goto not_enough_data;
4743 node_length = QT_UINT32 (buffer);
4744 fourcc = QT_FOURCC (buffer + 4);
4746 /* ignore empty nodes */
4747 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
4750 type = qtdemux_type_get (fourcc);
4752 end = buffer + length;
4754 GST_LOG_OBJECT (qtdemux,
4755 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
4756 GST_FOURCC_ARGS (fourcc), node_length, type->name);
4758 if (node_length > length)
4759 goto broken_atom_size;
4761 if (type->flags & QT_FLAG_CONTAINER) {
4762 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
4767 if (node_length < 20) {
4768 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
4771 GST_DEBUG_OBJECT (qtdemux,
4772 "parsing stsd (sample table, sample description) atom");
4773 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
4783 /* also read alac (or whatever) in stead of mp4a in the following,
4784 * since a similar layout is used in other cases as well */
4785 if (fourcc == FOURCC_mp4a)
4790 /* There are two things we might encounter here: a true mp4a atom, and
4791 an mp4a entry in an stsd atom. The latter is what we're interested
4792 in, and it looks like an atom, but isn't really one. The true mp4a
4793 atom is short, so we detect it based on length here. */
4794 if (length < min_size) {
4795 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
4796 GST_FOURCC_ARGS (fourcc));
4800 /* 'version' here is the sound sample description version. Types 0 and
4801 1 are documented in the QTFF reference, but type 2 is not: it's
4802 described in Apple header files instead (struct SoundDescriptionV2
4804 version = QT_UINT16 (buffer + 16);
4806 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
4807 GST_FOURCC_ARGS (fourcc), version);
4809 /* parse any esds descriptors */
4821 GST_WARNING_OBJECT (qtdemux,
4822 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
4823 GST_FOURCC_ARGS (fourcc), version);
4828 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4840 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
4841 GST_FOURCC_ARGS (fourcc));
4842 version = QT_UINT32 (buffer + 16);
4843 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
4844 if (1 || version == 0x00000000) {
4845 buf = buffer + 0x32;
4847 /* FIXME Quicktime uses PASCAL string while
4848 * the iso format uses C strings. Check the file
4849 * type before attempting to parse the string here. */
4850 tlen = QT_UINT8 (buf);
4851 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
4853 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
4854 /* the string has a reserved space of 32 bytes so skip
4855 * the remaining 31 */
4857 buf += 4; /* and 4 bytes reserved */
4859 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
4861 qtdemux_parse_container (qtdemux, node, buf, end);
4867 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
4868 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
4873 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
4878 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
4879 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
4887 version = QT_UINT32 (buffer + 12);
4888 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
4895 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
4900 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4905 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
4909 if (!strcmp (type->name, "unknown"))
4910 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
4914 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
4915 GST_FOURCC_ARGS (fourcc));
4921 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4922 (_("This file is corrupt and cannot be played.")),
4923 ("Not enough data for an atom header, got only %u bytes", length));
4928 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4929 (_("This file is corrupt and cannot be played.")),
4930 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
4931 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
4938 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
4942 guint32 child_fourcc;
4944 for (child = g_node_first_child (node); child;
4945 child = g_node_next_sibling (child)) {
4946 buffer = (guint8 *) child->data;
4948 child_fourcc = QT_FOURCC (buffer + 4);
4950 if (G_UNLIKELY (child_fourcc == fourcc)) {
4958 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
4959 GstByteReader * parser)
4963 guint32 child_fourcc, child_len;
4965 for (child = g_node_first_child (node); child;
4966 child = g_node_next_sibling (child)) {
4967 buffer = (guint8 *) child->data;
4969 child_len = QT_UINT32 (buffer);
4970 child_fourcc = QT_FOURCC (buffer + 4);
4972 if (G_UNLIKELY (child_fourcc == fourcc)) {
4973 if (G_UNLIKELY (child_len < (4 + 4)))
4975 /* FIXME: must verify if atom length < parent atom length */
4976 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4984 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
4985 GstByteReader * parser)
4989 guint32 child_fourcc, child_len;
4991 for (child = g_node_next_sibling (node); child;
4992 child = g_node_next_sibling (child)) {
4993 buffer = (guint8 *) child->data;
4995 child_fourcc = QT_FOURCC (buffer + 4);
4997 if (child_fourcc == fourcc) {
4999 child_len = QT_UINT32 (buffer);
5000 if (G_UNLIKELY (child_len < (4 + 4)))
5002 /* FIXME: must verify if atom length < parent atom length */
5003 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
5012 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
5014 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
5018 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
5022 query = gst_query_new_allocation (stream->caps, FALSE);
5024 if (!gst_pad_peer_query (stream->pad, query)) {
5025 /* not a problem, just debug a little */
5026 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
5029 if (stream->allocator)
5030 gst_object_unref (stream->allocator);
5032 if (gst_query_get_n_allocation_params (query) > 0) {
5033 /* try the allocator */
5034 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
5036 stream->use_allocator = TRUE;
5038 stream->allocator = NULL;
5039 gst_allocation_params_init (&stream->params);
5040 stream->use_allocator = FALSE;
5042 gst_query_unref (query);
5046 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
5047 QtDemuxStream * stream, GstTagList * list)
5049 /* consistent default for push based mode */
5050 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
5052 if (stream->subtype == FOURCC_vide) {
5053 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5056 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5059 /* fps is calculated base on the duration of the first frames since
5060 * qt does not have a fixed framerate. */
5061 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
5066 stream->fps_n = stream->timescale;
5067 if (stream->min_duration == 0)
5070 stream->fps_d = stream->min_duration;
5075 gint depth, palette_count;
5076 const guint32 *palette_data = NULL;
5078 gst_caps_set_simple (stream->caps,
5079 "width", G_TYPE_INT, stream->width,
5080 "height", G_TYPE_INT, stream->height,
5081 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5083 /* calculate pixel-aspect-ratio using display width and height */
5084 GST_DEBUG_OBJECT (qtdemux,
5085 "video size %dx%d, target display size %dx%d", stream->width,
5086 stream->height, stream->display_width, stream->display_height);
5088 if (stream->display_width > 0 && stream->display_height > 0 &&
5089 stream->width > 0 && stream->height > 0) {
5092 /* calculate the pixel aspect ratio using the display and pixel w/h */
5093 n = stream->display_width * stream->height;
5094 d = stream->display_height * stream->width;
5097 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5098 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5099 GST_TYPE_FRACTION, n, d, NULL);
5102 /* qt file might have pasp atom */
5103 if (stream->par_w > 0 && stream->par_h > 0) {
5104 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5105 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5106 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5109 depth = stream->bits_per_sample;
5111 /* more than 32 bits means grayscale */
5112 gray = (depth > 32);
5113 /* low 32 bits specify the depth */
5116 /* different number of palette entries is determined by depth. */
5118 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
5119 palette_count = (1 << depth);
5121 switch (palette_count) {
5125 palette_data = ff_qt_default_palette_2;
5128 palette_data = ff_qt_default_palette_4;
5132 palette_data = ff_qt_grayscale_palette_16;
5134 palette_data = ff_qt_default_palette_16;
5138 palette_data = ff_qt_grayscale_palette_256;
5140 palette_data = ff_qt_default_palette_256;
5143 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5144 (_("The video in this file might not play correctly.")),
5145 ("unsupported palette depth %d", depth));
5151 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5152 * don't free any of the buffer data. */
5153 palette = _gst_buffer_new_wrapped ((gpointer) palette_data,
5154 palette_count * 4, NULL);
5156 gst_caps_set_simple (stream->caps, "palette_data",
5157 GST_TYPE_BUFFER, palette, NULL);
5158 gst_buffer_unref (palette);
5159 } else if (palette_count != 0) {
5160 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5161 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5163 gst_object_unref (stream->pad);
5167 qtdemux->n_video_streams++;
5168 } else if (stream->subtype == FOURCC_soun) {
5169 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
5172 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5175 /* FIXME: Need to set channel-mask here and maybe reorder */
5176 gst_caps_set_simple (stream->caps,
5177 "rate", G_TYPE_INT, (int) stream->rate,
5178 "channels", G_TYPE_INT, stream->n_channels, NULL);
5180 qtdemux->n_audio_streams++;
5181 } else if (stream->subtype == FOURCC_strm) {
5182 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5183 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
5184 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
5187 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5189 qtdemux->n_sub_streams++;
5191 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5196 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5198 gst_pad_use_fixed_caps (stream->pad);
5199 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5200 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5201 gst_pad_set_active (stream->pad, TRUE);
5203 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5204 gst_pad_push_event (stream->pad, gst_event_new_stream_start ());
5205 gst_pad_set_caps (stream->pad, stream->caps);
5207 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5208 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5209 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5211 if (stream->pending_tags)
5212 gst_tag_list_free (stream->pending_tags);
5213 stream->pending_tags = list;
5214 /* global tags go on each pad anyway */
5215 stream->send_global_tags = TRUE;
5217 qtdemux_do_allocation (qtdemux, stream);
5223 /* find next atom with @fourcc starting at @offset */
5224 static GstFlowReturn
5225 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5226 guint64 * length, guint32 fourcc)
5232 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5233 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5239 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5240 if (G_UNLIKELY (ret != GST_FLOW_OK))
5242 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
5245 gst_buffer_unref (buf);
5248 gst_buffer_map (buf, &map, GST_MAP_READ);
5249 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
5250 gst_buffer_unmap (buf, &map);
5251 gst_buffer_unref (buf);
5253 if (G_UNLIKELY (*length == 0)) {
5254 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5255 ret = GST_FLOW_ERROR;
5259 if (lfourcc == fourcc) {
5260 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5264 GST_LOG_OBJECT (qtdemux,
5265 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5266 GST_FOURCC_ARGS (fourcc), *offset);
5275 /* might simply have had last one */
5276 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5281 /* should only do something in pull mode */
5282 /* call with OBJECT lock */
5283 static GstFlowReturn
5284 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5286 guint64 length, offset;
5287 GstBuffer *buf = NULL;
5288 GstFlowReturn ret = GST_FLOW_OK;
5289 GstFlowReturn res = GST_FLOW_OK;
5292 offset = qtdemux->moof_offset;
5293 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5296 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5297 return GST_FLOW_EOS;
5300 /* best not do pull etc with lock held */
5301 GST_OBJECT_UNLOCK (qtdemux);
5303 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5304 if (ret != GST_FLOW_OK)
5307 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5308 if (G_UNLIKELY (ret != GST_FLOW_OK))
5310 gst_buffer_map (buf, &map, GST_MAP_READ);
5311 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
5312 gst_buffer_unmap (buf, &map);
5313 gst_buffer_unref (buf);
5318 gst_buffer_unmap (buf, &map);
5319 gst_buffer_unref (buf);
5323 /* look for next moof */
5324 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5325 if (G_UNLIKELY (ret != GST_FLOW_OK))
5329 GST_OBJECT_LOCK (qtdemux);
5331 qtdemux->moof_offset = offset;
5337 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5339 res = GST_FLOW_ERROR;
5344 /* maybe upstream temporarily flushing */
5345 if (ret != GST_FLOW_FLUSHING) {
5346 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5349 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5350 /* resume at current position next time */
5357 /* initialise bytereaders for stbl sub-atoms */
5359 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5361 stream->stbl_index = -1; /* no samples have yet been parsed */
5363 /* time-to-sample atom */
5364 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5367 /* copy atom data into a new buffer for later use */
5368 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5370 /* skip version + flags */
5371 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5372 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5374 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5376 /* make sure there's enough data */
5377 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
5378 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
5379 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
5380 stream->n_sample_times);
5381 if (!stream->n_sample_times)
5385 /* sync sample atom */
5386 stream->stps_present = FALSE;
5387 if ((stream->stss_present =
5388 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5389 &stream->stss) ? TRUE : FALSE) == TRUE) {
5390 /* copy atom data into a new buffer for later use */
5391 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5393 /* skip version + flags */
5394 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5395 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5398 if (stream->n_sample_syncs) {
5399 /* make sure there's enough data */
5400 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5404 /* partial sync sample atom */
5405 if ((stream->stps_present =
5406 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5407 &stream->stps) ? TRUE : FALSE) == TRUE) {
5408 /* copy atom data into a new buffer for later use */
5409 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5411 /* skip version + flags */
5412 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5413 !gst_byte_reader_get_uint32_be (&stream->stps,
5414 &stream->n_sample_partial_syncs))
5417 /* if there are no entries, the stss table contains the real
5419 if (stream->n_sample_partial_syncs) {
5420 /* make sure there's enough data */
5421 if (!qt_atom_parser_has_chunks (&stream->stps,
5422 stream->n_sample_partial_syncs, 4))
5429 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5432 /* copy atom data into a new buffer for later use */
5433 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5435 /* skip version + flags */
5436 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5437 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5440 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5443 if (!stream->n_samples)
5446 /* sample-to-chunk atom */
5447 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5450 /* copy atom data into a new buffer for later use */
5451 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5453 /* skip version + flags */
5454 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5455 !gst_byte_reader_get_uint32_be (&stream->stsc,
5456 &stream->n_samples_per_chunk))
5459 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5460 stream->n_samples_per_chunk);
5462 /* make sure there's enough data */
5463 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5469 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5470 stream->co_size = sizeof (guint32);
5471 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5473 stream->co_size = sizeof (guint64);
5477 /* copy atom data into a new buffer for later use */
5478 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5480 /* skip version + flags */
5481 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5484 /* chunks_are_chunks == 0 means treat chunks as samples */
5485 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5486 if (stream->chunks_are_chunks) {
5487 /* skip number of entries */
5488 if (!gst_byte_reader_skip (&stream->stco, 4))
5491 /* make sure there are enough data in the stsz atom */
5492 if (!stream->sample_size) {
5493 /* different sizes for each sample */
5494 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5498 /* treat chunks as samples */
5499 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5503 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5504 stream->n_samples, (guint) sizeof (QtDemuxSample),
5505 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5507 if (stream->n_samples >=
5508 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5509 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5510 "be larger than %uMB (broken file?)", stream->n_samples,
5511 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5515 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5516 if (!stream->samples) {
5517 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5523 /* composition time-to-sample */
5524 if ((stream->ctts_present =
5525 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5526 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5527 /* copy atom data into a new buffer for later use */
5528 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5530 /* skip version + flags */
5531 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5532 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5533 &stream->n_composition_times))
5536 /* make sure there's enough data */
5537 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5546 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5547 (_("This file is corrupt and cannot be played.")), (NULL));
5552 gst_qtdemux_stbl_free (stream);
5553 if (!qtdemux->fragmented) {
5554 /* not quite good */
5555 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5558 /* may pick up samples elsewhere */
5564 /* collect samples from the next sample to be parsed up to sample @n for @stream
5565 * by reading the info from @stbl
5567 * This code can be executed from both the streaming thread and the seeking
5568 * thread so it takes the object lock to protect itself
5571 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
5574 QtDemuxSample *samples, *first, *cur, *last;
5575 guint32 n_samples_per_chunk;
5578 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
5579 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
5580 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
5582 n_samples = stream->n_samples;
5585 goto out_of_samples;
5587 GST_OBJECT_LOCK (qtdemux);
5588 if (n <= stream->stbl_index)
5589 goto already_parsed;
5591 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
5593 if (!stream->stsz.data) {
5594 /* so we already parsed and passed all the moov samples;
5595 * onto fragmented ones */
5596 g_assert (qtdemux->fragmented);
5600 /* pointer to the sample table */
5601 samples = stream->samples;
5603 /* starts from -1, moves to the next sample index to parse */
5604 stream->stbl_index++;
5606 /* keep track of the first and last sample to fill */
5607 first = &samples[stream->stbl_index];
5610 if (stream->chunks_are_chunks) {
5611 /* set the sample sizes */
5612 if (stream->sample_size == 0) {
5613 /* different sizes for each sample */
5614 for (cur = first; cur <= last; cur++) {
5615 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
5616 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
5617 (guint) (cur - samples), cur->size);
5620 /* samples have the same size */
5621 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
5622 for (cur = first; cur <= last; cur++)
5623 cur->size = stream->sample_size;
5627 n_samples_per_chunk = stream->n_samples_per_chunk;
5630 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
5633 if (stream->stsc_chunk_index >= stream->last_chunk
5634 || stream->stsc_chunk_index < stream->first_chunk) {
5635 stream->first_chunk =
5636 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5637 stream->samples_per_chunk =
5638 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5639 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
5641 /* chunk numbers are counted from 1 it seems */
5642 if (G_UNLIKELY (stream->first_chunk == 0))
5645 --stream->first_chunk;
5647 /* the last chunk of each entry is calculated by taking the first chunk
5648 * of the next entry; except if there is no next, where we fake it with
5650 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
5651 stream->last_chunk = G_MAXUINT32;
5653 stream->last_chunk =
5654 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
5655 if (G_UNLIKELY (stream->last_chunk == 0))
5658 --stream->last_chunk;
5661 GST_LOG_OBJECT (qtdemux,
5662 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
5663 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
5665 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
5668 if (stream->last_chunk != G_MAXUINT32) {
5669 if (!qt_atom_parser_peek_sub (&stream->stco,
5670 stream->first_chunk * stream->co_size,
5671 (stream->last_chunk - stream->first_chunk) * stream->co_size,
5676 stream->co_chunk = stream->stco;
5677 if (!gst_byte_reader_skip (&stream->co_chunk,
5678 stream->first_chunk * stream->co_size))
5682 stream->stsc_chunk_index = stream->first_chunk;
5685 last_chunk = stream->last_chunk;
5687 if (stream->chunks_are_chunks) {
5688 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5689 guint32 samples_per_chunk;
5690 guint64 chunk_offset;
5692 if (!stream->stsc_sample_index
5693 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
5694 &stream->chunk_offset))
5697 samples_per_chunk = stream->samples_per_chunk;
5698 chunk_offset = stream->chunk_offset;
5700 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
5701 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
5702 G_GUINT64_FORMAT, (guint) (cur - samples), stream->chunk_offset);
5704 cur->offset = chunk_offset;
5705 chunk_offset += cur->size;
5708 if (G_UNLIKELY (cur > last)) {
5710 stream->stsc_sample_index = k + 1;
5711 stream->chunk_offset = chunk_offset;
5712 stream->stsc_chunk_index = j;
5716 stream->stsc_sample_index = 0;
5718 stream->stsc_chunk_index = j;
5720 cur = &samples[stream->stsc_chunk_index];
5722 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5725 stream->stsc_chunk_index = j;
5730 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
5733 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
5734 "%" G_GUINT64_FORMAT, j, cur->offset);
5736 if (stream->samples_per_frame * stream->bytes_per_frame) {
5738 (stream->samples_per_chunk * stream->n_channels) /
5739 stream->samples_per_frame * stream->bytes_per_frame;
5741 cur->size = stream->samples_per_chunk;
5744 GST_DEBUG_OBJECT (qtdemux,
5745 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
5746 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
5747 GST_SECOND, stream->timescale)), cur->size);
5749 cur->timestamp = stream->stco_sample_index;
5750 cur->duration = stream->samples_per_chunk;
5751 cur->keyframe = TRUE;
5754 stream->stco_sample_index += stream->samples_per_chunk;
5756 stream->stsc_chunk_index = j;
5758 stream->stsc_index++;
5761 if (!stream->chunks_are_chunks)
5765 guint32 n_sample_times;
5767 n_sample_times = stream->n_sample_times;
5770 for (i = stream->stts_index; i < n_sample_times; i++) {
5771 guint32 stts_samples;
5772 gint32 stts_duration;
5775 if (stream->stts_sample_index >= stream->stts_samples
5776 || !stream->stts_sample_index) {
5778 stream->stts_samples =
5779 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5780 stream->stts_duration =
5781 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5783 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
5784 i, stream->stts_samples, stream->stts_duration);
5786 stream->stts_sample_index = 0;
5789 stts_samples = stream->stts_samples;
5790 stts_duration = stream->stts_duration;
5791 stts_time = stream->stts_time;
5793 for (j = stream->stts_sample_index; j < stts_samples; j++) {
5794 GST_DEBUG_OBJECT (qtdemux,
5795 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
5796 (guint) (cur - samples), j,
5797 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
5798 stream->timescale)));
5800 cur->timestamp = stts_time;
5801 cur->duration = stts_duration;
5803 /* avoid 32-bit wrap-around,
5804 * but still mind possible 'negative' duration */
5805 stts_time += (gint64) stts_duration;
5808 if (G_UNLIKELY (cur > last)) {
5810 stream->stts_time = stts_time;
5811 stream->stts_sample_index = j + 1;
5815 stream->stts_sample_index = 0;
5816 stream->stts_time = stts_time;
5817 stream->stts_index++;
5819 /* fill up empty timestamps with the last timestamp, this can happen when
5820 * the last samples do not decode and so we don't have timestamps for them.
5821 * We however look at the last timestamp to estimate the track length so we
5822 * need something in here. */
5823 for (; cur < last; cur++) {
5824 GST_DEBUG_OBJECT (qtdemux,
5825 "fill sample %d: timestamp %" GST_TIME_FORMAT,
5826 (guint) (cur - samples),
5827 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
5828 stream->timescale)));
5829 cur->timestamp = stream->stts_time;
5835 /* sample sync, can be NULL */
5836 if (stream->stss_present == TRUE) {
5837 guint32 n_sample_syncs;
5839 n_sample_syncs = stream->n_sample_syncs;
5841 if (!n_sample_syncs) {
5842 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
5843 stream->all_keyframe = TRUE;
5845 for (i = stream->stss_index; i < n_sample_syncs; i++) {
5846 /* note that the first sample is index 1, not 0 */
5849 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
5851 if (G_LIKELY (index > 0 && index <= n_samples)) {
5853 samples[index].keyframe = TRUE;
5854 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5855 /* and exit if we have enough samples */
5856 if (G_UNLIKELY (index >= n)) {
5863 stream->stss_index = i;
5866 /* stps marks partial sync frames like open GOP I-Frames */
5867 if (stream->stps_present == TRUE) {
5868 guint32 n_sample_partial_syncs;
5870 n_sample_partial_syncs = stream->n_sample_partial_syncs;
5872 /* if there are no entries, the stss table contains the real
5874 if (n_sample_partial_syncs) {
5875 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
5876 /* note that the first sample is index 1, not 0 */
5879 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
5881 if (G_LIKELY (index > 0 && index <= n_samples)) {
5883 samples[index].keyframe = TRUE;
5884 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5885 /* and exit if we have enough samples */
5886 if (G_UNLIKELY (index >= n)) {
5893 stream->stps_index = i;
5897 /* no stss, all samples are keyframes */
5898 stream->all_keyframe = TRUE;
5899 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
5904 /* composition time to sample */
5905 if (stream->ctts_present == TRUE) {
5906 guint32 n_composition_times;
5908 gint32 ctts_soffset;
5910 /* Fill in the pts_offsets */
5912 n_composition_times = stream->n_composition_times;
5914 for (i = stream->ctts_index; i < n_composition_times; i++) {
5915 if (stream->ctts_sample_index >= stream->ctts_count
5916 || !stream->ctts_sample_index) {
5917 stream->ctts_count =
5918 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
5919 stream->ctts_soffset =
5920 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
5921 stream->ctts_sample_index = 0;
5924 ctts_count = stream->ctts_count;
5925 ctts_soffset = stream->ctts_soffset;
5927 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
5928 cur->pts_offset = ctts_soffset;
5931 if (G_UNLIKELY (cur > last)) {
5933 stream->ctts_sample_index = j + 1;
5937 stream->ctts_sample_index = 0;
5938 stream->ctts_index++;
5942 stream->stbl_index = n;
5943 /* if index has been completely parsed, free data that is no-longer needed */
5944 if (n + 1 == stream->n_samples) {
5945 gst_qtdemux_stbl_free (stream);
5946 GST_DEBUG_OBJECT (qtdemux,
5947 "parsed all available samples; checking for more");
5948 while (n + 1 == stream->n_samples)
5949 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
5952 GST_OBJECT_UNLOCK (qtdemux);
5959 GST_LOG_OBJECT (qtdemux,
5960 "Tried to parse up to sample %u but this sample has already been parsed",
5962 /* if fragmented, there may be more */
5963 if (qtdemux->fragmented && n == stream->stbl_index)
5965 GST_OBJECT_UNLOCK (qtdemux);
5971 GST_LOG_OBJECT (qtdemux,
5972 "Tried to parse up to sample %u but there are only %u samples", n + 1,
5974 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5975 (_("This file is corrupt and cannot be played.")), (NULL));
5980 GST_OBJECT_UNLOCK (qtdemux);
5981 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5982 (_("This file is corrupt and cannot be played.")), (NULL));
5987 /* collect all segment info for @stream.
5990 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
5995 /* parse and prepare segment info from the edit list */
5996 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
5997 stream->n_segments = 0;
5998 stream->segments = NULL;
5999 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
6003 guint64 time, stime;
6006 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
6007 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
6010 buffer = elst->data;
6012 n_segments = QT_UINT32 (buffer + 12);
6014 /* we might allocate a bit too much, at least allocate 1 segment */
6015 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
6017 /* segments always start from 0 */
6021 for (i = 0; i < n_segments; i++) {
6024 QtDemuxSegment *segment;
6027 media_time = QT_UINT32 (buffer + 20 + i * 12);
6029 /* -1 media time is an empty segment, just ignore it */
6030 if (media_time == G_MAXUINT32)
6033 duration = QT_UINT32 (buffer + 16 + i * 12);
6035 segment = &stream->segments[count++];
6037 /* time and duration expressed in global timescale */
6038 segment->time = stime;
6039 /* add non scaled values so we don't cause roundoff errors */
6041 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
6042 segment->stop_time = stime;
6043 segment->duration = stime - segment->time;
6044 /* media_time expressed in stream timescale */
6045 segment->media_start =
6046 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
6047 segment->media_stop = segment->media_start + segment->duration;
6048 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
6050 if (rate_int <= 1) {
6051 /* 0 is not allowed, some programs write 1 instead of the floating point
6053 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
6057 segment->rate = rate_int / 65536.0;
6060 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
6061 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
6062 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
6063 GST_TIME_ARGS (segment->duration),
6064 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
6066 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
6067 stream->n_segments = count;
6071 /* push based does not handle segments, so act accordingly here,
6072 * and warn if applicable */
6073 if (!qtdemux->pullbased) {
6074 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
6075 /* remove and use default one below, we stream like it anyway */
6076 g_free (stream->segments);
6077 stream->segments = NULL;
6078 stream->n_segments = 0;
6081 /* no segments, create one to play the complete trak */
6082 if (stream->n_segments == 0) {
6083 GstClockTime stream_duration =
6084 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6086 if (stream->segments == NULL)
6087 stream->segments = g_new (QtDemuxSegment, 1);
6089 /* represent unknown our way */
6090 if (stream_duration == 0)
6091 stream_duration = -1;
6093 stream->segments[0].time = 0;
6094 stream->segments[0].stop_time = stream_duration;
6095 stream->segments[0].duration = stream_duration;
6096 stream->segments[0].media_start = 0;
6097 stream->segments[0].media_stop = stream_duration;
6098 stream->segments[0].rate = 1.0;
6100 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6101 GST_TIME_ARGS (stream_duration));
6102 stream->n_segments = 1;
6104 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6110 * Parses the stsd atom of a svq3 trak looking for
6111 * the SMI and gama atoms.
6114 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6115 guint8 ** gamma, GstBuffer ** seqh)
6117 guint8 *_gamma = NULL;
6118 GstBuffer *_seqh = NULL;
6119 guint8 *stsd_data = stsd->data;
6120 guint32 length = QT_UINT32 (stsd_data);
6124 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6130 version = QT_UINT16 (stsd_data);
6135 while (length > 8) {
6136 guint32 fourcc, size;
6138 size = QT_UINT32 (stsd_data);
6139 fourcc = QT_FOURCC (stsd_data + 4);
6140 data = stsd_data + 8;
6147 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6148 " for gama atom, expected 12", size);
6153 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6155 if (_seqh != NULL) {
6156 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6157 " found, ignoring");
6159 seqh_size = QT_UINT32 (data + 4);
6160 if (seqh_size > 0) {
6161 _seqh = gst_buffer_new_and_alloc (seqh_size);
6162 _gst_buffer_copy_into_mem (_seqh, 0, data + 8, seqh_size);
6169 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6170 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6174 if (size <= length) {
6180 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6183 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6184 G_GUINT16_FORMAT, version);
6195 gst_buffer_unref (_seqh);
6200 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6207 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6208 * atom that might contain a 'data' atom with the rtsp uri.
6209 * This case was reported in bug #597497, some info about
6210 * the hndl atom can be found in TN1195
6212 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6213 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6216 guint32 dref_num_entries = 0;
6217 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6218 gst_byte_reader_skip (&dref, 4) &&
6219 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6222 /* search dref entries for hndl atom */
6223 for (i = 0; i < dref_num_entries; i++) {
6224 guint32 size = 0, type;
6225 guint8 string_len = 0;
6226 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6227 qt_atom_parser_get_fourcc (&dref, &type)) {
6228 if (type == FOURCC_hndl) {
6229 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6231 /* skip data reference handle bytes and the
6232 * following pascal string and some extra 4
6233 * bytes I have no idea what are */
6234 if (!gst_byte_reader_skip (&dref, 4) ||
6235 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6236 !gst_byte_reader_skip (&dref, string_len + 4)) {
6237 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6241 /* iterate over the atoms to find the data atom */
6242 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6246 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6247 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6248 if (atom_type == FOURCC_data) {
6249 const guint8 *uri_aux = NULL;
6251 /* found the data atom that might contain the rtsp uri */
6252 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6253 "hndl atom, interpreting it as an URI");
6254 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6256 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6257 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6259 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6260 "didn't contain a rtsp address");
6262 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6267 /* skipping to the next entry */
6268 if (!gst_byte_reader_skip (&dref, atom_size - 8))
6271 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6278 /* skip to the next entry */
6279 if (!gst_byte_reader_skip (&dref, size - 8))
6282 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6285 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6292 less_than (gconstpointer a, gconstpointer b)
6294 const guint32 *av = a, *bv = b;
6299 #define AMR_NB_ALL_MODES 0x81ff
6300 #define AMR_WB_ALL_MODES 0x83ff
6302 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
6304 /* The 'damr' atom is of the form:
6306 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
6307 * 32 b 8 b 16 b 8 b 8 b
6309 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
6310 * represents the highest mode used in the stream (and thus the maximum
6311 * bitrate), with a couple of special cases as seen below.
6314 /* Map of frame type ID -> bitrate */
6315 static const guint nb_bitrates[] = {
6316 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
6318 static const guint wb_bitrates[] = {
6319 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
6325 gst_buffer_map (buf, &map, GST_MAP_READ);
6327 if (map.size != 0x11) {
6328 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
6332 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
6333 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
6334 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
6338 mode_set = QT_UINT16 (map.data + 13);
6340 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
6341 max_mode = 7 + (wb ? 1 : 0);
6343 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
6344 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
6346 if (max_mode == -1) {
6347 GST_DEBUG ("No mode indication was found (mode set) = %x",
6352 gst_buffer_unmap (buf, &map);
6353 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
6356 gst_buffer_unmap (buf, &map);
6361 * With each track we associate a new QtDemuxStream that contains all the info
6363 * traks that do not decode to something (like strm traks) will not have a pad.
6366 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6381 QtDemuxStream *stream;
6382 GstTagList *list = NULL;
6383 gchar *codec = NULL;
6384 const guint8 *stsd_data;
6385 guint16 lang_code; /* quicktime lang code or packed iso code */
6387 guint32 tkhd_flags = 0;
6388 guint8 tkhd_version = 0;
6390 guint value_size, len;
6392 stream = g_new0 (QtDemuxStream, 1);
6393 /* new streams always need a discont */
6394 stream->discont = TRUE;
6395 /* we enable clipping for raw audio/video streams */
6396 stream->need_clip = FALSE;
6397 stream->need_process = FALSE;
6398 stream->segment_index = -1;
6399 stream->time_position = 0;
6400 stream->sample_index = -1;
6401 stream->last_ret = GST_FLOW_OK;
6403 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6404 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6405 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6408 /* pick between 64 or 32 bits */
6409 value_size = tkhd_version == 1 ? 8 : 4;
6410 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6411 !gst_byte_reader_get_uint32_be (&tkhd, &stream->track_id))
6414 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6415 tkhd_version, tkhd_flags, stream->track_id);
6417 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6420 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6421 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6422 if (qtdemux->major_brand != FOURCC_mjp2 ||
6423 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6427 len = QT_UINT32 ((guint8 *) mdhd->data);
6428 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6429 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6430 if (version == 0x01000000) {
6433 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6434 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6435 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6439 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6440 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6441 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6444 if (lang_code < 0x800) {
6445 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6447 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6448 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6449 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6450 stream->lang_id[3] = 0;
6453 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6455 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6457 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6458 lang_code, stream->lang_id);
6460 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6463 /* fragmented files may have bogus duration in moov */
6464 if (!qtdemux->fragmented &&
6465 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6466 guint64 tdur1, tdur2;
6468 /* don't overflow */
6469 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6470 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6473 * some of those trailers, nowadays, have prologue images that are
6474 * themselves vide tracks as well. I haven't really found a way to
6475 * identify those yet, except for just looking at their duration. */
6476 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6477 GST_WARNING_OBJECT (qtdemux,
6478 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6479 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6480 "found, assuming preview image or something; skipping track",
6481 stream->duration, stream->timescale, qtdemux->duration,
6482 qtdemux->timescale);
6488 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6491 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6492 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6494 len = QT_UINT32 ((guint8 *) hdlr->data);
6496 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6497 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6498 GST_FOURCC_ARGS (stream->subtype));
6500 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6503 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6507 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6509 stsd_data = (const guint8 *) stsd->data;
6511 /* stsd should at least have one entry */
6512 len = QT_UINT32 (stsd_data);
6516 /* and that entry should fit within stsd */
6517 len = QT_UINT32 (stsd_data + 16);
6518 if (len > QT_UINT32 (stsd_data) + 16)
6520 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6522 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6523 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6524 GST_FOURCC_ARGS (stream->fourcc));
6526 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6527 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6528 goto error_encrypted;
6530 if (stream->subtype == FOURCC_vide) {
6531 guint32 w = 0, h = 0;
6533 stream->sampled = TRUE;
6535 /* version 1 uses some 64-bit ints */
6536 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6537 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6538 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6541 stream->display_width = w >> 16;
6542 stream->display_height = h >> 16;
6548 stream->width = QT_UINT16 (stsd_data + offset + 32);
6549 stream->height = QT_UINT16 (stsd_data + offset + 34);
6550 stream->fps_n = 0; /* this is filled in later */
6551 stream->fps_d = 0; /* this is filled in later */
6552 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6553 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6555 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6556 QT_UINT16 (stsd_data + offset + 48));
6559 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6561 list = gst_tag_list_new_empty ();
6562 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6563 GST_TAG_VIDEO_CODEC, codec, NULL);
6570 /* pick 'the' stsd child */
6571 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
6573 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
6574 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
6578 const guint8 *pasp_data = (const guint8 *) pasp->data;
6580 stream->par_w = QT_UINT32 (pasp_data + 8);
6581 stream->par_h = QT_UINT32 (pasp_data + 12);
6588 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
6593 gint len = QT_UINT32 (stsd_data) - 0x66;
6594 const guint8 *avc_data = stsd_data + 0x66;
6597 while (len >= 0x8) {
6600 if (QT_UINT32 (avc_data) <= len)
6601 size = QT_UINT32 (avc_data) - 0x8;
6606 /* No real data, so break out */
6609 switch (QT_FOURCC (avc_data + 0x4)) {
6612 /* parse, if found */
6615 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
6617 /* First 4 bytes are the length of the atom, the next 4 bytes
6618 * are the fourcc, the next 1 byte is the version, and the
6619 * subsequent bytes are sequence parameter set like data. */
6620 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
6621 avc_data + 8 + 1, size - 1);
6623 buf = gst_buffer_new_and_alloc (size);
6624 _gst_buffer_copy_into_mem (buf, 0, avc_data + 0x8, size);
6625 gst_caps_set_simple (stream->caps,
6626 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6627 gst_buffer_unref (buf);
6633 guint avg_bitrate, max_bitrate;
6635 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
6639 max_bitrate = QT_UINT32 (avc_data + 0xc);
6640 avg_bitrate = QT_UINT32 (avc_data + 0x10);
6642 if (!max_bitrate && !avg_bitrate)
6645 /* Some muxers seem to swap the average and maximum bitrates
6646 * (I'm looking at you, YouTube), so we swap for sanity. */
6647 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
6648 guint temp = avg_bitrate;
6650 avg_bitrate = max_bitrate;
6655 list = gst_tag_list_new_empty ();
6657 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6658 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6659 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6661 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6662 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6663 GST_TAG_BITRATE, avg_bitrate, NULL);
6674 avc_data += size + 8;
6686 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
6687 GST_FOURCC_ARGS (fourcc));
6689 /* codec data might be in glbl extension atom */
6691 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
6697 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
6699 len = QT_UINT32 (data);
6702 buf = gst_buffer_new_and_alloc (len);
6703 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
6704 gst_caps_set_simple (stream->caps,
6705 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6706 gst_buffer_unref (buf);
6713 /* see annex I of the jpeg2000 spec */
6714 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
6716 const gchar *colorspace = NULL;
6718 guint32 ncomp_map = 0;
6719 gint32 *comp_map = NULL;
6720 guint32 nchan_def = 0;
6721 gint32 *chan_def = NULL;
6723 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
6724 /* some required atoms */
6725 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
6728 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
6732 /* number of components; redundant with info in codestream, but useful
6734 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
6735 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
6737 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
6739 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
6742 GST_DEBUG_OBJECT (qtdemux, "found colr");
6743 /* extract colour space info */
6744 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
6745 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
6747 colorspace = "sRGB";
6750 colorspace = "GRAY";
6753 colorspace = "sYUV";
6761 /* colr is required, and only values 16, 17, and 18 are specified,
6762 so error if we have no colorspace */
6765 /* extract component mapping */
6766 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
6768 guint32 cmap_len = 0;
6770 cmap_len = QT_UINT32 (cmap->data);
6771 if (cmap_len >= 8) {
6772 /* normal box, subtract off header */
6774 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
6775 if (cmap_len % 4 == 0) {
6776 ncomp_map = (cmap_len / 4);
6777 comp_map = g_new0 (gint32, ncomp_map);
6778 for (i = 0; i < ncomp_map; i++) {
6781 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
6782 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
6783 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
6784 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
6789 /* extract channel definitions */
6790 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
6792 guint32 cdef_len = 0;
6794 cdef_len = QT_UINT32 (cdef->data);
6795 if (cdef_len >= 10) {
6796 /* normal box, subtract off header and len */
6798 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
6799 if (cdef_len % 6 == 0) {
6800 nchan_def = (cdef_len / 6);
6801 chan_def = g_new0 (gint32, nchan_def);
6802 for (i = 0; i < nchan_def; i++)
6804 for (i = 0; i < nchan_def; i++) {
6805 guint16 cn, typ, asoc;
6806 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
6807 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
6808 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
6809 if (cn < nchan_def) {
6812 chan_def[cn] = asoc;
6815 chan_def[cn] = 0; /* alpha */
6818 chan_def[cn] = -typ;
6826 gst_caps_set_simple (stream->caps,
6827 "num-components", G_TYPE_INT, ncomp, NULL);
6828 gst_caps_set_simple (stream->caps,
6829 "colorspace", G_TYPE_STRING, colorspace, NULL);
6832 GValue arr = { 0, };
6833 GValue elt = { 0, };
6835 g_value_init (&arr, GST_TYPE_ARRAY);
6836 g_value_init (&elt, G_TYPE_INT);
6837 for (i = 0; i < ncomp_map; i++) {
6838 g_value_set_int (&elt, comp_map[i]);
6839 gst_value_array_append_value (&arr, &elt);
6841 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6842 "component-map", &arr);
6843 g_value_unset (&elt);
6844 g_value_unset (&arr);
6849 GValue arr = { 0, };
6850 GValue elt = { 0, };
6852 g_value_init (&arr, GST_TYPE_ARRAY);
6853 g_value_init (&elt, G_TYPE_INT);
6854 for (i = 0; i < nchan_def; i++) {
6855 g_value_set_int (&elt, chan_def[i]);
6856 gst_value_array_append_value (&arr, &elt);
6858 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6859 "channel-definitions", &arr);
6860 g_value_unset (&elt);
6861 g_value_unset (&arr);
6865 /* some optional atoms */
6866 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
6867 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
6869 /* indicate possible fields in caps */
6871 data = (guint8 *) field->data + 8;
6873 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
6874 (gint) * data, NULL);
6876 /* add codec_data if provided */
6881 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
6882 data = prefix->data;
6883 len = QT_UINT32 (data);
6886 buf = gst_buffer_new_and_alloc (len);
6887 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
6888 gst_caps_set_simple (stream->caps,
6889 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6890 gst_buffer_unref (buf);
6899 GstBuffer *seqh = NULL;
6900 guint8 *gamma_data = NULL;
6901 gint len = QT_UINT32 (stsd_data);
6903 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
6905 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
6906 QT_FP32 (gamma_data), NULL);
6909 /* sorry for the bad name, but we don't know what this is, other
6910 * than its own fourcc */
6911 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
6915 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
6916 buf = gst_buffer_new_and_alloc (len);
6917 _gst_buffer_copy_into_mem (buf, 0, stsd_data, len);
6918 gst_caps_set_simple (stream->caps,
6919 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6920 gst_buffer_unref (buf);
6925 gst_caps_set_simple (stream->caps,
6926 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
6933 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
6934 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
6938 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
6942 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
6943 /* collect the headers and store them in a stream list so that we can
6944 * send them out first */
6945 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
6955 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
6956 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
6959 ovc1_data = ovc1->data;
6960 ovc1_len = QT_UINT32 (ovc1_data);
6961 if (ovc1_len <= 198) {
6962 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
6965 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
6966 _gst_buffer_copy_into_mem (buf, 0, ovc1_data + 198, ovc1_len - 198);
6967 gst_caps_set_simple (stream->caps,
6968 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6969 gst_buffer_unref (buf);
6977 GST_INFO_OBJECT (qtdemux,
6978 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
6979 GST_FOURCC_ARGS (fourcc), stream->caps);
6981 } else if (stream->subtype == FOURCC_soun) {
6982 int version, samplesize;
6983 guint16 compression_id;
6984 gboolean amrwb = FALSE;
6990 version = QT_UINT32 (stsd_data + offset);
6991 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
6992 samplesize = QT_UINT16 (stsd_data + offset + 10);
6993 compression_id = QT_UINT16 (stsd_data + offset + 12);
6994 stream->rate = QT_FP32 (stsd_data + offset + 16);
6996 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
6997 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
6998 QT_UINT32 (stsd_data + offset + 4));
6999 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7000 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
7001 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
7002 GST_LOG_OBJECT (qtdemux, "packet size: %d",
7003 QT_UINT16 (stsd_data + offset + 14));
7004 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7006 if (compression_id == 0xfffe)
7007 stream->sampled = TRUE;
7009 /* first assume uncompressed audio */
7010 stream->bytes_per_sample = samplesize / 8;
7011 stream->samples_per_frame = stream->n_channels;
7012 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
7013 stream->samples_per_packet = stream->samples_per_frame;
7014 stream->bytes_per_packet = stream->bytes_per_sample;
7018 /* Yes, these have to be hard-coded */
7021 stream->samples_per_packet = 6;
7022 stream->bytes_per_packet = 1;
7023 stream->bytes_per_frame = 1 * stream->n_channels;
7024 stream->bytes_per_sample = 1;
7025 stream->samples_per_frame = 6 * stream->n_channels;
7030 stream->samples_per_packet = 3;
7031 stream->bytes_per_packet = 1;
7032 stream->bytes_per_frame = 1 * stream->n_channels;
7033 stream->bytes_per_sample = 1;
7034 stream->samples_per_frame = 3 * stream->n_channels;
7039 stream->samples_per_packet = 64;
7040 stream->bytes_per_packet = 34;
7041 stream->bytes_per_frame = 34 * stream->n_channels;
7042 stream->bytes_per_sample = 2;
7043 stream->samples_per_frame = 64 * stream->n_channels;
7049 stream->samples_per_packet = 1;
7050 stream->bytes_per_packet = 1;
7051 stream->bytes_per_frame = 1 * stream->n_channels;
7052 stream->bytes_per_sample = 1;
7053 stream->samples_per_frame = 1 * stream->n_channels;
7058 stream->samples_per_packet = 160;
7059 stream->bytes_per_packet = 33;
7060 stream->bytes_per_frame = 33 * stream->n_channels;
7061 stream->bytes_per_sample = 2;
7062 stream->samples_per_frame = 160 * stream->n_channels;
7069 if (version == 0x00010000) {
7077 /* only parse extra decoding config for non-pcm audio */
7078 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7079 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
7080 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
7081 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
7083 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7084 stream->samples_per_packet);
7085 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7086 stream->bytes_per_packet);
7087 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
7088 stream->bytes_per_frame);
7089 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
7090 stream->bytes_per_sample);
7092 if (!stream->sampled && stream->bytes_per_packet) {
7093 stream->samples_per_frame = (stream->bytes_per_frame /
7094 stream->bytes_per_packet) * stream->samples_per_packet;
7095 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
7096 stream->samples_per_frame);
7101 } else if (version == 0x00020000) {
7108 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7109 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
7110 stream->rate = qtfp.fp;
7111 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
7113 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7114 stream->samples_per_packet);
7115 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7116 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7119 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
7122 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
7131 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
7133 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
7135 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
7137 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
7140 gst_caps_set_simple (stream->caps,
7141 "format", G_TYPE_STRING, "S24_3LE", NULL);
7148 const guint8 *owma_data;
7149 const gchar *codec_name = NULL;
7153 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
7154 /* FIXME this should also be gst_riff_strf_auds,
7155 * but the latter one is actually missing bits-per-sample :( */
7160 gint32 nSamplesPerSec;
7161 gint32 nAvgBytesPerSec;
7163 gint16 wBitsPerSample;
7168 GST_DEBUG_OBJECT (qtdemux, "parse owma");
7169 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
7172 owma_data = owma->data;
7173 owma_len = QT_UINT32 (owma_data);
7174 if (owma_len <= 54) {
7175 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
7178 wfex = (WAVEFORMATEX *) (owma_data + 36);
7179 buf = gst_buffer_new_and_alloc (owma_len - 54);
7180 _gst_buffer_copy_into_mem (buf, 0, owma_data + 54, owma_len - 54);
7181 if (wfex->wFormatTag == 0x0161) {
7182 codec_name = "Windows Media Audio";
7184 } else if (wfex->wFormatTag == 0x0162) {
7185 codec_name = "Windows Media Audio 9 Pro";
7187 } else if (wfex->wFormatTag == 0x0163) {
7188 codec_name = "Windows Media Audio 9 Lossless";
7189 /* is that correct? gstffmpegcodecmap.c is missing it, but
7190 * fluendo codec seems to support it */
7194 gst_caps_set_simple (stream->caps,
7195 "codec_data", GST_TYPE_BUFFER, buf,
7196 "wmaversion", G_TYPE_INT, version,
7197 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
7198 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
7199 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7200 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7202 gst_buffer_unref (buf);
7206 codec = g_strdup (codec_name);
7218 list = gst_tag_list_new_empty ();
7219 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7220 GST_TAG_AUDIO_CODEC, codec, NULL);
7224 /* some bitrate info may have ended up in caps */
7225 s = gst_caps_get_structure (stream->caps, 0);
7226 gst_structure_get_int (s, "bitrate", &bitrate);
7228 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7232 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7236 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7238 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7240 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7244 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7245 16 bits is a byte-swapped wave-style codec identifier,
7246 and we can find a WAVE header internally to a 'wave' atom here.
7247 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7248 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7251 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7252 if (len < offset + 20) {
7253 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7255 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7256 const guint8 *data = stsd_data + offset + 16;
7258 GNode *waveheadernode;
7260 wavenode = g_node_new ((guint8 *) data);
7261 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7262 const guint8 *waveheader;
7265 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7266 if (waveheadernode) {
7267 waveheader = (const guint8 *) waveheadernode->data;
7268 headerlen = QT_UINT32 (waveheader);
7270 if (headerlen > 8) {
7271 gst_riff_strf_auds *header = NULL;
7272 GstBuffer *headerbuf;
7278 headerbuf = gst_buffer_new_and_alloc (headerlen);
7279 _gst_buffer_copy_into_mem (headerbuf, 0, waveheader, headerlen);
7281 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7282 headerbuf, &header, &extra)) {
7283 gst_caps_unref (stream->caps);
7284 /* FIXME: Need to do something with the channel reorder map */
7285 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7286 header, extra, NULL, NULL, NULL);
7289 gst_buffer_unref (extra);
7293 GST_DEBUG ("Didn't find waveheadernode for this codec");
7295 g_node_destroy (wavenode);
7298 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7302 /* FIXME: what is in the chunk? */
7305 gint len = QT_UINT32 (stsd_data);
7307 /* seems to be always = 116 = 0x74 */
7313 gint len = QT_UINT32 (stsd_data);
7316 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7318 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x4C, len - 0x4C);
7319 gst_caps_set_simple (stream->caps,
7320 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7321 gst_buffer_unref (buf);
7323 gst_caps_set_simple (stream->caps,
7324 "samplesize", G_TYPE_INT, samplesize, NULL);
7329 GNode *alac, *wave = NULL;
7331 /* apparently, m4a has this atom appended directly in the stsd entry,
7332 * while mov has it in a wave atom */
7333 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7335 /* alac now refers to stsd entry atom */
7336 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7338 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7340 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7343 gint len = QT_UINT32 (alac->data);
7347 GST_DEBUG_OBJECT (qtdemux,
7348 "discarding alac atom with unexpected len %d", len);
7350 /* codec-data contains alac atom size and prefix,
7351 * ffmpeg likes it that way, not quite gst-ish though ...*/
7352 buf = gst_buffer_new_and_alloc (len);
7353 _gst_buffer_copy_into_mem (buf, 0, alac->data, len);
7354 gst_caps_set_simple (stream->caps,
7355 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7356 gst_buffer_unref (buf);
7359 gst_caps_set_simple (stream->caps,
7360 "samplesize", G_TYPE_INT, samplesize, NULL);
7368 gint len = QT_UINT32 (stsd_data);
7371 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7374 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x34, len - 0x34);
7376 /* If we have enough data, let's try to get the 'damr' atom. See
7377 * the 3GPP container spec (26.244) for more details. */
7378 if ((len - 0x34) > 8 &&
7379 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
7381 list = gst_tag_list_new_empty ();
7382 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7383 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
7386 gst_caps_set_simple (stream->caps,
7387 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7388 gst_buffer_unref (buf);
7396 GST_INFO_OBJECT (qtdemux,
7397 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7398 GST_FOURCC_ARGS (fourcc), stream->caps);
7400 } else if (stream->subtype == FOURCC_strm) {
7401 if (fourcc == FOURCC_rtsp) {
7402 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7404 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7405 GST_FOURCC_ARGS (fourcc));
7406 goto unknown_stream;
7408 stream->sampled = TRUE;
7409 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
7411 stream->sampled = TRUE;
7416 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7418 list = gst_tag_list_new_empty ();
7419 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7420 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7425 /* hunt for sort-of codec data */
7432 /* look for palette */
7433 /* target mp4s atom */
7434 len = QT_UINT32 (stsd_data + offset);
7435 data = stsd_data + offset;
7436 /* verify sufficient length,
7437 * and esds present with decConfigDescr of expected size and position */
7438 if ((len >= 106 + 8)
7439 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7440 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7445 /* move to decConfigDescr data */
7446 data = data + 8 + 42;
7447 for (i = 0; i < 16; i++) {
7448 clut[i] = QT_UINT32 (data);
7452 s = gst_structure_new ("application/x-gst-dvd", "event",
7453 G_TYPE_STRING, "dvd-spu-clut-change",
7454 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7455 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7456 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7457 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7458 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7459 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7460 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7461 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7464 /* store event and trigger custom processing */
7465 stream->pending_event =
7466 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7467 stream->need_process = TRUE;
7475 goto unknown_stream;
7478 /* promote to sampled format */
7479 if (stream->fourcc == FOURCC_samr) {
7480 /* force mono 8000 Hz for AMR */
7481 stream->sampled = TRUE;
7482 stream->n_channels = 1;
7483 stream->rate = 8000;
7484 } else if (stream->fourcc == FOURCC_sawb) {
7485 /* force mono 16000 Hz for AMR-WB */
7486 stream->sampled = TRUE;
7487 stream->n_channels = 1;
7488 stream->rate = 16000;
7489 } else if (stream->fourcc == FOURCC_mp4a) {
7490 stream->sampled = TRUE;
7493 /* collect sample information */
7494 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7495 goto samples_failed;
7497 if (qtdemux->fragmented) {
7501 /* need all moov samples as basis; probably not many if any at all */
7502 /* prevent moof parsing taking of at this time */
7503 offset = qtdemux->moof_offset;
7504 qtdemux->moof_offset = 0;
7505 if (stream->n_samples &&
7506 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7507 qtdemux->moof_offset = offset;
7508 goto samples_failed;
7510 qtdemux->moof_offset = 0;
7511 /* movie duration more reliable in this case (e.g. mehd) */
7512 if (qtdemux->segment.duration &&
7513 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7514 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7515 stream->timescale, GST_SECOND);
7516 /* need defaults for fragments */
7517 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7520 /* configure segments */
7521 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7522 goto segments_failed;
7524 /* add some language tag, if useful */
7525 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7526 strcmp (stream->lang_id, "und")) {
7527 const gchar *lang_code;
7530 list = gst_tag_list_new_empty ();
7532 /* convert ISO 639-2 code to ISO 639-1 */
7533 lang_code = gst_tag_get_language_code (stream->lang_id);
7534 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7535 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7538 /* now we are ready to add the stream */
7539 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7540 goto too_many_streams;
7542 stream->pending_tags = list;
7543 qtdemux->streams[qtdemux->n_streams] = stream;
7544 qtdemux->n_streams++;
7545 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7552 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7553 (_("This file is corrupt and cannot be played.")), (NULL));
7559 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7566 /* we posted an error already */
7567 /* free stbl sub-atoms */
7568 gst_qtdemux_stbl_free (stream);
7574 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7575 GST_FOURCC_ARGS (stream->subtype));
7581 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7582 (_("This file contains too many streams. Only playing first %d"),
7583 GST_QTDEMUX_MAX_STREAMS), (NULL));
7588 /* If we can estimate the overall bitrate, and don't have information about the
7589 * stream bitrate for exactly one stream, this guesses the stream bitrate as
7590 * the overall bitrate minus the sum of the bitrates of all other streams. This
7591 * should be useful for the common case where we have one audio and one video
7592 * stream and can estimate the bitrate of one, but not the other. */
7594 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
7596 QtDemuxStream *stream = NULL;
7597 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
7601 if (qtdemux->fragmented)
7604 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
7606 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)) {
7607 GST_DEBUG_OBJECT (qtdemux,
7608 "Size in bytes of the stream not known - bailing");
7612 /* Subtract the header size */
7613 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
7614 size, qtdemux->header_size);
7615 g_assert (size >= qtdemux->header_size);
7616 size = size - qtdemux->header_size;
7618 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
7619 duration == GST_CLOCK_TIME_NONE) {
7620 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
7624 for (i = 0; i < qtdemux->n_streams; i++) {
7625 switch (qtdemux->streams[i]->subtype) {
7628 /* retrieve bitrate, prefer avg then max */
7630 if (qtdemux->streams[i]->pending_tags) {
7631 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7632 GST_TAG_MAXIMUM_BITRATE, &bitrate);
7633 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7634 GST_TAG_BITRATE, &bitrate);
7637 sum_bitrate += bitrate;
7640 GST_DEBUG_OBJECT (qtdemux,
7641 ">1 stream with unknown bitrate - bailing");
7644 stream = qtdemux->streams[i];
7648 /* For other subtypes, we assume no significant impact on bitrate */
7654 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
7658 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
7660 if (sys_bitrate < sum_bitrate) {
7661 /* This can happen, since sum_bitrate might be derived from maximum
7662 * bitrates and not average bitrates */
7663 GST_DEBUG_OBJECT (qtdemux,
7664 "System bitrate less than sum bitrate - bailing");
7668 bitrate = sys_bitrate - sum_bitrate;
7669 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
7670 ", Stream bitrate = %u", sys_bitrate, bitrate);
7672 if (!stream->pending_tags)
7673 stream->pending_tags = gst_tag_list_new_empty ();
7675 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
7676 GST_TAG_BITRATE, bitrate, NULL);
7679 static GstFlowReturn
7680 qtdemux_expose_streams (GstQTDemux * qtdemux)
7683 GstFlowReturn ret = GST_FLOW_OK;
7685 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7687 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7688 QtDemuxStream *stream = qtdemux->streams[i];
7689 guint32 sample_num = 0;
7694 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7695 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7697 if (qtdemux->fragmented) {
7698 /* need all moov samples first */
7699 GST_OBJECT_LOCK (qtdemux);
7700 while (stream->n_samples == 0)
7701 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7703 GST_OBJECT_UNLOCK (qtdemux);
7705 /* discard any stray moof */
7706 qtdemux->moof_offset = 0;
7709 /* prepare braking */
7710 if (ret != GST_FLOW_ERROR)
7713 /* in pull mode, we should have parsed some sample info by now;
7714 * and quite some code will not handle no samples.
7715 * in push mode, we'll just have to deal with it */
7716 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7717 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7718 gst_qtdemux_stream_free (qtdemux, stream);
7719 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7720 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7721 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7722 qtdemux->n_streams--;
7727 /* parse number of initial sample to set frame rate cap */
7728 while (sample_num < stream->n_samples && sample_num < samples) {
7729 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7733 /* collect and sort durations */
7734 samples = MIN (stream->stbl_index + 1, samples);
7735 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7737 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7739 while (sample_num < samples) {
7740 g_array_append_val (durations, stream->samples[sample_num].duration);
7743 g_array_sort (durations, less_than);
7744 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7745 g_array_free (durations, TRUE);
7748 /* now we have all info and can expose */
7749 list = stream->pending_tags;
7750 stream->pending_tags = NULL;
7751 gst_qtdemux_add_stream (qtdemux, stream, list);
7754 gst_qtdemux_guess_bitrate (qtdemux);
7756 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7758 /* check if we should post a redirect in case there is a single trak
7759 * and it is a redirecting trak */
7760 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7763 qtdemux_post_global_tags (qtdemux);
7765 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7766 "an external content");
7767 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7768 gst_structure_new ("redirect",
7769 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7771 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7772 qtdemux->posted_redirect = TRUE;
7778 /* check if major or compatible brand is 3GP */
7779 static inline gboolean
7780 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7783 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7784 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7785 } else if (qtdemux->comp_brands != NULL) {
7789 gboolean res = FALSE;
7791 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
7795 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7796 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7800 gst_buffer_unmap (qtdemux->comp_brands, &map);
7807 /* check if tag is a spec'ed 3GP tag keyword storing a string */
7808 static inline gboolean
7809 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
7811 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
7812 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
7813 || fourcc == FOURCC_albm;
7817 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
7818 const char *dummy, GNode * node)
7820 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7824 gdouble longitude, latitude, altitude;
7827 len = QT_UINT32 (node->data);
7834 /* TODO: language code skipped */
7836 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
7839 /* do not alarm in trivial case, but bail out otherwise */
7840 if (*(data + offset) != 0) {
7841 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
7845 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7846 GST_TAG_GEO_LOCATION_NAME, name, NULL);
7847 offset += strlen (name);
7851 if (len < offset + 2 + 4 + 4 + 4)
7854 /* +1 +1 = skip null-terminator and location role byte */
7856 /* table in spec says unsigned, semantics say negative has meaning ... */
7857 longitude = QT_SFP32 (data + offset);
7860 latitude = QT_SFP32 (data + offset);
7863 altitude = QT_SFP32 (data + offset);
7865 /* one invalid means all are invalid */
7866 if (longitude >= -180.0 && longitude <= 180.0 &&
7867 latitude >= -90.0 && latitude <= 90.0) {
7868 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7869 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
7870 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
7871 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
7874 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
7881 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
7888 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7895 len = QT_UINT32 (node->data);
7899 y = QT_UINT16 ((guint8 *) node->data + 12);
7901 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
7904 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
7906 date = g_date_new_dmy (1, 1, y);
7907 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
7912 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
7913 const char *dummy, GNode * node)
7916 char *tag_str = NULL;
7921 len = QT_UINT32 (node->data);
7926 entity = (guint8 *) node->data + offset;
7927 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
7928 GST_DEBUG_OBJECT (qtdemux,
7929 "classification info: %c%c%c%c invalid classification entity",
7930 entity[0], entity[1], entity[2], entity[3]);
7935 table = QT_UINT16 ((guint8 *) node->data + offset);
7937 /* Language code skipped */
7941 /* Tag format: "XXXX://Y[YYYY]/classification info string"
7942 * XXXX: classification entity, fixed length 4 chars.
7943 * Y[YYYY]: classification table, max 5 chars.
7945 tag_str = g_strdup_printf ("----://%u/%s",
7946 table, (char *) node->data + offset);
7948 /* memcpy To be sure we're preserving byte order */
7949 memcpy (tag_str, entity, 4);
7950 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
7952 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
7962 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
7968 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
7969 const char *dummy, GNode * node)
7971 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7977 gboolean ret = TRUE;
7979 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7981 len = QT_UINT32 (data->data);
7982 type = QT_UINT32 ((guint8 *) data->data + 8);
7983 if (type == 0x00000001 && len > 16) {
7984 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
7987 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7988 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
7992 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7996 len = QT_UINT32 (node->data);
7997 type = QT_UINT32 ((guint8 *) node->data + 4);
7998 if ((type >> 24) == 0xa9) {
7999 /* Type starts with the (C) symbol, so the next 32 bits are
8000 * the language code, which we ignore */
8002 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
8003 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
8004 QT_FOURCC ((guint8 *) node->data + 4))) {
8005 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
8007 /* we go for 3GP style encoding if major brands claims so,
8008 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
8009 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8010 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
8011 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
8013 /* 16-bit Language code is ignored here as well */
8014 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
8021 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
8022 ret = FALSE; /* may have to fallback */
8024 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8025 len - offset, env_vars);
8027 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
8028 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
8032 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
8039 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
8040 const char *dummy, GNode * node)
8042 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
8046 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
8047 const char *dummy, GNode * node)
8049 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8051 char *s, *t, *k = NULL;
8056 /* first try normal string tag if major brand not 3GP */
8057 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
8058 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
8059 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
8060 * let's try it 3gpp way after minor safety check */
8062 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
8068 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
8072 len = QT_UINT32 (data);
8076 count = QT_UINT8 (data + 14);
8078 for (; count; count--) {
8081 if (offset + 1 > len)
8083 slen = QT_UINT8 (data + offset);
8085 if (offset + slen > len)
8087 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8090 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
8092 t = g_strjoin (",", k, s, NULL);
8100 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
8107 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
8108 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
8117 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
8123 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
8124 const char *tag2, GNode * node)
8131 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8133 len = QT_UINT32 (data->data);
8134 type = QT_UINT32 ((guint8 *) data->data + 8);
8135 if (type == 0x00000000 && len >= 22) {
8136 n1 = QT_UINT16 ((guint8 *) data->data + 18);
8137 n2 = QT_UINT16 ((guint8 *) data->data + 20);
8139 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
8140 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8144 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
8145 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8153 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8161 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8163 len = QT_UINT32 (data->data);
8164 type = QT_UINT32 ((guint8 *) data->data + 8);
8165 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
8166 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8167 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
8168 n1 = QT_UINT16 ((guint8 *) data->data + 16);
8170 /* do not add bpm=0 */
8171 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
8172 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8173 tag1, (gdouble) n1, NULL);
8180 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
8181 const char *dummy, GNode * node)
8188 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8190 len = QT_UINT32 (data->data);
8191 type = QT_UINT32 ((guint8 *) data->data + 8);
8192 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
8193 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8194 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
8195 num = QT_UINT32 ((guint8 *) data->data + 16);
8197 /* do not add num=0 */
8198 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
8199 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8207 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8215 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8217 len = QT_UINT32 (data->data);
8218 type = QT_UINT32 ((guint8 *) data->data + 8);
8219 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
8220 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
8222 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
8223 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
8224 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
8225 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8226 tag1, sample, NULL);
8227 gst_sample_unref (sample);
8234 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8242 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8244 len = QT_UINT32 (data->data);
8245 type = QT_UINT32 ((guint8 *) data->data + 8);
8246 if (type == 0x00000001 && len > 16) {
8247 guint y, m = 1, d = 1;
8250 s = g_strndup ((char *) data->data + 16, len - 16);
8251 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
8252 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
8253 if (ret >= 1 && y > 1500 && y < 3000) {
8256 date = g_date_new_dmy (d, m, y);
8257 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
8261 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
8269 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8274 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8276 /* re-route to normal string tag if major brand says so
8277 * or no data atom and compatible brand suggests so */
8278 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8279 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
8280 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
8287 len = QT_UINT32 (data->data);
8288 type = QT_UINT32 ((guint8 *) data->data + 8);
8289 if (type == 0x00000000 && len >= 18) {
8290 n = QT_UINT16 ((guint8 *) data->data + 16);
8294 genre = gst_tag_id3_genre_get (n - 1);
8295 if (genre != NULL) {
8296 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
8297 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8306 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
8307 guint8 * data, guint32 datasize)
8312 /* make a copy to have \0 at the end */
8313 datacopy = g_strndup ((gchar *) data, datasize);
8315 /* convert the str to double */
8316 if (sscanf (datacopy, "%lf", &value) == 1) {
8317 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
8318 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
8320 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
8328 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
8329 const char *tag_bis, GNode * node)
8338 const gchar *meanstr;
8339 const gchar *namestr;
8341 /* checking the whole ---- atom size for consistency */
8342 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8343 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8347 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8349 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8353 meansize = QT_UINT32 (mean->data);
8354 if (meansize <= 12) {
8355 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8358 meanstr = ((gchar *) mean->data) + 12;
8360 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8362 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8366 namesize = QT_UINT32 (name->data);
8367 if (namesize <= 12) {
8368 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8371 namestr = ((gchar *) name->data) + 12;
8378 * uint24 - data type
8382 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8384 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8387 datasize = QT_UINT32 (data->data);
8388 if (datasize <= 16) {
8389 GST_WARNING_OBJECT (demux, "Data atom too small");
8392 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8394 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8397 const gchar name[28];
8398 const gchar tag[28];
8401 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8402 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8403 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8404 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8405 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8406 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8407 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8408 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8412 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8413 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8414 switch (gst_tag_get_type (tags[i].tag)) {
8416 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8417 ((guint8 *) data->data) + 16, datasize - 16);
8420 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8429 if (i == G_N_ELEMENTS (tags))
8443 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8444 namestr_dbg = g_strndup (namestr, namesize - 12);
8446 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8447 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8449 g_free (namestr_dbg);
8450 g_free (meanstr_dbg);
8456 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
8457 const char *tag_bis, GNode * node)
8462 GstTagList *taglist = NULL;
8464 GST_LOG_OBJECT (demux, "parsing ID32");
8467 len = GST_READ_UINT32_BE (data);
8469 /* need at least full box and language tag */
8473 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
8474 gst_buffer_fill (buf, 0, data + 14, len - 14);
8476 taglist = gst_tag_list_from_id3v2_tag (buf);
8478 GST_LOG_OBJECT (demux, "parsing ok");
8479 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
8481 GST_LOG_OBJECT (demux, "parsing failed");
8485 gst_tag_list_free (taglist);
8487 gst_buffer_unref (buf);
8490 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8491 const char *tag, const char *tag_bis, GNode * node);
8494 FOURCC_pcst -> if media is a podcast -> bool
8495 FOURCC_cpil -> if media is part of a compilation -> bool
8496 FOURCC_pgap -> if media is part of a gapless context -> bool
8497 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8503 const gchar *gst_tag;
8504 const gchar *gst_tag_bis;
8505 const GstQTDemuxAddTagFunc func;
8508 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8509 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8510 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8511 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8512 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8513 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8514 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8515 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8516 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8517 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8518 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8519 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8520 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8521 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8522 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8523 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8524 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8525 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8526 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8527 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8528 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8529 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8530 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8531 qtdemux_tag_add_num}, {
8532 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8533 qtdemux_tag_add_num}, {
8534 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8535 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8536 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8537 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8538 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8539 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8540 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8541 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8542 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8543 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8544 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8545 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8546 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8547 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8548 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8549 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8550 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8551 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8552 qtdemux_tag_add_classification}, {
8554 /* This is a special case, some tags are stored in this
8555 * 'reverse dns naming', according to:
8556 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8559 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
8560 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
8561 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
8565 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8577 len = QT_UINT32 (data);
8578 buf = gst_buffer_new_and_alloc (len);
8579 _gst_buffer_copy_into_mem (buf, 0, data, len);
8581 /* heuristic to determine style of tag */
8582 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8583 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8585 else if (demux->major_brand == FOURCC_qt__)
8586 style = "quicktime";
8587 /* fall back to assuming iso/3gp tag style */
8591 /* santize the name for the caps. */
8592 for (i = 0; i < 4; i++) {
8593 guint8 d = data[4 + i];
8594 if (g_ascii_isalnum (d))
8595 ndata[i] = g_ascii_tolower (d);
8600 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8601 ndata[0], ndata[1], ndata[2], ndata[3]);
8602 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8604 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
8605 // TODO conver to metadata or ???
8606 // gst_buffer_set_caps (buf, caps);
8607 gst_caps_unref (caps);
8608 g_free (media_type);
8610 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
8613 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8614 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
8615 gst_buffer_unref (buf);
8619 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8627 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8629 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8631 GST_LOG_OBJECT (qtdemux, "no ilst");
8636 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8639 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8640 if (!qtdemux->tag_list)
8641 qtdemux->tag_list = gst_tag_list_new_empty ();
8644 while (i < G_N_ELEMENTS (add_funcs)) {
8645 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8649 len = QT_UINT32 (node->data);
8651 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8652 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8654 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8655 add_funcs[i].gst_tag_bis, node);
8657 g_node_destroy (node);
8663 /* parsed nodes have been removed, pass along remainder as blob */
8664 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8665 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8667 /* parse up XMP_ node if existing */
8668 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8671 GstTagList *taglist;
8673 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
8674 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
8675 taglist = gst_tag_list_from_xmp_buffer (buf);
8676 gst_buffer_unref (buf);
8678 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8680 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8687 GstStructure *structure; /* helper for sort function */
8689 guint min_req_bitrate;
8690 guint min_req_qt_version;
8694 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8696 GstQtReference *ref_a = (GstQtReference *) a;
8697 GstQtReference *ref_b = (GstQtReference *) b;
8699 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8700 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8702 /* known bitrates go before unknown; higher bitrates go first */
8703 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8706 /* sort the redirects and post a message for the application.
8709 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8711 GstQtReference *best;
8714 GValue list_val = { 0, };
8717 g_assert (references != NULL);
8719 references = g_list_sort (references, qtdemux_redirects_sort_func);
8721 best = (GstQtReference *) references->data;
8723 g_value_init (&list_val, GST_TYPE_LIST);
8725 for (l = references; l != NULL; l = l->next) {
8726 GstQtReference *ref = (GstQtReference *) l->data;
8727 GValue struct_val = { 0, };
8729 ref->structure = gst_structure_new ("redirect",
8730 "new-location", G_TYPE_STRING, ref->location, NULL);
8732 if (ref->min_req_bitrate > 0) {
8733 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8734 ref->min_req_bitrate, NULL);
8737 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8738 g_value_set_boxed (&struct_val, ref->structure);
8739 gst_value_list_append_value (&list_val, &struct_val);
8740 g_value_unset (&struct_val);
8741 /* don't free anything here yet, since we need best->structure below */
8744 g_assert (best != NULL);
8745 s = gst_structure_copy (best->structure);
8747 if (g_list_length (references) > 1) {
8748 gst_structure_set_value (s, "locations", &list_val);
8751 g_value_unset (&list_val);
8753 for (l = references; l != NULL; l = l->next) {
8754 GstQtReference *ref = (GstQtReference *) l->data;
8756 gst_structure_free (ref->structure);
8757 g_free (ref->location);
8760 g_list_free (references);
8762 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8763 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8764 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8765 qtdemux->posted_redirect = TRUE;
8768 /* look for redirect nodes, collect all redirect information and
8772 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8774 GNode *rmra, *rmda, *rdrf;
8776 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8778 GList *redirects = NULL;
8780 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8782 GstQtReference ref = { NULL, NULL, 0, 0 };
8785 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8786 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8787 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8788 ref.min_req_bitrate);
8791 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
8792 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
8793 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
8795 #ifndef GST_DISABLE_GST_DEBUG
8796 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
8798 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
8800 GST_LOG_OBJECT (qtdemux,
8801 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
8802 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
8803 bitmask, check_type);
8804 if (package == FOURCC_qtim && check_type == 0) {
8805 ref.min_req_qt_version = version;
8809 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
8814 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
8815 ref_data = (guint8 *) rdrf->data + 20;
8816 if (ref_type == FOURCC_alis) {
8817 guint record_len, record_version, fn_len;
8819 /* MacOSX alias record, google for alias-layout.txt */
8820 record_len = QT_UINT16 (ref_data + 4);
8821 record_version = QT_UINT16 (ref_data + 4 + 2);
8822 fn_len = QT_UINT8 (ref_data + 50);
8823 if (record_len > 50 && record_version == 2 && fn_len > 0) {
8824 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
8826 } else if (ref_type == FOURCC_url_) {
8827 ref.location = g_strdup ((gchar *) ref_data);
8829 GST_DEBUG_OBJECT (qtdemux,
8830 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
8831 GST_FOURCC_ARGS (ref_type));
8833 if (ref.location != NULL) {
8834 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
8835 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
8837 GST_WARNING_OBJECT (qtdemux,
8838 "Failed to extract redirect location from rdrf atom");
8842 /* look for others */
8843 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
8846 if (redirects != NULL) {
8847 qtdemux_process_redirects (qtdemux, redirects);
8854 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
8859 tags = gst_tag_list_new_empty ();
8861 if (qtdemux->major_brand == FOURCC_mjp2)
8862 fmt = "Motion JPEG 2000";
8863 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
8865 else if (qtdemux->major_brand == FOURCC_qt__)
8867 else if (qtdemux->fragmented)
8870 fmt = "ISO MP4/M4A";
8872 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
8873 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
8875 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
8881 /* we have read th complete moov node now.
8882 * This function parses all of the relevant info, creates the traks and
8883 * prepares all data structures for playback
8886 qtdemux_parse_tree (GstQTDemux * qtdemux)
8893 guint64 creation_time;
8894 GstDateTime *datetime = NULL;
8897 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
8899 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
8900 return qtdemux_parse_redirects (qtdemux);
8903 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
8905 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
8906 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
8907 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
8908 } else if (version == 0) {
8909 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
8910 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
8911 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
8913 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
8917 /* Moving qt creation time (secs since 1904) to unix time */
8918 if (creation_time != 0) {
8919 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
8922 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
8923 /* some data cleansing sanity */
8924 g_get_current_time (&now);
8925 if (now.tv_sec + 24 * 3600 < creation_time) {
8926 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
8928 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
8931 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
8932 "please file a bug at http://bugzilla.gnome.org");
8936 if (!qtdemux->tag_list)
8937 qtdemux->tag_list = gst_tag_list_new_empty ();
8939 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
8940 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
8942 gst_date_time_unref (datetime);
8945 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
8946 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
8948 /* check for fragmented file and get some (default) data */
8949 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
8952 GstByteReader mehd_data;
8954 /* let track parsing or anyone know weird stuff might happen ... */
8955 qtdemux->fragmented = TRUE;
8957 /* compensate for total duration */
8958 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
8960 qtdemux_parse_mehd (qtdemux, &mehd_data);
8963 /* set duration in the segment info */
8964 gst_qtdemux_get_duration (qtdemux, &duration);
8966 qtdemux->segment.duration = duration;
8967 /* also do not exceed duration; stop is set that way post seek anyway,
8968 * and segment activation falls back to duration,
8969 * whereas loop only checks stop, so let's align this here as well */
8970 qtdemux->segment.stop = duration;
8973 /* parse all traks */
8974 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
8976 qtdemux_parse_trak (qtdemux, trak);
8977 /* iterate all siblings */
8978 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
8982 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
8984 qtdemux_parse_udta (qtdemux, udta);
8986 GST_LOG_OBJECT (qtdemux, "No udta node found.");
8989 /* maybe also some tags in meta box */
8990 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
8992 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
8993 qtdemux_parse_udta (qtdemux, udta);
8995 GST_LOG_OBJECT (qtdemux, "No meta node found.");
8998 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
9003 /* taken from ffmpeg */
9005 get_size (guint8 * ptr, guint8 ** end)
9014 len = (len << 7) | (c & 0x7f);
9023 /* this can change the codec originally present in @list */
9025 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
9026 GNode * esds, GstTagList * list)
9028 int len = QT_UINT32 (esds->data);
9029 guint8 *ptr = esds->data;
9030 guint8 *end = ptr + len;
9032 guint8 *data_ptr = NULL;
9034 guint8 object_type_id = 0;
9035 const char *codec_name = NULL;
9036 GstCaps *caps = NULL;
9038 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
9040 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
9043 tag = QT_UINT8 (ptr);
9044 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
9046 len = get_size (ptr, &ptr);
9047 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
9051 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
9052 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
9056 guint max_bitrate, avg_bitrate;
9058 object_type_id = QT_UINT8 (ptr);
9059 max_bitrate = QT_UINT32 (ptr + 5);
9060 avg_bitrate = QT_UINT32 (ptr + 9);
9061 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
9062 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
9063 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
9064 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
9065 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
9066 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9067 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9068 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9070 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9071 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
9078 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
9084 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
9088 GST_ERROR_OBJECT (qtdemux, "parse error");
9093 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
9094 * in use, and should also be used to override some other parameters for some
9096 switch (object_type_id) {
9097 case 0x20: /* MPEG-4 */
9098 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
9099 * profile_and_level_indication */
9100 if (data_ptr != NULL && data_len >= 5 &&
9101 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
9102 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
9103 data_ptr + 4, data_len - 4);
9105 break; /* Nothing special needed here */
9106 case 0x21: /* H.264 */
9107 codec_name = "H.264 / AVC";
9108 caps = gst_caps_new_simple ("video/x-h264",
9109 "stream-format", G_TYPE_STRING, "avc",
9110 "alignment", G_TYPE_STRING, "au", NULL);
9112 case 0x40: /* AAC (any) */
9113 case 0x66: /* AAC Main */
9114 case 0x67: /* AAC LC */
9115 case 0x68: /* AAC SSR */
9116 /* Override channels and rate based on the codec_data, as it's often
9118 /* Only do so for basic setup without HE-AAC extension */
9119 if (data_ptr && data_len == 2) {
9120 guint channels, rateindex, rate;
9122 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
9123 channels = (data_ptr[1] & 0x7f) >> 3;
9124 if (channels > 0 && channels < 7) {
9125 stream->n_channels = channels;
9126 } else if (channels == 7) {
9127 stream->n_channels = 8;
9130 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
9131 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
9133 stream->rate = rate;
9136 /* Set level and profile if possible */
9137 if (data_ptr != NULL && data_len >= 2) {
9138 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
9139 data_ptr, data_len);
9142 case 0x60: /* MPEG-2, various profiles */
9148 codec_name = "MPEG-2 video";
9150 gst_caps_unref (stream->caps);
9151 stream->caps = gst_caps_new_simple ("video/mpeg",
9152 "mpegversion", G_TYPE_INT, 2,
9153 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9155 case 0x69: /* MP3 has two different values, accept either */
9157 /* change to mpeg1 layer 3 audio */
9158 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
9159 "mpegversion", G_TYPE_INT, 1, NULL);
9160 codec_name = "MPEG-1 layer 3";
9162 case 0x6A: /* MPEG-1 */
9163 codec_name = "MPEG-1 video";
9165 gst_caps_unref (stream->caps);
9166 stream->caps = gst_caps_new_simple ("video/mpeg",
9167 "mpegversion", G_TYPE_INT, 1,
9168 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9170 case 0x6C: /* MJPEG */
9171 caps = gst_caps_new_empty_simple ("image/jpeg");
9172 codec_name = "Motion-JPEG";
9174 case 0x6D: /* PNG */
9175 caps = gst_caps_new_empty_simple ("image/png");
9176 codec_name = "PNG still images";
9178 case 0x6E: /* JPEG2000 */
9179 codec_name = "JPEG-2000";
9180 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9182 case 0xA4: /* Dirac */
9183 codec_name = "Dirac";
9184 caps = gst_caps_new_empty_simple ("video/x-dirac");
9186 case 0xA5: /* AC3 */
9187 codec_name = "AC-3 audio";
9188 caps = gst_caps_new_simple ("audio/x-ac3",
9189 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9191 case 0xE1: /* QCELP */
9192 /* QCELP, the codec_data is a riff tag (little endian) with
9193 * 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). */
9194 caps = gst_caps_new_empty_simple ("audio/qcelp");
9195 codec_name = "QCELP";
9201 /* If we have a replacement caps, then change our caps for this stream */
9203 gst_caps_unref (stream->caps);
9204 stream->caps = caps;
9207 if (codec_name && list)
9208 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9209 GST_TAG_AUDIO_CODEC, codec_name, NULL);
9211 /* Add the codec_data attribute to caps, if we have it */
9215 buffer = gst_buffer_new_and_alloc (data_len);
9216 _gst_buffer_copy_into_mem (buffer, 0, data_ptr, data_len);
9218 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
9219 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
9221 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
9223 gst_buffer_unref (buffer);
9228 #define _codec(name) \
9231 *codec_name = g_strdup (name); \
9236 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9237 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9240 const GstStructure *s;
9244 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
9245 _codec ("PNG still images");
9246 caps = gst_caps_new_empty_simple ("image/png");
9248 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
9249 _codec ("JPEG still images");
9250 caps = gst_caps_new_empty_simple ("image/jpeg");
9252 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
9253 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
9254 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
9255 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
9256 _codec ("Motion-JPEG");
9257 caps = gst_caps_new_empty_simple ("image/jpeg");
9259 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
9260 _codec ("Motion-JPEG format B");
9261 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
9263 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
9264 _codec ("JPEG-2000");
9265 /* override to what it should be according to spec, avoid palette_data */
9266 stream->bits_per_sample = 24;
9267 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9269 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
9270 _codec ("Sorensen video v.3");
9271 caps = gst_caps_new_simple ("video/x-svq",
9272 "svqversion", G_TYPE_INT, 3, NULL);
9274 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
9275 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
9276 _codec ("Sorensen video v.1");
9277 caps = gst_caps_new_simple ("video/x-svq",
9278 "svqversion", G_TYPE_INT, 1, NULL);
9280 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9284 _codec ("Raw RGB video");
9285 bps = QT_UINT16 (stsd_data + 98);
9286 /* set common stuff */
9287 caps = gst_caps_new_empty_simple ("video/x-raw");
9291 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB15", NULL);
9294 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB16", NULL);
9297 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB", NULL);
9300 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "ARGB", NULL);
9308 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
9309 _codec ("Raw planar YUV 4:2:0");
9310 caps = gst_caps_new_simple ("video/x-raw",
9311 "format", G_TYPE_STRING, "I420", NULL);
9313 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
9314 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
9315 _codec ("Raw packed YUV 4:2:2");
9316 caps = gst_caps_new_simple ("video/x-raw",
9317 "format", G_TYPE_STRING, "YUY2", NULL);
9319 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
9320 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
9321 _codec ("Raw packed YUV 4:2:2");
9322 caps = gst_caps_new_simple ("video/x-raw",
9323 "format", G_TYPE_STRING, "UYVY", NULL);
9325 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
9326 _codec ("Raw packed YUV 10-bit 4:2:2");
9327 caps = gst_caps_new_simple ("video/x-raw",
9328 "format", G_TYPE_STRING, "v210", NULL);
9330 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
9331 _codec ("Raw packed RGB 10-bit 4:4:4");
9332 caps = gst_caps_new_simple ("video/x-raw",
9333 "format", G_TYPE_STRING, "r210", NULL);
9335 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
9336 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
9337 _codec ("MPEG-1 video");
9338 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9339 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9341 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
9342 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
9343 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
9344 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
9345 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
9346 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
9347 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
9348 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
9349 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
9350 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
9351 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
9352 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
9353 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
9354 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
9355 _codec ("MPEG-2 video");
9356 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
9357 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9359 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
9360 _codec ("GIF still images");
9361 caps = gst_caps_new_empty_simple ("image/gif");
9363 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
9364 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
9365 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
9366 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9368 /* ffmpeg uses the height/width props, don't know why */
9369 caps = gst_caps_new_empty_simple ("video/x-h263");
9371 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9372 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9373 _codec ("MPEG-4 video");
9374 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9375 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9377 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9378 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9379 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9380 caps = gst_caps_new_simple ("video/x-msmpeg",
9381 "msmpegversion", G_TYPE_INT, 43, NULL);
9383 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9384 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9385 _codec ("3ivX video");
9386 caps = gst_caps_new_empty_simple ("video/x-3ivx");
9388 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9390 caps = gst_caps_new_simple ("video/x-divx",
9391 "divxversion", G_TYPE_INT, 3, NULL);
9393 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9394 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9396 caps = gst_caps_new_simple ("video/x-divx",
9397 "divxversion", G_TYPE_INT, 4, NULL);
9399 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9401 caps = gst_caps_new_simple ("video/x-divx",
9402 "divxversion", G_TYPE_INT, 5, NULL);
9404 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9405 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9406 _codec ("XVID MPEG-4");
9407 caps = gst_caps_new_empty_simple ("video/x-xvid");
9410 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9411 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9412 caps = gst_caps_new_simple ("video/mpeg",
9413 "mpegversion", G_TYPE_INT, 4, NULL);
9415 *codec_name = g_strdup ("FFmpeg MPEG-4");
9418 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9420 caps = gst_caps_new_empty_simple ("video/x-cinepak");
9422 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9423 _codec ("Apple QuickDraw");
9424 caps = gst_caps_new_empty_simple ("video/x-qdrw");
9426 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9427 _codec ("Apple video");
9428 caps = gst_caps_new_empty_simple ("video/x-apple-video");
9430 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9431 _codec ("H.264 / AVC");
9432 caps = gst_caps_new_simple ("video/x-h264",
9433 "stream-format", G_TYPE_STRING, "avc",
9434 "alignment", G_TYPE_STRING, "au", NULL);
9436 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9437 _codec ("Run-length encoding");
9438 caps = gst_caps_new_simple ("video/x-rle",
9439 "layout", G_TYPE_STRING, "quicktime", NULL);
9441 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9442 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9443 _codec ("Indeo Video 3");
9444 caps = gst_caps_new_simple ("video/x-indeo",
9445 "indeoversion", G_TYPE_INT, 3, NULL);
9447 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9448 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9449 _codec ("Intel Video 4");
9450 caps = gst_caps_new_simple ("video/x-indeo",
9451 "indeoversion", G_TYPE_INT, 4, NULL);
9453 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9454 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9455 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9456 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9457 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9458 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9459 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9460 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9461 _codec ("DV Video");
9462 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9463 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9465 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9466 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9467 _codec ("DVCPro50 Video");
9468 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9469 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9471 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9472 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9473 _codec ("DVCProHD Video");
9474 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9475 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9477 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9478 _codec ("Apple Graphics (SMC)");
9479 caps = gst_caps_new_empty_simple ("video/x-smc");
9481 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9483 caps = gst_caps_new_empty_simple ("video/x-vp3");
9485 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9487 caps = gst_caps_new_empty_simple ("video/x-theora");
9488 /* theora uses one byte of padding in the data stream because it does not
9489 * allow 0 sized packets while theora does */
9490 stream->padding = 1;
9492 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9494 caps = gst_caps_new_empty_simple ("video/x-dirac");
9496 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9497 _codec ("TIFF still images");
9498 caps = gst_caps_new_empty_simple ("image/tiff");
9500 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9501 _codec ("Apple Intermediate Codec");
9502 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9504 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9505 _codec ("AVID DNxHD");
9506 caps = gst_caps_from_string ("video/x-dnxhd");
9508 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9510 caps = gst_caps_from_string ("video/x-vp8");
9514 caps = gst_caps_new_simple ("video/x-wmv",
9515 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
9517 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9522 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9523 GST_FOURCC_ARGS (fourcc));
9524 caps = gst_caps_new_empty_simple (s);
9529 /* enable clipping for raw video streams */
9530 s = gst_caps_get_structure (caps, 0);
9531 name = gst_structure_get_name (s);
9532 if (g_str_has_prefix (name, "video/x-raw")) {
9533 stream->need_clip = TRUE;
9539 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9540 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9543 const GstStructure *s;
9547 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9550 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9551 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9552 _codec ("Raw 8-bit PCM audio");
9553 caps = gst_caps_new_simple ("audio/x-raw",
9554 "format", G_TYPE_STRING, "U8",
9555 "layout", G_TYPE_STRING, "interleaved", NULL);
9557 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9558 endian = G_BIG_ENDIAN;
9560 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9564 GstAudioFormat format;
9567 endian = G_LITTLE_ENDIAN;
9569 depth = stream->bytes_per_packet * 8;
9570 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
9572 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9576 caps = gst_caps_new_simple ("audio/x-raw",
9577 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
9578 "layout", G_TYPE_STRING, "interleaved", NULL);
9581 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9582 _codec ("Raw 64-bit floating-point audio");
9583 caps = gst_caps_new_simple ("audio/x-raw",
9584 "format", G_TYPE_STRING, "F64BE",
9585 "layout", G_TYPE_STRING, "interleaved", NULL);
9587 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9588 _codec ("Raw 32-bit floating-point audio");
9589 caps = gst_caps_new_simple ("audio/x-raw",
9590 "format", G_TYPE_STRING, "F32BE",
9591 "layout", G_TYPE_STRING, "interleaved", NULL);
9594 _codec ("Raw 24-bit PCM audio");
9595 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9597 caps = gst_caps_new_simple ("audio/x-raw",
9598 "format", G_TYPE_STRING, "S24BE",
9599 "layout", G_TYPE_STRING, "interleaved", NULL);
9601 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9602 _codec ("Raw 32-bit PCM audio");
9603 caps = gst_caps_new_simple ("audio/x-raw",
9604 "format", G_TYPE_STRING, "S32BE",
9605 "layout", G_TYPE_STRING, "interleaved", NULL);
9607 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9608 _codec ("Mu-law audio");
9609 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
9611 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9612 _codec ("A-law audio");
9613 caps = gst_caps_new_empty_simple ("audio/x-alaw");
9617 _codec ("Microsoft ADPCM");
9618 /* Microsoft ADPCM-ACM code 2 */
9619 caps = gst_caps_new_simple ("audio/x-adpcm",
9620 "layout", G_TYPE_STRING, "microsoft", NULL);
9624 _codec ("DVI/IMA ADPCM");
9625 caps = gst_caps_new_simple ("audio/x-adpcm",
9626 "layout", G_TYPE_STRING, "dvi", NULL);
9630 _codec ("DVI/Intel IMA ADPCM");
9631 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9632 caps = gst_caps_new_simple ("audio/x-adpcm",
9633 "layout", G_TYPE_STRING, "quicktime", NULL);
9637 /* MPEG layer 3, CBR only (pre QT4.1) */
9638 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9639 _codec ("MPEG-1 layer 3");
9640 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9641 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9642 "mpegversion", G_TYPE_INT, 1, NULL);
9645 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9646 _codec ("EAC-3 audio");
9647 caps = gst_caps_new_simple ("audio/x-eac3",
9648 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9649 stream->sampled = TRUE;
9651 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9652 _codec ("AC-3 audio");
9653 caps = gst_caps_new_simple ("audio/x-ac3",
9654 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9655 stream->sampled = TRUE;
9657 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9659 caps = gst_caps_new_simple ("audio/x-mace",
9660 "maceversion", G_TYPE_INT, 3, NULL);
9662 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9664 caps = gst_caps_new_simple ("audio/x-mace",
9665 "maceversion", G_TYPE_INT, 6, NULL);
9667 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9669 caps = gst_caps_new_empty_simple ("application/ogg");
9671 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9672 _codec ("DV audio");
9673 caps = gst_caps_new_empty_simple ("audio/x-dv");
9675 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9676 _codec ("MPEG-4 AAC audio");
9677 caps = gst_caps_new_simple ("audio/mpeg",
9678 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9679 "stream-format", G_TYPE_STRING, "raw", NULL);
9681 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9682 _codec ("QDesign Music");
9683 caps = gst_caps_new_empty_simple ("audio/x-qdm");
9685 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9686 _codec ("QDesign Music v.2");
9687 /* FIXME: QDesign music version 2 (no constant) */
9689 caps = gst_caps_new_simple ("audio/x-qdm2",
9690 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9691 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9692 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9694 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
9697 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9698 _codec ("GSM audio");
9699 caps = gst_caps_new_empty_simple ("audio/x-gsm");
9701 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9702 _codec ("AMR audio");
9703 caps = gst_caps_new_empty_simple ("audio/AMR");
9705 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9706 _codec ("AMR-WB audio");
9707 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
9709 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9710 _codec ("Quicktime IMA ADPCM");
9711 caps = gst_caps_new_simple ("audio/x-adpcm",
9712 "layout", G_TYPE_STRING, "quicktime", NULL);
9714 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9715 _codec ("Apple lossless audio");
9716 caps = gst_caps_new_empty_simple ("audio/x-alac");
9718 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9719 _codec ("QualComm PureVoice");
9720 caps = gst_caps_from_string ("audio/qcelp");
9724 caps = gst_caps_new_empty_simple ("audio/x-wma");
9726 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
9732 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9733 GST_FOURCC_ARGS (fourcc));
9734 caps = gst_caps_new_empty_simple (s);
9740 GstCaps *templ_caps =
9741 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
9742 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
9743 gst_caps_unref (caps);
9744 gst_caps_unref (templ_caps);
9745 caps = intersection;
9748 /* enable clipping for raw audio streams */
9749 s = gst_caps_get_structure (caps, 0);
9750 name = gst_structure_get_name (s);
9751 if (g_str_has_prefix (name, "audio/x-raw")) {
9752 stream->need_clip = TRUE;
9758 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9759 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9763 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9766 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
9767 _codec ("DVD subtitle");
9768 caps = gst_caps_new_empty_simple ("video/x-dvd-subpicture");
9770 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
9771 _codec ("Quicktime timed text");
9773 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
9774 _codec ("3GPP timed text");
9776 caps = gst_caps_new_empty_simple ("text/plain");
9777 /* actual text piece needs to be extracted */
9778 stream->need_process = TRUE;
9784 s = g_strdup_printf ("text/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9785 GST_FOURCC_ARGS (fourcc));
9786 caps = gst_caps_new_empty_simple (s);