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));
121 /* timestamp + offset + duration - pts is the duration */
122 #define QTSAMPLE_DUR_PTS(stream,sample,pts) (gst_util_uint64_scale ((sample)->timestamp + \
123 (sample)->pts_offset + (sample)->duration, GST_SECOND, (stream)->timescale) - (pts));
125 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
128 * Quicktime has tracks and segments. A track is a continuous piece of
129 * multimedia content. The track is not always played from start to finish but
130 * instead, pieces of the track are 'cut out' and played in sequence. This is
131 * what the segments do.
133 * Inside the track we have keyframes (K) and delta frames. The track has its
134 * own timing, which starts from 0 and extends to end. The position in the track
135 * is called the media_time.
137 * The segments now describe the pieces that should be played from this track
138 * and are basically tupples of media_time/duration/rate entries. We can have
139 * multiple segments and they are all played after one another. An example:
141 * segment 1: media_time: 1 second, duration: 1 second, rate 1
142 * segment 2: media_time: 3 second, duration: 2 second, rate 2
144 * To correctly play back this track, one must play: 1 second of media starting
145 * from media_time 1 followed by 2 seconds of media starting from media_time 3
148 * Each of the segments will be played at a specific time, the first segment at
149 * time 0, the second one after the duration of the first one, etc.. Note that
150 * the time in resulting playback is not identical to the media_time of the
153 * Visually, assuming the track has 4 second of media_time:
156 * .-----------------------------------------------------------.
157 * track: | K.....K.........K........K.......K.......K...........K... |
158 * '-----------------------------------------------------------'
160 * .------------^ ^ .----------^ ^
161 * / .-------------' / .------------------'
163 * .--------------. .--------------.
164 * | segment 1 | | segment 2 |
165 * '--------------' '--------------'
167 * The challenge here is to cut out the right pieces of the track for each of
168 * the playback segments. This fortunatly can easily be done with the SEGMENT
169 * events of gstreamer.
171 * For playback of segment 1, we need to provide the decoder with the keyframe
172 * (a), in the above figure, but we must instruct it only to output the decoded
173 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
174 * position set to the time of the segment: 0.
176 * We then proceed to push data from keyframe (a) to frame (b). The decoder
177 * decodes but clips all before media_time 1.
179 * After finishing a segment, we push out a new SEGMENT event with the clipping
180 * boundaries of the new data.
182 * This is a good usecase for the GStreamer accumulated SEGMENT events.
185 struct _QtDemuxSegment
187 /* global time and duration, all gst time */
191 /* media time of trak, all gst time */
197 struct _QtDemuxStream
206 /* if the stream has a redirect URI in its headers, we store it here */
213 guint64 duration; /* in timescale */
217 gchar lang_id[4]; /* ISO 639-2T language code */
221 QtDemuxSample *samples;
222 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
223 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
224 the framerate, in timescale units */
226 /* if we use chunks or samples */
238 /* Numerator/denominator framerate */
241 guint16 bits_per_sample;
242 guint16 color_table_id;
247 guint samples_per_packet;
248 guint samples_per_frame;
249 guint bytes_per_packet;
250 guint bytes_per_sample;
251 guint bytes_per_frame;
254 /* when a discontinuity is pending */
257 /* list of buffers to push first */
260 /* if we need to clip this buffer. This is only needed for uncompressed
264 /* buffer needs some custom processing, e.g. subtitles */
265 gboolean need_process;
267 /* current position */
268 guint32 segment_index;
269 guint32 sample_index;
270 guint64 time_position; /* in gst time */
272 /* the Gst segment we are processing out, used for clipping */
275 /* last GstFlowReturn */
276 GstFlowReturn last_ret;
278 /* quicktime segments */
280 QtDemuxSegment *segments;
285 GstTagList *pending_tags;
286 gboolean send_global_tags;
288 GstEvent *pending_event;
298 gboolean chunks_are_chunks;
302 GstByteReader co_chunk;
304 guint32 current_chunk;
306 guint32 samples_per_chunk;
307 guint32 stco_sample_index;
309 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
312 guint32 n_samples_per_chunk;
313 guint32 stsc_chunk_index;
314 guint32 stsc_sample_index;
315 guint64 chunk_offset;
318 guint32 stts_samples;
319 guint32 n_sample_times;
320 guint32 stts_sample_index;
322 guint32 stts_duration;
324 gboolean stss_present;
325 guint32 n_sample_syncs;
328 gboolean stps_present;
329 guint32 n_sample_partial_syncs;
332 gboolean ctts_present;
333 guint32 n_composition_times;
335 guint32 ctts_sample_index;
340 gboolean parsed_trex;
341 guint32 def_sample_duration;
342 guint32 def_sample_size;
343 guint32 def_sample_flags;
348 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
349 QTDEMUX_STATE_HEADER, /* Parsing the header */
350 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
351 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
354 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
355 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
356 guint32 fourcc, GstByteReader * parser);
357 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
358 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
359 guint32 fourcc, GstByteReader * parser);
361 static GstStaticPadTemplate gst_qtdemux_sink_template =
362 GST_STATIC_PAD_TEMPLATE ("sink",
365 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
369 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
370 GST_STATIC_PAD_TEMPLATE ("video_%u",
373 GST_STATIC_CAPS_ANY);
375 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
376 GST_STATIC_PAD_TEMPLATE ("audio_%u",
379 GST_STATIC_CAPS_ANY);
381 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
382 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
385 GST_STATIC_CAPS_ANY);
387 #define gst_qtdemux_parent_class parent_class
388 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
390 static void gst_qtdemux_dispose (GObject * object);
393 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
396 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
397 QtDemuxStream * str, gint64 media_offset);
400 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
401 static GstIndex *gst_qtdemux_get_index (GstElement * element);
403 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
404 GstStateChange transition);
405 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
406 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
407 GstObject * parent, GstPadMode mode, gboolean active);
409 static void gst_qtdemux_loop (GstPad * pad);
410 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
412 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
415 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
416 const guint8 * buffer, guint length);
417 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
418 const guint8 * buffer, guint length);
419 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
421 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
422 QtDemuxStream * stream, GNode * esds, GstTagList * list);
423 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
424 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
425 gchar ** codec_name);
426 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
427 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
428 gchar ** codec_name);
429 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
430 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
431 gchar ** codec_name);
432 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
433 QtDemuxStream * stream, guint32 n);
434 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
437 gst_qtdemux_class_init (GstQTDemuxClass * klass)
439 GObjectClass *gobject_class;
440 GstElementClass *gstelement_class;
442 gobject_class = (GObjectClass *) klass;
443 gstelement_class = (GstElementClass *) klass;
445 parent_class = g_type_class_peek_parent (klass);
447 gobject_class->dispose = gst_qtdemux_dispose;
449 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
451 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
452 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
455 gst_tag_register_musicbrainz_tags ();
457 gst_element_class_add_pad_template (gstelement_class,
458 gst_static_pad_template_get (&gst_qtdemux_sink_template));
459 gst_element_class_add_pad_template (gstelement_class,
460 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
461 gst_element_class_add_pad_template (gstelement_class,
462 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
463 gst_element_class_add_pad_template (gstelement_class,
464 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
465 gst_element_class_set_details_simple (gstelement_class, "QuickTime demuxer",
467 "Demultiplex a QuickTime file into audio and video streams",
468 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
470 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
475 gst_qtdemux_init (GstQTDemux * qtdemux)
478 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
479 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
480 gst_pad_set_activatemode_function (qtdemux->sinkpad,
481 qtdemux_sink_activate_mode);
482 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
483 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
484 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
486 qtdemux->state = QTDEMUX_STATE_INITIAL;
487 qtdemux->pullbased = FALSE;
488 qtdemux->posted_redirect = FALSE;
489 qtdemux->neededbytes = 16;
491 qtdemux->adapter = gst_adapter_new ();
493 qtdemux->first_mdat = -1;
494 qtdemux->got_moov = FALSE;
495 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
496 qtdemux->mdatbuffer = NULL;
497 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
499 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
503 gst_qtdemux_dispose (GObject * object)
505 GstQTDemux *qtdemux = GST_QTDEMUX (object);
507 if (qtdemux->adapter) {
508 g_object_unref (G_OBJECT (qtdemux->adapter));
509 qtdemux->adapter = NULL;
512 G_OBJECT_CLASS (parent_class)->dispose (object);
516 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
518 if (qtdemux->posted_redirect) {
519 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
520 (_("This file contains no playable streams.")),
521 ("no known streams found, a redirect message has been posted"));
523 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
524 (_("This file contains no playable streams.")),
525 ("no known streams found"));
530 _gst_buffer_copy_into_mem (GstBuffer * dest, gsize offset, const guint8 * src,
535 g_return_if_fail (gst_buffer_is_writable (dest));
537 bsize = gst_buffer_get_size (dest);
538 g_return_if_fail (bsize >= offset + size);
540 gst_buffer_fill (dest, offset, src, size);
544 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
548 buf = gst_buffer_new ();
549 gst_buffer_take_memory (buf, -1,
550 gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
551 mem, free_func, size, 0, size));
557 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
564 if (G_UNLIKELY (size == 0)) {
566 GstBuffer *tmp = NULL;
568 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
569 if (ret != GST_FLOW_OK)
572 gst_buffer_map (tmp, &map, GST_MAP_READ);
573 size = QT_UINT32 (map.data);
574 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
576 gst_buffer_unmap (tmp, &map);
577 gst_buffer_unref (tmp);
580 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
581 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
582 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
583 /* we're pulling header but already got most interesting bits,
584 * so never mind the rest (e.g. tags) (that much) */
585 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
589 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
590 (_("This file is invalid and cannot be played.")),
591 ("atom has bogus size %" G_GUINT64_FORMAT, size));
592 return GST_FLOW_ERROR;
596 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
598 if (G_UNLIKELY (flow != GST_FLOW_OK))
601 bsize = gst_buffer_get_size (*buf);
602 /* Catch short reads - we don't want any partial atoms */
603 if (G_UNLIKELY (bsize < size)) {
604 GST_WARNING_OBJECT (qtdemux,
605 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
606 gst_buffer_unref (*buf);
616 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
617 GstFormat dest_format, gint64 * dest_value)
620 QtDemuxStream *stream = gst_pad_get_element_private (pad);
621 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
624 if (stream->subtype != FOURCC_vide) {
629 switch (src_format) {
630 case GST_FORMAT_TIME:
631 switch (dest_format) {
632 case GST_FORMAT_BYTES:{
633 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
637 *dest_value = stream->samples[index].offset;
639 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
640 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
641 GST_TIME_ARGS (src_value), *dest_value);
649 case GST_FORMAT_BYTES:
650 switch (dest_format) {
651 case GST_FORMAT_TIME:{
653 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
660 gst_util_uint64_scale (stream->samples[index].timestamp,
661 GST_SECOND, stream->timescale);
662 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
663 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
664 src_value, GST_TIME_ARGS (*dest_value));
677 gst_object_unref (qtdemux);
684 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
688 *duration = GST_CLOCK_TIME_NONE;
690 if (qtdemux->duration != 0) {
691 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
692 *duration = gst_util_uint64_scale (qtdemux->duration,
693 GST_SECOND, qtdemux->timescale);
700 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
703 gboolean res = FALSE;
704 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
706 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
708 switch (GST_QUERY_TYPE (query)) {
709 case GST_QUERY_POSITION:
710 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
711 gst_query_set_position (query, GST_FORMAT_TIME,
712 qtdemux->segment.position);
716 case GST_QUERY_DURATION:{
719 gst_query_parse_duration (query, &fmt, NULL);
720 if (fmt == GST_FORMAT_TIME) {
721 gint64 duration = -1;
723 gst_qtdemux_get_duration (qtdemux, &duration);
725 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
731 case GST_QUERY_CONVERT:{
732 GstFormat src_fmt, dest_fmt;
733 gint64 src_value, dest_value = 0;
735 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
737 res = gst_qtdemux_src_convert (pad,
738 src_fmt, src_value, dest_fmt, &dest_value);
740 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
745 case GST_QUERY_FORMATS:
746 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
749 case GST_QUERY_SEEKING:{
753 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
754 if (fmt == GST_FORMAT_TIME) {
755 gint64 duration = -1;
757 gst_qtdemux_get_duration (qtdemux, &duration);
759 if (!qtdemux->pullbased) {
762 /* we might be able with help from upstream */
764 q = gst_query_new_seeking (GST_FORMAT_BYTES);
765 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
766 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
767 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
771 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
777 res = gst_pad_query_default (pad, parent, query);
785 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
787 if (G_LIKELY (stream->pad)) {
788 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
789 GST_DEBUG_PAD_NAME (stream->pad));
791 if (G_UNLIKELY (stream->pending_tags)) {
792 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
793 stream->pending_tags);
794 gst_pad_push_event (stream->pad,
795 gst_event_new_tag (stream->pending_tags));
796 stream->pending_tags = NULL;
799 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
800 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
802 gst_pad_push_event (stream->pad,
803 gst_event_new_tag (gst_tag_list_copy (qtdemux->tag_list)));
804 stream->send_global_tags = FALSE;
809 /* push event on all source pads; takes ownership of the event */
811 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
814 gboolean has_valid_stream = FALSE;
815 GstEventType etype = GST_EVENT_TYPE (event);
817 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
818 GST_EVENT_TYPE_NAME (event));
820 for (n = 0; n < qtdemux->n_streams; n++) {
822 QtDemuxStream *stream = qtdemux->streams[n];
824 if ((pad = stream->pad)) {
825 has_valid_stream = TRUE;
827 if (etype == GST_EVENT_EOS) {
828 /* let's not send twice */
829 if (stream->sent_eos)
831 stream->sent_eos = TRUE;
834 gst_pad_push_event (pad, gst_event_ref (event));
838 gst_event_unref (event);
840 /* if it is EOS and there are no pads, post an error */
841 if (!has_valid_stream && etype == GST_EVENT_EOS) {
842 gst_qtdemux_post_no_playable_stream_error (qtdemux);
846 /* push a pending newsegment event, if any from the streaming thread */
848 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
850 if (qtdemux->pending_newsegment) {
851 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
852 qtdemux->pending_newsegment = NULL;
862 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
864 if (s1->timestamp > *media_time)
870 /* find the index of the sample that includes the data for @media_time using a
871 * binary search. Only to be called in optimized cases of linear search below.
873 * Returns the index of the sample.
876 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
879 QtDemuxSample *result;
882 /* convert media_time to mov format */
884 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
886 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
887 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
888 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
890 if (G_LIKELY (result))
891 index = result - str->samples;
900 /* find the index of the sample that includes the data for @media_offset using a
903 * Returns the index of the sample.
906 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
907 QtDemuxStream * str, gint64 media_offset)
909 QtDemuxSample *result = str->samples;
912 if (result == NULL || str->n_samples == 0)
915 if (media_offset == result->offset)
919 while (index < str->n_samples - 1) {
920 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
923 if (media_offset < result->offset)
934 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
939 /* find the index of the sample that includes the data for @media_time using a
940 * linear search, and keeping in mind that not all samples may have been parsed
941 * yet. If possible, it will delegate to binary search.
943 * Returns the index of the sample.
946 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
952 /* convert media_time to mov format */
954 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
956 if (mov_time == str->samples[0].timestamp)
959 /* use faster search if requested time in already parsed range */
960 if (str->stbl_index >= 0 &&
961 mov_time <= str->samples[str->stbl_index].timestamp)
962 return gst_qtdemux_find_index (qtdemux, str, media_time);
964 while (index < str->n_samples - 1) {
965 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
968 if (mov_time < str->samples[index + 1].timestamp)
978 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
983 /* find the index of the keyframe needed to decode the sample at @index
986 * Returns the index of the keyframe.
989 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
992 guint32 new_index = index;
994 if (index >= str->n_samples) {
995 new_index = str->n_samples;
999 /* all keyframes, return index */
1000 if (str->all_keyframe) {
1005 /* else go back until we have a keyframe */
1007 if (str->samples[new_index].keyframe)
1017 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1018 "gave %u", index, new_index);
1023 /* find the segment for @time_position for @stream
1025 * Returns -1 if the segment cannot be found.
1028 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1029 guint64 time_position)
1034 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1035 GST_TIME_ARGS (time_position));
1037 /* find segment corresponding to time_position if we are looking
1040 for (i = 0; i < stream->n_segments; i++) {
1041 QtDemuxSegment *segment = &stream->segments[i];
1043 GST_LOG_OBJECT (qtdemux,
1044 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1045 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1047 /* For the last segment we include stop_time in the last segment */
1048 if (i < stream->n_segments - 1) {
1049 if (segment->time <= time_position && time_position < segment->stop_time) {
1050 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1055 if (segment->time <= time_position && time_position <= segment->stop_time) {
1056 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1065 /* move the stream @str to the sample position @index.
1067 * Updates @str->sample_index and marks discontinuity if needed.
1070 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1073 /* no change needed */
1074 if (index == str->sample_index)
1077 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1080 /* position changed, we have a discont */
1081 str->sample_index = index;
1082 /* Each time we move in the stream we store the position where we are
1084 str->from_sample = index;
1085 str->discont = TRUE;
1089 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1090 gint64 * key_time, gint64 * key_offset)
1093 gint64 min_byte_offset = -1;
1096 min_offset = desired_time;
1098 /* for each stream, find the index of the sample in the segment
1099 * and move back to the previous keyframe. */
1100 for (n = 0; n < qtdemux->n_streams; n++) {
1102 guint32 index, kindex;
1104 guint64 media_start;
1107 QtDemuxSegment *seg;
1109 str = qtdemux->streams[n];
1111 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1112 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1114 /* segment not found, continue with normal flow */
1118 /* get segment and time in the segment */
1119 seg = &str->segments[seg_idx];
1120 seg_time = desired_time - seg->time;
1122 /* get the media time in the segment */
1123 media_start = seg->media_start + seg_time;
1125 /* get the index of the sample with media time */
1126 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1127 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1128 " at offset %" G_GUINT64_FORMAT,
1129 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1131 /* find previous keyframe */
1132 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1134 /* if the keyframe is at a different position, we need to update the
1135 * requested seek time */
1136 if (index != kindex) {
1139 /* get timestamp of keyframe */
1141 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1143 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT
1144 " at offset %" G_GUINT64_FORMAT,
1145 kindex, GST_TIME_ARGS (media_time), str->samples[kindex].offset);
1147 /* keyframes in the segment get a chance to change the
1148 * desired_offset. keyframes out of the segment are
1150 if (media_time >= seg->media_start) {
1153 /* this keyframe is inside the segment, convert back to
1155 seg_time = (media_time - seg->media_start) + seg->time;
1156 if (seg_time < min_offset)
1157 min_offset = seg_time;
1161 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1162 min_byte_offset = str->samples[index].offset;
1166 *key_time = min_offset;
1168 *key_offset = min_byte_offset;
1172 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1173 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1177 g_return_val_if_fail (format != NULL, FALSE);
1178 g_return_val_if_fail (cur != NULL, FALSE);
1179 g_return_val_if_fail (stop != NULL, FALSE);
1181 if (*format == GST_FORMAT_TIME)
1185 if (cur_type != GST_SEEK_TYPE_NONE)
1186 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1187 if (res && stop_type != GST_SEEK_TYPE_NONE)
1188 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1191 *format = GST_FORMAT_TIME;
1196 /* perform seek in push based mode:
1197 find BYTE position to move to based on time and delegate to upstream
1200 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1205 GstSeekType cur_type, stop_type;
1210 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1212 gst_event_parse_seek (event, &rate, &format, &flags,
1213 &cur_type, &cur, &stop_type, &stop);
1215 /* FIXME, always play to the end */
1218 /* only forward streaming and seeking is possible */
1220 goto unsupported_seek;
1222 /* convert to TIME if needed and possible */
1223 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1227 /* find reasonable corresponding BYTE position,
1228 * also try to mind about keyframes, since we can not go back a bit for them
1230 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1235 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1236 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1239 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1240 GST_DEBUG_OBJECT (qtdemux,
1241 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1242 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1243 GST_OBJECT_LOCK (qtdemux);
1244 qtdemux->requested_seek_time = cur;
1245 qtdemux->seek_offset = byte_cur;
1246 GST_OBJECT_UNLOCK (qtdemux);
1249 /* BYTE seek event */
1250 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1252 res = gst_pad_push_event (qtdemux->sinkpad, event);
1259 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1265 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1270 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1275 /* perform the seek.
1277 * We set all segment_indexes in the streams to unknown and
1278 * adjust the time_position to the desired position. this is enough
1279 * to trigger a segment switch in the streaming thread to start
1280 * streaming from the desired position.
1282 * Keyframe seeking is a little more complicated when dealing with
1283 * segments. Ideally we want to move to the previous keyframe in
1284 * the segment but there might not be a keyframe in the segment. In
1285 * fact, none of the segments could contain a keyframe. We take a
1286 * practical approach: seek to the previous keyframe in the segment,
1287 * if there is none, seek to the beginning of the segment.
1289 * Called with STREAM_LOCK
1292 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1294 gint64 desired_offset;
1297 desired_offset = segment->position;
1299 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1300 GST_TIME_ARGS (desired_offset));
1302 /* may not have enough fragmented info to do this adjustment,
1303 * and we can't scan (and probably should not) at this time with
1304 * possibly flushing upstream */
1305 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1308 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1309 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1310 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1311 desired_offset = min_offset;
1314 /* and set all streams to the final position */
1315 for (n = 0; n < qtdemux->n_streams; n++) {
1316 QtDemuxStream *stream = qtdemux->streams[n];
1318 stream->time_position = desired_offset;
1319 stream->sample_index = -1;
1320 stream->segment_index = -1;
1321 stream->last_ret = GST_FLOW_OK;
1322 stream->sent_eos = FALSE;
1324 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1325 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1327 segment->position = desired_offset;
1328 segment->time = desired_offset;
1330 /* we stop at the end */
1331 if (segment->stop == -1)
1332 segment->stop = segment->duration;
1337 /* do a seek in pull based mode */
1339 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1344 GstSeekType cur_type, stop_type;
1348 GstSegment seeksegment;
1352 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1354 gst_event_parse_seek (event, &rate, &format, &flags,
1355 &cur_type, &cur, &stop_type, &stop);
1357 /* we have to have a format as the segment format. Try to convert
1359 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1363 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1365 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1369 flush = flags & GST_SEEK_FLAG_FLUSH;
1371 /* stop streaming, either by flushing or by pausing the task */
1373 /* unlock upstream pull_range */
1374 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1375 /* make sure out loop function exits */
1376 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1378 /* non flushing seek, pause the task */
1379 gst_pad_pause_task (qtdemux->sinkpad);
1382 /* wait for streaming to finish */
1383 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1385 /* copy segment, we need this because we still need the old
1386 * segment when we close the current segment. */
1387 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1390 /* configure the segment with the seek variables */
1391 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1392 gst_segment_do_seek (&seeksegment, rate, format, flags,
1393 cur_type, cur, stop_type, stop, &update);
1396 /* now do the seek, this actually never returns FALSE */
1397 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1399 /* prepare for streaming again */
1401 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop (TRUE));
1402 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop (TRUE));
1405 /* commit the new segment */
1406 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1408 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1409 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1410 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1411 qtdemux->segment.format, qtdemux->segment.position));
1414 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1415 for (i = 0; i < qtdemux->n_streams; i++)
1416 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1418 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1421 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1428 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1434 qtdemux_ensure_index (GstQTDemux * qtdemux)
1438 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1440 /* Build complete index */
1441 for (i = 0; i < qtdemux->n_streams; i++) {
1442 QtDemuxStream *stream = qtdemux->streams[i];
1444 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1452 GST_LOG_OBJECT (qtdemux,
1453 "Building complete index of stream %u for seeking failed!", i);
1459 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1462 gboolean res = TRUE;
1463 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1465 switch (GST_EVENT_TYPE (event)) {
1466 case GST_EVENT_SEEK:
1468 #ifndef GST_DISABLE_GST_DEBUG
1469 GstClockTime ts = gst_util_get_timestamp ();
1471 /* Build complete index for seeking;
1472 * if not a fragmented file at least */
1473 if (!qtdemux->fragmented)
1474 if (!qtdemux_ensure_index (qtdemux))
1476 #ifndef GST_DISABLE_GST_DEBUG
1477 ts = gst_util_get_timestamp () - ts;
1478 GST_INFO_OBJECT (qtdemux,
1479 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1482 if (qtdemux->pullbased) {
1483 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1484 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams &&
1485 !qtdemux->fragmented) {
1486 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1488 GST_DEBUG_OBJECT (qtdemux,
1489 "ignoring seek in push mode in current state");
1492 gst_event_unref (event);
1495 case GST_EVENT_NAVIGATION:
1497 gst_event_unref (event);
1500 res = gst_pad_event_default (pad, parent, event);
1510 GST_ERROR_OBJECT (qtdemux, "Index failed");
1511 gst_event_unref (event);
1517 /* stream/index return sample that is min/max w.r.t. byte position,
1518 * time is min/max w.r.t. time of samples,
1519 * the latter need not be time of the former sample */
1521 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1522 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1525 gint64 time, min_time;
1526 QtDemuxStream *stream;
1532 for (n = 0; n < qtdemux->n_streams; ++n) {
1535 gboolean set_sample;
1537 str = qtdemux->streams[n];
1544 i = str->n_samples - 1;
1547 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1548 if (str->samples[i].size &&
1549 ((fw && (str->samples[i].offset >= byte_pos)) ||
1551 (str->samples[i].offset + str->samples[i].size <=
1553 /* move stream to first available sample */
1555 gst_qtdemux_move_stream (qtdemux, str, i);
1558 /* determine min/max time */
1559 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1560 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1561 if (min_time == -1 || (!fw && time > min_time) ||
1562 (fw && time < min_time)) {
1565 /* determine stream with leading sample, to get its position */
1567 && (str->samples[i].offset < stream->samples[index].offset))
1569 && (str->samples[i].offset > stream->samples[index].offset))) {
1576 /* no sample for this stream, mark eos */
1578 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1590 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1593 GstQTDemux *demux = GST_QTDEMUX (parent);
1596 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1598 switch (GST_EVENT_TYPE (event)) {
1599 case GST_EVENT_SEGMENT:
1602 QtDemuxStream *stream;
1606 /* some debug output */
1607 gst_event_copy_segment (event, &segment);
1608 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1611 /* chain will send initial newsegment after pads have been added */
1612 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1613 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1617 /* we only expect a BYTE segment, e.g. following a seek */
1618 if (segment.format == GST_FORMAT_BYTES) {
1619 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1620 gint64 requested_seek_time;
1621 guint64 seek_offset;
1623 offset = segment.start;
1625 GST_OBJECT_LOCK (demux);
1626 requested_seek_time = demux->requested_seek_time;
1627 seek_offset = demux->seek_offset;
1628 demux->requested_seek_time = -1;
1629 demux->seek_offset = -1;
1630 GST_OBJECT_UNLOCK (demux);
1632 if (offset == seek_offset) {
1633 segment.start = requested_seek_time;
1635 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1636 NULL, (gint64 *) & segment.start);
1637 if ((gint64) segment.start < 0)
1641 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1642 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1643 NULL, (gint64 *) & segment.stop);
1644 /* keyframe seeking should already arrange for start >= stop,
1645 * but make sure in other rare cases */
1646 segment.stop = MAX (segment.stop, segment.start);
1649 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1653 /* accept upstream's notion of segment and distribute along */
1654 segment.time = segment.start;
1655 segment.duration = demux->segment.duration;
1656 segment.base = gst_segment_to_running_time (&demux->segment,
1657 GST_FORMAT_TIME, demux->segment.position);
1659 gst_segment_copy_into (&segment, &demux->segment);
1660 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
1661 gst_qtdemux_push_event (demux, gst_event_new_segment (&segment));
1663 /* clear leftover in current segment, if any */
1664 gst_adapter_clear (demux->adapter);
1665 /* set up streaming thread */
1666 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1667 demux->offset = offset;
1669 demux->todrop = stream->samples[idx].offset - offset;
1670 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1672 /* set up for EOS */
1673 demux->neededbytes = -1;
1677 gst_event_unref (event);
1682 case GST_EVENT_FLUSH_STOP:
1687 /* clean up, force EOS if no more info follows */
1688 gst_adapter_clear (demux->adapter);
1690 demux->neededbytes = -1;
1691 /* reset flow return, e.g. following seek */
1692 for (i = 0; i < demux->n_streams; i++) {
1693 demux->streams[i]->last_ret = GST_FLOW_OK;
1694 demux->streams[i]->sent_eos = FALSE;
1696 dur = demux->segment.duration;
1697 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1698 demux->segment.duration = dur;
1702 /* If we are in push mode, and get an EOS before we've seen any streams,
1703 * then error out - we have nowhere to send the EOS */
1704 if (!demux->pullbased) {
1706 gboolean has_valid_stream = FALSE;
1707 for (i = 0; i < demux->n_streams; i++) {
1708 if (demux->streams[i]->pad != NULL) {
1709 has_valid_stream = TRUE;
1713 if (!has_valid_stream)
1714 gst_qtdemux_post_no_playable_stream_error (demux);
1721 res = gst_pad_event_default (demux->sinkpad, parent, event);
1729 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1731 GstQTDemux *demux = GST_QTDEMUX (element);
1733 GST_OBJECT_LOCK (demux);
1734 if (demux->element_index)
1735 gst_object_unref (demux->element_index);
1737 demux->element_index = gst_object_ref (index);
1739 demux->element_index = NULL;
1741 GST_OBJECT_UNLOCK (demux);
1742 /* object lock might be taken again */
1744 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1745 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
1746 demux->element_index, demux->index_id);
1750 gst_qtdemux_get_index (GstElement * element)
1752 GstIndex *result = NULL;
1753 GstQTDemux *demux = GST_QTDEMUX (element);
1755 GST_OBJECT_LOCK (demux);
1756 if (demux->element_index)
1757 result = gst_object_ref (demux->element_index);
1758 GST_OBJECT_UNLOCK (demux);
1760 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1767 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1769 g_free ((gpointer) stream->stco.data);
1770 stream->stco.data = NULL;
1771 g_free ((gpointer) stream->stsz.data);
1772 stream->stsz.data = NULL;
1773 g_free ((gpointer) stream->stsc.data);
1774 stream->stsc.data = NULL;
1775 g_free ((gpointer) stream->stts.data);
1776 stream->stts.data = NULL;
1777 g_free ((gpointer) stream->stss.data);
1778 stream->stss.data = NULL;
1779 g_free ((gpointer) stream->stps.data);
1780 stream->stps.data = NULL;
1781 g_free ((gpointer) stream->ctts.data);
1782 stream->ctts.data = NULL;
1786 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
1788 while (stream->buffers) {
1789 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1790 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1793 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
1794 g_free (stream->samples);
1796 gst_caps_unref (stream->caps);
1797 g_free (stream->segments);
1798 if (stream->pending_tags)
1799 gst_tag_list_free (stream->pending_tags);
1800 g_free (stream->redirect_uri);
1801 /* free stbl sub-atoms */
1802 gst_qtdemux_stbl_free (stream);
1806 static GstStateChangeReturn
1807 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1809 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1810 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1812 switch (transition) {
1813 case GST_STATE_CHANGE_PAUSED_TO_READY:
1819 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1821 switch (transition) {
1822 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1825 qtdemux->state = QTDEMUX_STATE_INITIAL;
1826 qtdemux->neededbytes = 16;
1827 qtdemux->todrop = 0;
1828 qtdemux->pullbased = FALSE;
1829 qtdemux->posted_redirect = FALSE;
1830 qtdemux->offset = 0;
1831 qtdemux->first_mdat = -1;
1832 qtdemux->header_size = 0;
1833 qtdemux->got_moov = FALSE;
1834 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1835 if (qtdemux->mdatbuffer)
1836 gst_buffer_unref (qtdemux->mdatbuffer);
1837 qtdemux->mdatbuffer = NULL;
1838 if (qtdemux->comp_brands)
1839 gst_buffer_unref (qtdemux->comp_brands);
1840 qtdemux->comp_brands = NULL;
1841 if (qtdemux->tag_list)
1842 gst_tag_list_free (qtdemux->tag_list);
1843 qtdemux->tag_list = NULL;
1845 if (qtdemux->element_index)
1846 gst_object_unref (qtdemux->element_index);
1847 qtdemux->element_index = NULL;
1849 gst_adapter_clear (qtdemux->adapter);
1850 for (n = 0; n < qtdemux->n_streams; n++) {
1851 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1852 qtdemux->streams[n] = NULL;
1854 qtdemux->major_brand = 0;
1855 qtdemux->n_streams = 0;
1856 qtdemux->n_video_streams = 0;
1857 qtdemux->n_audio_streams = 0;
1858 qtdemux->n_sub_streams = 0;
1859 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1860 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1861 qtdemux->seek_offset = 0;
1862 qtdemux->upstream_seekable = FALSE;
1863 qtdemux->upstream_size = 0;
1874 qtdemux_post_global_tags (GstQTDemux * qtdemux)
1876 if (qtdemux->tag_list) {
1877 /* all header tags ready and parsed, push them */
1878 GST_INFO_OBJECT (qtdemux, "posting global tags: %" GST_PTR_FORMAT,
1880 /* post now, send event on pads later */
1881 gst_element_post_message (GST_ELEMENT (qtdemux),
1882 gst_message_new_tag (GST_OBJECT (qtdemux),
1883 gst_tag_list_copy (qtdemux->tag_list)));
1888 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1890 /* counts as header data */
1891 qtdemux->header_size += length;
1893 /* only consider at least a sufficiently complete ftyp atom */
1897 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1898 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1899 GST_FOURCC_ARGS (qtdemux->major_brand));
1900 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1901 _gst_buffer_copy_into_mem (buf, 0, buffer + 16, length - 16);
1906 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
1908 /* Strip out bogus fields */
1910 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
1912 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
1914 if (qtdemux->tag_list) {
1915 /* prioritize native tags using _KEEP mode */
1916 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
1917 gst_tag_list_free (taglist);
1919 qtdemux->tag_list = taglist;
1924 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1926 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
1927 0x97, 0xA9, 0x42, 0xE8,
1928 0x9C, 0x71, 0x99, 0x94,
1929 0x91, 0xE3, 0xAF, 0xAC
1933 /* counts as header data */
1934 qtdemux->header_size += length;
1936 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
1938 if (length <= offset + 16) {
1939 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
1943 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
1945 GstTagList *taglist;
1947 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
1948 length - offset - 16, NULL);
1949 taglist = gst_tag_list_from_xmp_buffer (buf);
1950 gst_buffer_unref (buf);
1952 qtdemux_handle_xmp_taglist (qtdemux, taglist);
1955 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
1959 /* caller verifies at least 8 bytes in buf */
1961 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1962 guint64 * plength, guint32 * pfourcc)
1967 length = QT_UINT32 (data);
1968 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1969 fourcc = QT_FOURCC (data + 4);
1970 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1973 length = G_MAXUINT32;
1974 } else if (length == 1 && size >= 16) {
1975 /* this means we have an extended size, which is the 64 bit value of
1976 * the next 8 bytes */
1977 length = QT_UINT64 (data + 8);
1978 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1988 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
1990 guint32 version = 0;
1991 guint64 duration = 0;
1993 if (!gst_byte_reader_get_uint32_be (br, &version))
1998 if (!gst_byte_reader_get_uint64_be (br, &duration))
2003 if (!gst_byte_reader_get_uint32_be (br, &dur))
2008 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2009 qtdemux->duration = duration;
2015 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2021 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2022 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2024 if (!stream->parsed_trex && qtdemux->moov_node) {
2026 GstByteReader trex_data;
2028 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2030 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2033 guint32 id = 0, dur = 0, size = 0, flags = 0;
2035 /* skip version/flags */
2036 if (!gst_byte_reader_skip (&trex_data, 4))
2038 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2040 if (id != stream->track_id)
2042 /* sample description index; ignore */
2043 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2045 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2047 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2049 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2052 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2053 "duration %d, size %d, flags 0x%x", stream->track_id,
2056 stream->parsed_trex = TRUE;
2057 stream->def_sample_duration = dur;
2058 stream->def_sample_size = size;
2059 stream->def_sample_flags = flags;
2062 /* iterate all siblings */
2063 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2069 *ds_duration = stream->def_sample_duration;
2070 *ds_size = stream->def_sample_size;
2071 *ds_size = stream->def_sample_size;
2073 /* even then, above values are better than random ... */
2074 if (G_UNLIKELY (!stream->parsed_trex)) {
2075 GST_WARNING_OBJECT (qtdemux,
2076 "failed to find fragment defaults for stream %d", stream->track_id);
2084 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2085 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2086 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2087 gint64 * base_offset, gint64 * running_offset)
2090 gint32 data_offset = 0;
2091 guint32 flags = 0, first_flags = 0, samples_count = 0;
2094 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2095 QtDemuxSample *sample;
2096 gboolean ismv = FALSE;
2098 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2099 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2100 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2103 /* presence of stss or not can't really tell us much,
2104 * and flags and so on tend to be marginally reliable in these files */
2105 if (stream->subtype == FOURCC_soun) {
2106 GST_DEBUG_OBJECT (qtdemux,
2107 "sound track in fragmented file; marking all keyframes");
2108 stream->all_keyframe = TRUE;
2111 if (!gst_byte_reader_skip (trun, 1) ||
2112 !gst_byte_reader_get_uint24_be (trun, &flags))
2115 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2118 if (flags & TR_DATA_OFFSET) {
2119 /* note this is really signed */
2120 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2122 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2123 /* default base offset = first byte of moof */
2124 if (*base_offset == -1) {
2125 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2126 *base_offset = moof_offset;
2128 *running_offset = *base_offset + data_offset;
2130 /* if no offset at all, that would mean data starts at moof start,
2131 * which is a bit wrong and is ismv crappy way, so compensate
2132 * assuming data is in mdat following moof */
2133 if (*base_offset == -1) {
2134 *base_offset = moof_offset + moof_length + 8;
2135 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2138 if (*running_offset == -1)
2139 *running_offset = *base_offset;
2142 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2144 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2145 data_offset, flags, samples_count);
2147 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2148 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2149 GST_DEBUG_OBJECT (qtdemux,
2150 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2151 flags ^= TR_FIRST_SAMPLE_FLAGS;
2153 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2155 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2159 /* FIXME ? spec says other bits should also be checked to determine
2160 * entry size (and prefix size for that matter) */
2162 dur_offset = size_offset = 0;
2163 if (flags & TR_SAMPLE_DURATION) {
2164 GST_LOG_OBJECT (qtdemux, "entry duration present");
2165 dur_offset = entry_size;
2168 if (flags & TR_SAMPLE_SIZE) {
2169 GST_LOG_OBJECT (qtdemux, "entry size present");
2170 size_offset = entry_size;
2173 if (flags & TR_SAMPLE_FLAGS) {
2174 GST_LOG_OBJECT (qtdemux, "entry flags present");
2175 flags_offset = entry_size;
2178 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2179 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2180 ct_offset = entry_size;
2184 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2186 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2188 if (stream->n_samples >=
2189 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2192 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2193 stream->n_samples, (guint) sizeof (QtDemuxSample),
2194 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2196 /* create a new array of samples if it's the first sample parsed */
2197 if (stream->n_samples == 0)
2198 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2199 /* or try to reallocate it with space enough to insert the new samples */
2201 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2202 stream->n_samples + samples_count);
2203 if (stream->samples == NULL)
2206 if (G_UNLIKELY (stream->n_samples == 0)) {
2207 /* the timestamp of the first sample is also provided by the tfra entry
2208 * but we shouldn't rely on it as it is at the end of files */
2211 /* subsequent fragments extend stream */
2213 stream->samples[stream->n_samples - 1].timestamp +
2214 stream->samples[stream->n_samples - 1].duration;
2216 sample = stream->samples + stream->n_samples;
2217 for (i = 0; i < samples_count; i++) {
2218 guint32 dur, size, sflags, ct;
2220 /* first read sample data */
2221 if (flags & TR_SAMPLE_DURATION) {
2222 dur = QT_UINT32 (data + dur_offset);
2224 dur = d_sample_duration;
2226 if (flags & TR_SAMPLE_SIZE) {
2227 size = QT_UINT32 (data + size_offset);
2229 size = d_sample_size;
2231 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2233 sflags = first_flags;
2235 sflags = d_sample_flags;
2237 } else if (flags & TR_SAMPLE_FLAGS) {
2238 sflags = QT_UINT32 (data + flags_offset);
2240 sflags = d_sample_flags;
2242 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2243 ct = QT_UINT32 (data + ct_offset);
2249 /* fill the sample information */
2250 sample->offset = *running_offset;
2251 sample->pts_offset = ct;
2252 sample->size = size;
2253 sample->timestamp = timestamp;
2254 sample->duration = dur;
2255 /* sample-is-difference-sample */
2256 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2257 * now idea how it relates to bitfield other than massive LE/BE confusion */
2258 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2259 *running_offset += size;
2264 stream->n_samples += samples_count;
2270 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2275 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2281 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2282 "be larger than %uMB (broken file?)", stream->n_samples,
2283 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2288 /* find stream with @id */
2289 static inline QtDemuxStream *
2290 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2292 QtDemuxStream *stream;
2296 if (G_UNLIKELY (!id)) {
2297 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2301 /* try to get it fast and simple */
2302 if (G_LIKELY (id <= qtdemux->n_streams)) {
2303 stream = qtdemux->streams[id - 1];
2304 if (G_LIKELY (stream->track_id == id))
2308 /* linear search otherwise */
2309 for (i = 0; i < qtdemux->n_streams; i++) {
2310 stream = qtdemux->streams[i];
2311 if (stream->track_id == id)
2319 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2320 QtDemuxStream ** stream, guint32 * default_sample_duration,
2321 guint32 * default_sample_size, guint32 * default_sample_flags,
2322 gint64 * base_offset)
2325 guint32 track_id = 0;
2327 if (!gst_byte_reader_skip (tfhd, 1) ||
2328 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2331 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2334 *stream = qtdemux_find_stream (qtdemux, track_id);
2335 if (G_UNLIKELY (!*stream))
2336 goto unknown_stream;
2338 if (flags & TF_BASE_DATA_OFFSET)
2339 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2342 /* obtain stream defaults */
2343 qtdemux_parse_trex (qtdemux, *stream,
2344 default_sample_duration, default_sample_size, default_sample_flags);
2346 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2347 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2348 if (!gst_byte_reader_skip (tfhd, 4))
2351 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2352 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2355 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2356 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2359 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2360 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2367 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2372 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2378 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2379 guint64 moof_offset, QtDemuxStream * stream)
2381 GNode *moof_node, *traf_node, *tfhd_node, *trun_node;
2382 GstByteReader trun_data, tfhd_data;
2383 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2384 gint64 base_offset, running_offset;
2386 /* NOTE @stream ignored */
2388 moof_node = g_node_new ((guint8 *) buffer);
2389 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2390 qtdemux_node_dump (qtdemux, moof_node);
2392 /* unknown base_offset to start with */
2393 base_offset = running_offset = -1;
2394 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2396 /* Fragment Header node */
2398 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2402 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2403 &ds_size, &ds_flags, &base_offset))
2405 if (G_UNLIKELY (!stream)) {
2406 /* we lost track of offset, we'll need to regain it,
2407 * but can delay complaining until later or avoid doing so altogether */
2411 if (G_UNLIKELY (base_offset < -1))
2413 /* Track Run node */
2415 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2418 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2419 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2421 /* iterate all siblings */
2422 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2425 /* if no new base_offset provided for next traf,
2426 * base is end of current traf */
2427 base_offset = running_offset;
2428 running_offset = -1;
2430 /* iterate all siblings */
2431 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2433 g_node_destroy (moof_node);
2438 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2443 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2448 g_node_destroy (moof_node);
2449 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2450 (_("This file is corrupt and cannot be played.")), (NULL));
2455 /* might be used if some day we actually use mfra & co
2456 * for random access to fragments,
2457 * but that will require quite some modifications and much less relying
2458 * on a sample array */
2461 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2462 QtDemuxStream * stream)
2464 guint64 time = 0, moof_offset = 0;
2465 guint32 ver_flags, track_id, len, num_entries, i;
2466 guint value_size, traf_size, trun_size, sample_size;
2467 GstBuffer *buf = NULL;
2471 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2472 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2474 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2477 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2478 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2479 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2482 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2483 track_id, stream->track_id);
2484 if (track_id != stream->track_id) {
2488 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2489 sample_size = (len & 3) + 1;
2490 trun_size = ((len & 12) >> 2) + 1;
2491 traf_size = ((len & 48) >> 4) + 1;
2493 if (num_entries == 0)
2496 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2497 value_size + value_size + traf_size + trun_size + sample_size))
2500 for (i = 0; i < num_entries; i++) {
2501 qt_atom_parser_get_offset (&tfra, value_size, &time);
2502 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2503 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2504 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2505 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2507 GST_LOG_OBJECT (qtdemux,
2508 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2509 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2510 stream->timescale)), moof_offset);
2512 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2513 if (ret != GST_FLOW_OK)
2515 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2516 moof_offset, stream);
2517 gst_buffer_unref (buf);
2525 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2526 (_("This file is corrupt and cannot be played.")), (NULL));
2531 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2537 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2540 GNode *mfra_node, *tfra_node;
2543 if (!qtdemux->mfra_offset)
2546 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2547 if (ret != GST_FLOW_OK)
2550 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2551 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2552 GST_BUFFER_SIZE (buffer));
2554 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2557 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2558 /* iterate all siblings */
2559 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2561 g_node_destroy (mfra_node);
2562 gst_buffer_unref (buffer);
2568 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2569 (_("This file is corrupt and cannot be played.")), (NULL));
2574 static GstFlowReturn
2575 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2576 guint32 * mfro_size)
2578 GstFlowReturn ret = GST_FLOW_ERROR;
2579 GstBuffer *mfro = NULL;
2582 GstFormat fmt = GST_FORMAT_BYTES;
2584 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, &fmt, &len)) {
2585 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2586 "can not locate mfro");
2590 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2591 if (ret != GST_FLOW_OK)
2594 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2595 if (fourcc != FOURCC_mfro)
2598 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2599 if (GST_BUFFER_SIZE (mfro) >= 16) {
2600 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
2601 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
2602 if (*mfro_size >= len) {
2603 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
2604 ret = GST_FLOW_ERROR;
2607 *mfra_offset = len - *mfro_size;
2612 gst_buffer_unref (mfro);
2618 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
2621 guint32 mfra_size = 0;
2622 guint64 mfra_offset = 0;
2625 qtdemux->fragmented = FALSE;
2627 /* We check here if it is a fragmented mp4 container */
2628 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
2629 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
2630 qtdemux->fragmented = TRUE;
2631 GST_DEBUG_OBJECT (qtdemux,
2632 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
2633 qtdemux->mfra_offset = mfra_offset;
2638 static GstFlowReturn
2639 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
2643 GstBuffer *buf = NULL;
2644 GstFlowReturn ret = GST_FLOW_OK;
2645 guint64 cur_offset = qtdemux->offset;
2648 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
2649 if (G_UNLIKELY (ret != GST_FLOW_OK))
2651 gst_buffer_map (buf, &map, GST_MAP_READ);
2652 if (G_LIKELY (map.size >= 8))
2653 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
2654 gst_buffer_unmap (buf, &map);
2655 gst_buffer_unref (buf);
2657 /* maybe we already got most we needed, so only consider this eof */
2658 if (G_UNLIKELY (length == 0)) {
2659 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
2660 (_("Invalid atom size.")),
2661 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
2662 GST_FOURCC_ARGS (fourcc)));
2669 /* record for later parsing when needed */
2670 if (!qtdemux->moof_offset) {
2671 qtdemux->moof_offset = qtdemux->offset;
2680 GST_LOG_OBJECT (qtdemux,
2681 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
2682 GST_FOURCC_ARGS (fourcc), cur_offset);
2683 qtdemux->offset += length;
2690 if (qtdemux->got_moov) {
2691 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
2692 qtdemux->offset += length;
2696 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
2697 if (ret != GST_FLOW_OK)
2699 gst_buffer_map (moov, &map, GST_MAP_READ);
2700 if (length != map.size) {
2701 /* Some files have a 'moov' atom at the end of the file which contains
2702 * a terminal 'free' atom where the body of the atom is missing.
2703 * Check for, and permit, this special case.
2705 if (map.size >= 8) {
2706 guint8 *final_data = map.data + (map.size - 8);
2707 guint32 final_length = QT_UINT32 (final_data);
2708 guint32 final_fourcc = QT_FOURCC (final_data + 4);
2709 gst_buffer_unmap (moov, &map);
2710 if (final_fourcc == FOURCC_free
2711 && map.size + final_length - 8 == length) {
2712 /* Ok, we've found that special case. Allocate a new buffer with
2713 * that free atom actually present. */
2714 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
2715 gst_buffer_copy_into (newmoov, moov, 0, 0, map.size);
2716 gst_buffer_map (newmoov, &map, GST_MAP_WRITE);
2717 memset (map.data + length - final_length + 8, 0, final_length - 8);
2718 gst_buffer_unref (moov);
2724 if (length != map.size) {
2725 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2726 (_("This file is incomplete and cannot be played.")),
2727 ("We got less than expected (received %" G_GSIZE_FORMAT
2728 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
2729 (guint) length, cur_offset));
2730 gst_buffer_unmap (moov, &map);
2731 gst_buffer_unref (moov);
2732 ret = GST_FLOW_ERROR;
2735 qtdemux->offset += length;
2737 qtdemux_parse_moov (qtdemux, map.data, length);
2738 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
2740 qtdemux_parse_tree (qtdemux);
2741 g_node_destroy (qtdemux->moov_node);
2742 gst_buffer_unmap (moov, &map);
2743 gst_buffer_unref (moov);
2744 qtdemux->moov_node = NULL;
2745 qtdemux->got_moov = TRUE;
2753 /* extract major brand; might come in handy for ISO vs QT issues */
2754 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
2755 if (ret != GST_FLOW_OK)
2757 qtdemux->offset += length;
2758 gst_buffer_map (ftyp, &map, GST_MAP_READ);
2759 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
2760 gst_buffer_unmap (ftyp, &map);
2761 gst_buffer_unref (ftyp);
2768 /* uuid are extension atoms */
2769 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
2770 if (ret != GST_FLOW_OK)
2772 qtdemux->offset += length;
2773 gst_buffer_map (uuid, &map, GST_MAP_READ);
2774 qtdemux_parse_uuid (qtdemux, map.data, map.size);
2775 gst_buffer_unmap (uuid, &map);
2776 gst_buffer_unref (uuid);
2783 GST_LOG_OBJECT (qtdemux,
2784 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
2785 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
2787 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
2788 if (ret != GST_FLOW_OK)
2790 gst_buffer_map (unknown, &map, GST_MAP_READ);
2791 GST_MEMDUMP ("Unknown tag", map.data, map.size);
2792 gst_buffer_unmap (unknown, &map);
2793 gst_buffer_unref (unknown);
2794 qtdemux->offset += length;
2800 if (ret == GST_FLOW_EOS && qtdemux->got_moov) {
2801 /* digested all data, show what we have */
2802 ret = qtdemux_expose_streams (qtdemux);
2804 /* Only post, event on pads is done after newsegment */
2805 qtdemux_post_global_tags (qtdemux);
2807 qtdemux->state = QTDEMUX_STATE_MOVIE;
2808 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
2815 /* Seeks to the previous keyframe of the indexed stream and
2816 * aligns other streams with respect to the keyframe timestamp
2817 * of indexed stream. Only called in case of Reverse Playback
2819 static GstFlowReturn
2820 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
2823 guint32 seg_idx = 0, k_index = 0;
2824 guint32 ref_seg_idx, ref_k_index;
2825 guint64 k_pos = 0, last_stop = 0;
2826 QtDemuxSegment *seg = NULL;
2827 QtDemuxStream *ref_str = NULL;
2828 guint64 seg_media_start_mov; /* segment media start time in mov format */
2830 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
2831 * and finally align all the other streams on that timestamp with their
2832 * respective keyframes */
2833 for (n = 0; n < qtdemux->n_streams; n++) {
2834 QtDemuxStream *str = qtdemux->streams[n];
2836 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
2837 qtdemux->segment.position);
2839 /* segment not found, continue with normal flow */
2843 /* No candidate yet, take that one */
2849 /* So that stream has a segment, we prefer video streams */
2850 if (str->subtype == FOURCC_vide) {
2856 if (G_UNLIKELY (!ref_str)) {
2857 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
2861 if (G_UNLIKELY (!ref_str->from_sample)) {
2862 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
2866 /* So that stream has been playing from from_sample to to_sample. We will
2867 * get the timestamp of the previous sample and search for a keyframe before
2868 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
2869 if (ref_str->subtype == FOURCC_vide) {
2870 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
2871 ref_str->from_sample - 1);
2873 if (ref_str->from_sample >= 10)
2874 k_index = ref_str->from_sample - 10;
2879 /* get current segment for that stream */
2880 seg = &ref_str->segments[ref_str->segment_index];
2881 /* convert seg->media_start to mov format time for timestamp comparison */
2882 seg_media_start_mov =
2883 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
2884 /* Crawl back through segments to find the one containing this I frame */
2885 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
2886 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
2887 ref_str->segment_index);
2888 if (G_UNLIKELY (!ref_str->segment_index)) {
2889 /* Reached first segment, let's consider it's EOS */
2892 ref_str->segment_index--;
2893 seg = &ref_str->segments[ref_str->segment_index];
2894 /* convert seg->media_start to mov format time for timestamp comparison */
2895 seg_media_start_mov =
2896 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
2899 /* Calculate time position of the keyframe and where we should stop */
2901 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
2902 ref_str->timescale) - seg->media_start) + seg->time;
2904 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
2905 GST_SECOND, ref_str->timescale);
2906 last_stop = (last_stop - seg->media_start) + seg->time;
2908 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
2909 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
2910 k_index, GST_TIME_ARGS (k_pos));
2912 /* Set last_stop with the keyframe timestamp we pushed of that stream */
2913 qtdemux->segment.position = last_stop;
2914 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
2915 GST_TIME_ARGS (last_stop));
2917 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
2918 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
2922 ref_seg_idx = ref_str->segment_index;
2923 ref_k_index = k_index;
2925 /* Align them all on this */
2926 for (n = 0; n < qtdemux->n_streams; n++) {
2928 guint64 media_start = 0, seg_time = 0;
2929 QtDemuxStream *str = qtdemux->streams[n];
2931 /* aligning reference stream again might lead to backing up to yet another
2932 * keyframe (due to timestamp rounding issues),
2933 * potentially putting more load on downstream; so let's try to avoid */
2934 if (str == ref_str) {
2935 seg_idx = ref_seg_idx;
2936 seg = &str->segments[seg_idx];
2937 k_index = ref_k_index;
2938 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
2939 "sample at index %d", ref_str->segment_index, k_index);
2941 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
2942 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
2944 /* segment not found, continue with normal flow */
2948 /* get segment and time in the segment */
2949 seg = &str->segments[seg_idx];
2950 seg_time = k_pos - seg->time;
2952 /* get the media time in the segment */
2953 media_start = seg->media_start + seg_time;
2955 /* get the index of the sample with media time */
2956 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
2957 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
2958 GST_TIME_ARGS (media_start), index);
2960 /* find previous keyframe */
2961 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
2964 /* Remember until where we want to go */
2965 str->to_sample = str->from_sample - 1;
2966 /* Define our time position */
2967 str->time_position =
2968 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
2969 str->timescale) - seg->media_start) + seg->time;
2970 /* Now seek back in time */
2971 gst_qtdemux_move_stream (qtdemux, str, k_index);
2972 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
2973 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
2974 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
2980 return GST_FLOW_EOS;
2983 /* activate the given segment number @seg_idx of @stream at time @offset.
2984 * @offset is an absolute global position over all the segments.
2986 * This will push out a NEWSEGMENT event with the right values and
2987 * position the stream index to the first decodable sample before
2991 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
2992 guint32 seg_idx, guint64 offset)
2995 QtDemuxSegment *segment;
2996 guint32 index, kf_index;
2998 guint64 start, stop, time;
3001 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3004 /* update the current segment */
3005 stream->segment_index = seg_idx;
3007 /* get the segment */
3008 segment = &stream->segments[seg_idx];
3010 if (G_UNLIKELY (offset < segment->time)) {
3011 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3016 /* segment lies beyond total indicated duration */
3017 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3018 segment->time > qtdemux->segment.duration)) {
3019 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3020 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3025 /* get time in this segment */
3026 seg_time = offset - segment->time;
3028 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3029 GST_TIME_ARGS (seg_time));
3031 if (G_UNLIKELY (seg_time > segment->duration)) {
3032 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3033 GST_TIME_ARGS (segment->duration));
3037 /* qtdemux->segment.stop is in outside-time-realm, whereas
3038 * segment->media_stop is in track-time-realm.
3040 * In order to compare the two, we need to bring segment.stop
3041 * into the track-time-realm */
3043 stop = qtdemux->segment.stop;
3045 stop = qtdemux->segment.duration;
3047 stop = segment->media_stop;
3050 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3052 if (qtdemux->segment.rate >= 0) {
3053 start = MIN (segment->media_start + seg_time, stop);
3056 if (segment->media_start >= qtdemux->segment.start) {
3057 start = segment->media_start;
3058 time = segment->time;
3060 start = qtdemux->segment.start;
3061 time = segment->time + (qtdemux->segment.start - segment->media_start);
3064 start = MAX (segment->media_start, qtdemux->segment.start);
3065 stop = MIN (segment->media_start + seg_time, stop);
3068 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3069 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3070 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3072 /* combine global rate with that of the segment */
3073 rate = segment->rate * qtdemux->segment.rate;
3075 /* update the segment values used for clipping */
3076 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
3077 /* accumulate previous segments */
3078 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3079 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3080 ABS (stream->segment.rate);
3081 stream->segment.rate = rate;
3082 stream->segment.start = start;
3083 stream->segment.stop = stop;
3084 stream->segment.time = time;
3086 /* now prepare and send the segment */
3088 event = gst_event_new_segment (&stream->segment);
3089 gst_pad_push_event (stream->pad, event);
3090 /* assume we can send more data now */
3091 stream->last_ret = GST_FLOW_OK;
3092 /* clear to send tags on this pad now */
3093 gst_qtdemux_push_tags (qtdemux, stream);
3096 /* and move to the keyframe before the indicated media time of the
3098 if (qtdemux->segment.rate >= 0) {
3099 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3100 stream->to_sample = G_MAXUINT32;
3101 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3102 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3103 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3104 GST_SECOND, stream->timescale)));
3106 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3107 stream->to_sample = index;
3108 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3109 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3110 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3111 GST_SECOND, stream->timescale)));
3114 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3115 * encountered an error and printed a message so we return appropriately */
3119 /* we're at the right spot */
3120 if (index == stream->sample_index) {
3121 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3125 /* find keyframe of the target index */
3126 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3129 /* indent does stupid stuff with stream->samples[].timestamp */
3131 /* if we move forwards, we don't have to go back to the previous
3132 * keyframe since we already sent that. We can also just jump to
3133 * the keyframe right before the target index if there is one. */
3134 if (index > stream->sample_index) {
3135 /* moving forwards check if we move past a keyframe */
3136 if (kf_index > stream->sample_index) {
3137 GST_DEBUG_OBJECT (qtdemux,
3138 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3139 GST_TIME_ARGS (gst_util_uint64_scale (
3140 stream->samples[kf_index].timestamp,
3141 GST_SECOND, stream->timescale)));
3142 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3144 GST_DEBUG_OBJECT (qtdemux,
3145 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3146 " already sent", kf_index,
3147 GST_TIME_ARGS (gst_util_uint64_scale (
3148 stream->samples[kf_index].timestamp,
3149 GST_SECOND, stream->timescale)));
3152 GST_DEBUG_OBJECT (qtdemux,
3153 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3154 GST_TIME_ARGS (gst_util_uint64_scale (
3155 stream->samples[kf_index].timestamp,
3156 GST_SECOND, stream->timescale)));
3157 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3165 /* prepare to get the current sample of @stream, getting essential values.
3167 * This function will also prepare and send the segment when needed.
3169 * Return FALSE if the stream is EOS.
3172 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3173 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp,
3174 guint64 * duration, gboolean * keyframe)
3176 QtDemuxSample *sample;
3177 guint64 time_position;
3180 g_return_val_if_fail (stream != NULL, FALSE);
3182 time_position = stream->time_position;
3183 if (G_UNLIKELY (time_position == -1))
3186 seg_idx = stream->segment_index;
3187 if (G_UNLIKELY (seg_idx == -1)) {
3188 /* find segment corresponding to time_position if we are looking
3190 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3192 /* nothing found, we're really eos */
3197 /* different segment, activate it, sample_index will be set. */
3198 if (G_UNLIKELY (stream->segment_index != seg_idx))
3199 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3201 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3202 stream->sample_index, stream->n_samples);
3204 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3207 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3208 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3209 stream->sample_index);
3213 /* now get the info for the sample we're at */
3214 sample = &stream->samples[stream->sample_index];
3216 *timestamp = QTSAMPLE_PTS (stream, sample);
3217 *offset = sample->offset;
3218 *size = sample->size;
3219 *duration = QTSAMPLE_DUR_PTS (stream, sample, *timestamp);
3220 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3227 stream->time_position = -1;
3232 /* move to the next sample in @stream.
3234 * Moves to the next segment when needed.
3237 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3239 QtDemuxSample *sample;
3240 QtDemuxSegment *segment;
3242 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3243 /* Mark the stream as EOS */
3244 GST_DEBUG_OBJECT (qtdemux,
3245 "reached max allowed sample %u, mark EOS", stream->to_sample);
3246 stream->time_position = -1;
3250 /* move to next sample */
3251 stream->sample_index++;
3253 /* get current segment */
3254 segment = &stream->segments[stream->segment_index];
3256 /* reached the last sample, we need the next segment */
3257 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3260 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3261 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3262 stream->sample_index);
3266 /* get next sample */
3267 sample = &stream->samples[stream->sample_index];
3269 /* see if we are past the segment */
3270 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3271 GST_SECOND, stream->timescale) >= segment->media_stop))
3274 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3275 stream->timescale) >= segment->media_start) {
3276 /* inside the segment, update time_position, looks very familiar to
3277 * GStreamer segments, doesn't it? */
3278 stream->time_position =
3279 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3280 stream->timescale) - segment->media_start) + segment->time;
3282 /* not yet in segment, time does not yet increment. This means
3283 * that we are still prerolling keyframes to the decoder so it can
3284 * decode the first sample of the segment. */
3285 stream->time_position = segment->time;
3289 /* move to the next segment */
3292 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3294 if (stream->segment_index == stream->n_segments - 1) {
3295 /* are we at the end of the last segment, we're EOS */
3296 stream->time_position = -1;
3298 /* else we're only at the end of the current segment */
3299 stream->time_position = segment->stop_time;
3301 /* make sure we select a new segment */
3302 stream->segment_index = -1;
3307 gst_qtdemux_sync_streams (GstQTDemux * demux)
3311 if (demux->n_streams <= 1)
3314 for (i = 0; i < demux->n_streams; i++) {
3315 QtDemuxStream *stream;
3316 GstClockTime end_time;
3318 stream = demux->streams[i];
3323 /* TODO advance time on subtitle streams here, if any some day */
3325 /* some clips/trailers may have unbalanced streams at the end,
3326 * so send EOS on shorter stream to prevent stalling others */
3328 /* do not mess with EOS if SEGMENT seeking */
3329 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3332 if (demux->pullbased) {
3333 /* loop mode is sample time based */
3334 if (stream->time_position != -1)
3337 /* push mode is byte position based */
3338 if (stream->n_samples &&
3339 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3343 if (stream->sent_eos)
3346 /* only act if some gap */
3347 end_time = stream->segments[stream->n_segments - 1].stop_time;
3348 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3349 ", stream end: %" GST_TIME_FORMAT,
3350 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3351 if (end_time + 2 * GST_SECOND < demux->segment.position) {
3352 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3353 GST_PAD_NAME (stream->pad));
3354 stream->sent_eos = TRUE;
3355 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3360 /* EOS and NOT_LINKED need to be combined. This means that we return:
3362 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3363 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
3365 static GstFlowReturn
3366 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3370 gboolean unexpected = FALSE, not_linked = TRUE;
3372 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3374 /* store the value */
3375 stream->last_ret = ret;
3377 /* any other error that is not-linked or eos can be returned right away */
3378 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3381 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3382 for (i = 0; i < demux->n_streams; i++) {
3383 QtDemuxStream *ostream = demux->streams[i];
3385 ret = ostream->last_ret;
3387 /* no unexpected or unlinked, return */
3388 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3391 /* we check to see if we have at least 1 unexpected or all unlinked */
3392 unexpected |= (ret == GST_FLOW_EOS);
3393 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3396 /* when we get here, we all have unlinked or unexpected */
3398 ret = GST_FLOW_NOT_LINKED;
3399 else if (unexpected)
3402 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3406 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3407 * completely cliped */
3409 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3412 guint64 start, stop, cstart, cstop, diff;
3413 GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
3415 gint num_rate, denom_rate;
3420 size = gst_buffer_get_size (buf);
3423 /* depending on the type, setup the clip parameters */
3424 if (stream->subtype == FOURCC_soun) {
3425 frame_size = stream->bytes_per_frame;
3426 num_rate = GST_SECOND;
3427 denom_rate = (gint) stream->rate;
3429 } else if (stream->subtype == FOURCC_vide) {
3431 num_rate = stream->fps_n;
3432 denom_rate = stream->fps_d;
3437 /* we can only clip if we have a valid timestamp */
3438 timestamp = GST_BUFFER_TIMESTAMP (buf);
3439 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
3442 if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf))) {
3443 duration = GST_BUFFER_DURATION (buf);
3446 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3450 stop = start + duration;
3452 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3453 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3456 /* see if some clipping happened */
3457 diff = cstart - start;
3463 /* bring clipped time to samples and to bytes */
3464 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3467 GST_DEBUG_OBJECT (qtdemux,
3468 "clipping start to %" GST_TIME_FORMAT " %"
3469 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3475 diff = stop - cstop;
3480 /* bring clipped time to samples and then to bytes */
3481 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3483 GST_DEBUG_OBJECT (qtdemux,
3484 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3485 " bytes", GST_TIME_ARGS (cstop), diff);
3490 gst_buffer_resize (buf, offset, size);
3491 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3492 GST_BUFFER_DURATION (buf) = duration;
3496 /* dropped buffer */
3499 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3504 GST_DEBUG_OBJECT (qtdemux, "no timestamp on buffer");
3509 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3510 gst_buffer_unref (buf);
3515 /* the input buffer metadata must be writable,
3516 * but time/duration etc not yet set and need not be preserved */
3518 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3525 /* not many cases for now */
3526 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3527 /* send a one time dvd clut event */
3528 if (stream->pending_event && stream->pad)
3529 gst_pad_push_event (stream->pad, stream->pending_event);
3530 stream->pending_event = NULL;
3531 /* no further processing needed */
3532 stream->need_process = FALSE;
3535 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
3539 gst_buffer_map (buf, &map, GST_MAP_READ);
3541 if (G_LIKELY (map.size >= 2)) {
3542 nsize = GST_READ_UINT16_BE (map.data);
3543 nsize = MIN (nsize, map.size - 2);
3546 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
3549 /* takes care of UTF-8 validation or UTF-16 recognition,
3550 * no other encoding expected */
3551 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
3552 gst_buffer_unmap (buf, &map);
3554 gst_buffer_unref (buf);
3555 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
3557 /* may be 0-size subtitle, which is also sent to keep pipeline going */
3558 gst_buffer_resize (buf, 2, nsize);
3561 /* FIXME ? convert optional subsequent style info to markup */
3566 /* Sets a buffer's attributes properly and pushes it downstream.
3567 * Also checks for additional actions and custom processing that may
3568 * need to be done first.
3571 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3572 QtDemuxStream * stream, GstBuffer * buf,
3573 guint64 timestamp, guint64 duration, gboolean keyframe, guint64 position,
3574 guint64 byte_position)
3576 GstFlowReturn ret = GST_FLOW_OK;
3578 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
3582 gst_buffer_map (buf, &map, GST_MAP_READ);
3583 url = g_strndup ((gchar *) map.data, map.size);
3584 gst_buffer_unmap (buf, &map);
3585 if (url != NULL && strlen (url) != 0) {
3586 /* we have RTSP redirect now */
3587 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3588 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
3589 gst_structure_new ("redirect",
3590 "new-location", G_TYPE_STRING, url, NULL)));
3591 qtdemux->posted_redirect = TRUE;
3593 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
3599 /* position reporting */
3600 if (qtdemux->segment.rate >= 0) {
3601 qtdemux->segment.position = position;
3602 gst_qtdemux_sync_streams (qtdemux);
3605 if (G_UNLIKELY (!stream->pad)) {
3606 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
3607 gst_buffer_unref (buf);
3611 /* send out pending buffers */
3612 while (stream->buffers) {
3613 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
3615 if (G_UNLIKELY (stream->discont)) {
3616 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3617 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
3618 stream->discont = FALSE;
3621 gst_pad_push (stream->pad, buffer);
3623 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
3626 /* we're going to modify the metadata */
3627 buf = gst_buffer_make_writable (buf);
3629 if (G_UNLIKELY (stream->need_process))
3630 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
3632 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3633 GST_BUFFER_DURATION (buf) = duration;
3634 GST_BUFFER_OFFSET (buf) = -1;
3635 GST_BUFFER_OFFSET_END (buf) = -1;
3637 if (G_UNLIKELY (stream->padding)) {
3638 gst_buffer_resize (buf, stream->padding, -1);
3641 if (G_UNLIKELY (qtdemux->element_index)) {
3642 GstClockTime stream_time;
3645 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
3647 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
3648 GST_LOG_OBJECT (qtdemux,
3649 "adding association %" GST_TIME_FORMAT "-> %"
3650 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
3651 gst_index_add_association (qtdemux->element_index,
3653 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
3654 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
3655 GST_FORMAT_BYTES, byte_position, NULL);
3660 if (stream->need_clip)
3661 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
3663 if (G_UNLIKELY (buf == NULL))
3666 if (G_UNLIKELY (stream->discont)) {
3667 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3668 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3669 stream->discont = FALSE;
3673 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3675 GST_LOG_OBJECT (qtdemux,
3676 "Pushing buffer with time %" GST_TIME_FORMAT ", duration %"
3677 GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
3678 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
3680 ret = gst_pad_push (stream->pad, buf);
3686 static GstFlowReturn
3687 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
3689 GstFlowReturn ret = GST_FLOW_OK;
3690 GstBuffer *buf = NULL;
3691 QtDemuxStream *stream;
3694 guint64 timestamp = GST_CLOCK_TIME_NONE;
3695 guint64 duration = 0;
3696 gboolean keyframe = FALSE;
3701 gst_qtdemux_push_pending_newsegment (qtdemux);
3703 /* Figure out the next stream sample to output, min_time is expressed in
3704 * global time and runs over the edit list segments. */
3705 min_time = G_MAXUINT64;
3707 for (i = 0; i < qtdemux->n_streams; i++) {
3710 stream = qtdemux->streams[i];
3711 position = stream->time_position;
3713 /* position of -1 is EOS */
3714 if (position != -1 && position < min_time) {
3715 min_time = position;
3720 if (G_UNLIKELY (index == -1)) {
3721 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
3725 /* check for segment end */
3726 if (G_UNLIKELY (qtdemux->segment.stop != -1
3727 && qtdemux->segment.stop < min_time)) {
3728 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
3732 stream = qtdemux->streams[index];
3734 /* fetch info for the current sample of this stream */
3735 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
3736 &size, ×tamp, &duration, &keyframe)))
3739 GST_LOG_OBJECT (qtdemux,
3740 "pushing from stream %d, offset %" G_GUINT64_FORMAT
3741 ", size %d, timestamp=%" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
3742 index, offset, size, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
3744 /* hmm, empty sample, skip and move to next sample */
3745 if (G_UNLIKELY (size <= 0))
3748 /* last pushed sample was out of boundary, goto next sample */
3749 if (G_UNLIKELY (stream->last_ret == GST_FLOW_EOS))
3752 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
3755 ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
3756 if (G_UNLIKELY (ret != GST_FLOW_OK))
3759 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
3760 timestamp, duration, keyframe, min_time, offset);
3763 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
3764 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
3765 * we have no more data for the pad to push */
3766 if (ret == GST_FLOW_EOS)
3770 gst_qtdemux_advance_sample (qtdemux, stream);
3778 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
3784 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
3785 /* EOS will be raised if all are EOS */
3792 gst_qtdemux_loop (GstPad * pad)
3794 GstQTDemux *qtdemux;
3798 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
3800 cur_offset = qtdemux->offset;
3801 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
3802 cur_offset, qtdemux->state);
3804 switch (qtdemux->state) {
3805 case QTDEMUX_STATE_INITIAL:
3806 case QTDEMUX_STATE_HEADER:
3807 ret = gst_qtdemux_loop_state_header (qtdemux);
3809 case QTDEMUX_STATE_MOVIE:
3810 ret = gst_qtdemux_loop_state_movie (qtdemux);
3811 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
3812 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
3820 /* if something went wrong, pause */
3821 if (ret != GST_FLOW_OK)
3825 gst_object_unref (qtdemux);
3831 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3832 (NULL), ("streaming stopped, invalid state"));
3833 gst_pad_pause_task (pad);
3834 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3839 const gchar *reason = gst_flow_get_name (ret);
3841 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
3843 gst_pad_pause_task (pad);
3845 /* fatal errors need special actions */
3847 if (ret == GST_FLOW_EOS) {
3848 if (qtdemux->n_streams == 0) {
3849 /* we have no streams, post an error */
3850 gst_qtdemux_post_no_playable_stream_error (qtdemux);
3852 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3855 if ((stop = qtdemux->segment.stop) == -1)
3856 stop = qtdemux->segment.duration;
3858 if (qtdemux->segment.rate >= 0) {
3859 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
3860 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3861 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3862 GST_FORMAT_TIME, stop));
3864 /* For Reverse Playback */
3865 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
3866 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3867 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3868 GST_FORMAT_TIME, qtdemux->segment.start));
3871 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
3872 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3874 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
3875 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3876 (NULL), ("streaming stopped, reason %s", reason));
3877 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3886 * Returns the size of the first entry at the current offset.
3887 * If -1, there are none (which means EOS or empty file).
3890 next_entry_size (GstQTDemux * demux)
3892 QtDemuxStream *stream;
3895 guint64 smalloffs = (guint64) - 1;
3896 QtDemuxSample *sample;
3898 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
3901 for (i = 0; i < demux->n_streams; i++) {
3902 stream = demux->streams[i];
3904 if (stream->sample_index == -1)
3905 stream->sample_index = 0;
3907 if (stream->sample_index >= stream->n_samples) {
3908 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
3912 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
3913 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
3914 stream->sample_index);
3918 sample = &stream->samples[stream->sample_index];
3920 GST_LOG_OBJECT (demux,
3921 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3922 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
3923 sample->offset, sample->size);
3925 if (((smalloffs == -1)
3926 || (sample->offset < smalloffs)) && (sample->size)) {
3928 smalloffs = sample->offset;
3932 GST_LOG_OBJECT (demux,
3933 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
3934 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
3939 stream = demux->streams[smallidx];
3940 sample = &stream->samples[stream->sample_index];
3942 if (sample->offset >= demux->offset) {
3943 demux->todrop = sample->offset - demux->offset;
3944 return sample->size + demux->todrop;
3947 GST_DEBUG_OBJECT (demux,
3948 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
3953 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
3955 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
3957 gst_element_post_message (GST_ELEMENT_CAST (demux),
3958 gst_message_new_element (GST_OBJECT_CAST (demux),
3959 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
3963 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
3968 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
3971 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
3972 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
3973 GST_SEEK_TYPE_NONE, -1);
3975 res = gst_pad_push_event (demux->sinkpad, event);
3980 /* check for seekable upstream, above and beyond a mere query */
3982 gst_qtdemux_check_seekability (GstQTDemux * demux)
3985 gboolean seekable = FALSE;
3986 gint64 start = -1, stop = -1;
3988 if (demux->upstream_size)
3991 query = gst_query_new_seeking (GST_FORMAT_BYTES);
3992 if (!gst_pad_peer_query (demux->sinkpad, query)) {
3993 GST_DEBUG_OBJECT (demux, "seeking query failed");
3997 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
3999 /* try harder to query upstream size if we didn't get it the first time */
4000 if (seekable && stop == -1) {
4001 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4002 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4005 /* if upstream doesn't know the size, it's likely that it's not seekable in
4006 * practice even if it technically may be seekable */
4007 if (seekable && (start != 0 || stop <= start)) {
4008 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4013 gst_query_unref (query);
4015 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4016 G_GUINT64_FORMAT ")", seekable, start, stop);
4017 demux->upstream_seekable = seekable;
4018 demux->upstream_size = seekable ? stop : -1;
4021 /* FIXME, unverified after edit list updates */
4022 static GstFlowReturn
4023 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4026 GstFlowReturn ret = GST_FLOW_OK;
4028 demux = GST_QTDEMUX (parent);
4030 gst_adapter_push (demux->adapter, inbuf);
4032 /* we never really mean to buffer that much */
4033 if (demux->neededbytes == -1)
4036 GST_DEBUG_OBJECT (demux,
4037 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4038 demux->neededbytes, gst_adapter_available (demux->adapter));
4040 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4041 (ret == GST_FLOW_OK)) {
4043 GST_DEBUG_OBJECT (demux,
4044 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4045 demux->state, demux->neededbytes, demux->offset);
4047 switch (demux->state) {
4048 case QTDEMUX_STATE_INITIAL:{
4053 gst_qtdemux_check_seekability (demux);
4055 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4057 /* get fourcc/length, set neededbytes */
4058 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4060 gst_adapter_unmap (demux->adapter);
4062 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4063 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4065 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4066 (_("This file is invalid and cannot be played.")),
4067 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4068 GST_FOURCC_ARGS (fourcc)));
4069 ret = GST_FLOW_ERROR;
4072 if (fourcc == FOURCC_mdat) {
4073 if (demux->n_streams > 0) {
4074 /* we have the headers, start playback */
4075 demux->state = QTDEMUX_STATE_MOVIE;
4076 demux->neededbytes = next_entry_size (demux);
4077 demux->mdatleft = size;
4079 /* Only post, event on pads is done after newsegment */
4080 qtdemux_post_global_tags (demux);
4083 /* no headers yet, try to get them */
4086 guint64 old, target;
4089 old = demux->offset;
4090 target = old + size;
4092 /* try to jump over the atom with a seek */
4093 /* only bother if it seems worth doing so,
4094 * and avoids possible upstream/server problems */
4095 if (demux->upstream_seekable &&
4096 demux->upstream_size > 4 * (1 << 20)) {
4097 res = qtdemux_seek_offset (demux, target);
4099 GST_DEBUG_OBJECT (demux, "skipping seek");
4104 GST_DEBUG_OBJECT (demux, "seek success");
4105 /* remember the offset fo the first mdat so we can seek back to it
4106 * after we have the headers */
4107 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4108 demux->first_mdat = old;
4109 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4112 /* seek worked, continue reading */
4113 demux->offset = target;
4114 demux->neededbytes = 16;
4115 demux->state = QTDEMUX_STATE_INITIAL;
4117 /* seek failed, need to buffer */
4118 demux->offset = old;
4119 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4120 /* there may be multiple mdat (or alike) buffers */
4122 if (demux->mdatbuffer)
4123 bs = gst_buffer_get_size (demux->mdatbuffer);
4126 if (size + bs > 10 * (1 << 20))
4128 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4129 demux->neededbytes = size;
4130 if (!demux->mdatbuffer)
4131 demux->mdatoffset = demux->offset;
4134 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4135 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4136 (_("This file is invalid and cannot be played.")),
4137 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4138 GST_FOURCC_ARGS (fourcc), size));
4139 ret = GST_FLOW_ERROR;
4142 /* this means we already started buffering and still no moov header,
4143 * let's continue buffering everything till we get moov */
4144 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
4146 demux->neededbytes = size;
4147 demux->state = QTDEMUX_STATE_HEADER;
4151 case QTDEMUX_STATE_HEADER:{
4155 GST_DEBUG_OBJECT (demux, "In header");
4157 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4159 /* parse the header */
4160 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4162 if (fourcc == FOURCC_moov) {
4163 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4165 demux->got_moov = TRUE;
4167 /* prepare newsegment to send when streaming actually starts */
4168 if (!demux->pending_newsegment)
4169 demux->pending_newsegment = gst_event_new_segment (&demux->segment);
4171 qtdemux_parse_moov (demux, data, demux->neededbytes);
4172 qtdemux_node_dump (demux, demux->moov_node);
4173 qtdemux_parse_tree (demux);
4174 qtdemux_expose_streams (demux);
4176 g_node_destroy (demux->moov_node);
4177 demux->moov_node = NULL;
4178 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4179 } else if (fourcc == FOURCC_moof) {
4180 if (demux->got_moov && demux->fragmented) {
4181 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4182 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4183 demux->offset, NULL)) {
4184 gst_adapter_unmap (demux->adapter);
4185 ret = GST_FLOW_ERROR;
4189 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4191 } else if (fourcc == FOURCC_ftyp) {
4192 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4193 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4194 } else if (fourcc == FOURCC_uuid) {
4195 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4196 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4198 GST_WARNING_OBJECT (demux,
4199 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4200 GST_FOURCC_ARGS (fourcc));
4201 /* Let's jump that one and go back to initial state */
4203 gst_adapter_unmap (demux->adapter);
4206 if (demux->mdatbuffer && demux->n_streams) {
4207 /* the mdat was before the header */
4208 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4209 demux->n_streams, demux->mdatbuffer);
4210 /* restore our adapter/offset view of things with upstream;
4211 * put preceding buffered data ahead of current moov data.
4212 * This should also handle evil mdat, moov, mdat cases and alike */
4213 gst_adapter_clear (demux->adapter);
4214 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4215 demux->mdatbuffer = NULL;
4216 demux->offset = demux->mdatoffset;
4217 demux->neededbytes = next_entry_size (demux);
4218 demux->state = QTDEMUX_STATE_MOVIE;
4219 demux->mdatleft = gst_adapter_available (demux->adapter);
4221 /* Only post, event on pads is done after newsegment */
4222 qtdemux_post_global_tags (demux);
4225 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4226 gst_adapter_flush (demux->adapter, demux->neededbytes);
4228 if (demux->got_moov && demux->first_mdat != -1) {
4231 /* we need to seek back */
4232 res = qtdemux_seek_offset (demux, demux->first_mdat);
4234 demux->offset = demux->first_mdat;
4236 GST_DEBUG_OBJECT (demux, "Seek back failed");
4239 demux->offset += demux->neededbytes;
4241 demux->neededbytes = 16;
4242 demux->state = QTDEMUX_STATE_INITIAL;
4247 case QTDEMUX_STATE_BUFFER_MDAT:{
4251 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4253 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4254 gst_buffer_extract (buf, 0, fourcc, 4);
4255 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4256 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
4257 if (demux->mdatbuffer)
4258 demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
4260 demux->mdatbuffer = buf;
4261 demux->offset += demux->neededbytes;
4262 demux->neededbytes = 16;
4263 demux->state = QTDEMUX_STATE_INITIAL;
4264 gst_qtdemux_post_progress (demux, 1, 1);
4268 case QTDEMUX_STATE_MOVIE:{
4270 QtDemuxStream *stream = NULL;
4271 QtDemuxSample *sample;
4273 guint64 timestamp, duration, position;
4276 GST_DEBUG_OBJECT (demux,
4277 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4279 if (demux->fragmented) {
4280 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4282 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4283 /* if needed data starts within this atom,
4284 * then it should not exceed this atom */
4285 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4286 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4287 (_("This file is invalid and cannot be played.")),
4288 ("sample data crosses atom boundary"));
4289 ret = GST_FLOW_ERROR;
4292 demux->mdatleft -= demux->neededbytes;
4294 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4295 /* so we are dropping more than left in this atom */
4296 demux->todrop -= demux->mdatleft;
4297 demux->neededbytes -= demux->mdatleft;
4298 demux->mdatleft = 0;
4299 /* need to resume atom parsing so we do not miss any other pieces */
4300 demux->state = QTDEMUX_STATE_INITIAL;
4301 demux->neededbytes = 16;
4306 if (demux->todrop) {
4307 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4308 gst_adapter_flush (demux->adapter, demux->todrop);
4309 demux->neededbytes -= demux->todrop;
4310 demux->offset += demux->todrop;
4314 /* initial newsegment sent here after having added pads,
4315 * possible others in sink_event */
4316 if (G_UNLIKELY (demux->pending_newsegment)) {
4317 gst_qtdemux_push_event (demux, demux->pending_newsegment);
4318 demux->pending_newsegment = NULL;
4319 /* clear to send tags on all streams */
4320 for (i = 0; i < demux->n_streams; i++) {
4321 gst_qtdemux_push_tags (demux, demux->streams[i]);
4325 /* Figure out which stream this is packet belongs to */
4326 for (i = 0; i < demux->n_streams; i++) {
4327 stream = demux->streams[i];
4328 if (stream->sample_index >= stream->n_samples)
4330 GST_LOG_OBJECT (demux,
4331 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4332 " / size:%d)", i, stream->sample_index,
4333 stream->samples[stream->sample_index].offset,
4334 stream->samples[stream->sample_index].size);
4336 if (stream->samples[stream->sample_index].offset == demux->offset)
4340 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4341 goto unknown_stream;
4343 /* Put data in a buffer, set timestamps, caps, ... */
4344 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4345 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4346 GST_FOURCC_ARGS (stream->fourcc));
4348 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4350 sample = &stream->samples[stream->sample_index];
4352 position = QTSAMPLE_DTS (stream, sample);
4353 timestamp = QTSAMPLE_PTS (stream, sample);
4354 duration = QTSAMPLE_DUR_DTS (stream, sample, position);
4355 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4357 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4358 timestamp, duration, keyframe, position, demux->offset);
4361 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4363 stream->sample_index++;
4365 /* update current offset and figure out size of next buffer */
4366 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4367 demux->offset, demux->neededbytes);
4368 demux->offset += demux->neededbytes;
4369 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4372 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4373 if (demux->fragmented) {
4374 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4375 /* there may be more to follow, only finish this atom */
4376 demux->todrop = demux->mdatleft;
4377 demux->neededbytes = demux->todrop;
4389 /* when buffering movie data, at least show user something is happening */
4390 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4391 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4392 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4393 demux->neededbytes);
4402 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4403 ret = GST_FLOW_ERROR;
4408 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4414 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4415 (NULL), ("qtdemuxer invalid state %d", demux->state));
4416 ret = GST_FLOW_ERROR;
4421 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4422 (NULL), ("no 'moov' atom within the first 10 MB"));
4423 ret = GST_FLOW_ERROR;
4429 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
4434 query = gst_query_new_scheduling ();
4436 if (!gst_pad_peer_query (sinkpad, query)) {
4437 gst_query_unref (query);
4441 pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
4442 gst_query_unref (query);
4447 GST_DEBUG_OBJECT (sinkpad, "activating pull");
4448 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
4452 GST_DEBUG_OBJECT (sinkpad, "activating push");
4453 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
4458 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
4459 GstPadMode mode, gboolean active)
4462 GstQTDemux *demux = GST_QTDEMUX (parent);
4465 case GST_PAD_MODE_PUSH:
4466 demux->pullbased = FALSE;
4469 case GST_PAD_MODE_PULL:
4471 demux->pullbased = TRUE;
4472 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4475 res = gst_pad_stop_task (sinkpad);
4487 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4489 return g_malloc (items * size);
4493 qtdemux_zfree (void *opaque, void *addr)
4499 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4505 z = g_new0 (z_stream, 1);
4506 z->zalloc = qtdemux_zalloc;
4507 z->zfree = qtdemux_zfree;
4510 z->next_in = z_buffer;
4511 z->avail_in = z_length;
4513 buffer = (guint8 *) g_malloc (length);
4514 ret = inflateInit (z);
4515 while (z->avail_in > 0) {
4516 if (z->avail_out == 0) {
4518 buffer = (guint8 *) g_realloc (buffer, length);
4519 z->next_out = buffer + z->total_out;
4520 z->avail_out = 1024;
4522 ret = inflate (z, Z_SYNC_FLUSH);
4526 if (ret != Z_STREAM_END) {
4527 g_warning ("inflate() returned %d", ret);
4533 #endif /* HAVE_ZLIB */
4536 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4540 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4542 /* counts as header data */
4543 qtdemux->header_size += length;
4545 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4546 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4548 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4554 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4555 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4556 if (dcom == NULL || cmvd == NULL)
4557 goto invalid_compression;
4559 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4562 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4563 guint uncompressed_length;
4564 guint compressed_length;
4567 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4568 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4569 GST_LOG ("length = %u", uncompressed_length);
4572 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4573 compressed_length, uncompressed_length);
4575 qtdemux->moov_node_compressed = qtdemux->moov_node;
4576 qtdemux->moov_node = g_node_new (buf);
4578 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4579 uncompressed_length);
4582 #endif /* HAVE_ZLIB */
4584 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4585 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
4592 invalid_compression:
4594 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
4600 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
4603 while (G_UNLIKELY (buf < end)) {
4607 if (G_UNLIKELY (buf + 4 > end)) {
4608 GST_LOG_OBJECT (qtdemux, "buffer overrun");
4611 len = QT_UINT32 (buf);
4612 if (G_UNLIKELY (len == 0)) {
4613 GST_LOG_OBJECT (qtdemux, "empty container");
4616 if (G_UNLIKELY (len < 8)) {
4617 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
4620 if (G_UNLIKELY (len > (end - buf))) {
4621 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
4622 (gint) (end - buf));
4626 child = g_node_new ((guint8 *) buf);
4627 g_node_append (node, child);
4628 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
4629 qtdemux_parse_node (qtdemux, child, buf, len);
4637 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
4640 int len = QT_UINT32 (xdxt->data);
4641 guint8 *buf = xdxt->data;
4642 guint8 *end = buf + len;
4645 /* skip size and type */
4653 size = QT_UINT32 (buf);
4654 type = QT_FOURCC (buf + 4);
4656 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
4658 if (buf + size > end || size <= 0)
4664 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
4665 GST_FOURCC_ARGS (type));
4669 buffer = gst_buffer_new_and_alloc (size);
4670 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4671 stream->buffers = g_slist_append (stream->buffers, buffer);
4672 GST_LOG_OBJECT (qtdemux, "parsing theora header");
4675 buffer = gst_buffer_new_and_alloc (size);
4676 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4677 stream->buffers = g_slist_append (stream->buffers, buffer);
4678 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
4681 buffer = gst_buffer_new_and_alloc (size);
4682 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4683 stream->buffers = g_slist_append (stream->buffers, buffer);
4684 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
4687 GST_WARNING_OBJECT (qtdemux,
4688 "unknown theora cookie %" GST_FOURCC_FORMAT,
4689 GST_FOURCC_ARGS (type));
4698 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
4702 guint32 node_length = 0;
4703 const QtNodeType *type;
4706 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
4708 if (G_UNLIKELY (length < 8))
4709 goto not_enough_data;
4711 node_length = QT_UINT32 (buffer);
4712 fourcc = QT_FOURCC (buffer + 4);
4714 /* ignore empty nodes */
4715 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
4718 type = qtdemux_type_get (fourcc);
4720 end = buffer + length;
4722 GST_LOG_OBJECT (qtdemux,
4723 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
4724 GST_FOURCC_ARGS (fourcc), node_length, type->name);
4726 if (node_length > length)
4727 goto broken_atom_size;
4729 if (type->flags & QT_FLAG_CONTAINER) {
4730 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
4735 if (node_length < 20) {
4736 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
4739 GST_DEBUG_OBJECT (qtdemux,
4740 "parsing stsd (sample table, sample description) atom");
4741 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
4751 /* also read alac (or whatever) in stead of mp4a in the following,
4752 * since a similar layout is used in other cases as well */
4753 if (fourcc == FOURCC_mp4a)
4758 /* There are two things we might encounter here: a true mp4a atom, and
4759 an mp4a entry in an stsd atom. The latter is what we're interested
4760 in, and it looks like an atom, but isn't really one. The true mp4a
4761 atom is short, so we detect it based on length here. */
4762 if (length < min_size) {
4763 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
4764 GST_FOURCC_ARGS (fourcc));
4768 /* 'version' here is the sound sample description version. Types 0 and
4769 1 are documented in the QTFF reference, but type 2 is not: it's
4770 described in Apple header files instead (struct SoundDescriptionV2
4772 version = QT_UINT16 (buffer + 16);
4774 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
4775 GST_FOURCC_ARGS (fourcc), version);
4777 /* parse any esds descriptors */
4789 GST_WARNING_OBJECT (qtdemux,
4790 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
4791 GST_FOURCC_ARGS (fourcc), version);
4796 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4808 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
4809 GST_FOURCC_ARGS (fourcc));
4810 version = QT_UINT32 (buffer + 16);
4811 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
4812 if (1 || version == 0x00000000) {
4813 buf = buffer + 0x32;
4815 /* FIXME Quicktime uses PASCAL string while
4816 * the iso format uses C strings. Check the file
4817 * type before attempting to parse the string here. */
4818 tlen = QT_UINT8 (buf);
4819 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
4821 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
4822 /* the string has a reserved space of 32 bytes so skip
4823 * the remaining 31 */
4825 buf += 4; /* and 4 bytes reserved */
4827 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
4829 qtdemux_parse_container (qtdemux, node, buf, end);
4835 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
4836 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
4841 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
4846 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
4847 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
4855 version = QT_UINT32 (buffer + 12);
4856 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
4863 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
4868 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4873 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
4877 if (!strcmp (type->name, "unknown"))
4878 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
4882 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
4883 GST_FOURCC_ARGS (fourcc));
4889 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4890 (_("This file is corrupt and cannot be played.")),
4891 ("Not enough data for an atom header, got only %u bytes", length));
4896 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4897 (_("This file is corrupt and cannot be played.")),
4898 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
4899 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
4906 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
4910 guint32 child_fourcc;
4912 for (child = g_node_first_child (node); child;
4913 child = g_node_next_sibling (child)) {
4914 buffer = (guint8 *) child->data;
4916 child_fourcc = QT_FOURCC (buffer + 4);
4918 if (G_UNLIKELY (child_fourcc == fourcc)) {
4926 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
4927 GstByteReader * parser)
4931 guint32 child_fourcc, child_len;
4933 for (child = g_node_first_child (node); child;
4934 child = g_node_next_sibling (child)) {
4935 buffer = (guint8 *) child->data;
4937 child_len = QT_UINT32 (buffer);
4938 child_fourcc = QT_FOURCC (buffer + 4);
4940 if (G_UNLIKELY (child_fourcc == fourcc)) {
4941 if (G_UNLIKELY (child_len < (4 + 4)))
4943 /* FIXME: must verify if atom length < parent atom length */
4944 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4952 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
4953 GstByteReader * parser)
4957 guint32 child_fourcc, child_len;
4959 for (child = g_node_next_sibling (node); child;
4960 child = g_node_next_sibling (child)) {
4961 buffer = (guint8 *) child->data;
4963 child_fourcc = QT_FOURCC (buffer + 4);
4965 if (child_fourcc == fourcc) {
4967 child_len = QT_UINT32 (buffer);
4968 if (G_UNLIKELY (child_len < (4 + 4)))
4970 /* FIXME: must verify if atom length < parent atom length */
4971 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4980 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
4982 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
4986 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
4987 QtDemuxStream * stream, GstTagList * list)
4989 /* consistent default for push based mode */
4990 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
4992 if (stream->subtype == FOURCC_vide) {
4993 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
4996 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
4999 /* fps is calculated base on the duration of the first frames since
5000 * qt does not have a fixed framerate. */
5001 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
5006 stream->fps_n = stream->timescale;
5007 if (stream->min_duration == 0)
5010 stream->fps_d = stream->min_duration;
5015 gint depth, palette_count;
5016 const guint32 *palette_data = NULL;
5018 gst_caps_set_simple (stream->caps,
5019 "width", G_TYPE_INT, stream->width,
5020 "height", G_TYPE_INT, stream->height,
5021 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5023 /* calculate pixel-aspect-ratio using display width and height */
5024 GST_DEBUG_OBJECT (qtdemux,
5025 "video size %dx%d, target display size %dx%d", stream->width,
5026 stream->height, stream->display_width, stream->display_height);
5028 if (stream->display_width > 0 && stream->display_height > 0 &&
5029 stream->width > 0 && stream->height > 0) {
5032 /* calculate the pixel aspect ratio using the display and pixel w/h */
5033 n = stream->display_width * stream->height;
5034 d = stream->display_height * stream->width;
5037 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5038 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5039 GST_TYPE_FRACTION, n, d, NULL);
5042 /* qt file might have pasp atom */
5043 if (stream->par_w > 0 && stream->par_h > 0) {
5044 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5045 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5046 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5049 depth = stream->bits_per_sample;
5051 /* more than 32 bits means grayscale */
5052 gray = (depth > 32);
5053 /* low 32 bits specify the depth */
5056 /* different number of palette entries is determined by depth. */
5058 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
5059 palette_count = (1 << depth);
5061 switch (palette_count) {
5065 palette_data = ff_qt_default_palette_2;
5068 palette_data = ff_qt_default_palette_4;
5072 palette_data = ff_qt_grayscale_palette_16;
5074 palette_data = ff_qt_default_palette_16;
5078 palette_data = ff_qt_grayscale_palette_256;
5080 palette_data = ff_qt_default_palette_256;
5083 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5084 (_("The video in this file might not play correctly.")),
5085 ("unsupported palette depth %d", depth));
5091 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5092 * don't free any of the buffer data. */
5093 palette = _gst_buffer_new_wrapped ((gpointer) palette_data,
5094 palette_count, NULL);
5096 gst_caps_set_simple (stream->caps, "palette_data",
5097 GST_TYPE_BUFFER, palette, NULL);
5098 gst_buffer_unref (palette);
5099 } else if (palette_count != 0) {
5100 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5101 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5103 gst_object_unref (stream->pad);
5107 qtdemux->n_video_streams++;
5108 } else if (stream->subtype == FOURCC_soun) {
5109 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
5112 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5115 /* FIXME: Need to set channel-mask here and maybe reorder */
5116 gst_caps_set_simple (stream->caps,
5117 "rate", G_TYPE_INT, (int) stream->rate,
5118 "channels", G_TYPE_INT, stream->n_channels, NULL);
5120 qtdemux->n_audio_streams++;
5121 } else if (stream->subtype == FOURCC_strm) {
5122 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5123 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
5124 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
5127 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5129 qtdemux->n_sub_streams++;
5131 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5136 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5138 gst_pad_use_fixed_caps (stream->pad);
5139 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5140 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5141 gst_pad_set_active (stream->pad, TRUE);
5143 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5144 gst_pad_set_caps (stream->pad, stream->caps);
5146 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5147 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5148 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5150 if (stream->pending_tags)
5151 gst_tag_list_free (stream->pending_tags);
5152 stream->pending_tags = list;
5153 /* global tags go on each pad anyway */
5154 stream->send_global_tags = TRUE;
5160 /* find next atom with @fourcc starting at @offset */
5161 static GstFlowReturn
5162 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5163 guint64 * length, guint32 fourcc)
5169 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5170 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5175 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5176 if (G_UNLIKELY (ret != GST_FLOW_OK))
5178 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
5181 gst_buffer_unref (buf);
5184 gst_buffer_map (buf, &map, GST_MAP_READ);
5185 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
5186 gst_buffer_unmap (buf, &map);
5187 gst_buffer_unref (buf);
5189 if (G_UNLIKELY (*length == 0)) {
5190 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5191 ret = GST_FLOW_ERROR;
5195 if (lfourcc == fourcc) {
5196 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5200 GST_LOG_OBJECT (qtdemux,
5201 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5202 GST_FOURCC_ARGS (fourcc), *offset);
5211 /* might simply have had last one */
5212 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5217 /* should only do something in pull mode */
5218 /* call with OBJECT lock */
5219 static GstFlowReturn
5220 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5222 guint64 length, offset;
5223 GstBuffer *buf = NULL;
5224 GstFlowReturn ret = GST_FLOW_OK;
5225 GstFlowReturn res = GST_FLOW_OK;
5228 offset = qtdemux->moof_offset;
5229 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5232 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5233 return GST_FLOW_EOS;
5236 /* best not do pull etc with lock held */
5237 GST_OBJECT_UNLOCK (qtdemux);
5239 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5240 if (ret != GST_FLOW_OK)
5243 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5244 if (G_UNLIKELY (ret != GST_FLOW_OK))
5246 gst_buffer_map (buf, &map, GST_MAP_READ);
5247 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
5248 gst_buffer_unmap (buf, &map);
5249 gst_buffer_unref (buf);
5254 gst_buffer_unmap (buf, &map);
5255 gst_buffer_unref (buf);
5259 /* look for next moof */
5260 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5261 if (G_UNLIKELY (ret != GST_FLOW_OK))
5265 GST_OBJECT_LOCK (qtdemux);
5267 qtdemux->moof_offset = offset;
5273 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5275 res = GST_FLOW_ERROR;
5280 /* maybe upstream temporarily flushing */
5281 if (ret != GST_FLOW_FLUSHING) {
5282 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5285 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5286 /* resume at current position next time */
5293 /* initialise bytereaders for stbl sub-atoms */
5295 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5297 stream->stbl_index = -1; /* no samples have yet been parsed */
5299 /* time-to-sample atom */
5300 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5303 /* copy atom data into a new buffer for later use */
5304 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5306 /* skip version + flags */
5307 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5308 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5310 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5312 /* make sure there's enough data */
5313 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
5314 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
5315 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
5316 stream->n_sample_times);
5317 if (!stream->n_sample_times)
5321 /* sync sample atom */
5322 stream->stps_present = FALSE;
5323 if ((stream->stss_present =
5324 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5325 &stream->stss) ? TRUE : FALSE) == TRUE) {
5326 /* copy atom data into a new buffer for later use */
5327 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5329 /* skip version + flags */
5330 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5331 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5334 if (stream->n_sample_syncs) {
5335 /* make sure there's enough data */
5336 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5340 /* partial sync sample atom */
5341 if ((stream->stps_present =
5342 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5343 &stream->stps) ? TRUE : FALSE) == TRUE) {
5344 /* copy atom data into a new buffer for later use */
5345 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5347 /* skip version + flags */
5348 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5349 !gst_byte_reader_get_uint32_be (&stream->stps,
5350 &stream->n_sample_partial_syncs))
5353 /* if there are no entries, the stss table contains the real
5355 if (stream->n_sample_partial_syncs) {
5356 /* make sure there's enough data */
5357 if (!qt_atom_parser_has_chunks (&stream->stps,
5358 stream->n_sample_partial_syncs, 4))
5365 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5368 /* copy atom data into a new buffer for later use */
5369 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5371 /* skip version + flags */
5372 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5373 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5376 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5379 if (!stream->n_samples)
5382 /* sample-to-chunk atom */
5383 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5386 /* copy atom data into a new buffer for later use */
5387 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5389 /* skip version + flags */
5390 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5391 !gst_byte_reader_get_uint32_be (&stream->stsc,
5392 &stream->n_samples_per_chunk))
5395 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5396 stream->n_samples_per_chunk);
5398 /* make sure there's enough data */
5399 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5405 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5406 stream->co_size = sizeof (guint32);
5407 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5409 stream->co_size = sizeof (guint64);
5413 /* copy atom data into a new buffer for later use */
5414 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5416 /* skip version + flags */
5417 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5420 /* chunks_are_chunks == 0 means treat chunks as samples */
5421 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5422 if (stream->chunks_are_chunks) {
5423 /* skip number of entries */
5424 if (!gst_byte_reader_skip (&stream->stco, 4))
5427 /* make sure there are enough data in the stsz atom */
5428 if (!stream->sample_size) {
5429 /* different sizes for each sample */
5430 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5434 /* treat chunks as samples */
5435 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5439 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5440 stream->n_samples, (guint) sizeof (QtDemuxSample),
5441 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5443 if (stream->n_samples >=
5444 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5445 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5446 "be larger than %uMB (broken file?)", stream->n_samples,
5447 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5451 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5452 if (!stream->samples) {
5453 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5459 /* composition time-to-sample */
5460 if ((stream->ctts_present =
5461 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5462 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5463 /* copy atom data into a new buffer for later use */
5464 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5466 /* skip version + flags */
5467 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5468 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5469 &stream->n_composition_times))
5472 /* make sure there's enough data */
5473 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5482 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5483 (_("This file is corrupt and cannot be played.")), (NULL));
5488 gst_qtdemux_stbl_free (stream);
5489 if (!qtdemux->fragmented) {
5490 /* not quite good */
5491 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5494 /* may pick up samples elsewhere */
5500 /* collect samples from the next sample to be parsed up to sample @n for @stream
5501 * by reading the info from @stbl
5503 * This code can be executed from both the streaming thread and the seeking
5504 * thread so it takes the object lock to protect itself
5507 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
5510 QtDemuxSample *samples, *first, *cur, *last;
5511 guint32 n_samples_per_chunk;
5514 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
5515 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
5516 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
5518 n_samples = stream->n_samples;
5521 goto out_of_samples;
5523 GST_OBJECT_LOCK (qtdemux);
5524 if (n <= stream->stbl_index)
5525 goto already_parsed;
5527 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
5529 if (!stream->stsz.data) {
5530 /* so we already parsed and passed all the moov samples;
5531 * onto fragmented ones */
5532 g_assert (qtdemux->fragmented);
5536 /* pointer to the sample table */
5537 samples = stream->samples;
5539 /* starts from -1, moves to the next sample index to parse */
5540 stream->stbl_index++;
5542 /* keep track of the first and last sample to fill */
5543 first = &samples[stream->stbl_index];
5546 if (stream->chunks_are_chunks) {
5547 /* set the sample sizes */
5548 if (stream->sample_size == 0) {
5549 /* different sizes for each sample */
5550 for (cur = first; cur <= last; cur++) {
5551 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
5552 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
5553 (guint) (cur - samples), cur->size);
5556 /* samples have the same size */
5557 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
5558 for (cur = first; cur <= last; cur++)
5559 cur->size = stream->sample_size;
5563 n_samples_per_chunk = stream->n_samples_per_chunk;
5566 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
5569 if (stream->stsc_chunk_index >= stream->last_chunk
5570 || stream->stsc_chunk_index < stream->first_chunk) {
5571 stream->first_chunk =
5572 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5573 stream->samples_per_chunk =
5574 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5575 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
5577 /* chunk numbers are counted from 1 it seems */
5578 if (G_UNLIKELY (stream->first_chunk == 0))
5581 --stream->first_chunk;
5583 /* the last chunk of each entry is calculated by taking the first chunk
5584 * of the next entry; except if there is no next, where we fake it with
5586 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
5587 stream->last_chunk = G_MAXUINT32;
5589 stream->last_chunk =
5590 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
5591 if (G_UNLIKELY (stream->last_chunk == 0))
5594 --stream->last_chunk;
5597 GST_LOG_OBJECT (qtdemux,
5598 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
5599 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
5601 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
5604 if (stream->last_chunk != G_MAXUINT32) {
5605 if (!qt_atom_parser_peek_sub (&stream->stco,
5606 stream->first_chunk * stream->co_size,
5607 (stream->last_chunk - stream->first_chunk) * stream->co_size,
5612 stream->co_chunk = stream->stco;
5613 if (!gst_byte_reader_skip (&stream->co_chunk,
5614 stream->first_chunk * stream->co_size))
5618 stream->stsc_chunk_index = stream->first_chunk;
5621 last_chunk = stream->last_chunk;
5623 if (stream->chunks_are_chunks) {
5624 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5625 guint32 samples_per_chunk;
5626 guint64 chunk_offset;
5628 if (!stream->stsc_sample_index
5629 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
5630 &stream->chunk_offset))
5633 samples_per_chunk = stream->samples_per_chunk;
5634 chunk_offset = stream->chunk_offset;
5636 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
5637 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
5638 G_GUINT64_FORMAT, (guint) (cur - samples), stream->chunk_offset);
5640 cur->offset = chunk_offset;
5641 chunk_offset += cur->size;
5644 if (G_UNLIKELY (cur > last)) {
5646 stream->stsc_sample_index = k + 1;
5647 stream->chunk_offset = chunk_offset;
5648 stream->stsc_chunk_index = j;
5652 stream->stsc_sample_index = 0;
5654 stream->stsc_chunk_index = j;
5656 cur = &samples[stream->stsc_chunk_index];
5658 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5661 stream->stsc_chunk_index = j;
5666 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
5669 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
5670 "%" G_GUINT64_FORMAT, j, cur->offset);
5672 if (stream->samples_per_frame * stream->bytes_per_frame) {
5674 (stream->samples_per_chunk * stream->n_channels) /
5675 stream->samples_per_frame * stream->bytes_per_frame;
5677 cur->size = stream->samples_per_chunk;
5680 GST_DEBUG_OBJECT (qtdemux,
5681 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
5682 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
5683 GST_SECOND, stream->timescale)), cur->size);
5685 cur->timestamp = stream->stco_sample_index;
5686 cur->duration = stream->samples_per_chunk;
5687 cur->keyframe = TRUE;
5690 stream->stco_sample_index += stream->samples_per_chunk;
5692 stream->stsc_chunk_index = j;
5694 stream->stsc_index++;
5697 if (!stream->chunks_are_chunks)
5701 guint32 n_sample_times;
5703 n_sample_times = stream->n_sample_times;
5706 for (i = stream->stts_index; i < n_sample_times; i++) {
5707 guint32 stts_samples;
5708 gint32 stts_duration;
5711 if (stream->stts_sample_index >= stream->stts_samples
5712 || !stream->stts_sample_index) {
5714 stream->stts_samples =
5715 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5716 stream->stts_duration =
5717 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5719 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
5720 i, stream->stts_samples, stream->stts_duration);
5722 stream->stts_sample_index = 0;
5725 stts_samples = stream->stts_samples;
5726 stts_duration = stream->stts_duration;
5727 stts_time = stream->stts_time;
5729 for (j = stream->stts_sample_index; j < stts_samples; j++) {
5730 GST_DEBUG_OBJECT (qtdemux,
5731 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
5732 (guint) (cur - samples), j,
5733 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
5734 stream->timescale)));
5736 cur->timestamp = stts_time;
5737 cur->duration = stts_duration;
5739 /* avoid 32-bit wrap-around,
5740 * but still mind possible 'negative' duration */
5741 stts_time += (gint64) stts_duration;
5744 if (G_UNLIKELY (cur > last)) {
5746 stream->stts_time = stts_time;
5747 stream->stts_sample_index = j + 1;
5751 stream->stts_sample_index = 0;
5752 stream->stts_time = stts_time;
5753 stream->stts_index++;
5755 /* fill up empty timestamps with the last timestamp, this can happen when
5756 * the last samples do not decode and so we don't have timestamps for them.
5757 * We however look at the last timestamp to estimate the track length so we
5758 * need something in here. */
5759 for (; cur < last; cur++) {
5760 GST_DEBUG_OBJECT (qtdemux,
5761 "fill sample %d: timestamp %" GST_TIME_FORMAT,
5762 (guint) (cur - samples),
5763 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
5764 stream->timescale)));
5765 cur->timestamp = stream->stts_time;
5771 /* sample sync, can be NULL */
5772 if (stream->stss_present == TRUE) {
5773 guint32 n_sample_syncs;
5775 n_sample_syncs = stream->n_sample_syncs;
5777 if (!n_sample_syncs) {
5778 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
5779 stream->all_keyframe = TRUE;
5781 for (i = stream->stss_index; i < n_sample_syncs; i++) {
5782 /* note that the first sample is index 1, not 0 */
5785 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
5787 if (G_LIKELY (index > 0 && index <= n_samples)) {
5789 samples[index].keyframe = TRUE;
5790 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5791 /* and exit if we have enough samples */
5792 if (G_UNLIKELY (index >= n)) {
5799 stream->stss_index = i;
5802 /* stps marks partial sync frames like open GOP I-Frames */
5803 if (stream->stps_present == TRUE) {
5804 guint32 n_sample_partial_syncs;
5806 n_sample_partial_syncs = stream->n_sample_partial_syncs;
5808 /* if there are no entries, the stss table contains the real
5810 if (n_sample_partial_syncs) {
5811 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
5812 /* note that the first sample is index 1, not 0 */
5815 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
5817 if (G_LIKELY (index > 0 && index <= n_samples)) {
5819 samples[index].keyframe = TRUE;
5820 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5821 /* and exit if we have enough samples */
5822 if (G_UNLIKELY (index >= n)) {
5829 stream->stps_index = i;
5833 /* no stss, all samples are keyframes */
5834 stream->all_keyframe = TRUE;
5835 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
5840 /* composition time to sample */
5841 if (stream->ctts_present == TRUE) {
5842 guint32 n_composition_times;
5844 gint32 ctts_soffset;
5846 /* Fill in the pts_offsets */
5848 n_composition_times = stream->n_composition_times;
5850 for (i = stream->ctts_index; i < n_composition_times; i++) {
5851 if (stream->ctts_sample_index >= stream->ctts_count
5852 || !stream->ctts_sample_index) {
5853 stream->ctts_count =
5854 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
5855 stream->ctts_soffset =
5856 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
5857 stream->ctts_sample_index = 0;
5860 ctts_count = stream->ctts_count;
5861 ctts_soffset = stream->ctts_soffset;
5863 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
5864 cur->pts_offset = ctts_soffset;
5867 if (G_UNLIKELY (cur > last)) {
5869 stream->ctts_sample_index = j + 1;
5873 stream->ctts_sample_index = 0;
5874 stream->ctts_index++;
5878 stream->stbl_index = n;
5879 /* if index has been completely parsed, free data that is no-longer needed */
5880 if (n + 1 == stream->n_samples) {
5881 gst_qtdemux_stbl_free (stream);
5882 GST_DEBUG_OBJECT (qtdemux,
5883 "parsed all available samples; checking for more");
5884 while (n + 1 == stream->n_samples)
5885 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
5888 GST_OBJECT_UNLOCK (qtdemux);
5895 GST_LOG_OBJECT (qtdemux,
5896 "Tried to parse up to sample %u but this sample has already been parsed",
5898 /* if fragmented, there may be more */
5899 if (qtdemux->fragmented && n == stream->stbl_index)
5901 GST_OBJECT_UNLOCK (qtdemux);
5907 GST_LOG_OBJECT (qtdemux,
5908 "Tried to parse up to sample %u but there are only %u samples", n + 1,
5910 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5911 (_("This file is corrupt and cannot be played.")), (NULL));
5916 GST_OBJECT_UNLOCK (qtdemux);
5917 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5918 (_("This file is corrupt and cannot be played.")), (NULL));
5923 /* collect all segment info for @stream.
5926 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
5931 /* parse and prepare segment info from the edit list */
5932 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
5933 stream->n_segments = 0;
5934 stream->segments = NULL;
5935 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
5939 guint64 time, stime;
5942 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
5943 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
5946 buffer = elst->data;
5948 n_segments = QT_UINT32 (buffer + 12);
5950 /* we might allocate a bit too much, at least allocate 1 segment */
5951 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
5953 /* segments always start from 0 */
5957 for (i = 0; i < n_segments; i++) {
5960 QtDemuxSegment *segment;
5963 media_time = QT_UINT32 (buffer + 20 + i * 12);
5965 /* -1 media time is an empty segment, just ignore it */
5966 if (media_time == G_MAXUINT32)
5969 duration = QT_UINT32 (buffer + 16 + i * 12);
5971 segment = &stream->segments[count++];
5973 /* time and duration expressed in global timescale */
5974 segment->time = stime;
5975 /* add non scaled values so we don't cause roundoff errors */
5977 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
5978 segment->stop_time = stime;
5979 segment->duration = stime - segment->time;
5980 /* media_time expressed in stream timescale */
5981 segment->media_start =
5982 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
5983 segment->media_stop = segment->media_start + segment->duration;
5984 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
5986 if (rate_int <= 1) {
5987 /* 0 is not allowed, some programs write 1 instead of the floating point
5989 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
5993 segment->rate = rate_int / 65536.0;
5996 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
5997 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
5998 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
5999 GST_TIME_ARGS (segment->duration),
6000 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
6002 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
6003 stream->n_segments = count;
6007 /* push based does not handle segments, so act accordingly here,
6008 * and warn if applicable */
6009 if (!qtdemux->pullbased) {
6010 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
6011 /* remove and use default one below, we stream like it anyway */
6012 g_free (stream->segments);
6013 stream->segments = NULL;
6014 stream->n_segments = 0;
6017 /* no segments, create one to play the complete trak */
6018 if (stream->n_segments == 0) {
6019 GstClockTime stream_duration =
6020 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6022 if (stream->segments == NULL)
6023 stream->segments = g_new (QtDemuxSegment, 1);
6025 /* represent unknown our way */
6026 if (stream_duration == 0)
6027 stream_duration = -1;
6029 stream->segments[0].time = 0;
6030 stream->segments[0].stop_time = stream_duration;
6031 stream->segments[0].duration = stream_duration;
6032 stream->segments[0].media_start = 0;
6033 stream->segments[0].media_stop = stream_duration;
6034 stream->segments[0].rate = 1.0;
6036 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6037 GST_TIME_ARGS (stream_duration));
6038 stream->n_segments = 1;
6040 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6046 * Parses the stsd atom of a svq3 trak looking for
6047 * the SMI and gama atoms.
6050 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6051 guint8 ** gamma, GstBuffer ** seqh)
6053 guint8 *_gamma = NULL;
6054 GstBuffer *_seqh = NULL;
6055 guint8 *stsd_data = stsd->data;
6056 guint32 length = QT_UINT32 (stsd_data);
6060 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6066 version = QT_UINT16 (stsd_data);
6071 while (length > 8) {
6072 guint32 fourcc, size;
6074 size = QT_UINT32 (stsd_data);
6075 fourcc = QT_FOURCC (stsd_data + 4);
6076 data = stsd_data + 8;
6083 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6084 " for gama atom, expected 12", size);
6089 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6091 if (_seqh != NULL) {
6092 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6093 " found, ignoring");
6095 seqh_size = QT_UINT32 (data + 4);
6096 if (seqh_size > 0) {
6097 _seqh = gst_buffer_new_and_alloc (seqh_size);
6098 _gst_buffer_copy_into_mem (_seqh, 0, data + 8, seqh_size);
6105 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6106 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6110 if (size <= length) {
6116 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6119 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6120 G_GUINT16_FORMAT, version);
6131 gst_buffer_unref (_seqh);
6136 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6143 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6144 * atom that might contain a 'data' atom with the rtsp uri.
6145 * This case was reported in bug #597497, some info about
6146 * the hndl atom can be found in TN1195
6148 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6149 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6152 guint32 dref_num_entries = 0;
6153 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6154 gst_byte_reader_skip (&dref, 4) &&
6155 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6158 /* search dref entries for hndl atom */
6159 for (i = 0; i < dref_num_entries; i++) {
6160 guint32 size = 0, type;
6161 guint8 string_len = 0;
6162 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6163 qt_atom_parser_get_fourcc (&dref, &type)) {
6164 if (type == FOURCC_hndl) {
6165 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6167 /* skip data reference handle bytes and the
6168 * following pascal string and some extra 4
6169 * bytes I have no idea what are */
6170 if (!gst_byte_reader_skip (&dref, 4) ||
6171 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6172 !gst_byte_reader_skip (&dref, string_len + 4)) {
6173 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6177 /* iterate over the atoms to find the data atom */
6178 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6182 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6183 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6184 if (atom_type == FOURCC_data) {
6185 const guint8 *uri_aux = NULL;
6187 /* found the data atom that might contain the rtsp uri */
6188 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6189 "hndl atom, interpreting it as an URI");
6190 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6192 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6193 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6195 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6196 "didn't contain a rtsp address");
6198 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6203 /* skipping to the next entry */
6204 gst_byte_reader_skip (&dref, atom_size - 8);
6206 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6213 /* skip to the next entry */
6214 gst_byte_reader_skip (&dref, size - 8);
6216 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6219 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6226 less_than (gconstpointer a, gconstpointer b)
6228 const guint32 *av = a, *bv = b;
6233 #define AMR_NB_ALL_MODES 0x81ff
6234 #define AMR_WB_ALL_MODES 0x83ff
6236 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
6238 /* The 'damr' atom is of the form:
6240 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
6241 * 32 b 8 b 16 b 8 b 8 b
6243 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
6244 * represents the highest mode used in the stream (and thus the maximum
6245 * bitrate), with a couple of special cases as seen below.
6248 /* Map of frame type ID -> bitrate */
6249 static const guint nb_bitrates[] = {
6250 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
6252 static const guint wb_bitrates[] = {
6253 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
6259 gst_buffer_map (buf, &map, GST_MAP_READ);
6261 if (map.size != 0x11) {
6262 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
6266 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
6267 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
6268 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
6272 mode_set = QT_UINT16 (map.data + 13);
6274 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
6275 max_mode = 7 + (wb ? 1 : 0);
6277 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
6278 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
6280 if (max_mode == -1) {
6281 GST_DEBUG ("No mode indication was found (mode set) = %x",
6286 gst_buffer_unmap (buf, &map);
6287 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
6290 gst_buffer_unmap (buf, &map);
6295 * With each track we associate a new QtDemuxStream that contains all the info
6297 * traks that do not decode to something (like strm traks) will not have a pad.
6300 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6315 QtDemuxStream *stream;
6316 GstTagList *list = NULL;
6317 gchar *codec = NULL;
6318 const guint8 *stsd_data;
6319 guint16 lang_code; /* quicktime lang code or packed iso code */
6321 guint32 tkhd_flags = 0;
6322 guint8 tkhd_version = 0;
6324 guint value_size, len;
6326 stream = g_new0 (QtDemuxStream, 1);
6327 /* new streams always need a discont */
6328 stream->discont = TRUE;
6329 /* we enable clipping for raw audio/video streams */
6330 stream->need_clip = FALSE;
6331 stream->need_process = FALSE;
6332 stream->segment_index = -1;
6333 stream->time_position = 0;
6334 stream->sample_index = -1;
6335 stream->last_ret = GST_FLOW_OK;
6337 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6338 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6339 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6342 /* pick between 64 or 32 bits */
6343 value_size = tkhd_version == 1 ? 8 : 4;
6344 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6345 !gst_byte_reader_get_uint32_be (&tkhd, &stream->track_id))
6348 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6349 tkhd_version, tkhd_flags, stream->track_id);
6351 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6354 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6355 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6356 if (qtdemux->major_brand != FOURCC_mjp2 ||
6357 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6361 len = QT_UINT32 ((guint8 *) mdhd->data);
6362 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6363 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6364 if (version == 0x01000000) {
6367 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6368 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6369 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6373 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6374 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6375 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6378 if (lang_code < 0x800) {
6379 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6381 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6382 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6383 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6384 stream->lang_id[3] = 0;
6387 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6389 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6391 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6392 lang_code, stream->lang_id);
6394 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6397 /* fragmented files may have bogus duration in moov */
6398 if (!qtdemux->fragmented &&
6399 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6400 guint64 tdur1, tdur2;
6402 /* don't overflow */
6403 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6404 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6407 * some of those trailers, nowadays, have prologue images that are
6408 * themselves vide tracks as well. I haven't really found a way to
6409 * identify those yet, except for just looking at their duration. */
6410 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6411 GST_WARNING_OBJECT (qtdemux,
6412 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6413 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6414 "found, assuming preview image or something; skipping track",
6415 stream->duration, stream->timescale, qtdemux->duration,
6416 qtdemux->timescale);
6422 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6425 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6426 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6428 len = QT_UINT32 ((guint8 *) hdlr->data);
6430 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6431 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6432 GST_FOURCC_ARGS (stream->subtype));
6434 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6437 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6441 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6443 stsd_data = (const guint8 *) stsd->data;
6445 /* stsd should at least have one entry */
6446 len = QT_UINT32 (stsd_data);
6450 /* and that entry should fit within stsd */
6451 len = QT_UINT32 (stsd_data + 16);
6452 if (len > QT_UINT32 (stsd_data) + 16)
6454 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6456 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6457 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6458 GST_FOURCC_ARGS (stream->fourcc));
6460 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6461 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6462 goto error_encrypted;
6464 if (stream->subtype == FOURCC_vide) {
6465 guint32 w = 0, h = 0;
6467 stream->sampled = TRUE;
6469 /* version 1 uses some 64-bit ints */
6470 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6471 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6472 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6475 stream->display_width = w >> 16;
6476 stream->display_height = h >> 16;
6482 stream->width = QT_UINT16 (stsd_data + offset + 32);
6483 stream->height = QT_UINT16 (stsd_data + offset + 34);
6484 stream->fps_n = 0; /* this is filled in later */
6485 stream->fps_d = 0; /* this is filled in later */
6486 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6487 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6489 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6490 QT_UINT16 (stsd_data + offset + 48));
6493 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6495 list = gst_tag_list_new_empty ();
6496 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6497 GST_TAG_VIDEO_CODEC, codec, NULL);
6504 /* pick 'the' stsd child */
6505 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
6507 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
6508 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
6512 const guint8 *pasp_data = (const guint8 *) pasp->data;
6514 stream->par_w = QT_UINT32 (pasp_data + 8);
6515 stream->par_h = QT_UINT32 (pasp_data + 12);
6522 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
6527 gint len = QT_UINT32 (stsd_data) - 0x66;
6528 const guint8 *avc_data = stsd_data + 0x66;
6531 while (len >= 0x8) {
6534 if (QT_UINT32 (avc_data) <= len)
6535 size = QT_UINT32 (avc_data) - 0x8;
6540 /* No real data, so break out */
6543 switch (QT_FOURCC (avc_data + 0x4)) {
6546 /* parse, if found */
6549 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
6551 /* First 4 bytes are the length of the atom, the next 4 bytes
6552 * are the fourcc, the next 1 byte is the version, and the
6553 * subsequent bytes are sequence parameter set like data. */
6554 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
6555 avc_data + 8 + 1, size - 1);
6557 buf = gst_buffer_new_and_alloc (size);
6558 _gst_buffer_copy_into_mem (buf, 0, avc_data + 0x8, size);
6559 gst_caps_set_simple (stream->caps,
6560 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6561 gst_buffer_unref (buf);
6567 guint avg_bitrate, max_bitrate;
6569 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
6573 max_bitrate = QT_UINT32 (avc_data + 0xc);
6574 avg_bitrate = QT_UINT32 (avc_data + 0x10);
6576 if (!max_bitrate && !avg_bitrate)
6579 /* Some muxers seem to swap the average and maximum bitrates
6580 * (I'm looking at you, YouTube), so we swap for sanity. */
6581 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
6582 guint temp = avg_bitrate;
6584 avg_bitrate = max_bitrate;
6589 list = gst_tag_list_new_empty ();
6591 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6592 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6593 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6595 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6596 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6597 GST_TAG_BITRATE, avg_bitrate, NULL);
6608 avc_data += size + 8;
6620 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
6621 GST_FOURCC_ARGS (fourcc));
6623 /* codec data might be in glbl extension atom */
6625 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
6631 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
6633 len = QT_UINT32 (data);
6636 buf = gst_buffer_new_and_alloc (len);
6637 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
6638 gst_caps_set_simple (stream->caps,
6639 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6640 gst_buffer_unref (buf);
6647 /* see annex I of the jpeg2000 spec */
6648 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
6650 const gchar *colorspace = NULL;
6652 guint32 ncomp_map = 0;
6653 gint32 *comp_map = NULL;
6654 guint32 nchan_def = 0;
6655 gint32 *chan_def = NULL;
6657 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
6658 /* some required atoms */
6659 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
6662 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
6666 /* number of components; redundant with info in codestream, but useful
6668 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
6669 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
6671 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
6673 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
6676 GST_DEBUG_OBJECT (qtdemux, "found colr");
6677 /* extract colour space info */
6678 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
6679 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
6681 colorspace = "sRGB";
6684 colorspace = "GRAY";
6687 colorspace = "sYUV";
6695 /* colr is required, and only values 16, 17, and 18 are specified,
6696 so error if we have no colorspace */
6699 /* extract component mapping */
6700 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
6702 guint32 cmap_len = 0;
6704 cmap_len = QT_UINT32 (cmap->data);
6705 if (cmap_len >= 8) {
6706 /* normal box, subtract off header */
6708 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
6709 if (cmap_len % 4 == 0) {
6710 ncomp_map = (cmap_len / 4);
6711 comp_map = g_new0 (gint32, ncomp_map);
6712 for (i = 0; i < ncomp_map; i++) {
6715 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
6716 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
6717 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
6718 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
6723 /* extract channel definitions */
6724 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
6726 guint32 cdef_len = 0;
6728 cdef_len = QT_UINT32 (cdef->data);
6729 if (cdef_len >= 10) {
6730 /* normal box, subtract off header and len */
6732 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
6733 if (cdef_len % 6 == 0) {
6734 nchan_def = (cdef_len / 6);
6735 chan_def = g_new0 (gint32, nchan_def);
6736 for (i = 0; i < nchan_def; i++)
6738 for (i = 0; i < nchan_def; i++) {
6739 guint16 cn, typ, asoc;
6740 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
6741 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
6742 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
6743 if (cn < nchan_def) {
6746 chan_def[cn] = asoc;
6749 chan_def[cn] = 0; /* alpha */
6752 chan_def[cn] = -typ;
6760 gst_caps_set_simple (stream->caps,
6761 "num-components", G_TYPE_INT, ncomp, NULL);
6762 gst_caps_set_simple (stream->caps,
6763 "colorspace", G_TYPE_STRING, colorspace, NULL);
6766 GValue arr = { 0, };
6767 GValue elt = { 0, };
6769 g_value_init (&arr, GST_TYPE_ARRAY);
6770 g_value_init (&elt, G_TYPE_INT);
6771 for (i = 0; i < ncomp_map; i++) {
6772 g_value_set_int (&elt, comp_map[i]);
6773 gst_value_array_append_value (&arr, &elt);
6775 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6776 "component-map", &arr);
6777 g_value_unset (&elt);
6778 g_value_unset (&arr);
6783 GValue arr = { 0, };
6784 GValue elt = { 0, };
6786 g_value_init (&arr, GST_TYPE_ARRAY);
6787 g_value_init (&elt, G_TYPE_INT);
6788 for (i = 0; i < nchan_def; i++) {
6789 g_value_set_int (&elt, chan_def[i]);
6790 gst_value_array_append_value (&arr, &elt);
6792 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6793 "channel-definitions", &arr);
6794 g_value_unset (&elt);
6795 g_value_unset (&arr);
6799 /* some optional atoms */
6800 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
6801 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
6803 /* indicate possible fields in caps */
6805 data = (guint8 *) field->data + 8;
6807 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
6808 (gint) * data, NULL);
6810 /* add codec_data if provided */
6815 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
6816 data = prefix->data;
6817 len = QT_UINT32 (data);
6820 buf = gst_buffer_new_and_alloc (len);
6821 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
6822 gst_caps_set_simple (stream->caps,
6823 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6824 gst_buffer_unref (buf);
6833 GstBuffer *seqh = NULL;
6834 guint8 *gamma_data = NULL;
6835 gint len = QT_UINT32 (stsd_data);
6837 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
6839 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
6840 QT_FP32 (gamma_data), NULL);
6843 /* sorry for the bad name, but we don't know what this is, other
6844 * than its own fourcc */
6845 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
6849 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
6850 buf = gst_buffer_new_and_alloc (len);
6851 _gst_buffer_copy_into_mem (buf, 0, stsd_data, len);
6852 gst_caps_set_simple (stream->caps,
6853 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6854 gst_buffer_unref (buf);
6859 gst_caps_set_simple (stream->caps,
6860 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
6867 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
6868 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
6872 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
6876 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
6877 /* collect the headers and store them in a stream list so that we can
6878 * send them out first */
6879 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
6889 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
6890 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
6893 ovc1_data = ovc1->data;
6894 ovc1_len = QT_UINT32 (ovc1_data);
6895 if (ovc1_len <= 198) {
6896 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
6899 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
6900 _gst_buffer_copy_into_mem (buf, 0, ovc1_data + 198, ovc1_len - 198);
6901 gst_caps_set_simple (stream->caps,
6902 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6903 gst_buffer_unref (buf);
6911 GST_INFO_OBJECT (qtdemux,
6912 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
6913 GST_FOURCC_ARGS (fourcc), stream->caps);
6915 } else if (stream->subtype == FOURCC_soun) {
6916 int version, samplesize;
6917 guint16 compression_id;
6918 gboolean amrwb = FALSE;
6924 version = QT_UINT32 (stsd_data + offset);
6925 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
6926 samplesize = QT_UINT16 (stsd_data + offset + 10);
6927 compression_id = QT_UINT16 (stsd_data + offset + 12);
6928 stream->rate = QT_FP32 (stsd_data + offset + 16);
6930 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
6931 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
6932 QT_UINT32 (stsd_data + offset + 4));
6933 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
6934 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
6935 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
6936 GST_LOG_OBJECT (qtdemux, "packet size: %d",
6937 QT_UINT16 (stsd_data + offset + 14));
6938 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
6940 if (compression_id == 0xfffe)
6941 stream->sampled = TRUE;
6943 /* first assume uncompressed audio */
6944 stream->bytes_per_sample = samplesize / 8;
6945 stream->samples_per_frame = stream->n_channels;
6946 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
6947 stream->samples_per_packet = stream->samples_per_frame;
6948 stream->bytes_per_packet = stream->bytes_per_sample;
6952 /* Yes, these have to be hard-coded */
6955 stream->samples_per_packet = 6;
6956 stream->bytes_per_packet = 1;
6957 stream->bytes_per_frame = 1 * stream->n_channels;
6958 stream->bytes_per_sample = 1;
6959 stream->samples_per_frame = 6 * stream->n_channels;
6964 stream->samples_per_packet = 3;
6965 stream->bytes_per_packet = 1;
6966 stream->bytes_per_frame = 1 * stream->n_channels;
6967 stream->bytes_per_sample = 1;
6968 stream->samples_per_frame = 3 * stream->n_channels;
6973 stream->samples_per_packet = 64;
6974 stream->bytes_per_packet = 34;
6975 stream->bytes_per_frame = 34 * stream->n_channels;
6976 stream->bytes_per_sample = 2;
6977 stream->samples_per_frame = 64 * stream->n_channels;
6983 stream->samples_per_packet = 1;
6984 stream->bytes_per_packet = 1;
6985 stream->bytes_per_frame = 1 * stream->n_channels;
6986 stream->bytes_per_sample = 1;
6987 stream->samples_per_frame = 1 * stream->n_channels;
6992 stream->samples_per_packet = 160;
6993 stream->bytes_per_packet = 33;
6994 stream->bytes_per_frame = 33 * stream->n_channels;
6995 stream->bytes_per_sample = 2;
6996 stream->samples_per_frame = 160 * stream->n_channels;
7003 if (version == 0x00010000) {
7011 /* only parse extra decoding config for non-pcm audio */
7012 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7013 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
7014 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
7015 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
7017 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7018 stream->samples_per_packet);
7019 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7020 stream->bytes_per_packet);
7021 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
7022 stream->bytes_per_frame);
7023 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
7024 stream->bytes_per_sample);
7026 if (!stream->sampled && stream->bytes_per_packet) {
7027 stream->samples_per_frame = (stream->bytes_per_frame /
7028 stream->bytes_per_packet) * stream->samples_per_packet;
7029 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
7030 stream->samples_per_frame);
7035 } else if (version == 0x00020000) {
7042 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7043 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
7044 stream->rate = qtfp.fp;
7045 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
7047 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7048 stream->samples_per_packet);
7049 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7050 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7053 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
7056 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
7065 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
7067 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
7069 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
7071 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
7074 gst_caps_set_simple (stream->caps,
7075 "format", G_TYPE_STRING, "S24_3LE", NULL);
7082 const guint8 *owma_data;
7083 const gchar *codec_name = NULL;
7087 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
7088 /* FIXME this should also be gst_riff_strf_auds,
7089 * but the latter one is actually missing bits-per-sample :( */
7094 gint32 nSamplesPerSec;
7095 gint32 nAvgBytesPerSec;
7097 gint16 wBitsPerSample;
7102 GST_DEBUG_OBJECT (qtdemux, "parse owma");
7103 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
7106 owma_data = owma->data;
7107 owma_len = QT_UINT32 (owma_data);
7108 if (owma_len <= 54) {
7109 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
7112 wfex = (WAVEFORMATEX *) (owma_data + 36);
7113 buf = gst_buffer_new_and_alloc (owma_len - 54);
7114 _gst_buffer_copy_into_mem (buf, 0, owma_data + 54, owma_len - 54);
7115 if (wfex->wFormatTag == 0x0161) {
7116 codec_name = "Windows Media Audio";
7118 } else if (wfex->wFormatTag == 0x0162) {
7119 codec_name = "Windows Media Audio 9 Pro";
7121 } else if (wfex->wFormatTag == 0x0163) {
7122 codec_name = "Windows Media Audio 9 Lossless";
7123 /* is that correct? gstffmpegcodecmap.c is missing it, but
7124 * fluendo codec seems to support it */
7128 gst_caps_set_simple (stream->caps,
7129 "codec_data", GST_TYPE_BUFFER, buf,
7130 "wmaversion", G_TYPE_INT, version,
7131 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
7132 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
7133 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7134 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7136 gst_buffer_unref (buf);
7140 codec = g_strdup (codec_name);
7152 list = gst_tag_list_new_empty ();
7153 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7154 GST_TAG_AUDIO_CODEC, codec, NULL);
7158 /* some bitrate info may have ended up in caps */
7159 s = gst_caps_get_structure (stream->caps, 0);
7160 gst_structure_get_int (s, "bitrate", &bitrate);
7162 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7166 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7170 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7172 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7174 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7178 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7179 16 bits is a byte-swapped wave-style codec identifier,
7180 and we can find a WAVE header internally to a 'wave' atom here.
7181 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7182 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7185 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7186 if (len < offset + 20) {
7187 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7189 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7190 const guint8 *data = stsd_data + offset + 16;
7192 GNode *waveheadernode;
7194 wavenode = g_node_new ((guint8 *) data);
7195 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7196 const guint8 *waveheader;
7199 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7200 if (waveheadernode) {
7201 waveheader = (const guint8 *) waveheadernode->data;
7202 headerlen = QT_UINT32 (waveheader);
7204 if (headerlen > 8) {
7205 gst_riff_strf_auds *header = NULL;
7206 GstBuffer *headerbuf;
7212 headerbuf = gst_buffer_new_and_alloc (headerlen);
7213 _gst_buffer_copy_into_mem (headerbuf, 0, waveheader, headerlen);
7215 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7216 headerbuf, &header, &extra)) {
7217 gst_caps_unref (stream->caps);
7218 /* FIXME: Need to do something with the channel reorder map */
7219 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7220 header, extra, NULL, NULL, NULL);
7223 gst_buffer_unref (extra);
7227 GST_DEBUG ("Didn't find waveheadernode for this codec");
7229 g_node_destroy (wavenode);
7232 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7236 /* FIXME: what is in the chunk? */
7239 gint len = QT_UINT32 (stsd_data);
7241 /* seems to be always = 116 = 0x74 */
7247 gint len = QT_UINT32 (stsd_data);
7250 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7252 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x4C, len - 0x4C);
7253 gst_caps_set_simple (stream->caps,
7254 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7255 gst_buffer_unref (buf);
7257 gst_caps_set_simple (stream->caps,
7258 "samplesize", G_TYPE_INT, samplesize, NULL);
7263 GNode *alac, *wave = NULL;
7265 /* apparently, m4a has this atom appended directly in the stsd entry,
7266 * while mov has it in a wave atom */
7267 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7269 /* alac now refers to stsd entry atom */
7270 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7272 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7274 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7277 gint len = QT_UINT32 (alac->data);
7281 GST_DEBUG_OBJECT (qtdemux,
7282 "discarding alac atom with unexpected len %d", len);
7284 /* codec-data contains alac atom size and prefix,
7285 * ffmpeg likes it that way, not quite gst-ish though ...*/
7286 buf = gst_buffer_new_and_alloc (len);
7287 _gst_buffer_copy_into_mem (buf, 0, alac->data, len);
7288 gst_caps_set_simple (stream->caps,
7289 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7290 gst_buffer_unref (buf);
7293 gst_caps_set_simple (stream->caps,
7294 "samplesize", G_TYPE_INT, samplesize, NULL);
7302 gint len = QT_UINT32 (stsd_data);
7305 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7308 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x34, len - 0x34);
7310 /* If we have enough data, let's try to get the 'damr' atom. See
7311 * the 3GPP container spec (26.244) for more details. */
7312 if ((len - 0x34) > 8 &&
7313 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
7315 list = gst_tag_list_new_empty ();
7316 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7317 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
7320 gst_caps_set_simple (stream->caps,
7321 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7322 gst_buffer_unref (buf);
7330 GST_INFO_OBJECT (qtdemux,
7331 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7332 GST_FOURCC_ARGS (fourcc), stream->caps);
7334 } else if (stream->subtype == FOURCC_strm) {
7335 if (fourcc == FOURCC_rtsp) {
7336 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7338 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7339 GST_FOURCC_ARGS (fourcc));
7340 goto unknown_stream;
7342 stream->sampled = TRUE;
7343 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
7345 stream->sampled = TRUE;
7350 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7352 list = gst_tag_list_new_empty ();
7353 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7354 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7359 /* hunt for sort-of codec data */
7366 /* look for palette */
7367 /* target mp4s atom */
7368 len = QT_UINT32 (stsd_data + offset);
7369 data = stsd_data + offset;
7370 /* verify sufficient length,
7371 * and esds present with decConfigDescr of expected size and position */
7372 if ((len >= 106 + 8)
7373 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7374 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7379 /* move to decConfigDescr data */
7380 data = data + 8 + 42;
7381 for (i = 0; i < 16; i++) {
7382 clut[i] = QT_UINT32 (data);
7386 s = gst_structure_new ("application/x-gst-dvd", "event",
7387 G_TYPE_STRING, "dvd-spu-clut-change",
7388 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7389 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7390 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7391 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7392 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7393 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7394 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7395 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7398 /* store event and trigger custom processing */
7399 stream->pending_event =
7400 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7401 stream->need_process = TRUE;
7409 goto unknown_stream;
7412 /* promote to sampled format */
7413 if (stream->fourcc == FOURCC_samr) {
7414 /* force mono 8000 Hz for AMR */
7415 stream->sampled = TRUE;
7416 stream->n_channels = 1;
7417 stream->rate = 8000;
7418 } else if (stream->fourcc == FOURCC_sawb) {
7419 /* force mono 16000 Hz for AMR-WB */
7420 stream->sampled = TRUE;
7421 stream->n_channels = 1;
7422 stream->rate = 16000;
7423 } else if (stream->fourcc == FOURCC_mp4a) {
7424 stream->sampled = TRUE;
7427 /* collect sample information */
7428 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7429 goto samples_failed;
7431 if (qtdemux->fragmented) {
7435 /* need all moov samples as basis; probably not many if any at all */
7436 /* prevent moof parsing taking of at this time */
7437 offset = qtdemux->moof_offset;
7438 qtdemux->moof_offset = 0;
7439 if (stream->n_samples &&
7440 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7441 qtdemux->moof_offset = offset;
7442 goto samples_failed;
7444 qtdemux->moof_offset = 0;
7445 /* movie duration more reliable in this case (e.g. mehd) */
7446 if (qtdemux->segment.duration &&
7447 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7448 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7449 stream->timescale, GST_SECOND);
7450 /* need defaults for fragments */
7451 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7454 /* configure segments */
7455 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7456 goto segments_failed;
7458 /* add some language tag, if useful */
7459 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7460 strcmp (stream->lang_id, "und")) {
7461 const gchar *lang_code;
7464 list = gst_tag_list_new_empty ();
7466 /* convert ISO 639-2 code to ISO 639-1 */
7467 lang_code = gst_tag_get_language_code (stream->lang_id);
7468 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7469 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7472 /* now we are ready to add the stream */
7473 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7474 goto too_many_streams;
7476 stream->pending_tags = list;
7477 qtdemux->streams[qtdemux->n_streams] = stream;
7478 qtdemux->n_streams++;
7479 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7486 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7487 (_("This file is corrupt and cannot be played.")), (NULL));
7493 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7500 /* we posted an error already */
7501 /* free stbl sub-atoms */
7502 gst_qtdemux_stbl_free (stream);
7508 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7509 GST_FOURCC_ARGS (stream->subtype));
7515 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7516 (_("This file contains too many streams. Only playing first %d"),
7517 GST_QTDEMUX_MAX_STREAMS), (NULL));
7522 /* If we can estimate the overall bitrate, and don't have information about the
7523 * stream bitrate for exactly one stream, this guesses the stream bitrate as
7524 * the overall bitrate minus the sum of the bitrates of all other streams. This
7525 * should be useful for the common case where we have one audio and one video
7526 * stream and can estimate the bitrate of one, but not the other. */
7528 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
7530 QtDemuxStream *stream = NULL;
7531 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
7535 if (qtdemux->fragmented)
7538 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
7540 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)) {
7541 GST_DEBUG_OBJECT (qtdemux,
7542 "Size in bytes of the stream not known - bailing");
7546 /* Subtract the header size */
7547 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
7548 size, qtdemux->header_size);
7549 g_assert (size >= qtdemux->header_size);
7550 size = size - qtdemux->header_size;
7552 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
7553 duration == GST_CLOCK_TIME_NONE) {
7554 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
7558 for (i = 0; i < qtdemux->n_streams; i++) {
7559 switch (qtdemux->streams[i]->subtype) {
7562 /* retrieve bitrate, prefer avg then max */
7564 if (qtdemux->streams[i]->pending_tags) {
7565 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7566 GST_TAG_MAXIMUM_BITRATE, &bitrate);
7567 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7568 GST_TAG_BITRATE, &bitrate);
7571 sum_bitrate += bitrate;
7574 GST_DEBUG_OBJECT (qtdemux,
7575 ">1 stream with unknown bitrate - bailing");
7578 stream = qtdemux->streams[i];
7582 /* For other subtypes, we assume no significant impact on bitrate */
7588 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
7592 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
7594 if (sys_bitrate < sum_bitrate) {
7595 /* This can happen, since sum_bitrate might be derived from maximum
7596 * bitrates and not average bitrates */
7597 GST_DEBUG_OBJECT (qtdemux,
7598 "System bitrate less than sum bitrate - bailing");
7602 bitrate = sys_bitrate - sum_bitrate;
7603 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
7604 ", Stream bitrate = %u", sys_bitrate, bitrate);
7606 if (!stream->pending_tags)
7607 stream->pending_tags = gst_tag_list_new_empty ();
7609 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
7610 GST_TAG_BITRATE, bitrate, NULL);
7613 static GstFlowReturn
7614 qtdemux_expose_streams (GstQTDemux * qtdemux)
7617 GstFlowReturn ret = GST_FLOW_OK;
7619 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7621 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7622 QtDemuxStream *stream = qtdemux->streams[i];
7623 guint32 sample_num = 0;
7628 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7629 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7631 if (qtdemux->fragmented) {
7632 /* need all moov samples first */
7633 GST_OBJECT_LOCK (qtdemux);
7634 while (stream->n_samples == 0)
7635 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7637 GST_OBJECT_UNLOCK (qtdemux);
7639 /* discard any stray moof */
7640 qtdemux->moof_offset = 0;
7643 /* prepare braking */
7644 if (ret != GST_FLOW_ERROR)
7647 /* in pull mode, we should have parsed some sample info by now;
7648 * and quite some code will not handle no samples.
7649 * in push mode, we'll just have to deal with it */
7650 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7651 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7652 gst_qtdemux_stream_free (qtdemux, stream);
7653 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7654 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7655 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7656 qtdemux->n_streams--;
7661 /* parse number of initial sample to set frame rate cap */
7662 while (sample_num < stream->n_samples && sample_num < samples) {
7663 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7667 /* collect and sort durations */
7668 samples = MIN (stream->stbl_index + 1, samples);
7669 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7671 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7673 while (sample_num < samples) {
7674 g_array_append_val (durations, stream->samples[sample_num].duration);
7677 g_array_sort (durations, less_than);
7678 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7679 g_array_free (durations, TRUE);
7682 /* now we have all info and can expose */
7683 list = stream->pending_tags;
7684 stream->pending_tags = NULL;
7685 gst_qtdemux_add_stream (qtdemux, stream, list);
7688 gst_qtdemux_guess_bitrate (qtdemux);
7690 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7692 /* check if we should post a redirect in case there is a single trak
7693 * and it is a redirecting trak */
7694 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7697 qtdemux_post_global_tags (qtdemux);
7699 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7700 "an external content");
7701 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7702 gst_structure_new ("redirect",
7703 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7705 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7706 qtdemux->posted_redirect = TRUE;
7712 /* check if major or compatible brand is 3GP */
7713 static inline gboolean
7714 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7717 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7718 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7719 } else if (qtdemux->comp_brands != NULL) {
7723 gboolean res = FALSE;
7725 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
7729 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7730 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7734 gst_buffer_unmap (qtdemux->comp_brands, &map);
7741 /* check if tag is a spec'ed 3GP tag keyword storing a string */
7742 static inline gboolean
7743 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
7745 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
7746 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
7747 || fourcc == FOURCC_albm;
7751 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
7752 const char *dummy, GNode * node)
7754 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7758 gdouble longitude, latitude, altitude;
7761 len = QT_UINT32 (node->data);
7768 /* TODO: language code skipped */
7770 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
7773 /* do not alarm in trivial case, but bail out otherwise */
7774 if (*(data + offset) != 0) {
7775 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
7779 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7780 GST_TAG_GEO_LOCATION_NAME, name, NULL);
7781 offset += strlen (name);
7785 if (len < offset + 2 + 4 + 4 + 4)
7788 /* +1 +1 = skip null-terminator and location role byte */
7790 /* table in spec says unsigned, semantics say negative has meaning ... */
7791 longitude = QT_SFP32 (data + offset);
7794 latitude = QT_SFP32 (data + offset);
7797 altitude = QT_SFP32 (data + offset);
7799 /* one invalid means all are invalid */
7800 if (longitude >= -180.0 && longitude <= 180.0 &&
7801 latitude >= -90.0 && latitude <= 90.0) {
7802 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7803 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
7804 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
7805 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
7808 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
7815 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
7822 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7829 len = QT_UINT32 (node->data);
7833 y = QT_UINT16 ((guint8 *) node->data + 12);
7835 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
7838 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
7840 date = g_date_new_dmy (1, 1, y);
7841 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
7846 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
7847 const char *dummy, GNode * node)
7850 char *tag_str = NULL;
7855 len = QT_UINT32 (node->data);
7860 entity = (guint8 *) node->data + offset;
7861 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
7862 GST_DEBUG_OBJECT (qtdemux,
7863 "classification info: %c%c%c%c invalid classification entity",
7864 entity[0], entity[1], entity[2], entity[3]);
7869 table = QT_UINT16 ((guint8 *) node->data + offset);
7871 /* Language code skipped */
7875 /* Tag format: "XXXX://Y[YYYY]/classification info string"
7876 * XXXX: classification entity, fixed length 4 chars.
7877 * Y[YYYY]: classification table, max 5 chars.
7879 tag_str = g_strdup_printf ("----://%u/%s",
7880 table, (char *) node->data + offset);
7882 /* memcpy To be sure we're preserving byte order */
7883 memcpy (tag_str, entity, 4);
7884 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
7886 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
7896 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
7902 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
7903 const char *dummy, GNode * node)
7905 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7911 gboolean ret = TRUE;
7913 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7915 len = QT_UINT32 (data->data);
7916 type = QT_UINT32 ((guint8 *) data->data + 8);
7917 if (type == 0x00000001 && len > 16) {
7918 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
7921 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7922 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
7926 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7930 len = QT_UINT32 (node->data);
7931 type = QT_UINT32 ((guint8 *) node->data + 4);
7932 if ((type >> 24) == 0xa9) {
7933 /* Type starts with the (C) symbol, so the next 32 bits are
7934 * the language code, which we ignore */
7936 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
7937 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
7938 QT_FOURCC ((guint8 *) node->data + 4))) {
7939 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
7941 /* we go for 3GP style encoding if major brands claims so,
7942 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
7943 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
7944 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
7945 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
7947 /* 16-bit Language code is ignored here as well */
7948 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
7955 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
7956 ret = FALSE; /* may have to fallback */
7958 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
7959 len - offset, env_vars);
7961 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7962 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
7966 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7973 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
7974 const char *dummy, GNode * node)
7976 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
7980 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
7981 const char *dummy, GNode * node)
7983 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7985 char *s, *t, *k = NULL;
7990 /* first try normal string tag if major brand not 3GP */
7991 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
7992 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
7993 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
7994 * let's try it 3gpp way after minor safety check */
7996 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
8002 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
8006 len = QT_UINT32 (data);
8010 count = QT_UINT8 (data + 14);
8012 for (; count; count--) {
8015 if (offset + 1 > len)
8017 slen = QT_UINT8 (data + offset);
8019 if (offset + slen > len)
8021 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8024 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
8026 t = g_strjoin (",", k, s, NULL);
8034 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
8041 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
8042 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
8051 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
8057 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
8058 const char *tag2, GNode * node)
8065 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8067 len = QT_UINT32 (data->data);
8068 type = QT_UINT32 ((guint8 *) data->data + 8);
8069 if (type == 0x00000000 && len >= 22) {
8070 n1 = QT_UINT16 ((guint8 *) data->data + 18);
8071 n2 = QT_UINT16 ((guint8 *) data->data + 20);
8073 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
8074 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8078 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
8079 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8087 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8095 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8097 len = QT_UINT32 (data->data);
8098 type = QT_UINT32 ((guint8 *) data->data + 8);
8099 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
8100 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8101 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
8102 n1 = QT_UINT16 ((guint8 *) data->data + 16);
8104 /* do not add bpm=0 */
8105 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
8106 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8107 tag1, (gdouble) n1, NULL);
8114 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
8115 const char *dummy, GNode * node)
8122 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8124 len = QT_UINT32 (data->data);
8125 type = QT_UINT32 ((guint8 *) data->data + 8);
8126 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
8127 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8128 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
8129 num = QT_UINT32 ((guint8 *) data->data + 16);
8131 /* do not add num=0 */
8132 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
8133 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8141 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8149 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8151 len = QT_UINT32 (data->data);
8152 type = QT_UINT32 ((guint8 *) data->data + 8);
8153 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
8154 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
8156 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
8157 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
8158 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
8159 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8160 tag1, sample, NULL);
8161 gst_sample_unref (sample);
8168 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8176 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8178 len = QT_UINT32 (data->data);
8179 type = QT_UINT32 ((guint8 *) data->data + 8);
8180 if (type == 0x00000001 && len > 16) {
8181 guint y, m = 1, d = 1;
8184 s = g_strndup ((char *) data->data + 16, len - 16);
8185 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
8186 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
8187 if (ret >= 1 && y > 1500 && y < 3000) {
8190 date = g_date_new_dmy (d, m, y);
8191 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
8195 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
8203 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8208 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8210 /* re-route to normal string tag if major brand says so
8211 * or no data atom and compatible brand suggests so */
8212 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8213 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
8214 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
8221 len = QT_UINT32 (data->data);
8222 type = QT_UINT32 ((guint8 *) data->data + 8);
8223 if (type == 0x00000000 && len >= 18) {
8224 n = QT_UINT16 ((guint8 *) data->data + 16);
8228 genre = gst_tag_id3_genre_get (n - 1);
8229 if (genre != NULL) {
8230 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
8231 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8240 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
8241 guint8 * data, guint32 datasize)
8246 /* make a copy to have \0 at the end */
8247 datacopy = g_strndup ((gchar *) data, datasize);
8249 /* convert the str to double */
8250 if (sscanf (datacopy, "%lf", &value) == 1) {
8251 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
8252 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
8254 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
8262 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
8263 const char *tag_bis, GNode * node)
8272 const gchar *meanstr;
8273 const gchar *namestr;
8275 /* checking the whole ---- atom size for consistency */
8276 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8277 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8281 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8283 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8287 meansize = QT_UINT32 (mean->data);
8288 if (meansize <= 12) {
8289 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8292 meanstr = ((gchar *) mean->data) + 12;
8294 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8296 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8300 namesize = QT_UINT32 (name->data);
8301 if (namesize <= 12) {
8302 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8305 namestr = ((gchar *) name->data) + 12;
8312 * uint24 - data type
8316 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8318 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8321 datasize = QT_UINT32 (data->data);
8322 if (datasize <= 16) {
8323 GST_WARNING_OBJECT (demux, "Data atom too small");
8326 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8328 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8331 const gchar name[28];
8332 const gchar tag[28];
8335 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8336 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8337 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8338 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8339 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8340 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8341 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8342 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8346 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8347 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8348 switch (gst_tag_get_type (tags[i].tag)) {
8350 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8351 ((guint8 *) data->data) + 16, datasize - 16);
8354 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8363 if (i == G_N_ELEMENTS (tags))
8377 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8378 namestr_dbg = g_strndup (namestr, namesize - 12);
8380 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8381 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8383 g_free (namestr_dbg);
8384 g_free (meanstr_dbg);
8390 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
8391 const char *tag_bis, GNode * node)
8396 GstTagList *taglist = NULL;
8398 GST_LOG_OBJECT (demux, "parsing ID32");
8401 len = GST_READ_UINT32_BE (data);
8403 /* need at least full box and language tag */
8407 buf = gst_buffer_new_allocate (NULL, len - 14, 0);
8408 gst_buffer_fill (buf, 0, data + 14, len - 14);
8410 taglist = gst_tag_list_from_id3v2_tag (buf);
8412 GST_LOG_OBJECT (demux, "parsing ok");
8413 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
8415 GST_LOG_OBJECT (demux, "parsing failed");
8419 gst_tag_list_free (taglist);
8421 gst_buffer_unref (buf);
8424 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8425 const char *tag, const char *tag_bis, GNode * node);
8428 FOURCC_pcst -> if media is a podcast -> bool
8429 FOURCC_cpil -> if media is part of a compilation -> bool
8430 FOURCC_pgap -> if media is part of a gapless context -> bool
8431 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8437 const gchar *gst_tag;
8438 const gchar *gst_tag_bis;
8439 const GstQTDemuxAddTagFunc func;
8442 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8443 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8444 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8445 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8446 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8447 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8448 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8449 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8450 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8451 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8452 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8453 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8454 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8455 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8456 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8457 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8458 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8459 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8460 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8461 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8462 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8463 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8464 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8465 qtdemux_tag_add_num}, {
8466 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8467 qtdemux_tag_add_num}, {
8468 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8469 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8470 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8471 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8472 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8473 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8474 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8475 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8476 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8477 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8478 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8479 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8480 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8481 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8482 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8483 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8484 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8485 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8486 qtdemux_tag_add_classification}, {
8488 /* This is a special case, some tags are stored in this
8489 * 'reverse dns naming', according to:
8490 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8493 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
8494 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
8495 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
8499 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8511 len = QT_UINT32 (data);
8512 buf = gst_buffer_new_and_alloc (len);
8513 _gst_buffer_copy_into_mem (buf, 0, data, len);
8515 /* heuristic to determine style of tag */
8516 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8517 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8519 else if (demux->major_brand == FOURCC_qt__)
8520 style = "quicktime";
8521 /* fall back to assuming iso/3gp tag style */
8525 /* santize the name for the caps. */
8526 for (i = 0; i < 4; i++) {
8527 guint8 d = data[4 + i];
8528 if (g_ascii_isalnum (d))
8529 ndata[i] = g_ascii_tolower (d);
8534 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8535 ndata[0], ndata[1], ndata[2], ndata[3]);
8536 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8538 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
8539 // TODO conver to metadata or ???
8540 // gst_buffer_set_caps (buf, caps);
8541 gst_caps_unref (caps);
8542 g_free (media_type);
8544 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
8547 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8548 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
8549 gst_buffer_unref (buf);
8553 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8561 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8563 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8565 GST_LOG_OBJECT (qtdemux, "no ilst");
8570 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8573 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8574 if (!qtdemux->tag_list)
8575 qtdemux->tag_list = gst_tag_list_new_empty ();
8578 while (i < G_N_ELEMENTS (add_funcs)) {
8579 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8583 len = QT_UINT32 (node->data);
8585 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8586 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8588 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8589 add_funcs[i].gst_tag_bis, node);
8591 g_node_destroy (node);
8597 /* parsed nodes have been removed, pass along remainder as blob */
8598 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8599 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8601 /* parse up XMP_ node if existing */
8602 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8605 GstTagList *taglist;
8607 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
8608 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
8609 taglist = gst_tag_list_from_xmp_buffer (buf);
8610 gst_buffer_unref (buf);
8612 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8614 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8621 GstStructure *structure; /* helper for sort function */
8623 guint min_req_bitrate;
8624 guint min_req_qt_version;
8628 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8630 GstQtReference *ref_a = (GstQtReference *) a;
8631 GstQtReference *ref_b = (GstQtReference *) b;
8633 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8634 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8636 /* known bitrates go before unknown; higher bitrates go first */
8637 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8640 /* sort the redirects and post a message for the application.
8643 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8645 GstQtReference *best;
8648 GValue list_val = { 0, };
8651 g_assert (references != NULL);
8653 references = g_list_sort (references, qtdemux_redirects_sort_func);
8655 best = (GstQtReference *) references->data;
8657 g_value_init (&list_val, GST_TYPE_LIST);
8659 for (l = references; l != NULL; l = l->next) {
8660 GstQtReference *ref = (GstQtReference *) l->data;
8661 GValue struct_val = { 0, };
8663 ref->structure = gst_structure_new ("redirect",
8664 "new-location", G_TYPE_STRING, ref->location, NULL);
8666 if (ref->min_req_bitrate > 0) {
8667 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8668 ref->min_req_bitrate, NULL);
8671 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8672 g_value_set_boxed (&struct_val, ref->structure);
8673 gst_value_list_append_value (&list_val, &struct_val);
8674 g_value_unset (&struct_val);
8675 /* don't free anything here yet, since we need best->structure below */
8678 g_assert (best != NULL);
8679 s = gst_structure_copy (best->structure);
8681 if (g_list_length (references) > 1) {
8682 gst_structure_set_value (s, "locations", &list_val);
8685 g_value_unset (&list_val);
8687 for (l = references; l != NULL; l = l->next) {
8688 GstQtReference *ref = (GstQtReference *) l->data;
8690 gst_structure_free (ref->structure);
8691 g_free (ref->location);
8694 g_list_free (references);
8696 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8697 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8698 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8699 qtdemux->posted_redirect = TRUE;
8702 /* look for redirect nodes, collect all redirect information and
8706 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8708 GNode *rmra, *rmda, *rdrf;
8710 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8712 GList *redirects = NULL;
8714 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8716 GstQtReference ref = { NULL, NULL, 0, 0 };
8719 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8720 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8721 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8722 ref.min_req_bitrate);
8725 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
8726 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
8727 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
8729 #ifndef GST_DISABLE_GST_DEBUG
8730 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
8732 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
8734 GST_LOG_OBJECT (qtdemux,
8735 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
8736 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
8737 bitmask, check_type);
8738 if (package == FOURCC_qtim && check_type == 0) {
8739 ref.min_req_qt_version = version;
8743 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
8748 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
8749 ref_data = (guint8 *) rdrf->data + 20;
8750 if (ref_type == FOURCC_alis) {
8751 guint record_len, record_version, fn_len;
8753 /* MacOSX alias record, google for alias-layout.txt */
8754 record_len = QT_UINT16 (ref_data + 4);
8755 record_version = QT_UINT16 (ref_data + 4 + 2);
8756 fn_len = QT_UINT8 (ref_data + 50);
8757 if (record_len > 50 && record_version == 2 && fn_len > 0) {
8758 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
8760 } else if (ref_type == FOURCC_url_) {
8761 ref.location = g_strdup ((gchar *) ref_data);
8763 GST_DEBUG_OBJECT (qtdemux,
8764 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
8765 GST_FOURCC_ARGS (ref_type));
8767 if (ref.location != NULL) {
8768 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
8769 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
8771 GST_WARNING_OBJECT (qtdemux,
8772 "Failed to extract redirect location from rdrf atom");
8776 /* look for others */
8777 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
8780 if (redirects != NULL) {
8781 qtdemux_process_redirects (qtdemux, redirects);
8788 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
8793 tags = gst_tag_list_new_empty ();
8795 if (qtdemux->major_brand == FOURCC_mjp2)
8796 fmt = "Motion JPEG 2000";
8797 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
8799 else if (qtdemux->major_brand == FOURCC_qt__)
8801 else if (qtdemux->fragmented)
8804 fmt = "ISO MP4/M4A";
8806 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
8807 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
8809 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
8815 /* we have read th complete moov node now.
8816 * This function parses all of the relevant info, creates the traks and
8817 * prepares all data structures for playback
8820 qtdemux_parse_tree (GstQTDemux * qtdemux)
8827 guint64 creation_time;
8828 GstDateTime *datetime = NULL;
8831 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
8833 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
8834 return qtdemux_parse_redirects (qtdemux);
8837 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
8839 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
8840 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
8841 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
8842 } else if (version == 0) {
8843 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
8844 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
8845 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
8847 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
8851 /* Moving qt creation time (secs since 1904) to unix time */
8852 if (creation_time != 0) {
8853 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
8856 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
8857 /* some data cleansing sanity */
8858 g_get_current_time (&now);
8859 if (now.tv_sec + 24 * 3600 < creation_time) {
8860 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
8862 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
8865 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
8866 "please file a bug at http://bugzilla.gnome.org");
8870 if (!qtdemux->tag_list)
8871 qtdemux->tag_list = gst_tag_list_new_empty ();
8873 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
8874 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
8876 gst_date_time_unref (datetime);
8879 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
8880 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
8882 /* check for fragmented file and get some (default) data */
8883 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
8886 GstByteReader mehd_data;
8888 /* let track parsing or anyone know weird stuff might happen ... */
8889 qtdemux->fragmented = TRUE;
8891 /* compensate for total duration */
8892 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
8894 qtdemux_parse_mehd (qtdemux, &mehd_data);
8897 /* set duration in the segment info */
8898 gst_qtdemux_get_duration (qtdemux, &duration);
8900 qtdemux->segment.duration = duration;
8901 /* also do not exceed duration; stop is set that way post seek anyway,
8902 * and segment activation falls back to duration,
8903 * whereas loop only checks stop, so let's align this here as well */
8904 qtdemux->segment.stop = duration;
8907 /* parse all traks */
8908 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
8910 qtdemux_parse_trak (qtdemux, trak);
8911 /* iterate all siblings */
8912 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
8916 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
8918 qtdemux_parse_udta (qtdemux, udta);
8920 GST_LOG_OBJECT (qtdemux, "No udta node found.");
8923 /* maybe also some tags in meta box */
8924 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
8926 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
8927 qtdemux_parse_udta (qtdemux, udta);
8929 GST_LOG_OBJECT (qtdemux, "No meta node found.");
8932 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
8937 /* taken from ffmpeg */
8939 get_size (guint8 * ptr, guint8 ** end)
8948 len = (len << 7) | (c & 0x7f);
8957 /* this can change the codec originally present in @list */
8959 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
8960 GNode * esds, GstTagList * list)
8962 int len = QT_UINT32 (esds->data);
8963 guint8 *ptr = esds->data;
8964 guint8 *end = ptr + len;
8966 guint8 *data_ptr = NULL;
8968 guint8 object_type_id = 0;
8969 const char *codec_name = NULL;
8970 GstCaps *caps = NULL;
8972 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
8974 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
8977 tag = QT_UINT8 (ptr);
8978 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
8980 len = get_size (ptr, &ptr);
8981 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
8985 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
8986 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
8990 guint max_bitrate, avg_bitrate;
8992 object_type_id = QT_UINT8 (ptr);
8993 max_bitrate = QT_UINT32 (ptr + 5);
8994 avg_bitrate = QT_UINT32 (ptr + 9);
8995 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
8996 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
8997 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
8998 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
8999 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
9000 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9001 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9002 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9004 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9005 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
9012 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
9018 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
9022 GST_ERROR_OBJECT (qtdemux, "parse error");
9027 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
9028 * in use, and should also be used to override some other parameters for some
9030 switch (object_type_id) {
9031 case 0x20: /* MPEG-4 */
9032 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
9033 * profile_and_level_indication */
9034 if (data_ptr != NULL && data_len >= 5 &&
9035 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
9036 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
9037 data_ptr + 4, data_len - 4);
9039 break; /* Nothing special needed here */
9040 case 0x21: /* H.264 */
9041 codec_name = "H.264 / AVC";
9042 caps = gst_caps_new_simple ("video/x-h264",
9043 "stream-format", G_TYPE_STRING, "avc",
9044 "alignment", G_TYPE_STRING, "au", NULL);
9046 case 0x40: /* AAC (any) */
9047 case 0x66: /* AAC Main */
9048 case 0x67: /* AAC LC */
9049 case 0x68: /* AAC SSR */
9050 /* Override channels and rate based on the codec_data, as it's often
9052 /* Only do so for basic setup without HE-AAC extension */
9053 if (data_ptr && data_len == 2) {
9054 guint channels, rateindex, rate;
9056 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
9057 channels = (data_ptr[1] & 0x7f) >> 3;
9058 if (channels > 0 && channels < 7) {
9059 stream->n_channels = channels;
9060 } else if (channels == 7) {
9061 stream->n_channels = 8;
9064 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
9065 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
9067 stream->rate = rate;
9070 /* Set level and profile if possible */
9071 if (data_ptr != NULL && data_len >= 2) {
9072 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
9073 data_ptr, data_len);
9076 case 0x60: /* MPEG-2, various profiles */
9082 codec_name = "MPEG-2 video";
9084 gst_caps_unref (stream->caps);
9085 stream->caps = gst_caps_new_simple ("video/mpeg",
9086 "mpegversion", G_TYPE_INT, 2,
9087 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9089 case 0x69: /* MP3 has two different values, accept either */
9091 /* change to mpeg1 layer 3 audio */
9092 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
9093 "mpegversion", G_TYPE_INT, 1, NULL);
9094 codec_name = "MPEG-1 layer 3";
9096 case 0x6A: /* MPEG-1 */
9097 codec_name = "MPEG-1 video";
9099 gst_caps_unref (stream->caps);
9100 stream->caps = gst_caps_new_simple ("video/mpeg",
9101 "mpegversion", G_TYPE_INT, 1,
9102 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9104 case 0x6C: /* MJPEG */
9105 caps = gst_caps_new_empty_simple ("image/jpeg");
9106 codec_name = "Motion-JPEG";
9108 case 0x6D: /* PNG */
9109 caps = gst_caps_new_empty_simple ("image/png");
9110 codec_name = "PNG still images";
9112 case 0x6E: /* JPEG2000 */
9113 codec_name = "JPEG-2000";
9114 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9116 case 0xA4: /* Dirac */
9117 codec_name = "Dirac";
9118 caps = gst_caps_new_empty_simple ("video/x-dirac");
9120 case 0xA5: /* AC3 */
9121 codec_name = "AC-3 audio";
9122 caps = gst_caps_new_simple ("audio/x-ac3",
9123 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9125 case 0xE1: /* QCELP */
9126 /* QCELP, the codec_data is a riff tag (little endian) with
9127 * 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). */
9128 caps = gst_caps_new_empty_simple ("audio/qcelp");
9129 codec_name = "QCELP";
9135 /* If we have a replacement caps, then change our caps for this stream */
9137 gst_caps_unref (stream->caps);
9138 stream->caps = caps;
9141 if (codec_name && list)
9142 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9143 GST_TAG_AUDIO_CODEC, codec_name, NULL);
9145 /* Add the codec_data attribute to caps, if we have it */
9149 buffer = gst_buffer_new_and_alloc (data_len);
9150 _gst_buffer_copy_into_mem (buffer, 0, data_ptr, data_len);
9152 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
9153 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
9155 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
9157 gst_buffer_unref (buffer);
9162 #define _codec(name) \
9165 *codec_name = g_strdup (name); \
9170 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9171 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9174 const GstStructure *s;
9178 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
9179 _codec ("PNG still images");
9180 caps = gst_caps_new_empty_simple ("image/png");
9182 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
9183 _codec ("JPEG still images");
9184 caps = gst_caps_new_empty_simple ("image/jpeg");
9186 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
9187 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
9188 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
9189 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
9190 _codec ("Motion-JPEG");
9191 caps = gst_caps_new_empty_simple ("image/jpeg");
9193 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
9194 _codec ("Motion-JPEG format B");
9195 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
9197 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
9198 _codec ("JPEG-2000");
9199 /* override to what it should be according to spec, avoid palette_data */
9200 stream->bits_per_sample = 24;
9201 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9203 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
9204 _codec ("Sorensen video v.3");
9205 caps = gst_caps_new_simple ("video/x-svq",
9206 "svqversion", G_TYPE_INT, 3, NULL);
9208 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
9209 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
9210 _codec ("Sorensen video v.1");
9211 caps = gst_caps_new_simple ("video/x-svq",
9212 "svqversion", G_TYPE_INT, 1, NULL);
9214 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9218 _codec ("Raw RGB video");
9219 bps = QT_UINT16 (stsd_data + 98);
9220 /* set common stuff */
9221 caps = gst_caps_new_empty_simple ("video/x-raw");
9225 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB15", NULL);
9228 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB16", NULL);
9231 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB", NULL);
9234 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "ARGB", NULL);
9242 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
9243 _codec ("Raw planar YUV 4:2:0");
9244 caps = gst_caps_new_simple ("video/x-raw",
9245 "format", G_TYPE_STRING, "I420", NULL);
9247 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
9248 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
9249 _codec ("Raw packed YUV 4:2:2");
9250 caps = gst_caps_new_simple ("video/x-raw",
9251 "format", G_TYPE_STRING, "YUY2", NULL);
9253 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
9254 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
9255 _codec ("Raw packed YUV 4:2:2");
9256 caps = gst_caps_new_simple ("video/x-raw",
9257 "format", G_TYPE_STRING, "UYVY", NULL);
9259 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
9260 _codec ("Raw packed YUV 10-bit 4:2:2");
9261 caps = gst_caps_new_simple ("video/x-raw",
9262 "format", G_TYPE_STRING, "v210", NULL);
9264 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
9265 _codec ("Raw packed RGB 10-bit 4:4:4");
9266 caps = gst_caps_new_simple ("video/x-raw",
9267 "format", G_TYPE_STRING, "r210", NULL);
9269 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
9270 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
9271 _codec ("MPEG-1 video");
9272 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9273 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9275 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
9276 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
9277 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
9278 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
9279 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
9280 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
9281 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
9282 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
9283 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
9284 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
9285 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
9286 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
9287 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
9288 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
9289 _codec ("MPEG-2 video");
9290 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
9291 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9293 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
9294 _codec ("GIF still images");
9295 caps = gst_caps_new_empty_simple ("image/gif");
9297 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
9298 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
9299 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
9300 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9302 /* ffmpeg uses the height/width props, don't know why */
9303 caps = gst_caps_new_empty_simple ("video/x-h263");
9305 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9306 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9307 _codec ("MPEG-4 video");
9308 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9309 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9311 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9312 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9313 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9314 caps = gst_caps_new_simple ("video/x-msmpeg",
9315 "msmpegversion", G_TYPE_INT, 43, NULL);
9317 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9318 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9319 _codec ("3ivX video");
9320 caps = gst_caps_new_empty_simple ("video/x-3ivx");
9322 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9324 caps = gst_caps_new_simple ("video/x-divx",
9325 "divxversion", G_TYPE_INT, 3, NULL);
9327 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9328 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9330 caps = gst_caps_new_simple ("video/x-divx",
9331 "divxversion", G_TYPE_INT, 4, NULL);
9333 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9335 caps = gst_caps_new_simple ("video/x-divx",
9336 "divxversion", G_TYPE_INT, 5, NULL);
9338 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9339 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9340 _codec ("XVID MPEG-4");
9341 caps = gst_caps_new_empty_simple ("video/x-xvid");
9344 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9345 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9346 caps = gst_caps_new_simple ("video/mpeg",
9347 "mpegversion", G_TYPE_INT, 4, NULL);
9349 *codec_name = g_strdup ("FFmpeg MPEG-4");
9352 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9354 caps = gst_caps_new_empty_simple ("video/x-cinepak");
9356 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9357 _codec ("Apple QuickDraw");
9358 caps = gst_caps_new_empty_simple ("video/x-qdrw");
9360 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9361 _codec ("Apple video");
9362 caps = gst_caps_new_empty_simple ("video/x-apple-video");
9364 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9365 _codec ("H.264 / AVC");
9366 caps = gst_caps_new_simple ("video/x-h264",
9367 "stream-format", G_TYPE_STRING, "avc",
9368 "alignment", G_TYPE_STRING, "au", NULL);
9370 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9371 _codec ("Run-length encoding");
9372 caps = gst_caps_new_simple ("video/x-rle",
9373 "layout", G_TYPE_STRING, "quicktime", NULL);
9375 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9376 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9377 _codec ("Indeo Video 3");
9378 caps = gst_caps_new_simple ("video/x-indeo",
9379 "indeoversion", G_TYPE_INT, 3, NULL);
9381 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9382 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9383 _codec ("Intel Video 4");
9384 caps = gst_caps_new_simple ("video/x-indeo",
9385 "indeoversion", G_TYPE_INT, 4, NULL);
9387 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9388 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9389 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9390 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9391 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9392 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9393 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9394 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9395 _codec ("DV Video");
9396 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9397 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9399 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9400 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9401 _codec ("DVCPro50 Video");
9402 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9403 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9405 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9406 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9407 _codec ("DVCProHD Video");
9408 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9409 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9411 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9412 _codec ("Apple Graphics (SMC)");
9413 caps = gst_caps_new_empty_simple ("video/x-smc");
9415 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9417 caps = gst_caps_new_empty_simple ("video/x-vp3");
9419 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9421 caps = gst_caps_new_empty_simple ("video/x-theora");
9422 /* theora uses one byte of padding in the data stream because it does not
9423 * allow 0 sized packets while theora does */
9424 stream->padding = 1;
9426 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9428 caps = gst_caps_new_empty_simple ("video/x-dirac");
9430 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9431 _codec ("TIFF still images");
9432 caps = gst_caps_new_empty_simple ("image/tiff");
9434 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9435 _codec ("Apple Intermediate Codec");
9436 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9438 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9439 _codec ("AVID DNxHD");
9440 caps = gst_caps_from_string ("video/x-dnxhd");
9442 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9444 caps = gst_caps_from_string ("video/x-vp8");
9448 caps = gst_caps_new_simple ("video/x-wmv",
9449 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
9451 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9456 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9457 GST_FOURCC_ARGS (fourcc));
9458 caps = gst_caps_new_empty_simple (s);
9463 /* enable clipping for raw video streams */
9464 s = gst_caps_get_structure (caps, 0);
9465 name = gst_structure_get_name (s);
9466 if (g_str_has_prefix (name, "video/x-raw")) {
9467 stream->need_clip = TRUE;
9473 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9474 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9477 const GstStructure *s;
9481 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9484 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9485 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9486 _codec ("Raw 8-bit PCM audio");
9487 caps = gst_caps_new_simple ("audio/x-raw",
9488 "format", G_TYPE_STRING, "U8", NULL);
9490 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9491 endian = G_BIG_ENDIAN;
9493 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9497 GstAudioFormat format;
9500 endian = G_LITTLE_ENDIAN;
9502 depth = stream->bytes_per_packet * 8;
9503 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
9505 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9509 caps = gst_caps_new_simple ("audio/x-raw",
9510 "format", G_TYPE_STRING, gst_audio_format_to_string (format), NULL);
9513 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9514 _codec ("Raw 64-bit floating-point audio");
9515 caps = gst_caps_new_simple ("audio/x-raw",
9516 "format", G_TYPE_STRING, "F64BE", NULL);
9518 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9519 _codec ("Raw 32-bit floating-point audio");
9520 caps = gst_caps_new_simple ("audio/x-raw",
9521 "format", G_TYPE_STRING, "F32BE", NULL);
9524 _codec ("Raw 24-bit PCM audio");
9525 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9527 caps = gst_caps_new_simple ("audio/x-raw",
9528 "format", G_TYPE_STRING, "S24BE", NULL);
9530 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9531 _codec ("Raw 32-bit PCM audio");
9532 caps = gst_caps_new_simple ("audio/x-raw",
9533 "format", G_TYPE_STRING, "S32BE", NULL);
9535 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9536 _codec ("Mu-law audio");
9537 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
9539 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9540 _codec ("A-law audio");
9541 caps = gst_caps_new_empty_simple ("audio/x-alaw");
9545 _codec ("Microsoft ADPCM");
9546 /* Microsoft ADPCM-ACM code 2 */
9547 caps = gst_caps_new_simple ("audio/x-adpcm",
9548 "layout", G_TYPE_STRING, "microsoft", NULL);
9552 _codec ("DVI/IMA ADPCM");
9553 caps = gst_caps_new_simple ("audio/x-adpcm",
9554 "layout", G_TYPE_STRING, "dvi", NULL);
9558 _codec ("DVI/Intel IMA ADPCM");
9559 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9560 caps = gst_caps_new_simple ("audio/x-adpcm",
9561 "layout", G_TYPE_STRING, "quicktime", NULL);
9565 /* MPEG layer 3, CBR only (pre QT4.1) */
9566 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9567 _codec ("MPEG-1 layer 3");
9568 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9569 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9570 "mpegversion", G_TYPE_INT, 1, NULL);
9573 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9574 _codec ("EAC-3 audio");
9575 caps = gst_caps_new_simple ("audio/x-eac3",
9576 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9577 stream->sampled = TRUE;
9579 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9580 _codec ("AC-3 audio");
9581 caps = gst_caps_new_simple ("audio/x-ac3",
9582 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9583 stream->sampled = TRUE;
9585 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9587 caps = gst_caps_new_simple ("audio/x-mace",
9588 "maceversion", G_TYPE_INT, 3, NULL);
9590 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9592 caps = gst_caps_new_simple ("audio/x-mace",
9593 "maceversion", G_TYPE_INT, 6, NULL);
9595 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9597 caps = gst_caps_new_empty_simple ("application/ogg");
9599 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9600 _codec ("DV audio");
9601 caps = gst_caps_new_empty_simple ("audio/x-dv");
9603 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9604 _codec ("MPEG-4 AAC audio");
9605 caps = gst_caps_new_simple ("audio/mpeg",
9606 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9607 "stream-format", G_TYPE_STRING, "raw", NULL);
9609 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9610 _codec ("QDesign Music");
9611 caps = gst_caps_new_empty_simple ("audio/x-qdm");
9613 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9614 _codec ("QDesign Music v.2");
9615 /* FIXME: QDesign music version 2 (no constant) */
9617 caps = gst_caps_new_simple ("audio/x-qdm2",
9618 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9619 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9620 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9622 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
9625 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9626 _codec ("GSM audio");
9627 caps = gst_caps_new_empty_simple ("audio/x-gsm");
9629 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9630 _codec ("AMR audio");
9631 caps = gst_caps_new_empty_simple ("audio/AMR");
9633 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9634 _codec ("AMR-WB audio");
9635 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
9637 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9638 _codec ("Quicktime IMA ADPCM");
9639 caps = gst_caps_new_simple ("audio/x-adpcm",
9640 "layout", G_TYPE_STRING, "quicktime", NULL);
9642 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9643 _codec ("Apple lossless audio");
9644 caps = gst_caps_new_empty_simple ("audio/x-alac");
9646 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9647 _codec ("QualComm PureVoice");
9648 caps = gst_caps_from_string ("audio/qcelp");
9652 caps = gst_caps_new_empty_simple ("audio/x-wma");
9654 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
9660 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9661 GST_FOURCC_ARGS (fourcc));
9662 caps = gst_caps_new_empty_simple (s);
9668 GstCaps *templ_caps =
9669 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
9670 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
9671 gst_caps_unref (caps);
9672 gst_caps_unref (templ_caps);
9673 caps = intersection;
9676 /* enable clipping for raw audio streams */
9677 s = gst_caps_get_structure (caps, 0);
9678 name = gst_structure_get_name (s);
9679 if (g_str_has_prefix (name, "audio/x-raw")) {
9680 stream->need_clip = TRUE;
9686 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9687 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9691 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9694 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
9695 _codec ("DVD subtitle");
9696 caps = gst_caps_new_empty_simple ("video/x-dvd-subpicture");
9698 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
9699 _codec ("Quicktime timed text");
9701 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
9702 _codec ("3GPP timed text");
9704 caps = gst_caps_new_empty_simple ("text/plain");
9705 /* actual text piece needs to be extracted */
9706 stream->need_process = TRUE;
9712 s = g_strdup_printf ("text/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9713 GST_FOURCC_ARGS (fourcc));
9714 caps = gst_caps_new_empty_simple (s);