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 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
51 * with newer GLib versions (>= 2.31.0) */
52 #define GLIB_DISABLE_DEPRECATION_WARNINGS
54 #include "gst/gst-i18n-plugin.h"
56 #include <glib/gprintf.h>
57 #include <gst/tag/tag.h>
58 #include <gst/audio/audio.h>
60 #include "qtatomparser.h"
61 #include "qtdemux_types.h"
62 #include "qtdemux_dump.h"
63 #include "qtdemux_fourcc.h"
64 #include "qtdemux_lang.h"
66 #include "qtpalette.h"
68 #include "gst/riff/riff-media.h"
69 #include "gst/riff/riff-read.h"
71 #include <gst/pbutils/pbutils.h>
81 /* max. size considered 'sane' for non-mdat atoms */
82 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
84 /* if the sample index is larger than this, something is likely wrong */
85 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
87 /* For converting qt creation times to unix epoch times */
88 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
89 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
90 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
91 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
93 GST_DEBUG_CATEGORY (qtdemux_debug);
95 /*typedef struct _QtNode QtNode; */
96 typedef struct _QtDemuxSegment QtDemuxSegment;
97 typedef struct _QtDemuxSample QtDemuxSample;
106 struct _QtDemuxSample
109 gint32 pts_offset; /* Add this value to timestamp to get the pts */
111 guint64 timestamp; /* DTS In mov time */
112 guint32 duration; /* In mov time */
113 gboolean keyframe; /* TRUE when this packet is a keyframe */
116 /* timestamp is the DTS */
117 #define QTSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
118 GST_SECOND, (stream)->timescale)
119 /* timestamp + offset is the PTS */
120 #define QTSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
121 (sample)->pts_offset, GST_SECOND, (stream)->timescale)
122 /* timestamp + duration - dts is the duration */
123 #define QTSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
124 (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
125 /* timestamp + offset + duration - pts is the duration */
126 #define QTSAMPLE_DUR_PTS(stream,sample,pts) (gst_util_uint64_scale ((sample)->timestamp + \
127 (sample)->pts_offset + (sample)->duration, GST_SECOND, (stream)->timescale) - (pts));
129 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
132 * Quicktime has tracks and segments. A track is a continuous piece of
133 * multimedia content. The track is not always played from start to finish but
134 * instead, pieces of the track are 'cut out' and played in sequence. This is
135 * what the segments do.
137 * Inside the track we have keyframes (K) and delta frames. The track has its
138 * own timing, which starts from 0 and extends to end. The position in the track
139 * is called the media_time.
141 * The segments now describe the pieces that should be played from this track
142 * and are basically tupples of media_time/duration/rate entries. We can have
143 * multiple segments and they are all played after one another. An example:
145 * segment 1: media_time: 1 second, duration: 1 second, rate 1
146 * segment 2: media_time: 3 second, duration: 2 second, rate 2
148 * To correctly play back this track, one must play: 1 second of media starting
149 * from media_time 1 followed by 2 seconds of media starting from media_time 3
152 * Each of the segments will be played at a specific time, the first segment at
153 * time 0, the second one after the duration of the first one, etc.. Note that
154 * the time in resulting playback is not identical to the media_time of the
157 * Visually, assuming the track has 4 second of media_time:
160 * .-----------------------------------------------------------.
161 * track: | K.....K.........K........K.......K.......K...........K... |
162 * '-----------------------------------------------------------'
164 * .------------^ ^ .----------^ ^
165 * / .-------------' / .------------------'
167 * .--------------. .--------------.
168 * | segment 1 | | segment 2 |
169 * '--------------' '--------------'
171 * The challenge here is to cut out the right pieces of the track for each of
172 * the playback segments. This fortunatly can easily be done with the SEGMENT
173 * events of gstreamer.
175 * For playback of segment 1, we need to provide the decoder with the keyframe
176 * (a), in the above figure, but we must instruct it only to output the decoded
177 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
178 * position set to the time of the segment: 0.
180 * We then proceed to push data from keyframe (a) to frame (b). The decoder
181 * decodes but clips all before media_time 1.
183 * After finishing a segment, we push out a new SEGMENT event with the clipping
184 * boundaries of the new data.
186 * This is a good usecase for the GStreamer accumulated SEGMENT events.
189 struct _QtDemuxSegment
191 /* global time and duration, all gst time */
195 /* media time of trak, all gst time */
201 struct _QtDemuxStream
210 /* if the stream has a redirect URI in its headers, we store it here */
217 guint64 duration; /* in timescale */
221 gchar lang_id[4]; /* ISO 639-2T language code */
225 QtDemuxSample *samples;
226 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
227 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
228 the framerate, in timescale units */
230 /* if we use chunks or samples */
242 /* Numerator/denominator framerate */
245 guint16 bits_per_sample;
246 guint16 color_table_id;
251 guint samples_per_packet;
252 guint samples_per_frame;
253 guint bytes_per_packet;
254 guint bytes_per_sample;
255 guint bytes_per_frame;
258 /* when a discontinuity is pending */
261 /* list of buffers to push first */
264 /* if we need to clip this buffer. This is only needed for uncompressed
268 /* buffer needs some custom processing, e.g. subtitles */
269 gboolean need_process;
271 /* current position */
272 guint32 segment_index;
273 guint32 sample_index;
274 guint64 time_position; /* in gst time */
276 /* the Gst segment we are processing out, used for clipping */
279 /* last GstFlowReturn */
280 GstFlowReturn last_ret;
282 /* quicktime segments */
284 QtDemuxSegment *segments;
289 GstTagList *pending_tags;
290 gboolean send_global_tags;
292 GstEvent *pending_event;
302 gboolean chunks_are_chunks;
306 GstByteReader co_chunk;
308 guint32 current_chunk;
310 guint32 samples_per_chunk;
311 guint32 stco_sample_index;
313 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
316 guint32 n_samples_per_chunk;
317 guint32 stsc_chunk_index;
318 guint32 stsc_sample_index;
319 guint64 chunk_offset;
322 guint32 stts_samples;
323 guint32 n_sample_times;
324 guint32 stts_sample_index;
326 guint32 stts_duration;
328 gboolean stss_present;
329 guint32 n_sample_syncs;
332 gboolean stps_present;
333 guint32 n_sample_partial_syncs;
336 gboolean ctts_present;
337 guint32 n_composition_times;
339 guint32 ctts_sample_index;
344 gboolean parsed_trex;
345 guint32 def_sample_duration;
346 guint32 def_sample_size;
347 guint32 def_sample_flags;
352 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
353 QTDEMUX_STATE_HEADER, /* Parsing the header */
354 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
355 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
358 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
359 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
360 guint32 fourcc, GstByteReader * parser);
361 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
362 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
363 guint32 fourcc, GstByteReader * parser);
365 static GstStaticPadTemplate gst_qtdemux_sink_template =
366 GST_STATIC_PAD_TEMPLATE ("sink",
369 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
373 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
374 GST_STATIC_PAD_TEMPLATE ("video_%u",
377 GST_STATIC_CAPS_ANY);
379 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
380 GST_STATIC_PAD_TEMPLATE ("audio_%u",
383 GST_STATIC_CAPS_ANY);
385 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
386 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
389 GST_STATIC_CAPS_ANY);
391 #define gst_qtdemux_parent_class parent_class
392 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
394 static void gst_qtdemux_dispose (GObject * object);
397 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
400 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
401 QtDemuxStream * str, gint64 media_offset);
404 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
405 static GstIndex *gst_qtdemux_get_index (GstElement * element);
407 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
408 GstStateChange transition);
409 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
410 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
411 GstObject * parent, GstPadMode mode, gboolean active);
413 static void gst_qtdemux_loop (GstPad * pad);
414 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
416 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
419 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
420 const guint8 * buffer, guint length);
421 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
422 const guint8 * buffer, guint length);
423 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
425 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
426 QtDemuxStream * stream, GNode * esds, GstTagList * list);
427 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
428 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
429 gchar ** codec_name);
430 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
431 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
432 gchar ** codec_name);
433 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
434 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
435 gchar ** codec_name);
436 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
437 QtDemuxStream * stream, guint32 n);
438 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
441 gst_qtdemux_class_init (GstQTDemuxClass * klass)
443 GObjectClass *gobject_class;
444 GstElementClass *gstelement_class;
446 gobject_class = (GObjectClass *) klass;
447 gstelement_class = (GstElementClass *) klass;
449 parent_class = g_type_class_peek_parent (klass);
451 gobject_class->dispose = gst_qtdemux_dispose;
453 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
455 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
456 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
459 gst_tag_register_musicbrainz_tags ();
461 gst_element_class_add_pad_template (gstelement_class,
462 gst_static_pad_template_get (&gst_qtdemux_sink_template));
463 gst_element_class_add_pad_template (gstelement_class,
464 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
465 gst_element_class_add_pad_template (gstelement_class,
466 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
467 gst_element_class_add_pad_template (gstelement_class,
468 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
469 gst_element_class_set_details_simple (gstelement_class, "QuickTime demuxer",
471 "Demultiplex a QuickTime file into audio and video streams",
472 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
474 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
479 gst_qtdemux_init (GstQTDemux * qtdemux)
482 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
483 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
484 gst_pad_set_activatemode_function (qtdemux->sinkpad,
485 qtdemux_sink_activate_mode);
486 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
487 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
488 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
490 qtdemux->state = QTDEMUX_STATE_INITIAL;
491 qtdemux->pullbased = FALSE;
492 qtdemux->posted_redirect = FALSE;
493 qtdemux->neededbytes = 16;
495 qtdemux->adapter = gst_adapter_new ();
497 qtdemux->first_mdat = -1;
498 qtdemux->got_moov = FALSE;
499 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
500 qtdemux->mdatbuffer = NULL;
501 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
503 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
507 gst_qtdemux_dispose (GObject * object)
509 GstQTDemux *qtdemux = GST_QTDEMUX (object);
511 if (qtdemux->adapter) {
512 g_object_unref (G_OBJECT (qtdemux->adapter));
513 qtdemux->adapter = NULL;
516 G_OBJECT_CLASS (parent_class)->dispose (object);
520 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
522 if (qtdemux->posted_redirect) {
523 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
524 (_("This file contains no playable streams.")),
525 ("no known streams found, a redirect message has been posted"));
527 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
528 (_("This file contains no playable streams.")),
529 ("no known streams found"));
534 _gst_buffer_copy_into_mem (GstBuffer * dest, const guint8 * src,
535 gsize offset, gsize size)
540 g_return_if_fail (gst_buffer_is_writable (dest));
542 bsize = gst_buffer_get_size (dest);
543 g_return_if_fail (bsize >= offset + size);
545 bdata = gst_buffer_map (dest, &bsize, NULL, GST_MAP_WRITE);
546 memcpy (bdata + offset, src, size);
547 gst_buffer_unmap (dest, bdata, bsize);
551 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
555 buf = gst_buffer_new ();
556 gst_buffer_take_memory (buf, -1,
557 gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
558 mem, free_func, size, 0, size));
564 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
571 if (G_UNLIKELY (size == 0)) {
573 GstBuffer *tmp = NULL;
575 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
576 if (ret != GST_FLOW_OK)
579 bdata = gst_buffer_map (tmp, &bsize, NULL, GST_MAP_READ);
580 size = QT_UINT32 (bdata);
581 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
583 gst_buffer_unmap (tmp, bdata, bsize);
584 gst_buffer_unref (tmp);
587 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
588 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
589 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
590 /* we're pulling header but already got most interesting bits,
591 * so never mind the rest (e.g. tags) (that much) */
592 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
596 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
597 (_("This file is invalid and cannot be played.")),
598 ("atom has bogus size %" G_GUINT64_FORMAT, size));
599 return GST_FLOW_ERROR;
603 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
605 if (G_UNLIKELY (flow != GST_FLOW_OK))
608 bsize = gst_buffer_get_size (*buf);
609 /* Catch short reads - we don't want any partial atoms */
610 if (G_UNLIKELY (bsize < size)) {
611 GST_WARNING_OBJECT (qtdemux,
612 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
613 gst_buffer_unref (*buf);
623 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
624 GstFormat dest_format, gint64 * dest_value)
627 QtDemuxStream *stream = gst_pad_get_element_private (pad);
628 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
631 if (stream->subtype != FOURCC_vide) {
636 switch (src_format) {
637 case GST_FORMAT_TIME:
638 switch (dest_format) {
639 case GST_FORMAT_BYTES:{
640 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
644 *dest_value = stream->samples[index].offset;
646 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
647 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
648 GST_TIME_ARGS (src_value), *dest_value);
656 case GST_FORMAT_BYTES:
657 switch (dest_format) {
658 case GST_FORMAT_TIME:{
660 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
667 gst_util_uint64_scale (stream->samples[index].timestamp,
668 GST_SECOND, stream->timescale);
669 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
670 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
671 src_value, GST_TIME_ARGS (*dest_value));
684 gst_object_unref (qtdemux);
691 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
695 *duration = GST_CLOCK_TIME_NONE;
697 if (qtdemux->duration != 0) {
698 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
699 *duration = gst_util_uint64_scale (qtdemux->duration,
700 GST_SECOND, qtdemux->timescale);
707 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
710 gboolean res = FALSE;
711 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
713 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
715 switch (GST_QUERY_TYPE (query)) {
716 case GST_QUERY_POSITION:
717 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
718 gst_query_set_position (query, GST_FORMAT_TIME,
719 qtdemux->segment.position);
723 case GST_QUERY_DURATION:{
726 gst_query_parse_duration (query, &fmt, NULL);
727 if (fmt == GST_FORMAT_TIME) {
728 gint64 duration = -1;
730 gst_qtdemux_get_duration (qtdemux, &duration);
732 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
738 case GST_QUERY_CONVERT:{
739 GstFormat src_fmt, dest_fmt;
740 gint64 src_value, dest_value = 0;
742 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
744 res = gst_qtdemux_src_convert (pad,
745 src_fmt, src_value, dest_fmt, &dest_value);
747 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
752 case GST_QUERY_FORMATS:
753 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
756 case GST_QUERY_SEEKING:{
760 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
761 if (fmt == GST_FORMAT_TIME) {
762 gint64 duration = -1;
764 gst_qtdemux_get_duration (qtdemux, &duration);
766 if (!qtdemux->pullbased) {
769 /* we might be able with help from upstream */
771 q = gst_query_new_seeking (GST_FORMAT_BYTES);
772 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
773 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
774 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
778 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
784 res = gst_pad_query_default (pad, parent, query);
792 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
794 if (G_LIKELY (stream->pad)) {
795 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
796 GST_DEBUG_PAD_NAME (stream->pad));
798 if (G_UNLIKELY (stream->pending_tags)) {
799 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
800 stream->pending_tags);
801 gst_pad_push_event (stream->pad,
802 gst_event_new_tag (stream->pending_tags));
803 stream->pending_tags = NULL;
806 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
807 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
809 gst_pad_push_event (stream->pad,
810 gst_event_new_tag (gst_tag_list_copy (qtdemux->tag_list)));
811 stream->send_global_tags = FALSE;
816 /* push event on all source pads; takes ownership of the event */
818 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
821 gboolean has_valid_stream = FALSE;
822 GstEventType etype = GST_EVENT_TYPE (event);
824 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
825 GST_EVENT_TYPE_NAME (event));
827 for (n = 0; n < qtdemux->n_streams; n++) {
829 QtDemuxStream *stream = qtdemux->streams[n];
831 if ((pad = stream->pad)) {
832 has_valid_stream = TRUE;
834 if (etype == GST_EVENT_EOS) {
835 /* let's not send twice */
836 if (stream->sent_eos)
838 stream->sent_eos = TRUE;
841 gst_pad_push_event (pad, gst_event_ref (event));
845 gst_event_unref (event);
847 /* if it is EOS and there are no pads, post an error */
848 if (!has_valid_stream && etype == GST_EVENT_EOS) {
849 gst_qtdemux_post_no_playable_stream_error (qtdemux);
853 /* push a pending newsegment event, if any from the streaming thread */
855 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
857 if (qtdemux->pending_newsegment) {
858 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
859 qtdemux->pending_newsegment = NULL;
869 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
871 if (s1->timestamp > *media_time)
877 /* find the index of the sample that includes the data for @media_time using a
878 * binary search. Only to be called in optimized cases of linear search below.
880 * Returns the index of the sample.
883 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
886 QtDemuxSample *result;
889 /* convert media_time to mov format */
891 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
893 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
894 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
895 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
897 if (G_LIKELY (result))
898 index = result - str->samples;
907 /* find the index of the sample that includes the data for @media_offset using a
910 * Returns the index of the sample.
913 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
914 QtDemuxStream * str, gint64 media_offset)
916 QtDemuxSample *result = str->samples;
919 if (result == NULL || str->n_samples == 0)
922 if (media_offset == result->offset)
926 while (index < str->n_samples - 1) {
927 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
930 if (media_offset < result->offset)
941 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
946 /* find the index of the sample that includes the data for @media_time using a
947 * linear search, and keeping in mind that not all samples may have been parsed
948 * yet. If possible, it will delegate to binary search.
950 * Returns the index of the sample.
953 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
959 /* convert media_time to mov format */
961 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
963 if (mov_time == str->samples[0].timestamp)
966 /* use faster search if requested time in already parsed range */
967 if (str->stbl_index >= 0 &&
968 mov_time <= str->samples[str->stbl_index].timestamp)
969 return gst_qtdemux_find_index (qtdemux, str, media_time);
971 while (index < str->n_samples - 1) {
972 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
975 if (mov_time < str->samples[index + 1].timestamp)
985 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
990 /* find the index of the keyframe needed to decode the sample at @index
993 * Returns the index of the keyframe.
996 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
999 guint32 new_index = index;
1001 if (index >= str->n_samples) {
1002 new_index = str->n_samples;
1006 /* all keyframes, return index */
1007 if (str->all_keyframe) {
1012 /* else go back until we have a keyframe */
1014 if (str->samples[new_index].keyframe)
1024 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1025 "gave %u", index, new_index);
1030 /* find the segment for @time_position for @stream
1032 * Returns -1 if the segment cannot be found.
1035 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1036 guint64 time_position)
1041 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1042 GST_TIME_ARGS (time_position));
1044 /* find segment corresponding to time_position if we are looking
1047 for (i = 0; i < stream->n_segments; i++) {
1048 QtDemuxSegment *segment = &stream->segments[i];
1050 GST_LOG_OBJECT (qtdemux,
1051 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1052 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1054 /* For the last segment we include stop_time in the last segment */
1055 if (i < stream->n_segments - 1) {
1056 if (segment->time <= time_position && time_position < segment->stop_time) {
1057 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1062 if (segment->time <= time_position && time_position <= segment->stop_time) {
1063 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1072 /* move the stream @str to the sample position @index.
1074 * Updates @str->sample_index and marks discontinuity if needed.
1077 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1080 /* no change needed */
1081 if (index == str->sample_index)
1084 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1087 /* position changed, we have a discont */
1088 str->sample_index = index;
1089 /* Each time we move in the stream we store the position where we are
1091 str->from_sample = index;
1092 str->discont = TRUE;
1096 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1097 gint64 * key_time, gint64 * key_offset)
1100 gint64 min_byte_offset = -1;
1103 min_offset = desired_time;
1105 /* for each stream, find the index of the sample in the segment
1106 * and move back to the previous keyframe. */
1107 for (n = 0; n < qtdemux->n_streams; n++) {
1109 guint32 index, kindex;
1111 guint64 media_start;
1114 QtDemuxSegment *seg;
1116 str = qtdemux->streams[n];
1118 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1119 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1121 /* segment not found, continue with normal flow */
1125 /* get segment and time in the segment */
1126 seg = &str->segments[seg_idx];
1127 seg_time = desired_time - seg->time;
1129 /* get the media time in the segment */
1130 media_start = seg->media_start + seg_time;
1132 /* get the index of the sample with media time */
1133 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1134 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1135 " at offset %" G_GUINT64_FORMAT,
1136 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1138 /* find previous keyframe */
1139 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1141 /* if the keyframe is at a different position, we need to update the
1142 * requested seek time */
1143 if (index != kindex) {
1146 /* get timestamp of keyframe */
1148 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1150 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT
1151 " at offset %" G_GUINT64_FORMAT,
1152 kindex, GST_TIME_ARGS (media_time), str->samples[kindex].offset);
1154 /* keyframes in the segment get a chance to change the
1155 * desired_offset. keyframes out of the segment are
1157 if (media_time >= seg->media_start) {
1160 /* this keyframe is inside the segment, convert back to
1162 seg_time = (media_time - seg->media_start) + seg->time;
1163 if (seg_time < min_offset)
1164 min_offset = seg_time;
1168 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1169 min_byte_offset = str->samples[index].offset;
1173 *key_time = min_offset;
1175 *key_offset = min_byte_offset;
1179 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1180 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1184 g_return_val_if_fail (format != NULL, FALSE);
1185 g_return_val_if_fail (cur != NULL, FALSE);
1186 g_return_val_if_fail (stop != NULL, FALSE);
1188 if (*format == GST_FORMAT_TIME)
1192 if (cur_type != GST_SEEK_TYPE_NONE)
1193 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1194 if (res && stop_type != GST_SEEK_TYPE_NONE)
1195 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1198 *format = GST_FORMAT_TIME;
1203 /* perform seek in push based mode:
1204 find BYTE position to move to based on time and delegate to upstream
1207 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1212 GstSeekType cur_type, stop_type;
1217 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1219 gst_event_parse_seek (event, &rate, &format, &flags,
1220 &cur_type, &cur, &stop_type, &stop);
1222 /* FIXME, always play to the end */
1225 /* only forward streaming and seeking is possible */
1227 goto unsupported_seek;
1229 /* convert to TIME if needed and possible */
1230 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1234 /* find reasonable corresponding BYTE position,
1235 * also try to mind about keyframes, since we can not go back a bit for them
1237 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1242 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1243 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1246 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1247 GST_DEBUG_OBJECT (qtdemux,
1248 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1249 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1250 GST_OBJECT_LOCK (qtdemux);
1251 qtdemux->requested_seek_time = cur;
1252 qtdemux->seek_offset = byte_cur;
1253 GST_OBJECT_UNLOCK (qtdemux);
1256 /* BYTE seek event */
1257 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1259 res = gst_pad_push_event (qtdemux->sinkpad, event);
1266 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1272 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1277 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1282 /* perform the seek.
1284 * We set all segment_indexes in the streams to unknown and
1285 * adjust the time_position to the desired position. this is enough
1286 * to trigger a segment switch in the streaming thread to start
1287 * streaming from the desired position.
1289 * Keyframe seeking is a little more complicated when dealing with
1290 * segments. Ideally we want to move to the previous keyframe in
1291 * the segment but there might not be a keyframe in the segment. In
1292 * fact, none of the segments could contain a keyframe. We take a
1293 * practical approach: seek to the previous keyframe in the segment,
1294 * if there is none, seek to the beginning of the segment.
1296 * Called with STREAM_LOCK
1299 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1301 gint64 desired_offset;
1304 desired_offset = segment->position;
1306 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1307 GST_TIME_ARGS (desired_offset));
1309 /* may not have enough fragmented info to do this adjustment,
1310 * and we can't scan (and probably should not) at this time with
1311 * possibly flushing upstream */
1312 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1315 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1316 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1317 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1318 desired_offset = min_offset;
1321 /* and set all streams to the final position */
1322 for (n = 0; n < qtdemux->n_streams; n++) {
1323 QtDemuxStream *stream = qtdemux->streams[n];
1325 stream->time_position = desired_offset;
1326 stream->sample_index = -1;
1327 stream->segment_index = -1;
1328 stream->last_ret = GST_FLOW_OK;
1329 stream->sent_eos = FALSE;
1331 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1332 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1334 segment->position = desired_offset;
1335 segment->time = desired_offset;
1337 /* we stop at the end */
1338 if (segment->stop == -1)
1339 segment->stop = segment->duration;
1344 /* do a seek in pull based mode */
1346 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1351 GstSeekType cur_type, stop_type;
1355 GstSegment seeksegment;
1359 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1361 gst_event_parse_seek (event, &rate, &format, &flags,
1362 &cur_type, &cur, &stop_type, &stop);
1364 /* we have to have a format as the segment format. Try to convert
1366 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1370 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1372 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1376 flush = flags & GST_SEEK_FLAG_FLUSH;
1378 /* stop streaming, either by flushing or by pausing the task */
1380 /* unlock upstream pull_range */
1381 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1382 /* make sure out loop function exits */
1383 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1385 /* non flushing seek, pause the task */
1386 gst_pad_pause_task (qtdemux->sinkpad);
1389 /* wait for streaming to finish */
1390 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1392 /* copy segment, we need this because we still need the old
1393 * segment when we close the current segment. */
1394 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1397 /* configure the segment with the seek variables */
1398 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1399 gst_segment_do_seek (&seeksegment, rate, format, flags,
1400 cur_type, cur, stop_type, stop, &update);
1403 /* now do the seek, this actually never returns FALSE */
1404 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1406 /* prepare for streaming again */
1408 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop (TRUE));
1409 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop (TRUE));
1412 /* commit the new segment */
1413 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1415 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1416 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1417 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1418 qtdemux->segment.format, qtdemux->segment.position));
1421 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1422 for (i = 0; i < qtdemux->n_streams; i++)
1423 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1425 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1428 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1435 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1441 qtdemux_ensure_index (GstQTDemux * qtdemux)
1445 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1447 /* Build complete index */
1448 for (i = 0; i < qtdemux->n_streams; i++) {
1449 QtDemuxStream *stream = qtdemux->streams[i];
1451 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1459 GST_LOG_OBJECT (qtdemux,
1460 "Building complete index of stream %u for seeking failed!", i);
1466 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1469 gboolean res = TRUE;
1470 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1472 switch (GST_EVENT_TYPE (event)) {
1473 case GST_EVENT_SEEK:
1475 #ifndef GST_DISABLE_GST_DEBUG
1476 GstClockTime ts = gst_util_get_timestamp ();
1478 /* Build complete index for seeking;
1479 * if not a fragmented file at least */
1480 if (!qtdemux->fragmented)
1481 if (!qtdemux_ensure_index (qtdemux))
1483 #ifndef GST_DISABLE_GST_DEBUG
1484 ts = gst_util_get_timestamp () - ts;
1485 GST_INFO_OBJECT (qtdemux,
1486 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1489 if (qtdemux->pullbased) {
1490 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1491 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams &&
1492 !qtdemux->fragmented) {
1493 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1495 GST_DEBUG_OBJECT (qtdemux,
1496 "ignoring seek in push mode in current state");
1499 gst_event_unref (event);
1502 case GST_EVENT_NAVIGATION:
1504 gst_event_unref (event);
1507 res = gst_pad_event_default (pad, parent, event);
1517 GST_ERROR_OBJECT (qtdemux, "Index failed");
1518 gst_event_unref (event);
1524 /* stream/index return sample that is min/max w.r.t. byte position,
1525 * time is min/max w.r.t. time of samples,
1526 * the latter need not be time of the former sample */
1528 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1529 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1532 gint64 time, min_time;
1533 QtDemuxStream *stream;
1539 for (n = 0; n < qtdemux->n_streams; ++n) {
1542 gboolean set_sample;
1544 str = qtdemux->streams[n];
1551 i = str->n_samples - 1;
1554 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1555 if (str->samples[i].size &&
1556 ((fw && (str->samples[i].offset >= byte_pos)) ||
1558 (str->samples[i].offset + str->samples[i].size <=
1560 /* move stream to first available sample */
1562 gst_qtdemux_move_stream (qtdemux, str, i);
1565 /* determine min/max time */
1566 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1567 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1568 if (min_time == -1 || (!fw && time > min_time) ||
1569 (fw && time < min_time)) {
1572 /* determine stream with leading sample, to get its position */
1574 && (str->samples[i].offset < stream->samples[index].offset))
1576 && (str->samples[i].offset > stream->samples[index].offset))) {
1583 /* no sample for this stream, mark eos */
1585 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1597 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1600 GstQTDemux *demux = GST_QTDEMUX (parent);
1603 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1605 switch (GST_EVENT_TYPE (event)) {
1606 case GST_EVENT_SEGMENT:
1609 QtDemuxStream *stream;
1613 /* some debug output */
1614 gst_event_copy_segment (event, &segment);
1615 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1618 /* chain will send initial newsegment after pads have been added */
1619 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1620 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1624 /* we only expect a BYTE segment, e.g. following a seek */
1625 if (segment.format == GST_FORMAT_BYTES) {
1626 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1627 gint64 requested_seek_time;
1628 guint64 seek_offset;
1630 offset = segment.start;
1632 GST_OBJECT_LOCK (demux);
1633 requested_seek_time = demux->requested_seek_time;
1634 seek_offset = demux->seek_offset;
1635 demux->requested_seek_time = -1;
1636 demux->seek_offset = -1;
1637 GST_OBJECT_UNLOCK (demux);
1639 if (offset == seek_offset) {
1640 segment.start = requested_seek_time;
1642 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1643 NULL, (gint64 *) & segment.start);
1644 if ((gint64) segment.start < 0)
1648 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1649 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1650 NULL, (gint64 *) & segment.stop);
1651 /* keyframe seeking should already arrange for start >= stop,
1652 * but make sure in other rare cases */
1653 segment.stop = MAX (segment.stop, segment.start);
1656 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1660 /* accept upstream's notion of segment and distribute along */
1661 segment.time = segment.start;
1662 segment.duration = demux->segment.duration;
1663 segment.base = gst_segment_to_running_time (&demux->segment,
1664 GST_FORMAT_TIME, demux->segment.position);
1666 gst_segment_copy_into (&segment, &demux->segment);
1667 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
1668 gst_qtdemux_push_event (demux, gst_event_new_segment (&segment));
1670 /* clear leftover in current segment, if any */
1671 gst_adapter_clear (demux->adapter);
1672 /* set up streaming thread */
1673 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1674 demux->offset = offset;
1676 demux->todrop = stream->samples[idx].offset - offset;
1677 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1679 /* set up for EOS */
1680 demux->neededbytes = -1;
1684 gst_event_unref (event);
1689 case GST_EVENT_FLUSH_STOP:
1694 /* clean up, force EOS if no more info follows */
1695 gst_adapter_clear (demux->adapter);
1697 demux->neededbytes = -1;
1698 /* reset flow return, e.g. following seek */
1699 for (i = 0; i < demux->n_streams; i++) {
1700 demux->streams[i]->last_ret = GST_FLOW_OK;
1701 demux->streams[i]->sent_eos = FALSE;
1703 dur = demux->segment.duration;
1704 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1705 demux->segment.duration = dur;
1709 /* If we are in push mode, and get an EOS before we've seen any streams,
1710 * then error out - we have nowhere to send the EOS */
1711 if (!demux->pullbased) {
1713 gboolean has_valid_stream = FALSE;
1714 for (i = 0; i < demux->n_streams; i++) {
1715 if (demux->streams[i]->pad != NULL) {
1716 has_valid_stream = TRUE;
1720 if (!has_valid_stream)
1721 gst_qtdemux_post_no_playable_stream_error (demux);
1728 res = gst_pad_event_default (demux->sinkpad, parent, event);
1736 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1738 GstQTDemux *demux = GST_QTDEMUX (element);
1740 GST_OBJECT_LOCK (demux);
1741 if (demux->element_index)
1742 gst_object_unref (demux->element_index);
1744 demux->element_index = gst_object_ref (index);
1746 demux->element_index = NULL;
1748 GST_OBJECT_UNLOCK (demux);
1749 /* object lock might be taken again */
1751 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1752 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
1753 demux->element_index, demux->index_id);
1757 gst_qtdemux_get_index (GstElement * element)
1759 GstIndex *result = NULL;
1760 GstQTDemux *demux = GST_QTDEMUX (element);
1762 GST_OBJECT_LOCK (demux);
1763 if (demux->element_index)
1764 result = gst_object_ref (demux->element_index);
1765 GST_OBJECT_UNLOCK (demux);
1767 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1774 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1776 g_free ((gpointer) stream->stco.data);
1777 stream->stco.data = NULL;
1778 g_free ((gpointer) stream->stsz.data);
1779 stream->stsz.data = NULL;
1780 g_free ((gpointer) stream->stsc.data);
1781 stream->stsc.data = NULL;
1782 g_free ((gpointer) stream->stts.data);
1783 stream->stts.data = NULL;
1784 g_free ((gpointer) stream->stss.data);
1785 stream->stss.data = NULL;
1786 g_free ((gpointer) stream->stps.data);
1787 stream->stps.data = NULL;
1788 g_free ((gpointer) stream->ctts.data);
1789 stream->ctts.data = NULL;
1793 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
1795 while (stream->buffers) {
1796 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1797 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1800 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
1801 g_free (stream->samples);
1803 gst_caps_unref (stream->caps);
1804 g_free (stream->segments);
1805 if (stream->pending_tags)
1806 gst_tag_list_free (stream->pending_tags);
1807 g_free (stream->redirect_uri);
1808 /* free stbl sub-atoms */
1809 gst_qtdemux_stbl_free (stream);
1813 static GstStateChangeReturn
1814 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1816 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1817 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1819 switch (transition) {
1820 case GST_STATE_CHANGE_PAUSED_TO_READY:
1826 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1828 switch (transition) {
1829 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1832 qtdemux->state = QTDEMUX_STATE_INITIAL;
1833 qtdemux->neededbytes = 16;
1834 qtdemux->todrop = 0;
1835 qtdemux->pullbased = FALSE;
1836 qtdemux->posted_redirect = FALSE;
1837 qtdemux->offset = 0;
1838 qtdemux->first_mdat = -1;
1839 qtdemux->header_size = 0;
1840 qtdemux->got_moov = FALSE;
1841 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1842 if (qtdemux->mdatbuffer)
1843 gst_buffer_unref (qtdemux->mdatbuffer);
1844 qtdemux->mdatbuffer = NULL;
1845 if (qtdemux->comp_brands)
1846 gst_buffer_unref (qtdemux->comp_brands);
1847 qtdemux->comp_brands = NULL;
1848 if (qtdemux->tag_list)
1849 gst_tag_list_free (qtdemux->tag_list);
1850 qtdemux->tag_list = NULL;
1852 if (qtdemux->element_index)
1853 gst_object_unref (qtdemux->element_index);
1854 qtdemux->element_index = NULL;
1856 gst_adapter_clear (qtdemux->adapter);
1857 for (n = 0; n < qtdemux->n_streams; n++) {
1858 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1859 qtdemux->streams[n] = NULL;
1861 qtdemux->major_brand = 0;
1862 qtdemux->n_streams = 0;
1863 qtdemux->n_video_streams = 0;
1864 qtdemux->n_audio_streams = 0;
1865 qtdemux->n_sub_streams = 0;
1866 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1867 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1868 qtdemux->seek_offset = 0;
1869 qtdemux->upstream_seekable = FALSE;
1870 qtdemux->upstream_size = 0;
1881 qtdemux_post_global_tags (GstQTDemux * qtdemux)
1883 if (qtdemux->tag_list) {
1884 /* all header tags ready and parsed, push them */
1885 GST_INFO_OBJECT (qtdemux, "posting global tags: %" GST_PTR_FORMAT,
1887 /* post now, send event on pads later */
1888 gst_element_post_message (GST_ELEMENT (qtdemux),
1889 gst_message_new_tag (GST_OBJECT (qtdemux),
1890 gst_tag_list_copy (qtdemux->tag_list)));
1895 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1897 /* counts as header data */
1898 qtdemux->header_size += length;
1900 /* only consider at least a sufficiently complete ftyp atom */
1904 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1905 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1906 GST_FOURCC_ARGS (qtdemux->major_brand));
1907 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1908 _gst_buffer_copy_into_mem (buf, buffer + 16, 0, length - 16);
1913 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
1915 /* Strip out bogus fields */
1917 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
1919 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
1921 if (qtdemux->tag_list) {
1922 /* prioritize native tags using _KEEP mode */
1923 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
1924 gst_tag_list_free (taglist);
1926 qtdemux->tag_list = taglist;
1931 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1933 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
1934 0x97, 0xA9, 0x42, 0xE8,
1935 0x9C, 0x71, 0x99, 0x94,
1936 0x91, 0xE3, 0xAF, 0xAC
1940 /* counts as header data */
1941 qtdemux->header_size += length;
1943 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
1945 if (length <= offset + 16) {
1946 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
1950 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
1952 GstTagList *taglist;
1954 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
1955 length - offset - 16, NULL);
1956 taglist = gst_tag_list_from_xmp_buffer (buf);
1957 gst_buffer_unref (buf);
1959 qtdemux_handle_xmp_taglist (qtdemux, taglist);
1962 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
1966 /* caller verifies at least 8 bytes in buf */
1968 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1969 guint64 * plength, guint32 * pfourcc)
1974 length = QT_UINT32 (data);
1975 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1976 fourcc = QT_FOURCC (data + 4);
1977 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1980 length = G_MAXUINT32;
1981 } else if (length == 1 && size >= 16) {
1982 /* this means we have an extended size, which is the 64 bit value of
1983 * the next 8 bytes */
1984 length = QT_UINT64 (data + 8);
1985 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1995 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
1997 guint32 version = 0;
1998 guint64 duration = 0;
2000 if (!gst_byte_reader_get_uint32_be (br, &version))
2005 if (!gst_byte_reader_get_uint64_be (br, &duration))
2010 if (!gst_byte_reader_get_uint32_be (br, &dur))
2015 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2016 qtdemux->duration = duration;
2022 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2028 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2029 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2031 if (!stream->parsed_trex && qtdemux->moov_node) {
2033 GstByteReader trex_data;
2035 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2037 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2040 guint32 id = 0, dur = 0, size = 0, flags = 0;
2042 /* skip version/flags */
2043 if (!gst_byte_reader_skip (&trex_data, 4))
2045 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2047 if (id != stream->track_id)
2049 /* sample description index; ignore */
2050 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2052 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2054 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2056 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2059 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2060 "duration %d, size %d, flags 0x%x", stream->track_id,
2063 stream->parsed_trex = TRUE;
2064 stream->def_sample_duration = dur;
2065 stream->def_sample_size = size;
2066 stream->def_sample_flags = flags;
2069 /* iterate all siblings */
2070 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2076 *ds_duration = stream->def_sample_duration;
2077 *ds_size = stream->def_sample_size;
2078 *ds_size = stream->def_sample_size;
2080 /* even then, above values are better than random ... */
2081 if (G_UNLIKELY (!stream->parsed_trex)) {
2082 GST_WARNING_OBJECT (qtdemux,
2083 "failed to find fragment defaults for stream %d", stream->track_id);
2091 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2092 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2093 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2094 gint64 * base_offset, gint64 * running_offset)
2097 gint32 data_offset = 0;
2098 guint32 flags = 0, first_flags = 0, samples_count = 0;
2101 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2102 QtDemuxSample *sample;
2103 gboolean ismv = FALSE;
2105 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2106 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2107 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2110 /* presence of stss or not can't really tell us much,
2111 * and flags and so on tend to be marginally reliable in these files */
2112 if (stream->subtype == FOURCC_soun) {
2113 GST_DEBUG_OBJECT (qtdemux,
2114 "sound track in fragmented file; marking all keyframes");
2115 stream->all_keyframe = TRUE;
2118 if (!gst_byte_reader_skip (trun, 1) ||
2119 !gst_byte_reader_get_uint24_be (trun, &flags))
2122 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2125 if (flags & TR_DATA_OFFSET) {
2126 /* note this is really signed */
2127 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2129 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2130 /* default base offset = first byte of moof */
2131 if (*base_offset == -1) {
2132 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2133 *base_offset = moof_offset;
2135 *running_offset = *base_offset + data_offset;
2137 /* if no offset at all, that would mean data starts at moof start,
2138 * which is a bit wrong and is ismv crappy way, so compensate
2139 * assuming data is in mdat following moof */
2140 if (*base_offset == -1) {
2141 *base_offset = moof_offset + moof_length + 8;
2142 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2145 if (*running_offset == -1)
2146 *running_offset = *base_offset;
2149 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2151 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2152 data_offset, flags, samples_count);
2154 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2155 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2156 GST_DEBUG_OBJECT (qtdemux,
2157 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2158 flags ^= TR_FIRST_SAMPLE_FLAGS;
2160 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2162 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2166 /* FIXME ? spec says other bits should also be checked to determine
2167 * entry size (and prefix size for that matter) */
2169 dur_offset = size_offset = 0;
2170 if (flags & TR_SAMPLE_DURATION) {
2171 GST_LOG_OBJECT (qtdemux, "entry duration present");
2172 dur_offset = entry_size;
2175 if (flags & TR_SAMPLE_SIZE) {
2176 GST_LOG_OBJECT (qtdemux, "entry size present");
2177 size_offset = entry_size;
2180 if (flags & TR_SAMPLE_FLAGS) {
2181 GST_LOG_OBJECT (qtdemux, "entry flags present");
2182 flags_offset = entry_size;
2185 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2186 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2187 ct_offset = entry_size;
2191 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2193 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2195 if (stream->n_samples >=
2196 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2199 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2200 stream->n_samples, (guint) sizeof (QtDemuxSample),
2201 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2203 /* create a new array of samples if it's the first sample parsed */
2204 if (stream->n_samples == 0)
2205 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2206 /* or try to reallocate it with space enough to insert the new samples */
2208 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2209 stream->n_samples + samples_count);
2210 if (stream->samples == NULL)
2213 if (G_UNLIKELY (stream->n_samples == 0)) {
2214 /* the timestamp of the first sample is also provided by the tfra entry
2215 * but we shouldn't rely on it as it is at the end of files */
2218 /* subsequent fragments extend stream */
2220 stream->samples[stream->n_samples - 1].timestamp +
2221 stream->samples[stream->n_samples - 1].duration;
2223 sample = stream->samples + stream->n_samples;
2224 for (i = 0; i < samples_count; i++) {
2225 guint32 dur, size, sflags, ct;
2227 /* first read sample data */
2228 if (flags & TR_SAMPLE_DURATION) {
2229 dur = QT_UINT32 (data + dur_offset);
2231 dur = d_sample_duration;
2233 if (flags & TR_SAMPLE_SIZE) {
2234 size = QT_UINT32 (data + size_offset);
2236 size = d_sample_size;
2238 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2240 sflags = first_flags;
2242 sflags = d_sample_flags;
2244 } else if (flags & TR_SAMPLE_FLAGS) {
2245 sflags = QT_UINT32 (data + flags_offset);
2247 sflags = d_sample_flags;
2249 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2250 ct = QT_UINT32 (data + ct_offset);
2256 /* fill the sample information */
2257 sample->offset = *running_offset;
2258 sample->pts_offset = ct;
2259 sample->size = size;
2260 sample->timestamp = timestamp;
2261 sample->duration = dur;
2262 /* sample-is-difference-sample */
2263 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2264 * now idea how it relates to bitfield other than massive LE/BE confusion */
2265 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2266 *running_offset += size;
2271 stream->n_samples += samples_count;
2277 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2282 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2288 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2289 "be larger than %uMB (broken file?)", stream->n_samples,
2290 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2295 /* find stream with @id */
2296 static inline QtDemuxStream *
2297 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2299 QtDemuxStream *stream;
2303 if (G_UNLIKELY (!id)) {
2304 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2308 /* try to get it fast and simple */
2309 if (G_LIKELY (id <= qtdemux->n_streams)) {
2310 stream = qtdemux->streams[id - 1];
2311 if (G_LIKELY (stream->track_id == id))
2315 /* linear search otherwise */
2316 for (i = 0; i < qtdemux->n_streams; i++) {
2317 stream = qtdemux->streams[i];
2318 if (stream->track_id == id)
2326 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2327 QtDemuxStream ** stream, guint32 * default_sample_duration,
2328 guint32 * default_sample_size, guint32 * default_sample_flags,
2329 gint64 * base_offset)
2332 guint32 track_id = 0;
2334 if (!gst_byte_reader_skip (tfhd, 1) ||
2335 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2338 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2341 *stream = qtdemux_find_stream (qtdemux, track_id);
2342 if (G_UNLIKELY (!*stream))
2343 goto unknown_stream;
2345 if (flags & TF_BASE_DATA_OFFSET)
2346 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2349 /* obtain stream defaults */
2350 qtdemux_parse_trex (qtdemux, *stream,
2351 default_sample_duration, default_sample_size, default_sample_flags);
2353 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2354 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2355 if (!gst_byte_reader_skip (tfhd, 4))
2358 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2359 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2362 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2363 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2366 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2367 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2374 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2379 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2385 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2386 guint64 moof_offset, QtDemuxStream * stream)
2388 GNode *moof_node, *traf_node, *tfhd_node, *trun_node;
2389 GstByteReader trun_data, tfhd_data;
2390 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2391 gint64 base_offset, running_offset;
2393 /* NOTE @stream ignored */
2395 moof_node = g_node_new ((guint8 *) buffer);
2396 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2397 qtdemux_node_dump (qtdemux, moof_node);
2399 /* unknown base_offset to start with */
2400 base_offset = running_offset = -1;
2401 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2403 /* Fragment Header node */
2405 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2409 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2410 &ds_size, &ds_flags, &base_offset))
2412 if (G_UNLIKELY (!stream)) {
2413 /* we lost track of offset, we'll need to regain it,
2414 * but can delay complaining until later or avoid doing so altogether */
2418 if (G_UNLIKELY (base_offset < -1))
2420 /* Track Run node */
2422 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2425 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2426 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2428 /* iterate all siblings */
2429 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2432 /* if no new base_offset provided for next traf,
2433 * base is end of current traf */
2434 base_offset = running_offset;
2435 running_offset = -1;
2437 /* iterate all siblings */
2438 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2440 g_node_destroy (moof_node);
2445 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2450 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2455 g_node_destroy (moof_node);
2456 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2457 (_("This file is corrupt and cannot be played.")), (NULL));
2462 /* might be used if some day we actually use mfra & co
2463 * for random access to fragments,
2464 * but that will require quite some modifications and much less relying
2465 * on a sample array */
2468 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2469 QtDemuxStream * stream)
2471 guint64 time = 0, moof_offset = 0;
2472 guint32 ver_flags, track_id, len, num_entries, i;
2473 guint value_size, traf_size, trun_size, sample_size;
2474 GstBuffer *buf = NULL;
2478 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2479 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2481 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2484 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2485 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2486 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2489 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2490 track_id, stream->track_id);
2491 if (track_id != stream->track_id) {
2495 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2496 sample_size = (len & 3) + 1;
2497 trun_size = ((len & 12) >> 2) + 1;
2498 traf_size = ((len & 48) >> 4) + 1;
2500 if (num_entries == 0)
2503 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2504 value_size + value_size + traf_size + trun_size + sample_size))
2507 for (i = 0; i < num_entries; i++) {
2508 qt_atom_parser_get_offset (&tfra, value_size, &time);
2509 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2510 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2511 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2512 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2514 GST_LOG_OBJECT (qtdemux,
2515 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2516 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2517 stream->timescale)), moof_offset);
2519 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2520 if (ret != GST_FLOW_OK)
2522 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2523 moof_offset, stream);
2524 gst_buffer_unref (buf);
2532 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2533 (_("This file is corrupt and cannot be played.")), (NULL));
2538 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2544 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2547 GNode *mfra_node, *tfra_node;
2550 if (!qtdemux->mfra_offset)
2553 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2554 if (ret != GST_FLOW_OK)
2557 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2558 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2559 GST_BUFFER_SIZE (buffer));
2561 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2564 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2565 /* iterate all siblings */
2566 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2568 g_node_destroy (mfra_node);
2569 gst_buffer_unref (buffer);
2575 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2576 (_("This file is corrupt and cannot be played.")), (NULL));
2581 static GstFlowReturn
2582 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2583 guint32 * mfro_size)
2585 GstFlowReturn ret = GST_FLOW_ERROR;
2586 GstBuffer *mfro = NULL;
2589 GstFormat fmt = GST_FORMAT_BYTES;
2591 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, &fmt, &len)) {
2592 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2593 "can not locate mfro");
2597 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2598 if (ret != GST_FLOW_OK)
2601 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2602 if (fourcc != FOURCC_mfro)
2605 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2606 if (GST_BUFFER_SIZE (mfro) >= 16) {
2607 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
2608 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
2609 if (*mfro_size >= len) {
2610 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
2611 ret = GST_FLOW_ERROR;
2614 *mfra_offset = len - *mfro_size;
2619 gst_buffer_unref (mfro);
2625 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
2628 guint32 mfra_size = 0;
2629 guint64 mfra_offset = 0;
2632 qtdemux->fragmented = FALSE;
2634 /* We check here if it is a fragmented mp4 container */
2635 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
2636 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
2637 qtdemux->fragmented = TRUE;
2638 GST_DEBUG_OBJECT (qtdemux,
2639 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
2640 qtdemux->mfra_offset = mfra_offset;
2645 static GstFlowReturn
2646 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
2650 GstBuffer *buf = NULL;
2651 GstFlowReturn ret = GST_FLOW_OK;
2652 guint64 cur_offset = qtdemux->offset;
2656 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
2657 if (G_UNLIKELY (ret != GST_FLOW_OK))
2659 data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
2660 if (G_LIKELY (size >= 8))
2661 extract_initial_length_and_fourcc (data, size, &length, &fourcc);
2662 gst_buffer_unmap (buf, data, size);
2663 gst_buffer_unref (buf);
2665 /* maybe we already got most we needed, so only consider this eof */
2666 if (G_UNLIKELY (length == 0)) {
2667 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
2668 (_("Invalid atom size.")),
2669 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
2670 GST_FOURCC_ARGS (fourcc)));
2677 /* record for later parsing when needed */
2678 if (!qtdemux->moof_offset) {
2679 qtdemux->moof_offset = qtdemux->offset;
2688 GST_LOG_OBJECT (qtdemux,
2689 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
2690 GST_FOURCC_ARGS (fourcc), cur_offset);
2691 qtdemux->offset += length;
2698 if (qtdemux->got_moov) {
2699 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
2700 qtdemux->offset += length;
2704 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
2705 if (ret != GST_FLOW_OK)
2707 data = gst_buffer_map (moov, &size, NULL, GST_MAP_READ);
2708 if (length != size) {
2709 /* Some files have a 'moov' atom at the end of the file which contains
2710 * a terminal 'free' atom where the body of the atom is missing.
2711 * Check for, and permit, this special case.
2714 guint8 *final_data = data + (size - 8);
2715 guint32 final_length = QT_UINT32 (final_data);
2716 guint32 final_fourcc = QT_FOURCC (final_data + 4);
2717 gst_buffer_unmap (moov, data, size);
2718 if (final_fourcc == FOURCC_free && size + final_length - 8 == length) {
2719 /* Ok, we've found that special case. Allocate a new buffer with
2720 * that free atom actually present. */
2721 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
2722 gst_buffer_copy_into (newmoov, moov, 0, 0, size);
2723 data = gst_buffer_map (newmoov, &size, NULL, GST_MAP_WRITE);
2724 memset (data + length - final_length + 8, 0, final_length - 8);
2725 gst_buffer_unref (moov);
2731 if (length != size) {
2732 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2733 (_("This file is incomplete and cannot be played.")),
2734 ("We got less than expected (received %" G_GSIZE_FORMAT
2735 ", wanted %u, offset %" G_GUINT64_FORMAT ")", size,
2736 (guint) length, cur_offset));
2737 gst_buffer_unmap (moov, data, size);
2738 gst_buffer_unref (moov);
2739 ret = GST_FLOW_ERROR;
2742 qtdemux->offset += length;
2744 qtdemux_parse_moov (qtdemux, data, length);
2745 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
2747 qtdemux_parse_tree (qtdemux);
2748 g_node_destroy (qtdemux->moov_node);
2749 gst_buffer_unmap (moov, data, size);
2750 gst_buffer_unref (moov);
2751 qtdemux->moov_node = NULL;
2752 qtdemux->got_moov = TRUE;
2760 /* extract major brand; might come in handy for ISO vs QT issues */
2761 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
2762 if (ret != GST_FLOW_OK)
2764 qtdemux->offset += length;
2765 data = gst_buffer_map (ftyp, &size, NULL, GST_MAP_READ);
2766 qtdemux_parse_ftyp (qtdemux, data, size);
2767 gst_buffer_unmap (ftyp, data, size);
2768 gst_buffer_unref (ftyp);
2775 /* uuid are extension atoms */
2776 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
2777 if (ret != GST_FLOW_OK)
2779 qtdemux->offset += length;
2780 data = gst_buffer_map (uuid, &size, NULL, GST_MAP_READ);
2781 qtdemux_parse_uuid (qtdemux, data, size);
2782 gst_buffer_unmap (uuid, data, size);
2783 gst_buffer_unref (uuid);
2790 GST_LOG_OBJECT (qtdemux,
2791 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
2792 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
2794 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
2795 if (ret != GST_FLOW_OK)
2797 data = gst_buffer_map (unknown, &size, NULL, GST_MAP_READ);
2798 GST_MEMDUMP ("Unknown tag", data, size);
2799 gst_buffer_unmap (unknown, data, size);
2800 gst_buffer_unref (unknown);
2801 qtdemux->offset += length;
2807 if (ret == GST_FLOW_EOS && qtdemux->got_moov) {
2808 /* digested all data, show what we have */
2809 ret = qtdemux_expose_streams (qtdemux);
2811 /* Only post, event on pads is done after newsegment */
2812 qtdemux_post_global_tags (qtdemux);
2814 qtdemux->state = QTDEMUX_STATE_MOVIE;
2815 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
2822 /* Seeks to the previous keyframe of the indexed stream and
2823 * aligns other streams with respect to the keyframe timestamp
2824 * of indexed stream. Only called in case of Reverse Playback
2826 static GstFlowReturn
2827 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
2830 guint32 seg_idx = 0, k_index = 0;
2831 guint32 ref_seg_idx, ref_k_index;
2832 guint64 k_pos = 0, last_stop = 0;
2833 QtDemuxSegment *seg = NULL;
2834 QtDemuxStream *ref_str = NULL;
2835 guint64 seg_media_start_mov; /* segment media start time in mov format */
2837 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
2838 * and finally align all the other streams on that timestamp with their
2839 * respective keyframes */
2840 for (n = 0; n < qtdemux->n_streams; n++) {
2841 QtDemuxStream *str = qtdemux->streams[n];
2843 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
2844 qtdemux->segment.position);
2846 /* segment not found, continue with normal flow */
2850 /* No candidate yet, take that one */
2856 /* So that stream has a segment, we prefer video streams */
2857 if (str->subtype == FOURCC_vide) {
2863 if (G_UNLIKELY (!ref_str)) {
2864 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
2868 if (G_UNLIKELY (!ref_str->from_sample)) {
2869 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
2873 /* So that stream has been playing from from_sample to to_sample. We will
2874 * get the timestamp of the previous sample and search for a keyframe before
2875 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
2876 if (ref_str->subtype == FOURCC_vide) {
2877 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
2878 ref_str->from_sample - 1);
2880 if (ref_str->from_sample >= 10)
2881 k_index = ref_str->from_sample - 10;
2886 /* get current segment for that stream */
2887 seg = &ref_str->segments[ref_str->segment_index];
2888 /* convert seg->media_start to mov format time for timestamp comparison */
2889 seg_media_start_mov =
2890 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
2891 /* Crawl back through segments to find the one containing this I frame */
2892 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
2893 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
2894 ref_str->segment_index);
2895 if (G_UNLIKELY (!ref_str->segment_index)) {
2896 /* Reached first segment, let's consider it's EOS */
2899 ref_str->segment_index--;
2900 seg = &ref_str->segments[ref_str->segment_index];
2901 /* convert seg->media_start to mov format time for timestamp comparison */
2902 seg_media_start_mov =
2903 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
2906 /* Calculate time position of the keyframe and where we should stop */
2908 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
2909 ref_str->timescale) - seg->media_start) + seg->time;
2911 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
2912 GST_SECOND, ref_str->timescale);
2913 last_stop = (last_stop - seg->media_start) + seg->time;
2915 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
2916 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
2917 k_index, GST_TIME_ARGS (k_pos));
2919 /* Set last_stop with the keyframe timestamp we pushed of that stream */
2920 qtdemux->segment.position = last_stop;
2921 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
2922 GST_TIME_ARGS (last_stop));
2924 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
2925 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
2929 ref_seg_idx = ref_str->segment_index;
2930 ref_k_index = k_index;
2932 /* Align them all on this */
2933 for (n = 0; n < qtdemux->n_streams; n++) {
2935 guint64 media_start = 0, seg_time = 0;
2936 QtDemuxStream *str = qtdemux->streams[n];
2938 /* aligning reference stream again might lead to backing up to yet another
2939 * keyframe (due to timestamp rounding issues),
2940 * potentially putting more load on downstream; so let's try to avoid */
2941 if (str == ref_str) {
2942 seg_idx = ref_seg_idx;
2943 seg = &str->segments[seg_idx];
2944 k_index = ref_k_index;
2945 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
2946 "sample at index %d", ref_str->segment_index, k_index);
2948 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
2949 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
2951 /* segment not found, continue with normal flow */
2955 /* get segment and time in the segment */
2956 seg = &str->segments[seg_idx];
2957 seg_time = k_pos - seg->time;
2959 /* get the media time in the segment */
2960 media_start = seg->media_start + seg_time;
2962 /* get the index of the sample with media time */
2963 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
2964 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
2965 GST_TIME_ARGS (media_start), index);
2967 /* find previous keyframe */
2968 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
2971 /* Remember until where we want to go */
2972 str->to_sample = str->from_sample - 1;
2973 /* Define our time position */
2974 str->time_position =
2975 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
2976 str->timescale) - seg->media_start) + seg->time;
2977 /* Now seek back in time */
2978 gst_qtdemux_move_stream (qtdemux, str, k_index);
2979 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
2980 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
2981 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
2987 return GST_FLOW_EOS;
2990 /* activate the given segment number @seg_idx of @stream at time @offset.
2991 * @offset is an absolute global position over all the segments.
2993 * This will push out a NEWSEGMENT event with the right values and
2994 * position the stream index to the first decodable sample before
2998 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
2999 guint32 seg_idx, guint64 offset)
3002 QtDemuxSegment *segment;
3003 guint32 index, kf_index;
3005 guint64 start, stop, time;
3008 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3011 /* update the current segment */
3012 stream->segment_index = seg_idx;
3014 /* get the segment */
3015 segment = &stream->segments[seg_idx];
3017 if (G_UNLIKELY (offset < segment->time)) {
3018 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3023 /* segment lies beyond total indicated duration */
3024 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3025 segment->time > qtdemux->segment.duration)) {
3026 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3027 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3032 /* get time in this segment */
3033 seg_time = offset - segment->time;
3035 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3036 GST_TIME_ARGS (seg_time));
3038 if (G_UNLIKELY (seg_time > segment->duration)) {
3039 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3040 GST_TIME_ARGS (segment->duration));
3044 /* qtdemux->segment.stop is in outside-time-realm, whereas
3045 * segment->media_stop is in track-time-realm.
3047 * In order to compare the two, we need to bring segment.stop
3048 * into the track-time-realm */
3050 stop = qtdemux->segment.stop;
3052 stop = qtdemux->segment.duration;
3054 stop = segment->media_stop;
3057 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3059 if (qtdemux->segment.rate >= 0) {
3060 start = MIN (segment->media_start + seg_time, stop);
3063 if (segment->media_start >= qtdemux->segment.start) {
3064 start = segment->media_start;
3065 time = segment->time;
3067 start = qtdemux->segment.start;
3068 time = segment->time + (qtdemux->segment.start - segment->media_start);
3071 start = MAX (segment->media_start, qtdemux->segment.start);
3072 stop = MIN (segment->media_start + seg_time, stop);
3075 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3076 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3077 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3079 /* combine global rate with that of the segment */
3080 rate = segment->rate * qtdemux->segment.rate;
3082 /* update the segment values used for clipping */
3083 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
3084 /* accumulate previous segments */
3085 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3086 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3087 ABS (stream->segment.rate);
3088 stream->segment.rate = rate;
3089 stream->segment.start = start;
3090 stream->segment.stop = stop;
3091 stream->segment.time = time;
3093 /* now prepare and send the segment */
3095 event = gst_event_new_segment (&stream->segment);
3096 gst_pad_push_event (stream->pad, event);
3097 /* assume we can send more data now */
3098 stream->last_ret = GST_FLOW_OK;
3099 /* clear to send tags on this pad now */
3100 gst_qtdemux_push_tags (qtdemux, stream);
3103 /* and move to the keyframe before the indicated media time of the
3105 if (qtdemux->segment.rate >= 0) {
3106 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3107 stream->to_sample = G_MAXUINT32;
3108 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3109 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3110 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3111 GST_SECOND, stream->timescale)));
3113 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3114 stream->to_sample = index;
3115 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3116 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3117 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3118 GST_SECOND, stream->timescale)));
3121 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3122 * encountered an error and printed a message so we return appropriately */
3126 /* we're at the right spot */
3127 if (index == stream->sample_index) {
3128 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3132 /* find keyframe of the target index */
3133 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3136 /* indent does stupid stuff with stream->samples[].timestamp */
3138 /* if we move forwards, we don't have to go back to the previous
3139 * keyframe since we already sent that. We can also just jump to
3140 * the keyframe right before the target index if there is one. */
3141 if (index > stream->sample_index) {
3142 /* moving forwards check if we move past a keyframe */
3143 if (kf_index > stream->sample_index) {
3144 GST_DEBUG_OBJECT (qtdemux,
3145 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3146 GST_TIME_ARGS (gst_util_uint64_scale (
3147 stream->samples[kf_index].timestamp,
3148 GST_SECOND, stream->timescale)));
3149 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3151 GST_DEBUG_OBJECT (qtdemux,
3152 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3153 " already sent", kf_index,
3154 GST_TIME_ARGS (gst_util_uint64_scale (
3155 stream->samples[kf_index].timestamp,
3156 GST_SECOND, stream->timescale)));
3159 GST_DEBUG_OBJECT (qtdemux,
3160 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3161 GST_TIME_ARGS (gst_util_uint64_scale (
3162 stream->samples[kf_index].timestamp,
3163 GST_SECOND, stream->timescale)));
3164 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3172 /* prepare to get the current sample of @stream, getting essential values.
3174 * This function will also prepare and send the segment when needed.
3176 * Return FALSE if the stream is EOS.
3179 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3180 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp,
3181 guint64 * duration, gboolean * keyframe)
3183 QtDemuxSample *sample;
3184 guint64 time_position;
3187 g_return_val_if_fail (stream != NULL, FALSE);
3189 time_position = stream->time_position;
3190 if (G_UNLIKELY (time_position == -1))
3193 seg_idx = stream->segment_index;
3194 if (G_UNLIKELY (seg_idx == -1)) {
3195 /* find segment corresponding to time_position if we are looking
3197 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3199 /* nothing found, we're really eos */
3204 /* different segment, activate it, sample_index will be set. */
3205 if (G_UNLIKELY (stream->segment_index != seg_idx))
3206 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3208 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3209 stream->sample_index, stream->n_samples);
3211 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3214 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3215 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3216 stream->sample_index);
3220 /* now get the info for the sample we're at */
3221 sample = &stream->samples[stream->sample_index];
3223 *timestamp = QTSAMPLE_PTS (stream, sample);
3224 *offset = sample->offset;
3225 *size = sample->size;
3226 *duration = QTSAMPLE_DUR_PTS (stream, sample, *timestamp);
3227 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3234 stream->time_position = -1;
3239 /* move to the next sample in @stream.
3241 * Moves to the next segment when needed.
3244 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3246 QtDemuxSample *sample;
3247 QtDemuxSegment *segment;
3249 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3250 /* Mark the stream as EOS */
3251 GST_DEBUG_OBJECT (qtdemux,
3252 "reached max allowed sample %u, mark EOS", stream->to_sample);
3253 stream->time_position = -1;
3257 /* move to next sample */
3258 stream->sample_index++;
3260 /* get current segment */
3261 segment = &stream->segments[stream->segment_index];
3263 /* reached the last sample, we need the next segment */
3264 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3267 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3268 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3269 stream->sample_index);
3273 /* get next sample */
3274 sample = &stream->samples[stream->sample_index];
3276 /* see if we are past the segment */
3277 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3278 GST_SECOND, stream->timescale) >= segment->media_stop))
3281 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3282 stream->timescale) >= segment->media_start) {
3283 /* inside the segment, update time_position, looks very familiar to
3284 * GStreamer segments, doesn't it? */
3285 stream->time_position =
3286 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3287 stream->timescale) - segment->media_start) + segment->time;
3289 /* not yet in segment, time does not yet increment. This means
3290 * that we are still prerolling keyframes to the decoder so it can
3291 * decode the first sample of the segment. */
3292 stream->time_position = segment->time;
3296 /* move to the next segment */
3299 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3301 if (stream->segment_index == stream->n_segments - 1) {
3302 /* are we at the end of the last segment, we're EOS */
3303 stream->time_position = -1;
3305 /* else we're only at the end of the current segment */
3306 stream->time_position = segment->stop_time;
3308 /* make sure we select a new segment */
3309 stream->segment_index = -1;
3314 gst_qtdemux_sync_streams (GstQTDemux * demux)
3318 if (demux->n_streams <= 1)
3321 for (i = 0; i < demux->n_streams; i++) {
3322 QtDemuxStream *stream;
3323 GstClockTime end_time;
3325 stream = demux->streams[i];
3330 /* TODO advance time on subtitle streams here, if any some day */
3332 /* some clips/trailers may have unbalanced streams at the end,
3333 * so send EOS on shorter stream to prevent stalling others */
3335 /* do not mess with EOS if SEGMENT seeking */
3336 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3339 if (demux->pullbased) {
3340 /* loop mode is sample time based */
3341 if (stream->time_position != -1)
3344 /* push mode is byte position based */
3345 if (stream->n_samples &&
3346 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3350 if (stream->sent_eos)
3353 /* only act if some gap */
3354 end_time = stream->segments[stream->n_segments - 1].stop_time;
3355 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3356 ", stream end: %" GST_TIME_FORMAT,
3357 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3358 if (end_time + 2 * GST_SECOND < demux->segment.position) {
3359 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3360 GST_PAD_NAME (stream->pad));
3361 stream->sent_eos = TRUE;
3362 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3367 /* EOS and NOT_LINKED need to be combined. This means that we return:
3369 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3370 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
3372 static GstFlowReturn
3373 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3377 gboolean unexpected = FALSE, not_linked = TRUE;
3379 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3381 /* store the value */
3382 stream->last_ret = ret;
3384 /* any other error that is not-linked or eos can be returned right away */
3385 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3388 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3389 for (i = 0; i < demux->n_streams; i++) {
3390 QtDemuxStream *ostream = demux->streams[i];
3392 ret = ostream->last_ret;
3394 /* no unexpected or unlinked, return */
3395 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3398 /* we check to see if we have at least 1 unexpected or all unlinked */
3399 unexpected |= (ret == GST_FLOW_EOS);
3400 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3403 /* when we get here, we all have unlinked or unexpected */
3405 ret = GST_FLOW_NOT_LINKED;
3406 else if (unexpected)
3409 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3413 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3414 * completely cliped */
3416 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3419 guint64 start, stop, cstart, cstop, diff;
3420 GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
3422 gint num_rate, denom_rate;
3427 size = gst_buffer_get_size (buf);
3430 /* depending on the type, setup the clip parameters */
3431 if (stream->subtype == FOURCC_soun) {
3432 frame_size = stream->bytes_per_frame;
3433 num_rate = GST_SECOND;
3434 denom_rate = (gint) stream->rate;
3436 } else if (stream->subtype == FOURCC_vide) {
3438 num_rate = stream->fps_n;
3439 denom_rate = stream->fps_d;
3444 /* we can only clip if we have a valid timestamp */
3445 timestamp = GST_BUFFER_TIMESTAMP (buf);
3446 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
3449 if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf))) {
3450 duration = GST_BUFFER_DURATION (buf);
3453 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3457 stop = start + duration;
3459 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3460 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3463 /* see if some clipping happened */
3464 diff = cstart - start;
3470 /* bring clipped time to samples and to bytes */
3471 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3474 GST_DEBUG_OBJECT (qtdemux,
3475 "clipping start to %" GST_TIME_FORMAT " %"
3476 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3482 diff = stop - cstop;
3487 /* bring clipped time to samples and then to bytes */
3488 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3490 GST_DEBUG_OBJECT (qtdemux,
3491 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3492 " bytes", GST_TIME_ARGS (cstop), diff);
3497 gst_buffer_resize (buf, offset, size);
3498 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3499 GST_BUFFER_DURATION (buf) = duration;
3503 /* dropped buffer */
3506 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3511 GST_DEBUG_OBJECT (qtdemux, "no timestamp on buffer");
3516 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3517 gst_buffer_unref (buf);
3522 /* the input buffer metadata must be writable,
3523 * but time/duration etc not yet set and need not be preserved */
3525 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3533 /* not many cases for now */
3534 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3535 /* send a one time dvd clut event */
3536 if (stream->pending_event && stream->pad)
3537 gst_pad_push_event (stream->pad, stream->pending_event);
3538 stream->pending_event = NULL;
3539 /* no further processing needed */
3540 stream->need_process = FALSE;
3543 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
3547 data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
3549 if (G_LIKELY (size >= 2)) {
3550 nsize = GST_READ_UINT16_BE (data);
3551 nsize = MIN (nsize, size - 2);
3554 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
3557 /* takes care of UTF-8 validation or UTF-16 recognition,
3558 * no other encoding expected */
3559 str = gst_tag_freeform_string_to_utf8 ((gchar *) data + 2, nsize, NULL);
3560 gst_buffer_unmap (buf, data, size);
3562 gst_buffer_unref (buf);
3563 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
3565 /* may be 0-size subtitle, which is also sent to keep pipeline going */
3566 gst_buffer_resize (buf, 2, nsize);
3569 /* FIXME ? convert optional subsequent style info to markup */
3574 /* Sets a buffer's attributes properly and pushes it downstream.
3575 * Also checks for additional actions and custom processing that may
3576 * need to be done first.
3579 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3580 QtDemuxStream * stream, GstBuffer * buf,
3581 guint64 timestamp, guint64 duration, gboolean keyframe, guint64 position,
3582 guint64 byte_position)
3584 GstFlowReturn ret = GST_FLOW_OK;
3586 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
3591 bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
3592 url = g_strndup ((gchar *) bdata, bsize);
3593 gst_buffer_unmap (buf, bdata, bsize);
3594 if (url != NULL && strlen (url) != 0) {
3595 /* we have RTSP redirect now */
3596 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3597 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
3598 gst_structure_new ("redirect",
3599 "new-location", G_TYPE_STRING, url, NULL)));
3600 qtdemux->posted_redirect = TRUE;
3602 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
3608 /* position reporting */
3609 if (qtdemux->segment.rate >= 0) {
3610 qtdemux->segment.position = position;
3611 gst_qtdemux_sync_streams (qtdemux);
3614 if (G_UNLIKELY (!stream->pad)) {
3615 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
3616 gst_buffer_unref (buf);
3620 /* send out pending buffers */
3621 while (stream->buffers) {
3622 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
3624 if (G_UNLIKELY (stream->discont)) {
3625 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3626 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
3627 stream->discont = FALSE;
3630 gst_pad_push (stream->pad, buffer);
3632 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
3635 /* we're going to modify the metadata */
3636 buf = gst_buffer_make_writable (buf);
3638 if (G_UNLIKELY (stream->need_process))
3639 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
3641 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3642 GST_BUFFER_DURATION (buf) = duration;
3643 GST_BUFFER_OFFSET (buf) = -1;
3644 GST_BUFFER_OFFSET_END (buf) = -1;
3646 if (G_UNLIKELY (stream->padding)) {
3647 gst_buffer_resize (buf, stream->padding, -1);
3650 if (G_UNLIKELY (qtdemux->element_index)) {
3651 GstClockTime stream_time;
3654 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
3656 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
3657 GST_LOG_OBJECT (qtdemux,
3658 "adding association %" GST_TIME_FORMAT "-> %"
3659 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
3660 gst_index_add_association (qtdemux->element_index,
3662 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
3663 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
3664 GST_FORMAT_BYTES, byte_position, NULL);
3669 if (stream->need_clip)
3670 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
3672 if (G_UNLIKELY (buf == NULL))
3675 if (G_UNLIKELY (stream->discont)) {
3676 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3677 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3678 stream->discont = FALSE;
3682 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3684 GST_LOG_OBJECT (qtdemux,
3685 "Pushing buffer with time %" GST_TIME_FORMAT ", duration %"
3686 GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
3687 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
3689 ret = gst_pad_push (stream->pad, buf);
3695 static GstFlowReturn
3696 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
3698 GstFlowReturn ret = GST_FLOW_OK;
3699 GstBuffer *buf = NULL;
3700 QtDemuxStream *stream;
3703 guint64 timestamp = GST_CLOCK_TIME_NONE;
3704 guint64 duration = 0;
3705 gboolean keyframe = FALSE;
3710 gst_qtdemux_push_pending_newsegment (qtdemux);
3712 /* Figure out the next stream sample to output, min_time is expressed in
3713 * global time and runs over the edit list segments. */
3714 min_time = G_MAXUINT64;
3716 for (i = 0; i < qtdemux->n_streams; i++) {
3719 stream = qtdemux->streams[i];
3720 position = stream->time_position;
3722 /* position of -1 is EOS */
3723 if (position != -1 && position < min_time) {
3724 min_time = position;
3729 if (G_UNLIKELY (index == -1)) {
3730 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
3734 /* check for segment end */
3735 if (G_UNLIKELY (qtdemux->segment.stop != -1
3736 && qtdemux->segment.stop < min_time)) {
3737 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
3741 stream = qtdemux->streams[index];
3743 /* fetch info for the current sample of this stream */
3744 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
3745 &size, ×tamp, &duration, &keyframe)))
3748 GST_LOG_OBJECT (qtdemux,
3749 "pushing from stream %d, offset %" G_GUINT64_FORMAT
3750 ", size %d, timestamp=%" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
3751 index, offset, size, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
3753 /* hmm, empty sample, skip and move to next sample */
3754 if (G_UNLIKELY (size <= 0))
3757 /* last pushed sample was out of boundary, goto next sample */
3758 if (G_UNLIKELY (stream->last_ret == GST_FLOW_EOS))
3761 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
3764 ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
3765 if (G_UNLIKELY (ret != GST_FLOW_OK))
3768 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
3769 timestamp, duration, keyframe, min_time, offset);
3772 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
3773 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
3774 * we have no more data for the pad to push */
3775 if (ret == GST_FLOW_EOS)
3779 gst_qtdemux_advance_sample (qtdemux, stream);
3787 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
3793 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
3794 /* EOS will be raised if all are EOS */
3801 gst_qtdemux_loop (GstPad * pad)
3803 GstQTDemux *qtdemux;
3807 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
3809 cur_offset = qtdemux->offset;
3810 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
3811 cur_offset, qtdemux->state);
3813 switch (qtdemux->state) {
3814 case QTDEMUX_STATE_INITIAL:
3815 case QTDEMUX_STATE_HEADER:
3816 ret = gst_qtdemux_loop_state_header (qtdemux);
3818 case QTDEMUX_STATE_MOVIE:
3819 ret = gst_qtdemux_loop_state_movie (qtdemux);
3820 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
3821 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
3829 /* if something went wrong, pause */
3830 if (ret != GST_FLOW_OK)
3834 gst_object_unref (qtdemux);
3840 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3841 (NULL), ("streaming stopped, invalid state"));
3842 gst_pad_pause_task (pad);
3843 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3848 const gchar *reason = gst_flow_get_name (ret);
3850 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
3852 gst_pad_pause_task (pad);
3854 /* fatal errors need special actions */
3856 if (ret == GST_FLOW_EOS) {
3857 if (qtdemux->n_streams == 0) {
3858 /* we have no streams, post an error */
3859 gst_qtdemux_post_no_playable_stream_error (qtdemux);
3861 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3864 if ((stop = qtdemux->segment.stop) == -1)
3865 stop = qtdemux->segment.duration;
3867 if (qtdemux->segment.rate >= 0) {
3868 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
3869 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3870 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3871 GST_FORMAT_TIME, stop));
3873 /* For Reverse Playback */
3874 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
3875 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3876 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3877 GST_FORMAT_TIME, qtdemux->segment.start));
3880 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
3881 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3883 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
3884 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3885 (NULL), ("streaming stopped, reason %s", reason));
3886 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3895 * Returns the size of the first entry at the current offset.
3896 * If -1, there are none (which means EOS or empty file).
3899 next_entry_size (GstQTDemux * demux)
3901 QtDemuxStream *stream;
3904 guint64 smalloffs = (guint64) - 1;
3905 QtDemuxSample *sample;
3907 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
3910 for (i = 0; i < demux->n_streams; i++) {
3911 stream = demux->streams[i];
3913 if (stream->sample_index == -1)
3914 stream->sample_index = 0;
3916 if (stream->sample_index >= stream->n_samples) {
3917 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
3921 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
3922 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
3923 stream->sample_index);
3927 sample = &stream->samples[stream->sample_index];
3929 GST_LOG_OBJECT (demux,
3930 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3931 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
3932 sample->offset, sample->size);
3934 if (((smalloffs == -1)
3935 || (sample->offset < smalloffs)) && (sample->size)) {
3937 smalloffs = sample->offset;
3941 GST_LOG_OBJECT (demux,
3942 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
3943 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
3948 stream = demux->streams[smallidx];
3949 sample = &stream->samples[stream->sample_index];
3951 if (sample->offset >= demux->offset) {
3952 demux->todrop = sample->offset - demux->offset;
3953 return sample->size + demux->todrop;
3956 GST_DEBUG_OBJECT (demux,
3957 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
3962 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
3964 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
3966 gst_element_post_message (GST_ELEMENT_CAST (demux),
3967 gst_message_new_element (GST_OBJECT_CAST (demux),
3968 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
3972 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
3977 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
3980 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
3981 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
3982 GST_SEEK_TYPE_NONE, -1);
3984 res = gst_pad_push_event (demux->sinkpad, event);
3989 /* check for seekable upstream, above and beyond a mere query */
3991 gst_qtdemux_check_seekability (GstQTDemux * demux)
3994 gboolean seekable = FALSE;
3995 gint64 start = -1, stop = -1;
3997 if (demux->upstream_size)
4000 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4001 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4002 GST_DEBUG_OBJECT (demux, "seeking query failed");
4006 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4008 /* try harder to query upstream size if we didn't get it the first time */
4009 if (seekable && stop == -1) {
4010 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4011 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4014 /* if upstream doesn't know the size, it's likely that it's not seekable in
4015 * practice even if it technically may be seekable */
4016 if (seekable && (start != 0 || stop <= start)) {
4017 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4022 gst_query_unref (query);
4024 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4025 G_GUINT64_FORMAT ")", seekable, start, stop);
4026 demux->upstream_seekable = seekable;
4027 demux->upstream_size = seekable ? stop : -1;
4030 /* FIXME, unverified after edit list updates */
4031 static GstFlowReturn
4032 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4035 GstFlowReturn ret = GST_FLOW_OK;
4037 demux = GST_QTDEMUX (parent);
4039 gst_adapter_push (demux->adapter, inbuf);
4041 /* we never really mean to buffer that much */
4042 if (demux->neededbytes == -1)
4045 GST_DEBUG_OBJECT (demux,
4046 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4047 demux->neededbytes, gst_adapter_available (demux->adapter));
4049 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4050 (ret == GST_FLOW_OK)) {
4052 GST_DEBUG_OBJECT (demux,
4053 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4054 demux->state, demux->neededbytes, demux->offset);
4056 switch (demux->state) {
4057 case QTDEMUX_STATE_INITIAL:{
4062 gst_qtdemux_check_seekability (demux);
4064 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4066 /* get fourcc/length, set neededbytes */
4067 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4069 gst_adapter_unmap (demux->adapter);
4071 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4072 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4074 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4075 (_("This file is invalid and cannot be played.")),
4076 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4077 GST_FOURCC_ARGS (fourcc)));
4078 ret = GST_FLOW_ERROR;
4081 if (fourcc == FOURCC_mdat) {
4082 if (demux->n_streams > 0) {
4083 /* we have the headers, start playback */
4084 demux->state = QTDEMUX_STATE_MOVIE;
4085 demux->neededbytes = next_entry_size (demux);
4086 demux->mdatleft = size;
4088 /* Only post, event on pads is done after newsegment */
4089 qtdemux_post_global_tags (demux);
4092 /* no headers yet, try to get them */
4095 guint64 old, target;
4098 old = demux->offset;
4099 target = old + size;
4101 /* try to jump over the atom with a seek */
4102 /* only bother if it seems worth doing so,
4103 * and avoids possible upstream/server problems */
4104 if (demux->upstream_seekable &&
4105 demux->upstream_size > 4 * (1 << 20)) {
4106 res = qtdemux_seek_offset (demux, target);
4108 GST_DEBUG_OBJECT (demux, "skipping seek");
4113 GST_DEBUG_OBJECT (demux, "seek success");
4114 /* remember the offset fo the first mdat so we can seek back to it
4115 * after we have the headers */
4116 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4117 demux->first_mdat = old;
4118 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4121 /* seek worked, continue reading */
4122 demux->offset = target;
4123 demux->neededbytes = 16;
4124 demux->state = QTDEMUX_STATE_INITIAL;
4126 /* seek failed, need to buffer */
4127 demux->offset = old;
4128 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4129 /* there may be multiple mdat (or alike) buffers */
4131 if (demux->mdatbuffer)
4132 bs = gst_buffer_get_size (demux->mdatbuffer);
4135 if (size + bs > 10 * (1 << 20))
4137 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4138 demux->neededbytes = size;
4139 if (!demux->mdatbuffer)
4140 demux->mdatoffset = demux->offset;
4143 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4144 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4145 (_("This file is invalid and cannot be played.")),
4146 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4147 GST_FOURCC_ARGS (fourcc), size));
4148 ret = GST_FLOW_ERROR;
4151 /* this means we already started buffering and still no moov header,
4152 * let's continue buffering everything till we get moov */
4153 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
4155 demux->neededbytes = size;
4156 demux->state = QTDEMUX_STATE_HEADER;
4160 case QTDEMUX_STATE_HEADER:{
4164 GST_DEBUG_OBJECT (demux, "In header");
4166 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4168 /* parse the header */
4169 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4171 if (fourcc == FOURCC_moov) {
4172 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4174 demux->got_moov = TRUE;
4176 /* prepare newsegment to send when streaming actually starts */
4177 if (!demux->pending_newsegment)
4178 demux->pending_newsegment = gst_event_new_segment (&demux->segment);
4180 qtdemux_parse_moov (demux, data, demux->neededbytes);
4181 qtdemux_node_dump (demux, demux->moov_node);
4182 qtdemux_parse_tree (demux);
4183 qtdemux_expose_streams (demux);
4185 g_node_destroy (demux->moov_node);
4186 demux->moov_node = NULL;
4187 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4188 } else if (fourcc == FOURCC_moof) {
4189 if (demux->got_moov && demux->fragmented) {
4190 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4191 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4192 demux->offset, NULL)) {
4193 gst_adapter_unmap (demux->adapter);
4194 ret = GST_FLOW_ERROR;
4198 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4200 } else if (fourcc == FOURCC_ftyp) {
4201 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4202 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4203 } else if (fourcc == FOURCC_uuid) {
4204 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4205 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4207 GST_WARNING_OBJECT (demux,
4208 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4209 GST_FOURCC_ARGS (fourcc));
4210 /* Let's jump that one and go back to initial state */
4212 gst_adapter_unmap (demux->adapter);
4215 if (demux->mdatbuffer && demux->n_streams) {
4216 /* the mdat was before the header */
4217 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4218 demux->n_streams, demux->mdatbuffer);
4219 /* restore our adapter/offset view of things with upstream;
4220 * put preceding buffered data ahead of current moov data.
4221 * This should also handle evil mdat, moov, mdat cases and alike */
4222 gst_adapter_clear (demux->adapter);
4223 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4224 demux->mdatbuffer = NULL;
4225 demux->offset = demux->mdatoffset;
4226 demux->neededbytes = next_entry_size (demux);
4227 demux->state = QTDEMUX_STATE_MOVIE;
4228 demux->mdatleft = gst_adapter_available (demux->adapter);
4230 /* Only post, event on pads is done after newsegment */
4231 qtdemux_post_global_tags (demux);
4234 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4235 gst_adapter_flush (demux->adapter, demux->neededbytes);
4237 if (demux->got_moov && demux->first_mdat != -1) {
4240 /* we need to seek back */
4241 res = qtdemux_seek_offset (demux, demux->first_mdat);
4243 demux->offset = demux->first_mdat;
4245 GST_DEBUG_OBJECT (demux, "Seek back failed");
4248 demux->offset += demux->neededbytes;
4250 demux->neededbytes = 16;
4251 demux->state = QTDEMUX_STATE_INITIAL;
4256 case QTDEMUX_STATE_BUFFER_MDAT:{
4260 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4262 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4263 gst_buffer_extract (buf, 0, fourcc, 4);
4264 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4265 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
4266 if (demux->mdatbuffer)
4267 demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
4269 demux->mdatbuffer = buf;
4270 demux->offset += demux->neededbytes;
4271 demux->neededbytes = 16;
4272 demux->state = QTDEMUX_STATE_INITIAL;
4273 gst_qtdemux_post_progress (demux, 1, 1);
4277 case QTDEMUX_STATE_MOVIE:{
4279 QtDemuxStream *stream = NULL;
4280 QtDemuxSample *sample;
4282 guint64 timestamp, duration, position;
4285 GST_DEBUG_OBJECT (demux,
4286 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4288 if (demux->fragmented) {
4289 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4291 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4292 /* if needed data starts within this atom,
4293 * then it should not exceed this atom */
4294 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4295 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4296 (_("This file is invalid and cannot be played.")),
4297 ("sample data crosses atom boundary"));
4298 ret = GST_FLOW_ERROR;
4301 demux->mdatleft -= demux->neededbytes;
4303 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4304 /* so we are dropping more than left in this atom */
4305 demux->todrop -= demux->mdatleft;
4306 demux->neededbytes -= demux->mdatleft;
4307 demux->mdatleft = 0;
4308 /* need to resume atom parsing so we do not miss any other pieces */
4309 demux->state = QTDEMUX_STATE_INITIAL;
4310 demux->neededbytes = 16;
4315 if (demux->todrop) {
4316 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4317 gst_adapter_flush (demux->adapter, demux->todrop);
4318 demux->neededbytes -= demux->todrop;
4319 demux->offset += demux->todrop;
4323 /* initial newsegment sent here after having added pads,
4324 * possible others in sink_event */
4325 if (G_UNLIKELY (demux->pending_newsegment)) {
4326 gst_qtdemux_push_event (demux, demux->pending_newsegment);
4327 demux->pending_newsegment = NULL;
4328 /* clear to send tags on all streams */
4329 for (i = 0; i < demux->n_streams; i++) {
4330 gst_qtdemux_push_tags (demux, demux->streams[i]);
4334 /* Figure out which stream this is packet belongs to */
4335 for (i = 0; i < demux->n_streams; i++) {
4336 stream = demux->streams[i];
4337 if (stream->sample_index >= stream->n_samples)
4339 GST_LOG_OBJECT (demux,
4340 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4341 " / size:%d)", i, stream->sample_index,
4342 stream->samples[stream->sample_index].offset,
4343 stream->samples[stream->sample_index].size);
4345 if (stream->samples[stream->sample_index].offset == demux->offset)
4349 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4350 goto unknown_stream;
4352 /* Put data in a buffer, set timestamps, caps, ... */
4353 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4354 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4355 GST_FOURCC_ARGS (stream->fourcc));
4357 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4359 sample = &stream->samples[stream->sample_index];
4361 position = QTSAMPLE_DTS (stream, sample);
4362 timestamp = QTSAMPLE_PTS (stream, sample);
4363 duration = QTSAMPLE_DUR_DTS (stream, sample, position);
4364 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4366 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4367 timestamp, duration, keyframe, position, demux->offset);
4370 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4372 stream->sample_index++;
4374 /* update current offset and figure out size of next buffer */
4375 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4376 demux->offset, demux->neededbytes);
4377 demux->offset += demux->neededbytes;
4378 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4381 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4382 if (demux->fragmented) {
4383 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4384 /* there may be more to follow, only finish this atom */
4385 demux->todrop = demux->mdatleft;
4386 demux->neededbytes = demux->todrop;
4398 /* when buffering movie data, at least show user something is happening */
4399 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4400 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4401 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4402 demux->neededbytes);
4411 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4412 ret = GST_FLOW_ERROR;
4417 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4423 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4424 (NULL), ("qtdemuxer invalid state %d", demux->state));
4425 ret = GST_FLOW_ERROR;
4430 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4431 (NULL), ("no 'moov' atom within the first 10 MB"));
4432 ret = GST_FLOW_ERROR;
4438 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
4443 query = gst_query_new_scheduling ();
4445 if (!gst_pad_peer_query (sinkpad, query)) {
4446 gst_query_unref (query);
4450 pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
4451 gst_query_unref (query);
4456 GST_DEBUG_OBJECT (sinkpad, "activating pull");
4457 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
4461 GST_DEBUG_OBJECT (sinkpad, "activating push");
4462 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
4467 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
4468 GstPadMode mode, gboolean active)
4471 GstQTDemux *demux = GST_QTDEMUX (parent);
4474 case GST_PAD_MODE_PUSH:
4475 demux->pullbased = FALSE;
4478 case GST_PAD_MODE_PULL:
4480 demux->pullbased = TRUE;
4481 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4484 res = gst_pad_stop_task (sinkpad);
4496 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4498 return g_malloc (items * size);
4502 qtdemux_zfree (void *opaque, void *addr)
4508 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4514 z = g_new0 (z_stream, 1);
4515 z->zalloc = qtdemux_zalloc;
4516 z->zfree = qtdemux_zfree;
4519 z->next_in = z_buffer;
4520 z->avail_in = z_length;
4522 buffer = (guint8 *) g_malloc (length);
4523 ret = inflateInit (z);
4524 while (z->avail_in > 0) {
4525 if (z->avail_out == 0) {
4527 buffer = (guint8 *) g_realloc (buffer, length);
4528 z->next_out = buffer + z->total_out;
4529 z->avail_out = 1024;
4531 ret = inflate (z, Z_SYNC_FLUSH);
4535 if (ret != Z_STREAM_END) {
4536 g_warning ("inflate() returned %d", ret);
4542 #endif /* HAVE_ZLIB */
4545 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4549 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4551 /* counts as header data */
4552 qtdemux->header_size += length;
4554 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4555 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4557 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4563 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4564 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4565 if (dcom == NULL || cmvd == NULL)
4566 goto invalid_compression;
4568 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4571 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4572 guint uncompressed_length;
4573 guint compressed_length;
4576 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4577 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4578 GST_LOG ("length = %u", uncompressed_length);
4581 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4582 compressed_length, uncompressed_length);
4584 qtdemux->moov_node_compressed = qtdemux->moov_node;
4585 qtdemux->moov_node = g_node_new (buf);
4587 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4588 uncompressed_length);
4591 #endif /* HAVE_ZLIB */
4593 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4594 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
4601 invalid_compression:
4603 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
4609 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
4612 while (G_UNLIKELY (buf < end)) {
4616 if (G_UNLIKELY (buf + 4 > end)) {
4617 GST_LOG_OBJECT (qtdemux, "buffer overrun");
4620 len = QT_UINT32 (buf);
4621 if (G_UNLIKELY (len == 0)) {
4622 GST_LOG_OBJECT (qtdemux, "empty container");
4625 if (G_UNLIKELY (len < 8)) {
4626 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
4629 if (G_UNLIKELY (len > (end - buf))) {
4630 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
4631 (gint) (end - buf));
4635 child = g_node_new ((guint8 *) buf);
4636 g_node_append (node, child);
4637 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
4638 qtdemux_parse_node (qtdemux, child, buf, len);
4646 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
4649 int len = QT_UINT32 (xdxt->data);
4650 guint8 *buf = xdxt->data;
4651 guint8 *end = buf + len;
4654 /* skip size and type */
4662 size = QT_UINT32 (buf);
4663 type = QT_FOURCC (buf + 4);
4665 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
4667 if (buf + size > end || size <= 0)
4673 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
4674 GST_FOURCC_ARGS (type));
4678 buffer = gst_buffer_new_and_alloc (size);
4679 _gst_buffer_copy_into_mem (buffer, buf, 0, size);
4680 stream->buffers = g_slist_append (stream->buffers, buffer);
4681 GST_LOG_OBJECT (qtdemux, "parsing theora header");
4684 buffer = gst_buffer_new_and_alloc (size);
4685 _gst_buffer_copy_into_mem (buffer, buf, 0, size);
4686 stream->buffers = g_slist_append (stream->buffers, buffer);
4687 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
4690 buffer = gst_buffer_new_and_alloc (size);
4691 _gst_buffer_copy_into_mem (buffer, buf, 0, size);
4692 stream->buffers = g_slist_append (stream->buffers, buffer);
4693 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
4696 GST_WARNING_OBJECT (qtdemux,
4697 "unknown theora cookie %" GST_FOURCC_FORMAT,
4698 GST_FOURCC_ARGS (type));
4707 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
4711 guint32 node_length = 0;
4712 const QtNodeType *type;
4715 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
4717 if (G_UNLIKELY (length < 8))
4718 goto not_enough_data;
4720 node_length = QT_UINT32 (buffer);
4721 fourcc = QT_FOURCC (buffer + 4);
4723 /* ignore empty nodes */
4724 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
4727 type = qtdemux_type_get (fourcc);
4729 end = buffer + length;
4731 GST_LOG_OBJECT (qtdemux,
4732 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
4733 GST_FOURCC_ARGS (fourcc), node_length, type->name);
4735 if (node_length > length)
4736 goto broken_atom_size;
4738 if (type->flags & QT_FLAG_CONTAINER) {
4739 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
4744 if (node_length < 20) {
4745 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
4748 GST_DEBUG_OBJECT (qtdemux,
4749 "parsing stsd (sample table, sample description) atom");
4750 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
4760 /* also read alac (or whatever) in stead of mp4a in the following,
4761 * since a similar layout is used in other cases as well */
4762 if (fourcc == FOURCC_mp4a)
4767 /* There are two things we might encounter here: a true mp4a atom, and
4768 an mp4a entry in an stsd atom. The latter is what we're interested
4769 in, and it looks like an atom, but isn't really one. The true mp4a
4770 atom is short, so we detect it based on length here. */
4771 if (length < min_size) {
4772 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
4773 GST_FOURCC_ARGS (fourcc));
4777 /* 'version' here is the sound sample description version. Types 0 and
4778 1 are documented in the QTFF reference, but type 2 is not: it's
4779 described in Apple header files instead (struct SoundDescriptionV2
4781 version = QT_UINT16 (buffer + 16);
4783 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
4784 GST_FOURCC_ARGS (fourcc), version);
4786 /* parse any esds descriptors */
4798 GST_WARNING_OBJECT (qtdemux,
4799 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
4800 GST_FOURCC_ARGS (fourcc), version);
4805 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4817 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
4818 GST_FOURCC_ARGS (fourcc));
4819 version = QT_UINT32 (buffer + 16);
4820 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
4821 if (1 || version == 0x00000000) {
4822 buf = buffer + 0x32;
4824 /* FIXME Quicktime uses PASCAL string while
4825 * the iso format uses C strings. Check the file
4826 * type before attempting to parse the string here. */
4827 tlen = QT_UINT8 (buf);
4828 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
4830 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
4831 /* the string has a reserved space of 32 bytes so skip
4832 * the remaining 31 */
4834 buf += 4; /* and 4 bytes reserved */
4836 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
4838 qtdemux_parse_container (qtdemux, node, buf, end);
4844 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
4845 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
4850 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
4855 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
4856 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
4864 version = QT_UINT32 (buffer + 12);
4865 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
4872 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
4877 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4882 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
4886 if (!strcmp (type->name, "unknown"))
4887 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
4891 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
4892 GST_FOURCC_ARGS (fourcc));
4898 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4899 (_("This file is corrupt and cannot be played.")),
4900 ("Not enough data for an atom header, got only %u bytes", length));
4905 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4906 (_("This file is corrupt and cannot be played.")),
4907 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
4908 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
4915 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
4919 guint32 child_fourcc;
4921 for (child = g_node_first_child (node); child;
4922 child = g_node_next_sibling (child)) {
4923 buffer = (guint8 *) child->data;
4925 child_fourcc = QT_FOURCC (buffer + 4);
4927 if (G_UNLIKELY (child_fourcc == fourcc)) {
4935 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
4936 GstByteReader * parser)
4940 guint32 child_fourcc, child_len;
4942 for (child = g_node_first_child (node); child;
4943 child = g_node_next_sibling (child)) {
4944 buffer = (guint8 *) child->data;
4946 child_len = QT_UINT32 (buffer);
4947 child_fourcc = QT_FOURCC (buffer + 4);
4949 if (G_UNLIKELY (child_fourcc == fourcc)) {
4950 if (G_UNLIKELY (child_len < (4 + 4)))
4952 /* FIXME: must verify if atom length < parent atom length */
4953 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4961 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
4962 GstByteReader * parser)
4966 guint32 child_fourcc, child_len;
4968 for (child = g_node_next_sibling (node); child;
4969 child = g_node_next_sibling (child)) {
4970 buffer = (guint8 *) child->data;
4972 child_fourcc = QT_FOURCC (buffer + 4);
4974 if (child_fourcc == fourcc) {
4976 child_len = QT_UINT32 (buffer);
4977 if (G_UNLIKELY (child_len < (4 + 4)))
4979 /* FIXME: must verify if atom length < parent atom length */
4980 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4989 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
4991 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
4995 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
4996 QtDemuxStream * stream, GstTagList * list)
4998 /* consistent default for push based mode */
4999 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
5001 if (stream->subtype == FOURCC_vide) {
5002 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5005 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5008 /* fps is calculated base on the duration of the first frames since
5009 * qt does not have a fixed framerate. */
5010 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
5015 stream->fps_n = stream->timescale;
5016 if (stream->min_duration == 0)
5019 stream->fps_d = stream->min_duration;
5024 gint depth, palette_count;
5025 const guint32 *palette_data = NULL;
5027 gst_caps_set_simple (stream->caps,
5028 "width", G_TYPE_INT, stream->width,
5029 "height", G_TYPE_INT, stream->height,
5030 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5032 /* calculate pixel-aspect-ratio using display width and height */
5033 GST_DEBUG_OBJECT (qtdemux,
5034 "video size %dx%d, target display size %dx%d", stream->width,
5035 stream->height, stream->display_width, stream->display_height);
5037 if (stream->display_width > 0 && stream->display_height > 0 &&
5038 stream->width > 0 && stream->height > 0) {
5041 /* calculate the pixel aspect ratio using the display and pixel w/h */
5042 n = stream->display_width * stream->height;
5043 d = stream->display_height * stream->width;
5046 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5047 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5048 GST_TYPE_FRACTION, n, d, NULL);
5051 /* qt file might have pasp atom */
5052 if (stream->par_w > 0 && stream->par_h > 0) {
5053 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5054 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5055 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5058 depth = stream->bits_per_sample;
5060 /* more than 32 bits means grayscale */
5061 gray = (depth > 32);
5062 /* low 32 bits specify the depth */
5065 /* different number of palette entries is determined by depth. */
5067 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
5068 palette_count = (1 << depth);
5070 switch (palette_count) {
5074 palette_data = ff_qt_default_palette_2;
5077 palette_data = ff_qt_default_palette_4;
5081 palette_data = ff_qt_grayscale_palette_16;
5083 palette_data = ff_qt_default_palette_16;
5087 palette_data = ff_qt_grayscale_palette_256;
5089 palette_data = ff_qt_default_palette_256;
5092 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5093 (_("The video in this file might not play correctly.")),
5094 ("unsupported palette depth %d", depth));
5100 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5101 * don't free any of the buffer data. */
5102 palette = _gst_buffer_new_wrapped ((gpointer) palette_data,
5103 palette_count, NULL);
5105 gst_caps_set_simple (stream->caps, "palette_data",
5106 GST_TYPE_BUFFER, palette, NULL);
5107 gst_buffer_unref (palette);
5108 } else if (palette_count != 0) {
5109 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5110 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5112 gst_object_unref (stream->pad);
5116 qtdemux->n_video_streams++;
5117 } else if (stream->subtype == FOURCC_soun) {
5118 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
5121 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5124 /* FIXME: Need to set channel-mask here and maybe reorder */
5125 gst_caps_set_simple (stream->caps,
5126 "rate", G_TYPE_INT, (int) stream->rate,
5127 "channels", G_TYPE_INT, stream->n_channels, NULL);
5129 qtdemux->n_audio_streams++;
5130 } else if (stream->subtype == FOURCC_strm) {
5131 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5132 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
5133 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
5136 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5138 qtdemux->n_sub_streams++;
5140 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5145 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5147 gst_pad_use_fixed_caps (stream->pad);
5148 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5149 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5150 gst_pad_set_active (stream->pad, TRUE);
5152 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5153 gst_pad_set_caps (stream->pad, stream->caps);
5155 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5156 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5157 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5159 if (stream->pending_tags)
5160 gst_tag_list_free (stream->pending_tags);
5161 stream->pending_tags = list;
5162 /* global tags go on each pad anyway */
5163 stream->send_global_tags = TRUE;
5169 /* find next atom with @fourcc starting at @offset */
5170 static GstFlowReturn
5171 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5172 guint64 * length, guint32 fourcc)
5178 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5179 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5185 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5186 if (G_UNLIKELY (ret != GST_FLOW_OK))
5188 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
5191 gst_buffer_unref (buf);
5194 bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
5195 extract_initial_length_and_fourcc (bdata, 16, length, &lfourcc);
5196 gst_buffer_unmap (buf, bdata, bsize);
5197 gst_buffer_unref (buf);
5199 if (G_UNLIKELY (*length == 0)) {
5200 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5201 ret = GST_FLOW_ERROR;
5205 if (lfourcc == fourcc) {
5206 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5210 GST_LOG_OBJECT (qtdemux,
5211 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5212 GST_FOURCC_ARGS (fourcc), *offset);
5221 /* might simply have had last one */
5222 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5227 /* should only do something in pull mode */
5228 /* call with OBJECT lock */
5229 static GstFlowReturn
5230 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5232 guint64 length, offset;
5233 GstBuffer *buf = NULL;
5234 GstFlowReturn ret = GST_FLOW_OK;
5235 GstFlowReturn res = GST_FLOW_OK;
5239 offset = qtdemux->moof_offset;
5240 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5243 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5244 return GST_FLOW_EOS;
5247 /* best not do pull etc with lock held */
5248 GST_OBJECT_UNLOCK (qtdemux);
5250 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5251 if (ret != GST_FLOW_OK)
5254 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5255 if (G_UNLIKELY (ret != GST_FLOW_OK))
5257 bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
5258 if (!qtdemux_parse_moof (qtdemux, bdata, bsize, offset, NULL)) {
5259 gst_buffer_unmap (buf, bdata, bsize);
5260 gst_buffer_unref (buf);
5265 gst_buffer_unmap (buf, bdata, bsize);
5266 gst_buffer_unref (buf);
5270 /* look for next moof */
5271 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5272 if (G_UNLIKELY (ret != GST_FLOW_OK))
5276 GST_OBJECT_LOCK (qtdemux);
5278 qtdemux->moof_offset = offset;
5284 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5286 res = GST_FLOW_ERROR;
5291 /* maybe upstream temporarily flushing */
5292 if (ret != GST_FLOW_WRONG_STATE) {
5293 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5296 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5297 /* resume at current position next time */
5304 /* initialise bytereaders for stbl sub-atoms */
5306 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5308 stream->stbl_index = -1; /* no samples have yet been parsed */
5310 /* time-to-sample atom */
5311 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5314 /* copy atom data into a new buffer for later use */
5315 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5317 /* skip version + flags */
5318 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5319 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5321 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5323 /* make sure there's enough data */
5324 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
5325 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
5326 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
5327 stream->n_sample_times);
5328 if (!stream->n_sample_times)
5332 /* sync sample atom */
5333 stream->stps_present = FALSE;
5334 if ((stream->stss_present =
5335 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5336 &stream->stss) ? TRUE : FALSE) == TRUE) {
5337 /* copy atom data into a new buffer for later use */
5338 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5340 /* skip version + flags */
5341 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5342 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5345 if (stream->n_sample_syncs) {
5346 /* make sure there's enough data */
5347 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5351 /* partial sync sample atom */
5352 if ((stream->stps_present =
5353 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5354 &stream->stps) ? TRUE : FALSE) == TRUE) {
5355 /* copy atom data into a new buffer for later use */
5356 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5358 /* skip version + flags */
5359 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5360 !gst_byte_reader_get_uint32_be (&stream->stps,
5361 &stream->n_sample_partial_syncs))
5364 /* if there are no entries, the stss table contains the real
5366 if (stream->n_sample_partial_syncs) {
5367 /* make sure there's enough data */
5368 if (!qt_atom_parser_has_chunks (&stream->stps,
5369 stream->n_sample_partial_syncs, 4))
5376 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5379 /* copy atom data into a new buffer for later use */
5380 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5382 /* skip version + flags */
5383 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5384 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5387 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5390 if (!stream->n_samples)
5393 /* sample-to-chunk atom */
5394 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5397 /* copy atom data into a new buffer for later use */
5398 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5400 /* skip version + flags */
5401 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5402 !gst_byte_reader_get_uint32_be (&stream->stsc,
5403 &stream->n_samples_per_chunk))
5406 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5407 stream->n_samples_per_chunk);
5409 /* make sure there's enough data */
5410 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5416 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5417 stream->co_size = sizeof (guint32);
5418 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5420 stream->co_size = sizeof (guint64);
5424 /* copy atom data into a new buffer for later use */
5425 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5427 /* skip version + flags */
5428 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5431 /* chunks_are_chunks == 0 means treat chunks as samples */
5432 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5433 if (stream->chunks_are_chunks) {
5434 /* skip number of entries */
5435 if (!gst_byte_reader_skip (&stream->stco, 4))
5438 /* make sure there are enough data in the stsz atom */
5439 if (!stream->sample_size) {
5440 /* different sizes for each sample */
5441 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5445 /* treat chunks as samples */
5446 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5450 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5451 stream->n_samples, (guint) sizeof (QtDemuxSample),
5452 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5454 if (stream->n_samples >=
5455 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5456 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5457 "be larger than %uMB (broken file?)", stream->n_samples,
5458 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5462 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5463 if (!stream->samples) {
5464 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5470 /* composition time-to-sample */
5471 if ((stream->ctts_present =
5472 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5473 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5474 /* copy atom data into a new buffer for later use */
5475 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5477 /* skip version + flags */
5478 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5479 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5480 &stream->n_composition_times))
5483 /* make sure there's enough data */
5484 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5493 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5494 (_("This file is corrupt and cannot be played.")), (NULL));
5499 gst_qtdemux_stbl_free (stream);
5500 if (!qtdemux->fragmented) {
5501 /* not quite good */
5502 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5505 /* may pick up samples elsewhere */
5511 /* collect samples from the next sample to be parsed up to sample @n for @stream
5512 * by reading the info from @stbl
5514 * This code can be executed from both the streaming thread and the seeking
5515 * thread so it takes the object lock to protect itself
5518 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
5521 QtDemuxSample *samples, *first, *cur, *last;
5522 guint32 n_samples_per_chunk;
5525 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
5526 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
5527 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
5529 n_samples = stream->n_samples;
5532 goto out_of_samples;
5534 GST_OBJECT_LOCK (qtdemux);
5535 if (n <= stream->stbl_index)
5536 goto already_parsed;
5538 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
5540 if (!stream->stsz.data) {
5541 /* so we already parsed and passed all the moov samples;
5542 * onto fragmented ones */
5543 g_assert (qtdemux->fragmented);
5547 /* pointer to the sample table */
5548 samples = stream->samples;
5550 /* starts from -1, moves to the next sample index to parse */
5551 stream->stbl_index++;
5553 /* keep track of the first and last sample to fill */
5554 first = &samples[stream->stbl_index];
5557 if (stream->chunks_are_chunks) {
5558 /* set the sample sizes */
5559 if (stream->sample_size == 0) {
5560 /* different sizes for each sample */
5561 for (cur = first; cur <= last; cur++) {
5562 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
5563 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
5564 (guint) (cur - samples), cur->size);
5567 /* samples have the same size */
5568 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
5569 for (cur = first; cur <= last; cur++)
5570 cur->size = stream->sample_size;
5574 n_samples_per_chunk = stream->n_samples_per_chunk;
5577 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
5580 if (stream->stsc_chunk_index >= stream->last_chunk
5581 || stream->stsc_chunk_index < stream->first_chunk) {
5582 stream->first_chunk =
5583 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5584 stream->samples_per_chunk =
5585 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5586 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
5588 /* chunk numbers are counted from 1 it seems */
5589 if (G_UNLIKELY (stream->first_chunk == 0))
5592 --stream->first_chunk;
5594 /* the last chunk of each entry is calculated by taking the first chunk
5595 * of the next entry; except if there is no next, where we fake it with
5597 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
5598 stream->last_chunk = G_MAXUINT32;
5600 stream->last_chunk =
5601 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
5602 if (G_UNLIKELY (stream->last_chunk == 0))
5605 --stream->last_chunk;
5608 GST_LOG_OBJECT (qtdemux,
5609 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
5610 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
5612 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
5615 if (stream->last_chunk != G_MAXUINT32) {
5616 if (!qt_atom_parser_peek_sub (&stream->stco,
5617 stream->first_chunk * stream->co_size,
5618 (stream->last_chunk - stream->first_chunk) * stream->co_size,
5623 stream->co_chunk = stream->stco;
5624 if (!gst_byte_reader_skip (&stream->co_chunk,
5625 stream->first_chunk * stream->co_size))
5629 stream->stsc_chunk_index = stream->first_chunk;
5632 last_chunk = stream->last_chunk;
5634 if (stream->chunks_are_chunks) {
5635 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5636 guint32 samples_per_chunk;
5637 guint64 chunk_offset;
5639 if (!stream->stsc_sample_index
5640 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
5641 &stream->chunk_offset))
5644 samples_per_chunk = stream->samples_per_chunk;
5645 chunk_offset = stream->chunk_offset;
5647 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
5648 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
5649 G_GUINT64_FORMAT, (guint) (cur - samples), stream->chunk_offset);
5651 cur->offset = chunk_offset;
5652 chunk_offset += cur->size;
5655 if (G_UNLIKELY (cur > last)) {
5657 stream->stsc_sample_index = k + 1;
5658 stream->chunk_offset = chunk_offset;
5659 stream->stsc_chunk_index = j;
5663 stream->stsc_sample_index = 0;
5665 stream->stsc_chunk_index = j;
5667 cur = &samples[stream->stsc_chunk_index];
5669 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5672 stream->stsc_chunk_index = j;
5677 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
5680 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
5681 "%" G_GUINT64_FORMAT, j, cur->offset);
5683 if (stream->samples_per_frame * stream->bytes_per_frame) {
5685 (stream->samples_per_chunk * stream->n_channels) /
5686 stream->samples_per_frame * stream->bytes_per_frame;
5688 cur->size = stream->samples_per_chunk;
5691 GST_DEBUG_OBJECT (qtdemux,
5692 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
5693 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
5694 GST_SECOND, stream->timescale)), cur->size);
5696 cur->timestamp = stream->stco_sample_index;
5697 cur->duration = stream->samples_per_chunk;
5698 cur->keyframe = TRUE;
5701 stream->stco_sample_index += stream->samples_per_chunk;
5703 stream->stsc_chunk_index = j;
5705 stream->stsc_index++;
5708 if (!stream->chunks_are_chunks)
5712 guint32 n_sample_times;
5714 n_sample_times = stream->n_sample_times;
5717 for (i = stream->stts_index; i < n_sample_times; i++) {
5718 guint32 stts_samples;
5719 gint32 stts_duration;
5722 if (stream->stts_sample_index >= stream->stts_samples
5723 || !stream->stts_sample_index) {
5725 stream->stts_samples =
5726 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5727 stream->stts_duration =
5728 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5730 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
5731 i, stream->stts_samples, stream->stts_duration);
5733 stream->stts_sample_index = 0;
5736 stts_samples = stream->stts_samples;
5737 stts_duration = stream->stts_duration;
5738 stts_time = stream->stts_time;
5740 for (j = stream->stts_sample_index; j < stts_samples; j++) {
5741 GST_DEBUG_OBJECT (qtdemux,
5742 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
5743 (guint) (cur - samples), j,
5744 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
5745 stream->timescale)));
5747 cur->timestamp = stts_time;
5748 cur->duration = stts_duration;
5750 /* avoid 32-bit wrap-around,
5751 * but still mind possible 'negative' duration */
5752 stts_time += (gint64) stts_duration;
5755 if (G_UNLIKELY (cur > last)) {
5757 stream->stts_time = stts_time;
5758 stream->stts_sample_index = j + 1;
5762 stream->stts_sample_index = 0;
5763 stream->stts_time = stts_time;
5764 stream->stts_index++;
5766 /* fill up empty timestamps with the last timestamp, this can happen when
5767 * the last samples do not decode and so we don't have timestamps for them.
5768 * We however look at the last timestamp to estimate the track length so we
5769 * need something in here. */
5770 for (; cur < last; cur++) {
5771 GST_DEBUG_OBJECT (qtdemux,
5772 "fill sample %d: timestamp %" GST_TIME_FORMAT,
5773 (guint) (cur - samples),
5774 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
5775 stream->timescale)));
5776 cur->timestamp = stream->stts_time;
5782 /* sample sync, can be NULL */
5783 if (stream->stss_present == TRUE) {
5784 guint32 n_sample_syncs;
5786 n_sample_syncs = stream->n_sample_syncs;
5788 if (!n_sample_syncs) {
5789 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
5790 stream->all_keyframe = TRUE;
5792 for (i = stream->stss_index; i < n_sample_syncs; i++) {
5793 /* note that the first sample is index 1, not 0 */
5796 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
5798 if (G_LIKELY (index > 0 && index <= n_samples)) {
5800 samples[index].keyframe = TRUE;
5801 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5802 /* and exit if we have enough samples */
5803 if (G_UNLIKELY (index >= n)) {
5810 stream->stss_index = i;
5813 /* stps marks partial sync frames like open GOP I-Frames */
5814 if (stream->stps_present == TRUE) {
5815 guint32 n_sample_partial_syncs;
5817 n_sample_partial_syncs = stream->n_sample_partial_syncs;
5819 /* if there are no entries, the stss table contains the real
5821 if (n_sample_partial_syncs) {
5822 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
5823 /* note that the first sample is index 1, not 0 */
5826 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
5828 if (G_LIKELY (index > 0 && index <= n_samples)) {
5830 samples[index].keyframe = TRUE;
5831 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5832 /* and exit if we have enough samples */
5833 if (G_UNLIKELY (index >= n)) {
5840 stream->stps_index = i;
5844 /* no stss, all samples are keyframes */
5845 stream->all_keyframe = TRUE;
5846 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
5851 /* composition time to sample */
5852 if (stream->ctts_present == TRUE) {
5853 guint32 n_composition_times;
5855 gint32 ctts_soffset;
5857 /* Fill in the pts_offsets */
5859 n_composition_times = stream->n_composition_times;
5861 for (i = stream->ctts_index; i < n_composition_times; i++) {
5862 if (stream->ctts_sample_index >= stream->ctts_count
5863 || !stream->ctts_sample_index) {
5864 stream->ctts_count =
5865 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
5866 stream->ctts_soffset =
5867 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
5868 stream->ctts_sample_index = 0;
5871 ctts_count = stream->ctts_count;
5872 ctts_soffset = stream->ctts_soffset;
5874 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
5875 cur->pts_offset = ctts_soffset;
5878 if (G_UNLIKELY (cur > last)) {
5880 stream->ctts_sample_index = j + 1;
5884 stream->ctts_sample_index = 0;
5885 stream->ctts_index++;
5889 stream->stbl_index = n;
5890 /* if index has been completely parsed, free data that is no-longer needed */
5891 if (n + 1 == stream->n_samples) {
5892 gst_qtdemux_stbl_free (stream);
5893 GST_DEBUG_OBJECT (qtdemux,
5894 "parsed all available samples; checking for more");
5895 while (n + 1 == stream->n_samples)
5896 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
5899 GST_OBJECT_UNLOCK (qtdemux);
5906 GST_LOG_OBJECT (qtdemux,
5907 "Tried to parse up to sample %u but this sample has already been parsed",
5909 /* if fragmented, there may be more */
5910 if (qtdemux->fragmented && n == stream->stbl_index)
5912 GST_OBJECT_UNLOCK (qtdemux);
5918 GST_LOG_OBJECT (qtdemux,
5919 "Tried to parse up to sample %u but there are only %u samples", n + 1,
5921 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5922 (_("This file is corrupt and cannot be played.")), (NULL));
5927 GST_OBJECT_UNLOCK (qtdemux);
5928 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5929 (_("This file is corrupt and cannot be played.")), (NULL));
5934 /* collect all segment info for @stream.
5937 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
5942 /* parse and prepare segment info from the edit list */
5943 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
5944 stream->n_segments = 0;
5945 stream->segments = NULL;
5946 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
5950 guint64 time, stime;
5953 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
5954 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
5957 buffer = elst->data;
5959 n_segments = QT_UINT32 (buffer + 12);
5961 /* we might allocate a bit too much, at least allocate 1 segment */
5962 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
5964 /* segments always start from 0 */
5968 for (i = 0; i < n_segments; i++) {
5971 QtDemuxSegment *segment;
5974 media_time = QT_UINT32 (buffer + 20 + i * 12);
5976 /* -1 media time is an empty segment, just ignore it */
5977 if (media_time == G_MAXUINT32)
5980 duration = QT_UINT32 (buffer + 16 + i * 12);
5982 segment = &stream->segments[count++];
5984 /* time and duration expressed in global timescale */
5985 segment->time = stime;
5986 /* add non scaled values so we don't cause roundoff errors */
5988 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
5989 segment->stop_time = stime;
5990 segment->duration = stime - segment->time;
5991 /* media_time expressed in stream timescale */
5992 segment->media_start =
5993 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
5994 segment->media_stop = segment->media_start + segment->duration;
5995 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
5997 if (rate_int <= 1) {
5998 /* 0 is not allowed, some programs write 1 instead of the floating point
6000 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
6004 segment->rate = rate_int / 65536.0;
6007 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
6008 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
6009 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
6010 GST_TIME_ARGS (segment->duration),
6011 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
6013 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
6014 stream->n_segments = count;
6018 /* push based does not handle segments, so act accordingly here,
6019 * and warn if applicable */
6020 if (!qtdemux->pullbased) {
6021 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
6022 /* remove and use default one below, we stream like it anyway */
6023 g_free (stream->segments);
6024 stream->segments = NULL;
6025 stream->n_segments = 0;
6028 /* no segments, create one to play the complete trak */
6029 if (stream->n_segments == 0) {
6030 GstClockTime stream_duration =
6031 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6033 if (stream->segments == NULL)
6034 stream->segments = g_new (QtDemuxSegment, 1);
6036 /* represent unknown our way */
6037 if (stream_duration == 0)
6038 stream_duration = -1;
6040 stream->segments[0].time = 0;
6041 stream->segments[0].stop_time = stream_duration;
6042 stream->segments[0].duration = stream_duration;
6043 stream->segments[0].media_start = 0;
6044 stream->segments[0].media_stop = stream_duration;
6045 stream->segments[0].rate = 1.0;
6047 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6048 GST_TIME_ARGS (stream_duration));
6049 stream->n_segments = 1;
6051 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6057 * Parses the stsd atom of a svq3 trak looking for
6058 * the SMI and gama atoms.
6061 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6062 guint8 ** gamma, GstBuffer ** seqh)
6064 guint8 *_gamma = NULL;
6065 GstBuffer *_seqh = NULL;
6066 guint8 *stsd_data = stsd->data;
6067 guint32 length = QT_UINT32 (stsd_data);
6071 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6077 version = QT_UINT16 (stsd_data);
6082 while (length > 8) {
6083 guint32 fourcc, size;
6085 size = QT_UINT32 (stsd_data);
6086 fourcc = QT_FOURCC (stsd_data + 4);
6087 data = stsd_data + 8;
6094 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6095 " for gama atom, expected 12", size);
6100 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6102 if (_seqh != NULL) {
6103 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6104 " found, ignoring");
6106 seqh_size = QT_UINT32 (data + 4);
6107 if (seqh_size > 0) {
6108 _seqh = gst_buffer_new_and_alloc (seqh_size);
6109 _gst_buffer_copy_into_mem (_seqh, data + 8, 0, seqh_size);
6116 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6117 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6121 if (size <= length) {
6127 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6130 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6131 G_GUINT16_FORMAT, version);
6142 gst_buffer_unref (_seqh);
6147 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6154 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6155 * atom that might contain a 'data' atom with the rtsp uri.
6156 * This case was reported in bug #597497, some info about
6157 * the hndl atom can be found in TN1195
6159 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6160 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6163 guint32 dref_num_entries = 0;
6164 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6165 gst_byte_reader_skip (&dref, 4) &&
6166 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6169 /* search dref entries for hndl atom */
6170 for (i = 0; i < dref_num_entries; i++) {
6171 guint32 size = 0, type;
6172 guint8 string_len = 0;
6173 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6174 qt_atom_parser_get_fourcc (&dref, &type)) {
6175 if (type == FOURCC_hndl) {
6176 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6178 /* skip data reference handle bytes and the
6179 * following pascal string and some extra 4
6180 * bytes I have no idea what are */
6181 if (!gst_byte_reader_skip (&dref, 4) ||
6182 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6183 !gst_byte_reader_skip (&dref, string_len + 4)) {
6184 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6188 /* iterate over the atoms to find the data atom */
6189 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6193 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6194 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6195 if (atom_type == FOURCC_data) {
6196 const guint8 *uri_aux = NULL;
6198 /* found the data atom that might contain the rtsp uri */
6199 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6200 "hndl atom, interpreting it as an URI");
6201 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6203 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6204 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6206 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6207 "didn't contain a rtsp address");
6209 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6214 /* skipping to the next entry */
6215 gst_byte_reader_skip (&dref, atom_size - 8);
6217 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6224 /* skip to the next entry */
6225 gst_byte_reader_skip (&dref, size - 8);
6227 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6230 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6237 less_than (gconstpointer a, gconstpointer b)
6239 const guint32 *av = a, *bv = b;
6244 #define AMR_NB_ALL_MODES 0x81ff
6245 #define AMR_WB_ALL_MODES 0x83ff
6247 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
6249 /* The 'damr' atom is of the form:
6251 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
6252 * 32 b 8 b 16 b 8 b 8 b
6254 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
6255 * represents the highest mode used in the stream (and thus the maximum
6256 * bitrate), with a couple of special cases as seen below.
6259 /* Map of frame type ID -> bitrate */
6260 static const guint nb_bitrates[] = {
6261 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
6263 static const guint wb_bitrates[] = {
6264 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
6267 gsize size, max_mode;
6270 data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
6273 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, size);
6277 if (QT_FOURCC (data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
6278 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
6279 GST_FOURCC_ARGS (QT_UINT32 (data + 4)));
6283 mode_set = QT_UINT16 (data + 13);
6285 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
6286 max_mode = 7 + (wb ? 1 : 0);
6288 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
6289 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
6291 if (max_mode == -1) {
6292 GST_DEBUG ("No mode indication was found (mode set) = %x",
6297 gst_buffer_unmap (buf, data, size);
6298 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
6301 gst_buffer_unmap (buf, data, size);
6306 * With each track we associate a new QtDemuxStream that contains all the info
6308 * traks that do not decode to something (like strm traks) will not have a pad.
6311 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6326 QtDemuxStream *stream;
6327 GstTagList *list = NULL;
6328 gchar *codec = NULL;
6329 const guint8 *stsd_data;
6330 guint16 lang_code; /* quicktime lang code or packed iso code */
6332 guint32 tkhd_flags = 0;
6333 guint8 tkhd_version = 0;
6335 guint value_size, len;
6337 stream = g_new0 (QtDemuxStream, 1);
6338 /* new streams always need a discont */
6339 stream->discont = TRUE;
6340 /* we enable clipping for raw audio/video streams */
6341 stream->need_clip = FALSE;
6342 stream->need_process = FALSE;
6343 stream->segment_index = -1;
6344 stream->time_position = 0;
6345 stream->sample_index = -1;
6346 stream->last_ret = GST_FLOW_OK;
6348 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6349 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6350 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6353 /* pick between 64 or 32 bits */
6354 value_size = tkhd_version == 1 ? 8 : 4;
6355 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6356 !gst_byte_reader_get_uint32_be (&tkhd, &stream->track_id))
6359 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6360 tkhd_version, tkhd_flags, stream->track_id);
6362 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6365 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6366 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6367 if (qtdemux->major_brand != FOURCC_mjp2 ||
6368 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6372 len = QT_UINT32 ((guint8 *) mdhd->data);
6373 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6374 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6375 if (version == 0x01000000) {
6378 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6379 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6380 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6384 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6385 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6386 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6389 if (lang_code < 0x800) {
6390 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6392 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6393 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6394 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6395 stream->lang_id[3] = 0;
6398 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6400 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6402 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6403 lang_code, stream->lang_id);
6405 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6408 /* fragmented files may have bogus duration in moov */
6409 if (!qtdemux->fragmented &&
6410 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6411 guint64 tdur1, tdur2;
6413 /* don't overflow */
6414 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6415 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6418 * some of those trailers, nowadays, have prologue images that are
6419 * themselves vide tracks as well. I haven't really found a way to
6420 * identify those yet, except for just looking at their duration. */
6421 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6422 GST_WARNING_OBJECT (qtdemux,
6423 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6424 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6425 "found, assuming preview image or something; skipping track",
6426 stream->duration, stream->timescale, qtdemux->duration,
6427 qtdemux->timescale);
6433 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6436 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6437 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6439 len = QT_UINT32 ((guint8 *) hdlr->data);
6441 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6442 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6443 GST_FOURCC_ARGS (stream->subtype));
6445 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6448 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6452 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6454 stsd_data = (const guint8 *) stsd->data;
6456 /* stsd should at least have one entry */
6457 len = QT_UINT32 (stsd_data);
6461 /* and that entry should fit within stsd */
6462 len = QT_UINT32 (stsd_data + 16);
6463 if (len > QT_UINT32 (stsd_data) + 16)
6465 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6467 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6468 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6469 GST_FOURCC_ARGS (stream->fourcc));
6471 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6472 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6473 goto error_encrypted;
6475 if (stream->subtype == FOURCC_vide) {
6476 guint32 w = 0, h = 0;
6478 stream->sampled = TRUE;
6480 /* version 1 uses some 64-bit ints */
6481 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6482 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6483 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6486 stream->display_width = w >> 16;
6487 stream->display_height = h >> 16;
6493 stream->width = QT_UINT16 (stsd_data + offset + 32);
6494 stream->height = QT_UINT16 (stsd_data + offset + 34);
6495 stream->fps_n = 0; /* this is filled in later */
6496 stream->fps_d = 0; /* this is filled in later */
6497 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6498 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6500 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6501 QT_UINT16 (stsd_data + offset + 48));
6504 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6506 list = gst_tag_list_new_empty ();
6507 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6508 GST_TAG_VIDEO_CODEC, codec, NULL);
6515 /* pick 'the' stsd child */
6516 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
6518 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
6519 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
6523 const guint8 *pasp_data = (const guint8 *) pasp->data;
6525 stream->par_w = QT_UINT32 (pasp_data + 8);
6526 stream->par_h = QT_UINT32 (pasp_data + 12);
6533 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
6538 gint len = QT_UINT32 (stsd_data) - 0x66;
6539 const guint8 *avc_data = stsd_data + 0x66;
6542 while (len >= 0x8) {
6545 if (QT_UINT32 (avc_data) <= len)
6546 size = QT_UINT32 (avc_data) - 0x8;
6551 /* No real data, so break out */
6554 switch (QT_FOURCC (avc_data + 0x4)) {
6557 /* parse, if found */
6560 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
6562 /* First 4 bytes are the length of the atom, the next 4 bytes
6563 * are the fourcc, the next 1 byte is the version, and the
6564 * subsequent bytes are sequence parameter set like data. */
6565 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
6566 avc_data + 8 + 1, size - 1);
6568 buf = gst_buffer_new_and_alloc (size);
6569 _gst_buffer_copy_into_mem (buf, avc_data + 0x8, 0, size);
6570 gst_caps_set_simple (stream->caps,
6571 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6572 gst_buffer_unref (buf);
6578 guint avg_bitrate, max_bitrate;
6580 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
6584 max_bitrate = QT_UINT32 (avc_data + 0xc);
6585 avg_bitrate = QT_UINT32 (avc_data + 0x10);
6587 if (!max_bitrate && !avg_bitrate)
6590 /* Some muxers seem to swap the average and maximum bitrates
6591 * (I'm looking at you, YouTube), so we swap for sanity. */
6592 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
6593 guint temp = avg_bitrate;
6595 avg_bitrate = max_bitrate;
6600 list = gst_tag_list_new_empty ();
6602 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6603 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6604 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6606 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6607 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6608 GST_TAG_BITRATE, avg_bitrate, NULL);
6619 avc_data += size + 8;
6631 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
6632 GST_FOURCC_ARGS (fourcc));
6634 /* codec data might be in glbl extension atom */
6636 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
6642 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
6644 len = QT_UINT32 (data);
6647 buf = gst_buffer_new_and_alloc (len);
6648 _gst_buffer_copy_into_mem (buf, data + 8, 0, len);
6649 gst_caps_set_simple (stream->caps,
6650 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6651 gst_buffer_unref (buf);
6658 /* see annex I of the jpeg2000 spec */
6659 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
6661 const gchar *colorspace = NULL;
6663 guint32 ncomp_map = 0;
6664 gint32 *comp_map = NULL;
6665 guint32 nchan_def = 0;
6666 gint32 *chan_def = NULL;
6668 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
6669 /* some required atoms */
6670 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
6673 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
6677 /* number of components; redundant with info in codestream, but useful
6679 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
6680 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
6682 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
6684 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
6687 GST_DEBUG_OBJECT (qtdemux, "found colr");
6688 /* extract colour space info */
6689 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
6690 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
6692 colorspace = "sRGB";
6695 colorspace = "GRAY";
6698 colorspace = "sYUV";
6706 /* colr is required, and only values 16, 17, and 18 are specified,
6707 so error if we have no colorspace */
6710 /* extract component mapping */
6711 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
6713 guint32 cmap_len = 0;
6715 cmap_len = QT_UINT32 (cmap->data);
6716 if (cmap_len >= 8) {
6717 /* normal box, subtract off header */
6719 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
6720 if (cmap_len % 4 == 0) {
6721 ncomp_map = (cmap_len / 4);
6722 comp_map = g_new0 (gint32, ncomp_map);
6723 for (i = 0; i < ncomp_map; i++) {
6726 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
6727 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
6728 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
6729 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
6734 /* extract channel definitions */
6735 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
6737 guint32 cdef_len = 0;
6739 cdef_len = QT_UINT32 (cdef->data);
6740 if (cdef_len >= 10) {
6741 /* normal box, subtract off header and len */
6743 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
6744 if (cdef_len % 6 == 0) {
6745 nchan_def = (cdef_len / 6);
6746 chan_def = g_new0 (gint32, nchan_def);
6747 for (i = 0; i < nchan_def; i++)
6749 for (i = 0; i < nchan_def; i++) {
6750 guint16 cn, typ, asoc;
6751 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
6752 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
6753 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
6754 if (cn < nchan_def) {
6757 chan_def[cn] = asoc;
6760 chan_def[cn] = 0; /* alpha */
6763 chan_def[cn] = -typ;
6771 gst_caps_set_simple (stream->caps,
6772 "num-components", G_TYPE_INT, ncomp, NULL);
6773 gst_caps_set_simple (stream->caps,
6774 "colorspace", G_TYPE_STRING, colorspace, NULL);
6777 GValue arr = { 0, };
6778 GValue elt = { 0, };
6780 g_value_init (&arr, GST_TYPE_ARRAY);
6781 g_value_init (&elt, G_TYPE_INT);
6782 for (i = 0; i < ncomp_map; i++) {
6783 g_value_set_int (&elt, comp_map[i]);
6784 gst_value_array_append_value (&arr, &elt);
6786 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6787 "component-map", &arr);
6788 g_value_unset (&elt);
6789 g_value_unset (&arr);
6794 GValue arr = { 0, };
6795 GValue elt = { 0, };
6797 g_value_init (&arr, GST_TYPE_ARRAY);
6798 g_value_init (&elt, G_TYPE_INT);
6799 for (i = 0; i < nchan_def; i++) {
6800 g_value_set_int (&elt, chan_def[i]);
6801 gst_value_array_append_value (&arr, &elt);
6803 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6804 "channel-definitions", &arr);
6805 g_value_unset (&elt);
6806 g_value_unset (&arr);
6810 /* some optional atoms */
6811 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
6812 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
6814 /* indicate possible fields in caps */
6816 data = (guint8 *) field->data + 8;
6818 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
6819 (gint) * data, NULL);
6821 /* add codec_data if provided */
6826 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
6827 data = prefix->data;
6828 len = QT_UINT32 (data);
6831 buf = gst_buffer_new_and_alloc (len);
6832 _gst_buffer_copy_into_mem (buf, data + 8, 0, len);
6833 gst_caps_set_simple (stream->caps,
6834 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6835 gst_buffer_unref (buf);
6844 GstBuffer *seqh = NULL;
6845 guint8 *gamma_data = NULL;
6846 gint len = QT_UINT32 (stsd_data);
6848 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
6850 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
6851 QT_FP32 (gamma_data), NULL);
6854 /* sorry for the bad name, but we don't know what this is, other
6855 * than its own fourcc */
6856 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
6860 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
6861 buf = gst_buffer_new_and_alloc (len);
6862 _gst_buffer_copy_into_mem (buf, stsd_data, 0, len);
6863 gst_caps_set_simple (stream->caps,
6864 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6865 gst_buffer_unref (buf);
6870 gst_caps_set_simple (stream->caps,
6871 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
6878 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
6879 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
6883 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
6887 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
6888 /* collect the headers and store them in a stream list so that we can
6889 * send them out first */
6890 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
6900 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
6901 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
6904 ovc1_data = ovc1->data;
6905 ovc1_len = QT_UINT32 (ovc1_data);
6906 if (ovc1_len <= 198) {
6907 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
6910 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
6911 _gst_buffer_copy_into_mem (buf, ovc1_data + 198, 0, ovc1_len - 198);
6912 gst_caps_set_simple (stream->caps,
6913 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6914 gst_buffer_unref (buf);
6922 GST_INFO_OBJECT (qtdemux,
6923 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
6924 GST_FOURCC_ARGS (fourcc), stream->caps);
6926 } else if (stream->subtype == FOURCC_soun) {
6927 int version, samplesize;
6928 guint16 compression_id;
6929 gboolean amrwb = FALSE;
6935 version = QT_UINT32 (stsd_data + offset);
6936 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
6937 samplesize = QT_UINT16 (stsd_data + offset + 10);
6938 compression_id = QT_UINT16 (stsd_data + offset + 12);
6939 stream->rate = QT_FP32 (stsd_data + offset + 16);
6941 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
6942 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
6943 QT_UINT32 (stsd_data + offset + 4));
6944 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
6945 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
6946 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
6947 GST_LOG_OBJECT (qtdemux, "packet size: %d",
6948 QT_UINT16 (stsd_data + offset + 14));
6949 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
6951 if (compression_id == 0xfffe)
6952 stream->sampled = TRUE;
6954 /* first assume uncompressed audio */
6955 stream->bytes_per_sample = samplesize / 8;
6956 stream->samples_per_frame = stream->n_channels;
6957 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
6958 stream->samples_per_packet = stream->samples_per_frame;
6959 stream->bytes_per_packet = stream->bytes_per_sample;
6963 /* Yes, these have to be hard-coded */
6966 stream->samples_per_packet = 6;
6967 stream->bytes_per_packet = 1;
6968 stream->bytes_per_frame = 1 * stream->n_channels;
6969 stream->bytes_per_sample = 1;
6970 stream->samples_per_frame = 6 * stream->n_channels;
6975 stream->samples_per_packet = 3;
6976 stream->bytes_per_packet = 1;
6977 stream->bytes_per_frame = 1 * stream->n_channels;
6978 stream->bytes_per_sample = 1;
6979 stream->samples_per_frame = 3 * stream->n_channels;
6984 stream->samples_per_packet = 64;
6985 stream->bytes_per_packet = 34;
6986 stream->bytes_per_frame = 34 * stream->n_channels;
6987 stream->bytes_per_sample = 2;
6988 stream->samples_per_frame = 64 * stream->n_channels;
6994 stream->samples_per_packet = 1;
6995 stream->bytes_per_packet = 1;
6996 stream->bytes_per_frame = 1 * stream->n_channels;
6997 stream->bytes_per_sample = 1;
6998 stream->samples_per_frame = 1 * stream->n_channels;
7003 stream->samples_per_packet = 160;
7004 stream->bytes_per_packet = 33;
7005 stream->bytes_per_frame = 33 * stream->n_channels;
7006 stream->bytes_per_sample = 2;
7007 stream->samples_per_frame = 160 * stream->n_channels;
7014 if (version == 0x00010000) {
7022 /* only parse extra decoding config for non-pcm audio */
7023 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7024 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
7025 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
7026 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
7028 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7029 stream->samples_per_packet);
7030 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7031 stream->bytes_per_packet);
7032 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
7033 stream->bytes_per_frame);
7034 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
7035 stream->bytes_per_sample);
7037 if (!stream->sampled && stream->bytes_per_packet) {
7038 stream->samples_per_frame = (stream->bytes_per_frame /
7039 stream->bytes_per_packet) * stream->samples_per_packet;
7040 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
7041 stream->samples_per_frame);
7046 } else if (version == 0x00020000) {
7053 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7054 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
7055 stream->rate = qtfp.fp;
7056 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
7058 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7059 stream->samples_per_packet);
7060 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7061 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7064 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
7067 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
7076 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
7078 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
7080 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
7082 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
7085 gst_caps_set_simple (stream->caps,
7086 "format", G_TYPE_STRING, "S24_3LE", NULL);
7093 const guint8 *owma_data;
7094 const gchar *codec_name = NULL;
7098 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
7099 /* FIXME this should also be gst_riff_strf_auds,
7100 * but the latter one is actually missing bits-per-sample :( */
7105 gint32 nSamplesPerSec;
7106 gint32 nAvgBytesPerSec;
7108 gint16 wBitsPerSample;
7113 GST_DEBUG_OBJECT (qtdemux, "parse owma");
7114 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
7117 owma_data = owma->data;
7118 owma_len = QT_UINT32 (owma_data);
7119 if (owma_len <= 54) {
7120 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
7123 wfex = (WAVEFORMATEX *) (owma_data + 36);
7124 buf = gst_buffer_new_and_alloc (owma_len - 54);
7125 _gst_buffer_copy_into_mem (buf, owma_data + 54, 0, owma_len - 54);
7126 if (wfex->wFormatTag == 0x0161) {
7127 codec_name = "Windows Media Audio";
7129 } else if (wfex->wFormatTag == 0x0162) {
7130 codec_name = "Windows Media Audio 9 Pro";
7132 } else if (wfex->wFormatTag == 0x0163) {
7133 codec_name = "Windows Media Audio 9 Lossless";
7134 /* is that correct? gstffmpegcodecmap.c is missing it, but
7135 * fluendo codec seems to support it */
7139 gst_caps_set_simple (stream->caps,
7140 "codec_data", GST_TYPE_BUFFER, buf,
7141 "wmaversion", G_TYPE_INT, version,
7142 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
7143 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
7144 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7145 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7147 gst_buffer_unref (buf);
7151 codec = g_strdup (codec_name);
7163 list = gst_tag_list_new_empty ();
7164 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7165 GST_TAG_AUDIO_CODEC, codec, NULL);
7169 /* some bitrate info may have ended up in caps */
7170 s = gst_caps_get_structure (stream->caps, 0);
7171 gst_structure_get_int (s, "bitrate", &bitrate);
7173 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7177 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7181 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7183 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7185 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7189 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7190 16 bits is a byte-swapped wave-style codec identifier,
7191 and we can find a WAVE header internally to a 'wave' atom here.
7192 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7193 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7196 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7197 if (len < offset + 20) {
7198 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7200 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7201 const guint8 *data = stsd_data + offset + 16;
7203 GNode *waveheadernode;
7205 wavenode = g_node_new ((guint8 *) data);
7206 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7207 const guint8 *waveheader;
7210 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7211 if (waveheadernode) {
7212 waveheader = (const guint8 *) waveheadernode->data;
7213 headerlen = QT_UINT32 (waveheader);
7215 if (headerlen > 8) {
7216 gst_riff_strf_auds *header = NULL;
7217 GstBuffer *headerbuf;
7223 headerbuf = gst_buffer_new_and_alloc (headerlen);
7224 _gst_buffer_copy_into_mem (headerbuf, waveheader, 0, headerlen);
7226 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7227 headerbuf, &header, &extra)) {
7228 gst_caps_unref (stream->caps);
7229 /* FIXME: Need to do something with the channel reorder map */
7230 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7231 header, extra, NULL, NULL, NULL);
7234 gst_buffer_unref (extra);
7238 GST_DEBUG ("Didn't find waveheadernode for this codec");
7240 g_node_destroy (wavenode);
7243 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7247 /* FIXME: what is in the chunk? */
7250 gint len = QT_UINT32 (stsd_data);
7252 /* seems to be always = 116 = 0x74 */
7258 gint len = QT_UINT32 (stsd_data);
7261 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7263 _gst_buffer_copy_into_mem (buf, stsd_data + 0x4C, 0, len - 0x4C);
7264 gst_caps_set_simple (stream->caps,
7265 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7266 gst_buffer_unref (buf);
7268 gst_caps_set_simple (stream->caps,
7269 "samplesize", G_TYPE_INT, samplesize, NULL);
7274 GNode *alac, *wave = NULL;
7276 /* apparently, m4a has this atom appended directly in the stsd entry,
7277 * while mov has it in a wave atom */
7278 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7280 /* alac now refers to stsd entry atom */
7281 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7283 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7285 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7288 gint len = QT_UINT32 (alac->data);
7292 GST_DEBUG_OBJECT (qtdemux,
7293 "discarding alac atom with unexpected len %d", len);
7295 /* codec-data contains alac atom size and prefix,
7296 * ffmpeg likes it that way, not quite gst-ish though ...*/
7297 buf = gst_buffer_new_and_alloc (len);
7298 _gst_buffer_copy_into_mem (buf, alac->data, 0, len);
7299 gst_caps_set_simple (stream->caps,
7300 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7301 gst_buffer_unref (buf);
7304 gst_caps_set_simple (stream->caps,
7305 "samplesize", G_TYPE_INT, samplesize, NULL);
7313 gint len = QT_UINT32 (stsd_data);
7316 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7319 _gst_buffer_copy_into_mem (buf, stsd_data + 0x34, 0, len - 0x34);
7321 /* If we have enough data, let's try to get the 'damr' atom. See
7322 * the 3GPP container spec (26.244) for more details. */
7323 if ((len - 0x34) > 8 &&
7324 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
7326 list = gst_tag_list_new_empty ();
7327 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7328 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
7331 gst_caps_set_simple (stream->caps,
7332 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7333 gst_buffer_unref (buf);
7341 GST_INFO_OBJECT (qtdemux,
7342 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7343 GST_FOURCC_ARGS (fourcc), stream->caps);
7345 } else if (stream->subtype == FOURCC_strm) {
7346 if (fourcc == FOURCC_rtsp) {
7347 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7349 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7350 GST_FOURCC_ARGS (fourcc));
7351 goto unknown_stream;
7353 stream->sampled = TRUE;
7354 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
7356 stream->sampled = TRUE;
7361 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7363 list = gst_tag_list_new_empty ();
7364 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7365 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7370 /* hunt for sort-of codec data */
7377 /* look for palette */
7378 /* target mp4s atom */
7379 len = QT_UINT32 (stsd_data + offset);
7380 data = stsd_data + offset;
7381 /* verify sufficient length,
7382 * and esds present with decConfigDescr of expected size and position */
7383 if ((len >= 106 + 8)
7384 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7385 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7390 /* move to decConfigDescr data */
7391 data = data + 8 + 42;
7392 for (i = 0; i < 16; i++) {
7393 clut[i] = QT_UINT32 (data);
7397 s = gst_structure_new ("application/x-gst-dvd", "event",
7398 G_TYPE_STRING, "dvd-spu-clut-change",
7399 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7400 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7401 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7402 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7403 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7404 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7405 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7406 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7409 /* store event and trigger custom processing */
7410 stream->pending_event =
7411 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7412 stream->need_process = TRUE;
7420 goto unknown_stream;
7423 /* promote to sampled format */
7424 if (stream->fourcc == FOURCC_samr) {
7425 /* force mono 8000 Hz for AMR */
7426 stream->sampled = TRUE;
7427 stream->n_channels = 1;
7428 stream->rate = 8000;
7429 } else if (stream->fourcc == FOURCC_sawb) {
7430 /* force mono 16000 Hz for AMR-WB */
7431 stream->sampled = TRUE;
7432 stream->n_channels = 1;
7433 stream->rate = 16000;
7434 } else if (stream->fourcc == FOURCC_mp4a) {
7435 stream->sampled = TRUE;
7438 /* collect sample information */
7439 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7440 goto samples_failed;
7442 if (qtdemux->fragmented) {
7446 /* need all moov samples as basis; probably not many if any at all */
7447 /* prevent moof parsing taking of at this time */
7448 offset = qtdemux->moof_offset;
7449 qtdemux->moof_offset = 0;
7450 if (stream->n_samples &&
7451 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7452 qtdemux->moof_offset = offset;
7453 goto samples_failed;
7455 qtdemux->moof_offset = 0;
7456 /* movie duration more reliable in this case (e.g. mehd) */
7457 if (qtdemux->segment.duration &&
7458 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7459 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7460 stream->timescale, GST_SECOND);
7461 /* need defaults for fragments */
7462 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7465 /* configure segments */
7466 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7467 goto segments_failed;
7469 /* add some language tag, if useful */
7470 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7471 strcmp (stream->lang_id, "und")) {
7472 const gchar *lang_code;
7475 list = gst_tag_list_new_empty ();
7477 /* convert ISO 639-2 code to ISO 639-1 */
7478 lang_code = gst_tag_get_language_code (stream->lang_id);
7479 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7480 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7483 /* now we are ready to add the stream */
7484 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7485 goto too_many_streams;
7487 stream->pending_tags = list;
7488 qtdemux->streams[qtdemux->n_streams] = stream;
7489 qtdemux->n_streams++;
7490 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7497 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7498 (_("This file is corrupt and cannot be played.")), (NULL));
7504 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7511 /* we posted an error already */
7512 /* free stbl sub-atoms */
7513 gst_qtdemux_stbl_free (stream);
7519 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7520 GST_FOURCC_ARGS (stream->subtype));
7526 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7527 (_("This file contains too many streams. Only playing first %d"),
7528 GST_QTDEMUX_MAX_STREAMS), (NULL));
7533 /* If we can estimate the overall bitrate, and don't have information about the
7534 * stream bitrate for exactly one stream, this guesses the stream bitrate as
7535 * the overall bitrate minus the sum of the bitrates of all other streams. This
7536 * should be useful for the common case where we have one audio and one video
7537 * stream and can estimate the bitrate of one, but not the other. */
7539 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
7541 QtDemuxStream *stream = NULL;
7542 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
7546 if (qtdemux->fragmented)
7549 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
7551 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)) {
7552 GST_DEBUG_OBJECT (qtdemux,
7553 "Size in bytes of the stream not known - bailing");
7557 /* Subtract the header size */
7558 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
7559 size, qtdemux->header_size);
7560 g_assert (size >= qtdemux->header_size);
7561 size = size - qtdemux->header_size;
7563 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
7564 duration == GST_CLOCK_TIME_NONE) {
7565 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
7569 for (i = 0; i < qtdemux->n_streams; i++) {
7570 switch (qtdemux->streams[i]->subtype) {
7573 /* retrieve bitrate, prefer avg then max */
7575 if (qtdemux->streams[i]->pending_tags) {
7576 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7577 GST_TAG_MAXIMUM_BITRATE, &bitrate);
7578 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7579 GST_TAG_BITRATE, &bitrate);
7582 sum_bitrate += bitrate;
7585 GST_DEBUG_OBJECT (qtdemux,
7586 ">1 stream with unknown bitrate - bailing");
7589 stream = qtdemux->streams[i];
7593 /* For other subtypes, we assume no significant impact on bitrate */
7599 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
7603 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
7605 if (sys_bitrate < sum_bitrate) {
7606 /* This can happen, since sum_bitrate might be derived from maximum
7607 * bitrates and not average bitrates */
7608 GST_DEBUG_OBJECT (qtdemux,
7609 "System bitrate less than sum bitrate - bailing");
7613 bitrate = sys_bitrate - sum_bitrate;
7614 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
7615 ", Stream bitrate = %u", sys_bitrate, bitrate);
7617 if (!stream->pending_tags)
7618 stream->pending_tags = gst_tag_list_new_empty ();
7620 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
7621 GST_TAG_BITRATE, bitrate, NULL);
7624 static GstFlowReturn
7625 qtdemux_expose_streams (GstQTDemux * qtdemux)
7628 GstFlowReturn ret = GST_FLOW_OK;
7630 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7632 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7633 QtDemuxStream *stream = qtdemux->streams[i];
7634 guint32 sample_num = 0;
7639 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7640 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7642 if (qtdemux->fragmented) {
7643 /* need all moov samples first */
7644 GST_OBJECT_LOCK (qtdemux);
7645 while (stream->n_samples == 0)
7646 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7648 GST_OBJECT_UNLOCK (qtdemux);
7650 /* discard any stray moof */
7651 qtdemux->moof_offset = 0;
7654 /* prepare braking */
7655 if (ret != GST_FLOW_ERROR)
7658 /* in pull mode, we should have parsed some sample info by now;
7659 * and quite some code will not handle no samples.
7660 * in push mode, we'll just have to deal with it */
7661 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7662 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7663 gst_qtdemux_stream_free (qtdemux, stream);
7664 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7665 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7666 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7667 qtdemux->n_streams--;
7672 /* parse number of initial sample to set frame rate cap */
7673 while (sample_num < stream->n_samples && sample_num < samples) {
7674 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7678 /* collect and sort durations */
7679 samples = MIN (stream->stbl_index + 1, samples);
7680 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7682 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7684 while (sample_num < samples) {
7685 g_array_append_val (durations, stream->samples[sample_num].duration);
7688 g_array_sort (durations, less_than);
7689 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7690 g_array_free (durations, TRUE);
7693 /* now we have all info and can expose */
7694 list = stream->pending_tags;
7695 stream->pending_tags = NULL;
7696 gst_qtdemux_add_stream (qtdemux, stream, list);
7699 gst_qtdemux_guess_bitrate (qtdemux);
7701 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7703 /* check if we should post a redirect in case there is a single trak
7704 * and it is a redirecting trak */
7705 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7708 qtdemux_post_global_tags (qtdemux);
7710 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7711 "an external content");
7712 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7713 gst_structure_new ("redirect",
7714 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7716 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7717 qtdemux->posted_redirect = TRUE;
7723 /* check if major or compatible brand is 3GP */
7724 static inline gboolean
7725 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7728 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7729 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7730 } else if (qtdemux->comp_brands != NULL) {
7733 gboolean res = FALSE;
7735 data = gst_buffer_map (qtdemux->comp_brands, &size, NULL, GST_MAP_READ);
7737 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7738 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7742 gst_buffer_unmap (qtdemux->comp_brands, data, size);
7749 /* check if tag is a spec'ed 3GP tag keyword storing a string */
7750 static inline gboolean
7751 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
7753 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
7754 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
7755 || fourcc == FOURCC_albm;
7759 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
7760 const char *dummy, GNode * node)
7762 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7766 gdouble longitude, latitude, altitude;
7769 len = QT_UINT32 (node->data);
7776 /* TODO: language code skipped */
7778 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
7781 /* do not alarm in trivial case, but bail out otherwise */
7782 if (*(data + offset) != 0) {
7783 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
7787 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7788 GST_TAG_GEO_LOCATION_NAME, name, NULL);
7789 offset += strlen (name);
7793 if (len < offset + 2 + 4 + 4 + 4)
7796 /* +1 +1 = skip null-terminator and location role byte */
7798 /* table in spec says unsigned, semantics say negative has meaning ... */
7799 longitude = QT_SFP32 (data + offset);
7802 latitude = QT_SFP32 (data + offset);
7805 altitude = QT_SFP32 (data + offset);
7807 /* one invalid means all are invalid */
7808 if (longitude >= -180.0 && longitude <= 180.0 &&
7809 latitude >= -90.0 && latitude <= 90.0) {
7810 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7811 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
7812 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
7813 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
7816 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
7823 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
7830 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7837 len = QT_UINT32 (node->data);
7841 y = QT_UINT16 ((guint8 *) node->data + 12);
7843 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
7846 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
7848 date = g_date_new_dmy (1, 1, y);
7849 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
7854 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
7855 const char *dummy, GNode * node)
7858 char *tag_str = NULL;
7863 len = QT_UINT32 (node->data);
7868 entity = (guint8 *) node->data + offset;
7869 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
7870 GST_DEBUG_OBJECT (qtdemux,
7871 "classification info: %c%c%c%c invalid classification entity",
7872 entity[0], entity[1], entity[2], entity[3]);
7877 table = QT_UINT16 ((guint8 *) node->data + offset);
7879 /* Language code skipped */
7883 /* Tag format: "XXXX://Y[YYYY]/classification info string"
7884 * XXXX: classification entity, fixed length 4 chars.
7885 * Y[YYYY]: classification table, max 5 chars.
7887 tag_str = g_strdup_printf ("----://%u/%s",
7888 table, (char *) node->data + offset);
7890 /* memcpy To be sure we're preserving byte order */
7891 memcpy (tag_str, entity, 4);
7892 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
7894 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
7904 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
7910 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
7911 const char *dummy, GNode * node)
7913 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7919 gboolean ret = TRUE;
7921 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7923 len = QT_UINT32 (data->data);
7924 type = QT_UINT32 ((guint8 *) data->data + 8);
7925 if (type == 0x00000001 && len > 16) {
7926 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
7929 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7930 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
7934 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7938 len = QT_UINT32 (node->data);
7939 type = QT_UINT32 ((guint8 *) node->data + 4);
7940 if ((type >> 24) == 0xa9) {
7941 /* Type starts with the (C) symbol, so the next 32 bits are
7942 * the language code, which we ignore */
7944 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
7945 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
7946 QT_FOURCC ((guint8 *) node->data + 4))) {
7947 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
7949 /* we go for 3GP style encoding if major brands claims so,
7950 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
7951 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
7952 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
7953 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
7955 /* 16-bit Language code is ignored here as well */
7956 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
7963 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
7964 ret = FALSE; /* may have to fallback */
7966 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
7967 len - offset, env_vars);
7969 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7970 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
7974 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7981 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
7982 const char *dummy, GNode * node)
7984 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
7988 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
7989 const char *dummy, GNode * node)
7991 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7993 char *s, *t, *k = NULL;
7998 /* first try normal string tag if major brand not 3GP */
7999 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
8000 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
8001 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
8002 * let's try it 3gpp way after minor safety check */
8004 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
8010 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
8014 len = QT_UINT32 (data);
8018 count = QT_UINT8 (data + 14);
8020 for (; count; count--) {
8023 if (offset + 1 > len)
8025 slen = QT_UINT8 (data + offset);
8027 if (offset + slen > len)
8029 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8032 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
8034 t = g_strjoin (",", k, s, NULL);
8042 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
8049 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
8050 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
8059 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
8065 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
8066 const char *tag2, GNode * node)
8073 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8075 len = QT_UINT32 (data->data);
8076 type = QT_UINT32 ((guint8 *) data->data + 8);
8077 if (type == 0x00000000 && len >= 22) {
8078 n1 = QT_UINT16 ((guint8 *) data->data + 18);
8079 n2 = QT_UINT16 ((guint8 *) data->data + 20);
8081 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
8082 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8086 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
8087 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8095 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8103 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8105 len = QT_UINT32 (data->data);
8106 type = QT_UINT32 ((guint8 *) data->data + 8);
8107 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
8108 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8109 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
8110 n1 = QT_UINT16 ((guint8 *) data->data + 16);
8112 /* do not add bpm=0 */
8113 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
8114 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8115 tag1, (gdouble) n1, NULL);
8122 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
8123 const char *dummy, GNode * node)
8130 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8132 len = QT_UINT32 (data->data);
8133 type = QT_UINT32 ((guint8 *) data->data + 8);
8134 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
8135 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8136 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
8137 num = QT_UINT32 ((guint8 *) data->data + 16);
8139 /* do not add num=0 */
8140 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
8141 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8149 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8157 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8159 len = QT_UINT32 (data->data);
8160 type = QT_UINT32 ((guint8 *) data->data + 8);
8161 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
8162 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
8164 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
8165 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
8166 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
8167 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8168 tag1, sample, NULL);
8169 gst_sample_unref (sample);
8176 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8184 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8186 len = QT_UINT32 (data->data);
8187 type = QT_UINT32 ((guint8 *) data->data + 8);
8188 if (type == 0x00000001 && len > 16) {
8189 guint y, m = 1, d = 1;
8192 s = g_strndup ((char *) data->data + 16, len - 16);
8193 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
8194 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
8195 if (ret >= 1 && y > 1500 && y < 3000) {
8198 date = g_date_new_dmy (d, m, y);
8199 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
8203 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
8211 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8216 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8218 /* re-route to normal string tag if major brand says so
8219 * or no data atom and compatible brand suggests so */
8220 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8221 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
8222 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
8229 len = QT_UINT32 (data->data);
8230 type = QT_UINT32 ((guint8 *) data->data + 8);
8231 if (type == 0x00000000 && len >= 18) {
8232 n = QT_UINT16 ((guint8 *) data->data + 16);
8236 genre = gst_tag_id3_genre_get (n - 1);
8237 if (genre != NULL) {
8238 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
8239 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8248 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
8249 guint8 * data, guint32 datasize)
8254 /* make a copy to have \0 at the end */
8255 datacopy = g_strndup ((gchar *) data, datasize);
8257 /* convert the str to double */
8258 if (sscanf (datacopy, "%lf", &value) == 1) {
8259 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
8260 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
8262 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
8270 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
8271 const char *tag_bis, GNode * node)
8280 const gchar *meanstr;
8281 const gchar *namestr;
8283 /* checking the whole ---- atom size for consistency */
8284 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8285 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8289 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8291 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8295 meansize = QT_UINT32 (mean->data);
8296 if (meansize <= 12) {
8297 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8300 meanstr = ((gchar *) mean->data) + 12;
8302 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8304 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8308 namesize = QT_UINT32 (name->data);
8309 if (namesize <= 12) {
8310 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8313 namestr = ((gchar *) name->data) + 12;
8320 * uint24 - data type
8324 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8326 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8329 datasize = QT_UINT32 (data->data);
8330 if (datasize <= 16) {
8331 GST_WARNING_OBJECT (demux, "Data atom too small");
8334 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8336 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8339 const gchar name[28];
8340 const gchar tag[28];
8343 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8344 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8345 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8346 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8347 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8348 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8349 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8350 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8354 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8355 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8356 switch (gst_tag_get_type (tags[i].tag)) {
8358 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8359 ((guint8 *) data->data) + 16, datasize - 16);
8362 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8371 if (i == G_N_ELEMENTS (tags))
8385 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8386 namestr_dbg = g_strndup (namestr, namesize - 12);
8388 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8389 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8391 g_free (namestr_dbg);
8392 g_free (meanstr_dbg);
8398 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
8399 const char *tag_bis, GNode * node)
8404 GstTagList *taglist = NULL;
8406 GST_LOG_OBJECT (demux, "parsing ID32");
8409 len = GST_READ_UINT32_BE (data);
8411 /* need at least full box and language tag */
8415 buf = gst_buffer_new_allocate (NULL, len - 14, 0);
8416 gst_buffer_fill (buf, 0, data + 14, len - 14);
8418 taglist = gst_tag_list_from_id3v2_tag (buf);
8420 GST_LOG_OBJECT (demux, "parsing ok");
8421 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
8423 GST_LOG_OBJECT (demux, "parsing failed");
8427 gst_tag_list_free (taglist);
8429 gst_buffer_unref (buf);
8432 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8433 const char *tag, const char *tag_bis, GNode * node);
8436 FOURCC_pcst -> if media is a podcast -> bool
8437 FOURCC_cpil -> if media is part of a compilation -> bool
8438 FOURCC_pgap -> if media is part of a gapless context -> bool
8439 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8445 const gchar *gst_tag;
8446 const gchar *gst_tag_bis;
8447 const GstQTDemuxAddTagFunc func;
8450 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8451 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8452 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8453 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8454 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8455 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8456 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8457 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8458 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8459 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8460 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8461 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8462 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8463 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8464 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8465 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8466 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8467 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8468 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8469 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8470 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8471 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8472 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8473 qtdemux_tag_add_num}, {
8474 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8475 qtdemux_tag_add_num}, {
8476 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8477 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8478 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8479 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8480 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8481 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8482 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8483 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8484 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8485 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8486 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8487 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8488 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8489 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8490 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8491 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8492 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8493 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8494 qtdemux_tag_add_classification}, {
8496 /* This is a special case, some tags are stored in this
8497 * 'reverse dns naming', according to:
8498 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8501 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
8502 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
8503 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
8507 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8519 len = QT_UINT32 (data);
8520 buf = gst_buffer_new_and_alloc (len);
8521 _gst_buffer_copy_into_mem (buf, data, 0, len);
8523 /* heuristic to determine style of tag */
8524 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8525 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8527 else if (demux->major_brand == FOURCC_qt__)
8528 style = "quicktime";
8529 /* fall back to assuming iso/3gp tag style */
8533 /* santize the name for the caps. */
8534 for (i = 0; i < 4; i++) {
8535 guint8 d = data[4 + i];
8536 if (g_ascii_isalnum (d))
8537 ndata[i] = g_ascii_tolower (d);
8542 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8543 ndata[0], ndata[1], ndata[2], ndata[3]);
8544 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8546 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
8547 // TODO conver to metadata or ???
8548 // gst_buffer_set_caps (buf, caps);
8549 gst_caps_unref (caps);
8550 g_free (media_type);
8552 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
8555 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8556 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
8557 gst_buffer_unref (buf);
8561 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8569 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8571 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8573 GST_LOG_OBJECT (qtdemux, "no ilst");
8578 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8581 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8582 if (!qtdemux->tag_list)
8583 qtdemux->tag_list = gst_tag_list_new_empty ();
8586 while (i < G_N_ELEMENTS (add_funcs)) {
8587 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8591 len = QT_UINT32 (node->data);
8593 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8594 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8596 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8597 add_funcs[i].gst_tag_bis, node);
8599 g_node_destroy (node);
8605 /* parsed nodes have been removed, pass along remainder as blob */
8606 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8607 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8609 /* parse up XMP_ node if existing */
8610 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8613 GstTagList *taglist;
8615 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
8616 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
8617 taglist = gst_tag_list_from_xmp_buffer (buf);
8618 gst_buffer_unref (buf);
8620 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8622 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8629 GstStructure *structure; /* helper for sort function */
8631 guint min_req_bitrate;
8632 guint min_req_qt_version;
8636 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8638 GstQtReference *ref_a = (GstQtReference *) a;
8639 GstQtReference *ref_b = (GstQtReference *) b;
8641 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8642 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8644 /* known bitrates go before unknown; higher bitrates go first */
8645 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8648 /* sort the redirects and post a message for the application.
8651 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8653 GstQtReference *best;
8656 GValue list_val = { 0, };
8659 g_assert (references != NULL);
8661 references = g_list_sort (references, qtdemux_redirects_sort_func);
8663 best = (GstQtReference *) references->data;
8665 g_value_init (&list_val, GST_TYPE_LIST);
8667 for (l = references; l != NULL; l = l->next) {
8668 GstQtReference *ref = (GstQtReference *) l->data;
8669 GValue struct_val = { 0, };
8671 ref->structure = gst_structure_new ("redirect",
8672 "new-location", G_TYPE_STRING, ref->location, NULL);
8674 if (ref->min_req_bitrate > 0) {
8675 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8676 ref->min_req_bitrate, NULL);
8679 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8680 g_value_set_boxed (&struct_val, ref->structure);
8681 gst_value_list_append_value (&list_val, &struct_val);
8682 g_value_unset (&struct_val);
8683 /* don't free anything here yet, since we need best->structure below */
8686 g_assert (best != NULL);
8687 s = gst_structure_copy (best->structure);
8689 if (g_list_length (references) > 1) {
8690 gst_structure_set_value (s, "locations", &list_val);
8693 g_value_unset (&list_val);
8695 for (l = references; l != NULL; l = l->next) {
8696 GstQtReference *ref = (GstQtReference *) l->data;
8698 gst_structure_free (ref->structure);
8699 g_free (ref->location);
8702 g_list_free (references);
8704 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8705 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8706 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8707 qtdemux->posted_redirect = TRUE;
8710 /* look for redirect nodes, collect all redirect information and
8714 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8716 GNode *rmra, *rmda, *rdrf;
8718 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8720 GList *redirects = NULL;
8722 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8724 GstQtReference ref = { NULL, NULL, 0, 0 };
8727 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8728 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8729 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8730 ref.min_req_bitrate);
8733 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
8734 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
8735 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
8737 #ifndef GST_DISABLE_GST_DEBUG
8738 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
8740 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
8742 GST_LOG_OBJECT (qtdemux,
8743 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
8744 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
8745 bitmask, check_type);
8746 if (package == FOURCC_qtim && check_type == 0) {
8747 ref.min_req_qt_version = version;
8751 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
8756 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
8757 ref_data = (guint8 *) rdrf->data + 20;
8758 if (ref_type == FOURCC_alis) {
8759 guint record_len, record_version, fn_len;
8761 /* MacOSX alias record, google for alias-layout.txt */
8762 record_len = QT_UINT16 (ref_data + 4);
8763 record_version = QT_UINT16 (ref_data + 4 + 2);
8764 fn_len = QT_UINT8 (ref_data + 50);
8765 if (record_len > 50 && record_version == 2 && fn_len > 0) {
8766 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
8768 } else if (ref_type == FOURCC_url_) {
8769 ref.location = g_strdup ((gchar *) ref_data);
8771 GST_DEBUG_OBJECT (qtdemux,
8772 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
8773 GST_FOURCC_ARGS (ref_type));
8775 if (ref.location != NULL) {
8776 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
8777 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
8779 GST_WARNING_OBJECT (qtdemux,
8780 "Failed to extract redirect location from rdrf atom");
8784 /* look for others */
8785 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
8788 if (redirects != NULL) {
8789 qtdemux_process_redirects (qtdemux, redirects);
8796 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
8801 tags = gst_tag_list_new_empty ();
8803 if (qtdemux->major_brand == FOURCC_mjp2)
8804 fmt = "Motion JPEG 2000";
8805 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
8807 else if (qtdemux->major_brand == FOURCC_qt__)
8809 else if (qtdemux->fragmented)
8812 fmt = "ISO MP4/M4A";
8814 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
8815 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
8817 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
8823 /* we have read th complete moov node now.
8824 * This function parses all of the relevant info, creates the traks and
8825 * prepares all data structures for playback
8828 qtdemux_parse_tree (GstQTDemux * qtdemux)
8835 guint64 creation_time;
8836 GstDateTime *datetime = NULL;
8839 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
8841 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
8842 return qtdemux_parse_redirects (qtdemux);
8845 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
8847 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
8848 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
8849 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
8850 } else if (version == 0) {
8851 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
8852 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
8853 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
8855 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
8859 /* Moving qt creation time (secs since 1904) to unix time */
8860 if (creation_time != 0) {
8861 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
8864 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
8865 /* some data cleansing sanity */
8866 g_get_current_time (&now);
8867 if (now.tv_sec + 24 * 3600 < creation_time) {
8868 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
8870 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
8873 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
8874 "please file a bug at http://bugzilla.gnome.org");
8878 if (!qtdemux->tag_list)
8879 qtdemux->tag_list = gst_tag_list_new_empty ();
8881 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
8882 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
8884 gst_date_time_unref (datetime);
8887 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
8888 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
8890 /* check for fragmented file and get some (default) data */
8891 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
8894 GstByteReader mehd_data;
8896 /* let track parsing or anyone know weird stuff might happen ... */
8897 qtdemux->fragmented = TRUE;
8899 /* compensate for total duration */
8900 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
8902 qtdemux_parse_mehd (qtdemux, &mehd_data);
8905 /* set duration in the segment info */
8906 gst_qtdemux_get_duration (qtdemux, &duration);
8908 qtdemux->segment.duration = duration;
8909 /* also do not exceed duration; stop is set that way post seek anyway,
8910 * and segment activation falls back to duration,
8911 * whereas loop only checks stop, so let's align this here as well */
8912 qtdemux->segment.stop = duration;
8915 /* parse all traks */
8916 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
8918 qtdemux_parse_trak (qtdemux, trak);
8919 /* iterate all siblings */
8920 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
8924 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
8926 qtdemux_parse_udta (qtdemux, udta);
8928 GST_LOG_OBJECT (qtdemux, "No udta node found.");
8931 /* maybe also some tags in meta box */
8932 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
8934 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
8935 qtdemux_parse_udta (qtdemux, udta);
8937 GST_LOG_OBJECT (qtdemux, "No meta node found.");
8940 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
8945 /* taken from ffmpeg */
8947 get_size (guint8 * ptr, guint8 ** end)
8956 len = (len << 7) | (c & 0x7f);
8965 /* this can change the codec originally present in @list */
8967 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
8968 GNode * esds, GstTagList * list)
8970 int len = QT_UINT32 (esds->data);
8971 guint8 *ptr = esds->data;
8972 guint8 *end = ptr + len;
8974 guint8 *data_ptr = NULL;
8976 guint8 object_type_id = 0;
8977 const char *codec_name = NULL;
8978 GstCaps *caps = NULL;
8980 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
8982 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
8985 tag = QT_UINT8 (ptr);
8986 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
8988 len = get_size (ptr, &ptr);
8989 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
8993 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
8994 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
8998 guint max_bitrate, avg_bitrate;
9000 object_type_id = QT_UINT8 (ptr);
9001 max_bitrate = QT_UINT32 (ptr + 5);
9002 avg_bitrate = QT_UINT32 (ptr + 9);
9003 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
9004 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
9005 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
9006 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
9007 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
9008 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9009 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9010 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9012 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9013 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
9020 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
9026 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
9030 GST_ERROR_OBJECT (qtdemux, "parse error");
9035 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
9036 * in use, and should also be used to override some other parameters for some
9038 switch (object_type_id) {
9039 case 0x20: /* MPEG-4 */
9040 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
9041 * profile_and_level_indication */
9042 if (data_ptr != NULL && data_len >= 5 &&
9043 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
9044 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
9045 data_ptr + 4, data_len - 4);
9047 break; /* Nothing special needed here */
9048 case 0x21: /* H.264 */
9049 codec_name = "H.264 / AVC";
9050 caps = gst_caps_new_simple ("video/x-h264",
9051 "stream-format", G_TYPE_STRING, "avc",
9052 "alignment", G_TYPE_STRING, "au", NULL);
9054 case 0x40: /* AAC (any) */
9055 case 0x66: /* AAC Main */
9056 case 0x67: /* AAC LC */
9057 case 0x68: /* AAC SSR */
9058 /* Override channels and rate based on the codec_data, as it's often
9060 /* Only do so for basic setup without HE-AAC extension */
9061 if (data_ptr && data_len == 2) {
9062 guint channels, rateindex, rate;
9064 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
9065 channels = (data_ptr[1] & 0x7f) >> 3;
9066 if (channels > 0 && channels < 7) {
9067 stream->n_channels = channels;
9068 } else if (channels == 7) {
9069 stream->n_channels = 8;
9072 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
9073 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
9075 stream->rate = rate;
9078 /* Set level and profile if possible */
9079 if (data_ptr != NULL && data_len >= 2) {
9080 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
9081 data_ptr, data_len);
9084 case 0x60: /* MPEG-2, various profiles */
9090 codec_name = "MPEG-2 video";
9092 gst_caps_unref (stream->caps);
9093 stream->caps = gst_caps_new_simple ("video/mpeg",
9094 "mpegversion", G_TYPE_INT, 2,
9095 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9097 case 0x69: /* MP3 has two different values, accept either */
9099 /* change to mpeg1 layer 3 audio */
9100 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
9101 "mpegversion", G_TYPE_INT, 1, NULL);
9102 codec_name = "MPEG-1 layer 3";
9104 case 0x6A: /* MPEG-1 */
9105 codec_name = "MPEG-1 video";
9107 gst_caps_unref (stream->caps);
9108 stream->caps = gst_caps_new_simple ("video/mpeg",
9109 "mpegversion", G_TYPE_INT, 1,
9110 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9112 case 0x6C: /* MJPEG */
9113 caps = gst_caps_new_empty_simple ("image/jpeg");
9114 codec_name = "Motion-JPEG";
9116 case 0x6D: /* PNG */
9117 caps = gst_caps_new_empty_simple ("image/png");
9118 codec_name = "PNG still images";
9120 case 0x6E: /* JPEG2000 */
9121 codec_name = "JPEG-2000";
9122 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9124 case 0xA4: /* Dirac */
9125 codec_name = "Dirac";
9126 caps = gst_caps_new_empty_simple ("video/x-dirac");
9128 case 0xA5: /* AC3 */
9129 codec_name = "AC-3 audio";
9130 caps = gst_caps_new_simple ("audio/x-ac3",
9131 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9133 case 0xE1: /* QCELP */
9134 /* QCELP, the codec_data is a riff tag (little endian) with
9135 * 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). */
9136 caps = gst_caps_new_empty_simple ("audio/qcelp");
9137 codec_name = "QCELP";
9143 /* If we have a replacement caps, then change our caps for this stream */
9145 gst_caps_unref (stream->caps);
9146 stream->caps = caps;
9149 if (codec_name && list)
9150 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9151 GST_TAG_AUDIO_CODEC, codec_name, NULL);
9153 /* Add the codec_data attribute to caps, if we have it */
9157 buffer = gst_buffer_new_and_alloc (data_len);
9158 _gst_buffer_copy_into_mem (buffer, data_ptr, 0, data_len);
9160 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
9161 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
9163 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
9165 gst_buffer_unref (buffer);
9170 #define _codec(name) \
9173 *codec_name = g_strdup (name); \
9178 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9179 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9182 const GstStructure *s;
9186 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
9187 _codec ("PNG still images");
9188 caps = gst_caps_new_empty_simple ("image/png");
9190 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
9191 _codec ("JPEG still images");
9192 caps = gst_caps_new_empty_simple ("image/jpeg");
9194 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
9195 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
9196 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
9197 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
9198 _codec ("Motion-JPEG");
9199 caps = gst_caps_new_empty_simple ("image/jpeg");
9201 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
9202 _codec ("Motion-JPEG format B");
9203 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
9205 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
9206 _codec ("JPEG-2000");
9207 /* override to what it should be according to spec, avoid palette_data */
9208 stream->bits_per_sample = 24;
9209 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9211 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
9212 _codec ("Sorensen video v.3");
9213 caps = gst_caps_new_simple ("video/x-svq",
9214 "svqversion", G_TYPE_INT, 3, NULL);
9216 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
9217 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
9218 _codec ("Sorensen video v.1");
9219 caps = gst_caps_new_simple ("video/x-svq",
9220 "svqversion", G_TYPE_INT, 1, NULL);
9222 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9226 _codec ("Raw RGB video");
9227 bps = QT_UINT16 (stsd_data + 98);
9228 /* set common stuff */
9229 caps = gst_caps_new_empty_simple ("video/x-raw");
9233 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB15", NULL);
9236 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB16", NULL);
9239 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB", NULL);
9242 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "ARGB", NULL);
9250 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
9251 _codec ("Raw planar YUV 4:2:0");
9252 caps = gst_caps_new_simple ("video/x-raw",
9253 "format", G_TYPE_STRING, "I420", NULL);
9255 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
9256 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
9257 _codec ("Raw packed YUV 4:2:2");
9258 caps = gst_caps_new_simple ("video/x-raw",
9259 "format", G_TYPE_STRING, "YUY2", NULL);
9261 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
9262 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
9263 _codec ("Raw packed YUV 4:2:2");
9264 caps = gst_caps_new_simple ("video/x-raw",
9265 "format", G_TYPE_STRING, "UYVY", NULL);
9267 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
9268 _codec ("Raw packed YUV 10-bit 4:2:2");
9269 caps = gst_caps_new_simple ("video/x-raw",
9270 "format", G_TYPE_STRING, "v210", NULL);
9272 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
9273 _codec ("Raw packed RGB 10-bit 4:4:4");
9274 caps = gst_caps_new_simple ("video/x-raw",
9275 "format", G_TYPE_STRING, "r210", NULL);
9277 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
9278 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
9279 _codec ("MPEG-1 video");
9280 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9281 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9283 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
9284 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
9285 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
9286 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
9287 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
9288 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
9289 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
9290 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
9291 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
9292 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
9293 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
9294 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
9295 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
9296 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
9297 _codec ("MPEG-2 video");
9298 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
9299 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9301 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
9302 _codec ("GIF still images");
9303 caps = gst_caps_new_empty_simple ("image/gif");
9305 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
9306 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
9307 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
9308 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9310 /* ffmpeg uses the height/width props, don't know why */
9311 caps = gst_caps_new_empty_simple ("video/x-h263");
9313 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9314 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9315 _codec ("MPEG-4 video");
9316 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9317 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9319 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9320 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9321 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9322 caps = gst_caps_new_simple ("video/x-msmpeg",
9323 "msmpegversion", G_TYPE_INT, 43, NULL);
9325 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9326 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9327 _codec ("3ivX video");
9328 caps = gst_caps_new_empty_simple ("video/x-3ivx");
9330 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9332 caps = gst_caps_new_simple ("video/x-divx",
9333 "divxversion", G_TYPE_INT, 3, NULL);
9335 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9336 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9338 caps = gst_caps_new_simple ("video/x-divx",
9339 "divxversion", G_TYPE_INT, 4, NULL);
9341 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9343 caps = gst_caps_new_simple ("video/x-divx",
9344 "divxversion", G_TYPE_INT, 5, NULL);
9346 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9347 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9348 _codec ("XVID MPEG-4");
9349 caps = gst_caps_new_empty_simple ("video/x-xvid");
9352 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9353 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9354 caps = gst_caps_new_simple ("video/mpeg",
9355 "mpegversion", G_TYPE_INT, 4, NULL);
9357 *codec_name = g_strdup ("FFmpeg MPEG-4");
9360 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9362 caps = gst_caps_new_empty_simple ("video/x-cinepak");
9364 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9365 _codec ("Apple QuickDraw");
9366 caps = gst_caps_new_empty_simple ("video/x-qdrw");
9368 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9369 _codec ("Apple video");
9370 caps = gst_caps_new_empty_simple ("video/x-apple-video");
9372 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9373 _codec ("H.264 / AVC");
9374 caps = gst_caps_new_simple ("video/x-h264",
9375 "stream-format", G_TYPE_STRING, "avc",
9376 "alignment", G_TYPE_STRING, "au", NULL);
9378 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9379 _codec ("Run-length encoding");
9380 caps = gst_caps_new_simple ("video/x-rle",
9381 "layout", G_TYPE_STRING, "quicktime", NULL);
9383 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9384 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9385 _codec ("Indeo Video 3");
9386 caps = gst_caps_new_simple ("video/x-indeo",
9387 "indeoversion", G_TYPE_INT, 3, NULL);
9389 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9390 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9391 _codec ("Intel Video 4");
9392 caps = gst_caps_new_simple ("video/x-indeo",
9393 "indeoversion", G_TYPE_INT, 4, NULL);
9395 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9396 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9397 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9398 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9399 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9400 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9401 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9402 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9403 _codec ("DV Video");
9404 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9405 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9407 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9408 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9409 _codec ("DVCPro50 Video");
9410 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9411 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9413 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9414 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9415 _codec ("DVCProHD Video");
9416 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9417 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9419 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9420 _codec ("Apple Graphics (SMC)");
9421 caps = gst_caps_new_empty_simple ("video/x-smc");
9423 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9425 caps = gst_caps_new_empty_simple ("video/x-vp3");
9427 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9429 caps = gst_caps_new_empty_simple ("video/x-theora");
9430 /* theora uses one byte of padding in the data stream because it does not
9431 * allow 0 sized packets while theora does */
9432 stream->padding = 1;
9434 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9436 caps = gst_caps_new_empty_simple ("video/x-dirac");
9438 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9439 _codec ("TIFF still images");
9440 caps = gst_caps_new_empty_simple ("image/tiff");
9442 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9443 _codec ("Apple Intermediate Codec");
9444 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9446 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9447 _codec ("AVID DNxHD");
9448 caps = gst_caps_from_string ("video/x-dnxhd");
9450 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9452 caps = gst_caps_from_string ("video/x-vp8");
9456 caps = gst_caps_new_simple ("video/x-wmv",
9457 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
9459 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9464 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9465 GST_FOURCC_ARGS (fourcc));
9466 caps = gst_caps_new_empty_simple (s);
9471 /* enable clipping for raw video streams */
9472 s = gst_caps_get_structure (caps, 0);
9473 name = gst_structure_get_name (s);
9474 if (g_str_has_prefix (name, "video/x-raw")) {
9475 stream->need_clip = TRUE;
9481 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9482 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9485 const GstStructure *s;
9489 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9492 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9493 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9494 _codec ("Raw 8-bit PCM audio");
9495 caps = gst_caps_new_simple ("audio/x-raw",
9496 "format", G_TYPE_STRING, "U8", NULL);
9498 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9499 endian = G_BIG_ENDIAN;
9501 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9505 GstAudioFormat format;
9508 endian = G_LITTLE_ENDIAN;
9510 depth = stream->bytes_per_packet * 8;
9511 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
9513 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9517 caps = gst_caps_new_simple ("audio/x-raw",
9518 "format", G_TYPE_STRING, gst_audio_format_to_string (format), NULL);
9521 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9522 _codec ("Raw 64-bit floating-point audio");
9523 caps = gst_caps_new_simple ("audio/x-raw",
9524 "format", G_TYPE_STRING, "F64BE", NULL);
9526 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9527 _codec ("Raw 32-bit floating-point audio");
9528 caps = gst_caps_new_simple ("audio/x-raw",
9529 "format", G_TYPE_STRING, "F32BE", NULL);
9532 _codec ("Raw 24-bit PCM audio");
9533 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9535 caps = gst_caps_new_simple ("audio/x-raw",
9536 "format", G_TYPE_STRING, "S24BE", NULL);
9538 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9539 _codec ("Raw 32-bit PCM audio");
9540 caps = gst_caps_new_simple ("audio/x-raw",
9541 "format", G_TYPE_STRING, "S32BE", NULL);
9543 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9544 _codec ("Mu-law audio");
9545 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
9547 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9548 _codec ("A-law audio");
9549 caps = gst_caps_new_empty_simple ("audio/x-alaw");
9553 _codec ("Microsoft ADPCM");
9554 /* Microsoft ADPCM-ACM code 2 */
9555 caps = gst_caps_new_simple ("audio/x-adpcm",
9556 "layout", G_TYPE_STRING, "microsoft", NULL);
9560 _codec ("DVI/IMA ADPCM");
9561 caps = gst_caps_new_simple ("audio/x-adpcm",
9562 "layout", G_TYPE_STRING, "dvi", NULL);
9566 _codec ("DVI/Intel IMA ADPCM");
9567 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9568 caps = gst_caps_new_simple ("audio/x-adpcm",
9569 "layout", G_TYPE_STRING, "quicktime", NULL);
9573 /* MPEG layer 3, CBR only (pre QT4.1) */
9574 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9575 _codec ("MPEG-1 layer 3");
9576 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9577 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9578 "mpegversion", G_TYPE_INT, 1, NULL);
9581 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9582 _codec ("EAC-3 audio");
9583 caps = gst_caps_new_simple ("audio/x-eac3",
9584 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9585 stream->sampled = TRUE;
9587 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9588 _codec ("AC-3 audio");
9589 caps = gst_caps_new_simple ("audio/x-ac3",
9590 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9591 stream->sampled = TRUE;
9593 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9595 caps = gst_caps_new_simple ("audio/x-mace",
9596 "maceversion", G_TYPE_INT, 3, NULL);
9598 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9600 caps = gst_caps_new_simple ("audio/x-mace",
9601 "maceversion", G_TYPE_INT, 6, NULL);
9603 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9605 caps = gst_caps_new_empty_simple ("application/ogg");
9607 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9608 _codec ("DV audio");
9609 caps = gst_caps_new_empty_simple ("audio/x-dv");
9611 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9612 _codec ("MPEG-4 AAC audio");
9613 caps = gst_caps_new_simple ("audio/mpeg",
9614 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9615 "stream-format", G_TYPE_STRING, "raw", NULL);
9617 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9618 _codec ("QDesign Music");
9619 caps = gst_caps_new_empty_simple ("audio/x-qdm");
9621 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9622 _codec ("QDesign Music v.2");
9623 /* FIXME: QDesign music version 2 (no constant) */
9625 caps = gst_caps_new_simple ("audio/x-qdm2",
9626 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9627 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9628 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9630 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
9633 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9634 _codec ("GSM audio");
9635 caps = gst_caps_new_empty_simple ("audio/x-gsm");
9637 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9638 _codec ("AMR audio");
9639 caps = gst_caps_new_empty_simple ("audio/AMR");
9641 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9642 _codec ("AMR-WB audio");
9643 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
9645 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9646 _codec ("Quicktime IMA ADPCM");
9647 caps = gst_caps_new_simple ("audio/x-adpcm",
9648 "layout", G_TYPE_STRING, "quicktime", NULL);
9650 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9651 _codec ("Apple lossless audio");
9652 caps = gst_caps_new_empty_simple ("audio/x-alac");
9654 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9655 _codec ("QualComm PureVoice");
9656 caps = gst_caps_from_string ("audio/qcelp");
9660 caps = gst_caps_new_empty_simple ("audio/x-wma");
9662 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
9668 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9669 GST_FOURCC_ARGS (fourcc));
9670 caps = gst_caps_new_empty_simple (s);
9676 GstCaps *templ_caps =
9677 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
9678 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
9679 gst_caps_unref (caps);
9680 gst_caps_unref (templ_caps);
9681 caps = intersection;
9684 /* enable clipping for raw audio streams */
9685 s = gst_caps_get_structure (caps, 0);
9686 name = gst_structure_get_name (s);
9687 if (g_str_has_prefix (name, "audio/x-raw")) {
9688 stream->need_clip = TRUE;
9694 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9695 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9699 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9702 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
9703 _codec ("DVD subtitle");
9704 caps = gst_caps_new_empty_simple ("video/x-dvd-subpicture");
9706 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
9707 _codec ("Quicktime timed text");
9709 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
9710 _codec ("3GPP timed text");
9712 caps = gst_caps_new_empty_simple ("text/plain");
9713 /* actual text piece needs to be extracted */
9714 stream->need_process = TRUE;
9720 s = g_strdup_printf ("text/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9721 GST_FOURCC_ARGS (fourcc));
9722 caps = gst_caps_new_empty_simple (s);