2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 * SECTION:element-qtdemux
28 * Demuxes a .mov file into raw or compressed audio and/or video streams.
30 * This element supports both push and pull-based scheduling, depending on the
31 * capabilities of the upstream elements.
34 * <title>Example launch line</title>
36 * gst-launch filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
37 * ]| Play (parse and decode) a .mov file and try to output it to
38 * an automatically detected soundcard and videosink. If the MOV file contains
39 * compressed audio or video data, this will only work if you have the
40 * right decoder elements/plugins installed.
43 * Last reviewed on 2006-12-29 (0.10.5)
50 #include "gst/gst-i18n-plugin.h"
52 #include <glib/gprintf.h>
53 #include <gst/tag/tag.h>
54 #include <gst/audio/audio.h>
56 #include "qtatomparser.h"
57 #include "qtdemux_types.h"
58 #include "qtdemux_dump.h"
59 #include "qtdemux_fourcc.h"
60 #include "qtdemux_lang.h"
62 #include "qtpalette.h"
64 #include "gst/riff/riff-media.h"
65 #include "gst/riff/riff-read.h"
67 #include <gst/pbutils/pbutils.h>
77 /* max. size considered 'sane' for non-mdat atoms */
78 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
80 /* if the sample index is larger than this, something is likely wrong */
81 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
83 /* For converting qt creation times to unix epoch times */
84 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
85 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
86 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
87 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
89 GST_DEBUG_CATEGORY (qtdemux_debug);
91 /*typedef struct _QtNode QtNode; */
92 typedef struct _QtDemuxSegment QtDemuxSegment;
93 typedef struct _QtDemuxSample QtDemuxSample;
102 struct _QtDemuxSample
105 gint32 pts_offset; /* Add this value to timestamp to get the pts */
107 guint64 timestamp; /* DTS In mov time */
108 guint32 duration; /* In mov time */
109 gboolean keyframe; /* TRUE when this packet is a keyframe */
112 /* timestamp is the DTS */
113 #define QTSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
114 GST_SECOND, (stream)->timescale)
115 /* timestamp + offset is the PTS */
116 #define QTSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
117 (sample)->pts_offset, GST_SECOND, (stream)->timescale)
118 /* timestamp + duration - dts is the duration */
119 #define QTSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
120 (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
122 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
125 * Quicktime has tracks and segments. A track is a continuous piece of
126 * multimedia content. The track is not always played from start to finish but
127 * instead, pieces of the track are 'cut out' and played in sequence. This is
128 * what the segments do.
130 * Inside the track we have keyframes (K) and delta frames. The track has its
131 * own timing, which starts from 0 and extends to end. The position in the track
132 * is called the media_time.
134 * The segments now describe the pieces that should be played from this track
135 * and are basically tupples of media_time/duration/rate entries. We can have
136 * multiple segments and they are all played after one another. An example:
138 * segment 1: media_time: 1 second, duration: 1 second, rate 1
139 * segment 2: media_time: 3 second, duration: 2 second, rate 2
141 * To correctly play back this track, one must play: 1 second of media starting
142 * from media_time 1 followed by 2 seconds of media starting from media_time 3
145 * Each of the segments will be played at a specific time, the first segment at
146 * time 0, the second one after the duration of the first one, etc.. Note that
147 * the time in resulting playback is not identical to the media_time of the
150 * Visually, assuming the track has 4 second of media_time:
153 * .-----------------------------------------------------------.
154 * track: | K.....K.........K........K.......K.......K...........K... |
155 * '-----------------------------------------------------------'
157 * .------------^ ^ .----------^ ^
158 * / .-------------' / .------------------'
160 * .--------------. .--------------.
161 * | segment 1 | | segment 2 |
162 * '--------------' '--------------'
164 * The challenge here is to cut out the right pieces of the track for each of
165 * the playback segments. This fortunatly can easily be done with the SEGMENT
166 * events of gstreamer.
168 * For playback of segment 1, we need to provide the decoder with the keyframe
169 * (a), in the above figure, but we must instruct it only to output the decoded
170 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
171 * position set to the time of the segment: 0.
173 * We then proceed to push data from keyframe (a) to frame (b). The decoder
174 * decodes but clips all before media_time 1.
176 * After finishing a segment, we push out a new SEGMENT event with the clipping
177 * boundaries of the new data.
179 * This is a good usecase for the GStreamer accumulated SEGMENT events.
182 struct _QtDemuxSegment
184 /* global time and duration, all gst time */
188 /* media time of trak, all gst time */
194 struct _QtDemuxStream
203 /* if the stream has a redirect URI in its headers, we store it here */
210 guint64 duration; /* in timescale */
214 gchar lang_id[4]; /* ISO 639-2T language code */
218 QtDemuxSample *samples;
219 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
220 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
221 the framerate, in timescale units */
223 /* if we use chunks or samples */
235 /* Numerator/denominator framerate */
238 guint16 bits_per_sample;
239 guint16 color_table_id;
244 guint samples_per_packet;
245 guint samples_per_frame;
246 guint bytes_per_packet;
247 guint bytes_per_sample;
248 guint bytes_per_frame;
252 gboolean use_allocator;
253 GstAllocator *allocator;
254 GstAllocationParams params;
256 /* when a discontinuity is pending */
259 /* list of buffers to push first */
262 /* if we need to clip this buffer. This is only needed for uncompressed
266 /* buffer needs some custom processing, e.g. subtitles */
267 gboolean need_process;
269 /* current position */
270 guint32 segment_index;
271 guint32 sample_index;
272 guint64 time_position; /* in gst time */
274 /* the Gst segment we are processing out, used for clipping */
277 /* last GstFlowReturn */
278 GstFlowReturn last_ret;
280 /* quicktime segments */
282 QtDemuxSegment *segments;
287 GstTagList *pending_tags;
288 gboolean send_global_tags;
290 GstEvent *pending_event;
300 gboolean chunks_are_chunks;
304 GstByteReader co_chunk;
306 guint32 current_chunk;
308 guint32 samples_per_chunk;
309 guint32 stco_sample_index;
311 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
314 guint32 n_samples_per_chunk;
315 guint32 stsc_chunk_index;
316 guint32 stsc_sample_index;
317 guint64 chunk_offset;
320 guint32 stts_samples;
321 guint32 n_sample_times;
322 guint32 stts_sample_index;
324 guint32 stts_duration;
326 gboolean stss_present;
327 guint32 n_sample_syncs;
330 gboolean stps_present;
331 guint32 n_sample_partial_syncs;
334 gboolean ctts_present;
335 guint32 n_composition_times;
337 guint32 ctts_sample_index;
342 gboolean parsed_trex;
343 guint32 def_sample_duration;
344 guint32 def_sample_size;
345 guint32 def_sample_flags;
350 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
351 QTDEMUX_STATE_HEADER, /* Parsing the header */
352 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
353 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
356 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
357 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
358 guint32 fourcc, GstByteReader * parser);
359 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
360 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
361 guint32 fourcc, GstByteReader * parser);
363 static GstStaticPadTemplate gst_qtdemux_sink_template =
364 GST_STATIC_PAD_TEMPLATE ("sink",
367 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
371 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
372 GST_STATIC_PAD_TEMPLATE ("video_%u",
375 GST_STATIC_CAPS_ANY);
377 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
378 GST_STATIC_PAD_TEMPLATE ("audio_%u",
381 GST_STATIC_CAPS_ANY);
383 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
384 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
387 GST_STATIC_CAPS_ANY);
389 #define gst_qtdemux_parent_class parent_class
390 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
392 static void gst_qtdemux_dispose (GObject * object);
395 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
398 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
399 QtDemuxStream * str, gint64 media_offset);
402 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
403 static GstIndex *gst_qtdemux_get_index (GstElement * element);
405 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
406 GstStateChange transition);
407 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
408 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
409 GstObject * parent, GstPadMode mode, gboolean active);
411 static void gst_qtdemux_loop (GstPad * pad);
412 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
414 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
417 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
418 const guint8 * buffer, guint length);
419 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
420 const guint8 * buffer, guint length);
421 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
423 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
424 QtDemuxStream * stream, GNode * esds, GstTagList * list);
425 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
426 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
427 gchar ** codec_name);
428 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
429 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
430 gchar ** codec_name);
431 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
432 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
433 gchar ** codec_name);
434 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
435 QtDemuxStream * stream, guint32 n);
436 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
439 gst_qtdemux_class_init (GstQTDemuxClass * klass)
441 GObjectClass *gobject_class;
442 GstElementClass *gstelement_class;
444 gobject_class = (GObjectClass *) klass;
445 gstelement_class = (GstElementClass *) klass;
447 parent_class = g_type_class_peek_parent (klass);
449 gobject_class->dispose = gst_qtdemux_dispose;
451 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
453 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
454 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
457 gst_tag_register_musicbrainz_tags ();
459 gst_element_class_add_pad_template (gstelement_class,
460 gst_static_pad_template_get (&gst_qtdemux_sink_template));
461 gst_element_class_add_pad_template (gstelement_class,
462 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
463 gst_element_class_add_pad_template (gstelement_class,
464 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
465 gst_element_class_add_pad_template (gstelement_class,
466 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
467 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
469 "Demultiplex a QuickTime file into audio and video streams",
470 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
472 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
477 gst_qtdemux_init (GstQTDemux * qtdemux)
480 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
481 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
482 gst_pad_set_activatemode_function (qtdemux->sinkpad,
483 qtdemux_sink_activate_mode);
484 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
485 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
486 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
488 qtdemux->state = QTDEMUX_STATE_INITIAL;
489 qtdemux->pullbased = FALSE;
490 qtdemux->posted_redirect = FALSE;
491 qtdemux->neededbytes = 16;
493 qtdemux->adapter = gst_adapter_new ();
495 qtdemux->first_mdat = -1;
496 qtdemux->got_moov = FALSE;
497 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
498 qtdemux->mdatbuffer = NULL;
499 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
501 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
505 gst_qtdemux_dispose (GObject * object)
507 GstQTDemux *qtdemux = GST_QTDEMUX (object);
509 if (qtdemux->adapter) {
510 g_object_unref (G_OBJECT (qtdemux->adapter));
511 qtdemux->adapter = NULL;
514 G_OBJECT_CLASS (parent_class)->dispose (object);
518 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
520 if (qtdemux->posted_redirect) {
521 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
522 (_("This file contains no playable streams.")),
523 ("no known streams found, a redirect message has been posted"));
525 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
526 (_("This file contains no playable streams.")),
527 ("no known streams found"));
532 _gst_buffer_copy_into_mem (GstBuffer * dest, gsize offset, const guint8 * src,
537 g_return_if_fail (gst_buffer_is_writable (dest));
539 bsize = gst_buffer_get_size (dest);
540 g_return_if_fail (bsize >= offset + size);
542 gst_buffer_fill (dest, offset, src, size);
546 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
550 buf = gst_buffer_new ();
551 gst_buffer_append_memory (buf,
552 gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
553 mem, size, 0, size, mem, free_func));
559 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
566 if (G_UNLIKELY (size == 0)) {
568 GstBuffer *tmp = NULL;
570 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
571 if (ret != GST_FLOW_OK)
574 gst_buffer_map (tmp, &map, GST_MAP_READ);
575 size = QT_UINT32 (map.data);
576 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
578 gst_buffer_unmap (tmp, &map);
579 gst_buffer_unref (tmp);
582 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
583 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
584 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
585 /* we're pulling header but already got most interesting bits,
586 * so never mind the rest (e.g. tags) (that much) */
587 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
591 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
592 (_("This file is invalid and cannot be played.")),
593 ("atom has bogus size %" G_GUINT64_FORMAT, size));
594 return GST_FLOW_ERROR;
598 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
600 if (G_UNLIKELY (flow != GST_FLOW_OK))
603 bsize = gst_buffer_get_size (*buf);
604 /* Catch short reads - we don't want any partial atoms */
605 if (G_UNLIKELY (bsize < size)) {
606 GST_WARNING_OBJECT (qtdemux,
607 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
608 gst_buffer_unref (*buf);
618 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
619 GstFormat dest_format, gint64 * dest_value)
622 QtDemuxStream *stream = gst_pad_get_element_private (pad);
623 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
626 if (stream->subtype != FOURCC_vide) {
631 switch (src_format) {
632 case GST_FORMAT_TIME:
633 switch (dest_format) {
634 case GST_FORMAT_BYTES:{
635 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
639 *dest_value = stream->samples[index].offset;
641 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
642 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
643 GST_TIME_ARGS (src_value), *dest_value);
651 case GST_FORMAT_BYTES:
652 switch (dest_format) {
653 case GST_FORMAT_TIME:{
655 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
662 gst_util_uint64_scale (stream->samples[index].timestamp,
663 GST_SECOND, stream->timescale);
664 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
665 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
666 src_value, GST_TIME_ARGS (*dest_value));
679 gst_object_unref (qtdemux);
686 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
690 *duration = GST_CLOCK_TIME_NONE;
692 if (qtdemux->duration != 0) {
693 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
694 *duration = gst_util_uint64_scale (qtdemux->duration,
695 GST_SECOND, qtdemux->timescale);
702 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
705 gboolean res = FALSE;
706 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
708 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
710 switch (GST_QUERY_TYPE (query)) {
711 case GST_QUERY_POSITION:
712 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
713 gst_query_set_position (query, GST_FORMAT_TIME,
714 qtdemux->segment.position);
718 case GST_QUERY_DURATION:{
721 gst_query_parse_duration (query, &fmt, NULL);
722 if (fmt == GST_FORMAT_TIME) {
723 gint64 duration = -1;
725 gst_qtdemux_get_duration (qtdemux, &duration);
727 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
733 case GST_QUERY_CONVERT:{
734 GstFormat src_fmt, dest_fmt;
735 gint64 src_value, dest_value = 0;
737 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
739 res = gst_qtdemux_src_convert (pad,
740 src_fmt, src_value, dest_fmt, &dest_value);
742 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
747 case GST_QUERY_FORMATS:
748 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
751 case GST_QUERY_SEEKING:{
755 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
756 if (fmt == GST_FORMAT_TIME) {
757 gint64 duration = -1;
759 gst_qtdemux_get_duration (qtdemux, &duration);
761 if (!qtdemux->pullbased) {
764 /* we might be able with help from upstream */
766 q = gst_query_new_seeking (GST_FORMAT_BYTES);
767 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
768 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
769 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
773 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
779 res = gst_pad_query_default (pad, parent, query);
787 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
789 if (G_LIKELY (stream->pad)) {
790 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
791 GST_DEBUG_PAD_NAME (stream->pad));
793 if (G_UNLIKELY (stream->pending_tags)) {
794 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
795 stream->pending_tags);
796 gst_pad_push_event (stream->pad,
797 gst_event_new_tag (stream->pending_tags));
798 stream->pending_tags = NULL;
801 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
802 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
804 gst_pad_push_event (stream->pad,
805 gst_event_new_tag (gst_tag_list_copy (qtdemux->tag_list)));
806 stream->send_global_tags = FALSE;
811 /* push event on all source pads; takes ownership of the event */
813 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
816 gboolean has_valid_stream = FALSE;
817 GstEventType etype = GST_EVENT_TYPE (event);
819 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
820 GST_EVENT_TYPE_NAME (event));
822 for (n = 0; n < qtdemux->n_streams; n++) {
824 QtDemuxStream *stream = qtdemux->streams[n];
826 if ((pad = stream->pad)) {
827 has_valid_stream = TRUE;
829 if (etype == GST_EVENT_EOS) {
830 /* let's not send twice */
831 if (stream->sent_eos)
833 stream->sent_eos = TRUE;
836 gst_pad_push_event (pad, gst_event_ref (event));
840 gst_event_unref (event);
842 /* if it is EOS and there are no pads, post an error */
843 if (!has_valid_stream && etype == GST_EVENT_EOS) {
844 gst_qtdemux_post_no_playable_stream_error (qtdemux);
848 /* push a pending newsegment event, if any from the streaming thread */
850 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
852 if (qtdemux->pending_newsegment) {
853 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
854 qtdemux->pending_newsegment = NULL;
864 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
866 if (s1->timestamp > *media_time)
872 /* find the index of the sample that includes the data for @media_time using a
873 * binary search. Only to be called in optimized cases of linear search below.
875 * Returns the index of the sample.
878 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
881 QtDemuxSample *result;
884 /* convert media_time to mov format */
886 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
888 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
889 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
890 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
892 if (G_LIKELY (result))
893 index = result - str->samples;
902 /* find the index of the sample that includes the data for @media_offset using a
905 * Returns the index of the sample.
908 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
909 QtDemuxStream * str, gint64 media_offset)
911 QtDemuxSample *result = str->samples;
914 if (result == NULL || str->n_samples == 0)
917 if (media_offset == result->offset)
921 while (index < str->n_samples - 1) {
922 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
925 if (media_offset < result->offset)
936 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
941 /* find the index of the sample that includes the data for @media_time using a
942 * linear search, and keeping in mind that not all samples may have been parsed
943 * yet. If possible, it will delegate to binary search.
945 * Returns the index of the sample.
948 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
954 /* convert media_time to mov format */
956 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
958 if (mov_time == str->samples[0].timestamp)
961 /* use faster search if requested time in already parsed range */
962 if (str->stbl_index >= 0 &&
963 mov_time <= str->samples[str->stbl_index].timestamp)
964 return gst_qtdemux_find_index (qtdemux, str, media_time);
966 while (index < str->n_samples - 1) {
967 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
970 if (mov_time < str->samples[index + 1].timestamp)
980 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
985 /* find the index of the keyframe needed to decode the sample at @index
988 * Returns the index of the keyframe.
991 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
994 guint32 new_index = index;
996 if (index >= str->n_samples) {
997 new_index = str->n_samples;
1001 /* all keyframes, return index */
1002 if (str->all_keyframe) {
1007 /* else go back until we have a keyframe */
1009 if (str->samples[new_index].keyframe)
1019 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1020 "gave %u", index, new_index);
1025 /* find the segment for @time_position for @stream
1027 * Returns -1 if the segment cannot be found.
1030 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1031 guint64 time_position)
1036 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1037 GST_TIME_ARGS (time_position));
1039 /* find segment corresponding to time_position if we are looking
1042 for (i = 0; i < stream->n_segments; i++) {
1043 QtDemuxSegment *segment = &stream->segments[i];
1045 GST_LOG_OBJECT (qtdemux,
1046 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1047 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1049 /* For the last segment we include stop_time in the last segment */
1050 if (i < stream->n_segments - 1) {
1051 if (segment->time <= time_position && time_position < segment->stop_time) {
1052 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1057 if (segment->time <= time_position && time_position <= segment->stop_time) {
1058 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1067 /* move the stream @str to the sample position @index.
1069 * Updates @str->sample_index and marks discontinuity if needed.
1072 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1075 /* no change needed */
1076 if (index == str->sample_index)
1079 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1082 /* position changed, we have a discont */
1083 str->sample_index = index;
1084 /* Each time we move in the stream we store the position where we are
1086 str->from_sample = index;
1087 str->discont = TRUE;
1091 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1092 gint64 * key_time, gint64 * key_offset)
1095 gint64 min_byte_offset = -1;
1098 min_offset = desired_time;
1100 /* for each stream, find the index of the sample in the segment
1101 * and move back to the previous keyframe. */
1102 for (n = 0; n < qtdemux->n_streams; n++) {
1104 guint32 index, kindex;
1106 guint64 media_start;
1109 QtDemuxSegment *seg;
1111 str = qtdemux->streams[n];
1113 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1114 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1116 /* segment not found, continue with normal flow */
1120 /* get segment and time in the segment */
1121 seg = &str->segments[seg_idx];
1122 seg_time = desired_time - seg->time;
1124 /* get the media time in the segment */
1125 media_start = seg->media_start + seg_time;
1127 /* get the index of the sample with media time */
1128 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1129 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1130 " at offset %" G_GUINT64_FORMAT,
1131 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1133 /* find previous keyframe */
1134 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1136 /* if the keyframe is at a different position, we need to update the
1137 * requested seek time */
1138 if (index != kindex) {
1141 /* get timestamp of keyframe */
1143 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1145 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT
1146 " at offset %" G_GUINT64_FORMAT,
1147 kindex, GST_TIME_ARGS (media_time), str->samples[kindex].offset);
1149 /* keyframes in the segment get a chance to change the
1150 * desired_offset. keyframes out of the segment are
1152 if (media_time >= seg->media_start) {
1155 /* this keyframe is inside the segment, convert back to
1157 seg_time = (media_time - seg->media_start) + seg->time;
1158 if (seg_time < min_offset)
1159 min_offset = seg_time;
1163 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1164 min_byte_offset = str->samples[index].offset;
1168 *key_time = min_offset;
1170 *key_offset = min_byte_offset;
1174 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1175 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1179 g_return_val_if_fail (format != NULL, FALSE);
1180 g_return_val_if_fail (cur != NULL, FALSE);
1181 g_return_val_if_fail (stop != NULL, FALSE);
1183 if (*format == GST_FORMAT_TIME)
1187 if (cur_type != GST_SEEK_TYPE_NONE)
1188 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1189 if (res && stop_type != GST_SEEK_TYPE_NONE)
1190 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1193 *format = GST_FORMAT_TIME;
1198 /* perform seek in push based mode:
1199 find BYTE position to move to based on time and delegate to upstream
1202 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1207 GstSeekType cur_type, stop_type;
1212 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1214 gst_event_parse_seek (event, &rate, &format, &flags,
1215 &cur_type, &cur, &stop_type, &stop);
1217 /* FIXME, always play to the end */
1220 /* only forward streaming and seeking is possible */
1222 goto unsupported_seek;
1224 /* convert to TIME if needed and possible */
1225 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1229 /* find reasonable corresponding BYTE position,
1230 * also try to mind about keyframes, since we can not go back a bit for them
1232 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1237 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1238 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1241 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1242 GST_DEBUG_OBJECT (qtdemux,
1243 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1244 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1245 GST_OBJECT_LOCK (qtdemux);
1246 qtdemux->requested_seek_time = cur;
1247 qtdemux->seek_offset = byte_cur;
1248 GST_OBJECT_UNLOCK (qtdemux);
1251 /* BYTE seek event */
1252 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1254 res = gst_pad_push_event (qtdemux->sinkpad, event);
1261 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1267 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1272 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1277 /* perform the seek.
1279 * We set all segment_indexes in the streams to unknown and
1280 * adjust the time_position to the desired position. this is enough
1281 * to trigger a segment switch in the streaming thread to start
1282 * streaming from the desired position.
1284 * Keyframe seeking is a little more complicated when dealing with
1285 * segments. Ideally we want to move to the previous keyframe in
1286 * the segment but there might not be a keyframe in the segment. In
1287 * fact, none of the segments could contain a keyframe. We take a
1288 * practical approach: seek to the previous keyframe in the segment,
1289 * if there is none, seek to the beginning of the segment.
1291 * Called with STREAM_LOCK
1294 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1296 gint64 desired_offset;
1299 desired_offset = segment->position;
1301 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1302 GST_TIME_ARGS (desired_offset));
1304 /* may not have enough fragmented info to do this adjustment,
1305 * and we can't scan (and probably should not) at this time with
1306 * possibly flushing upstream */
1307 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1310 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1311 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1312 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1313 desired_offset = min_offset;
1316 /* and set all streams to the final position */
1317 for (n = 0; n < qtdemux->n_streams; n++) {
1318 QtDemuxStream *stream = qtdemux->streams[n];
1320 stream->time_position = desired_offset;
1321 stream->sample_index = -1;
1322 stream->segment_index = -1;
1323 stream->last_ret = GST_FLOW_OK;
1324 stream->sent_eos = FALSE;
1326 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1327 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1329 segment->position = desired_offset;
1330 segment->time = desired_offset;
1332 /* we stop at the end */
1333 if (segment->stop == -1)
1334 segment->stop = segment->duration;
1339 /* do a seek in pull based mode */
1341 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1346 GstSeekType cur_type, stop_type;
1350 GstSegment seeksegment;
1354 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1356 gst_event_parse_seek (event, &rate, &format, &flags,
1357 &cur_type, &cur, &stop_type, &stop);
1359 /* we have to have a format as the segment format. Try to convert
1361 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1365 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1367 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1371 flush = flags & GST_SEEK_FLAG_FLUSH;
1373 /* stop streaming, either by flushing or by pausing the task */
1375 /* unlock upstream pull_range */
1376 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1377 /* make sure out loop function exits */
1378 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1380 /* non flushing seek, pause the task */
1381 gst_pad_pause_task (qtdemux->sinkpad);
1384 /* wait for streaming to finish */
1385 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1387 /* copy segment, we need this because we still need the old
1388 * segment when we close the current segment. */
1389 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1392 /* configure the segment with the seek variables */
1393 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1394 gst_segment_do_seek (&seeksegment, rate, format, flags,
1395 cur_type, cur, stop_type, stop, &update);
1398 /* now do the seek, this actually never returns FALSE */
1399 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1401 /* prepare for streaming again */
1403 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop (TRUE));
1404 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop (TRUE));
1407 /* commit the new segment */
1408 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1410 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1411 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1412 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1413 qtdemux->segment.format, qtdemux->segment.position));
1416 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1417 for (i = 0; i < qtdemux->n_streams; i++)
1418 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1420 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1423 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1430 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1436 qtdemux_ensure_index (GstQTDemux * qtdemux)
1440 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1442 /* Build complete index */
1443 for (i = 0; i < qtdemux->n_streams; i++) {
1444 QtDemuxStream *stream = qtdemux->streams[i];
1446 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1454 GST_LOG_OBJECT (qtdemux,
1455 "Building complete index of stream %u for seeking failed!", i);
1461 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1464 gboolean res = TRUE;
1465 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1467 switch (GST_EVENT_TYPE (event)) {
1468 case GST_EVENT_SEEK:
1470 #ifndef GST_DISABLE_GST_DEBUG
1471 GstClockTime ts = gst_util_get_timestamp ();
1473 /* Build complete index for seeking;
1474 * if not a fragmented file at least */
1475 if (!qtdemux->fragmented)
1476 if (!qtdemux_ensure_index (qtdemux))
1478 #ifndef GST_DISABLE_GST_DEBUG
1479 ts = gst_util_get_timestamp () - ts;
1480 GST_INFO_OBJECT (qtdemux,
1481 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1484 if (qtdemux->pullbased) {
1485 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1486 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams &&
1487 !qtdemux->fragmented) {
1488 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1490 GST_DEBUG_OBJECT (qtdemux,
1491 "ignoring seek in push mode in current state");
1494 gst_event_unref (event);
1497 case GST_EVENT_NAVIGATION:
1499 gst_event_unref (event);
1502 res = gst_pad_event_default (pad, parent, event);
1512 GST_ERROR_OBJECT (qtdemux, "Index failed");
1513 gst_event_unref (event);
1519 /* stream/index return sample that is min/max w.r.t. byte position,
1520 * time is min/max w.r.t. time of samples,
1521 * the latter need not be time of the former sample */
1523 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1524 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1527 gint64 time, min_time;
1528 QtDemuxStream *stream;
1534 for (n = 0; n < qtdemux->n_streams; ++n) {
1537 gboolean set_sample;
1539 str = qtdemux->streams[n];
1546 i = str->n_samples - 1;
1549 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1550 if (str->samples[i].size &&
1551 ((fw && (str->samples[i].offset >= byte_pos)) ||
1553 (str->samples[i].offset + str->samples[i].size <=
1555 /* move stream to first available sample */
1557 gst_qtdemux_move_stream (qtdemux, str, i);
1560 /* determine min/max time */
1561 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1562 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1563 if (min_time == -1 || (!fw && time > min_time) ||
1564 (fw && time < min_time)) {
1567 /* determine stream with leading sample, to get its position */
1569 && (str->samples[i].offset < stream->samples[index].offset))
1571 && (str->samples[i].offset > stream->samples[index].offset))) {
1578 /* no sample for this stream, mark eos */
1580 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1592 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1595 GstQTDemux *demux = GST_QTDEMUX (parent);
1598 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1600 switch (GST_EVENT_TYPE (event)) {
1601 case GST_EVENT_SEGMENT:
1604 QtDemuxStream *stream;
1608 /* some debug output */
1609 gst_event_copy_segment (event, &segment);
1610 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1613 /* chain will send initial newsegment after pads have been added */
1614 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1615 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1619 /* we only expect a BYTE segment, e.g. following a seek */
1620 if (segment.format == GST_FORMAT_BYTES) {
1621 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1622 gint64 requested_seek_time;
1623 guint64 seek_offset;
1625 offset = segment.start;
1627 GST_OBJECT_LOCK (demux);
1628 requested_seek_time = demux->requested_seek_time;
1629 seek_offset = demux->seek_offset;
1630 demux->requested_seek_time = -1;
1631 demux->seek_offset = -1;
1632 GST_OBJECT_UNLOCK (demux);
1634 if (offset == seek_offset) {
1635 segment.start = requested_seek_time;
1637 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1638 NULL, (gint64 *) & segment.start);
1639 if ((gint64) segment.start < 0)
1643 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1644 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1645 NULL, (gint64 *) & segment.stop);
1646 /* keyframe seeking should already arrange for start >= stop,
1647 * but make sure in other rare cases */
1648 segment.stop = MAX (segment.stop, segment.start);
1651 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1655 /* accept upstream's notion of segment and distribute along */
1656 segment.time = segment.start;
1657 segment.duration = demux->segment.duration;
1658 segment.base = gst_segment_to_running_time (&demux->segment,
1659 GST_FORMAT_TIME, demux->segment.position);
1661 gst_segment_copy_into (&segment, &demux->segment);
1662 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
1663 gst_qtdemux_push_event (demux, gst_event_new_segment (&segment));
1665 /* clear leftover in current segment, if any */
1666 gst_adapter_clear (demux->adapter);
1667 /* set up streaming thread */
1668 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1669 demux->offset = offset;
1671 demux->todrop = stream->samples[idx].offset - offset;
1672 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1674 /* set up for EOS */
1675 demux->neededbytes = -1;
1679 gst_event_unref (event);
1684 case GST_EVENT_FLUSH_STOP:
1689 /* clean up, force EOS if no more info follows */
1690 gst_adapter_clear (demux->adapter);
1692 demux->neededbytes = -1;
1693 /* reset flow return, e.g. following seek */
1694 for (i = 0; i < demux->n_streams; i++) {
1695 demux->streams[i]->last_ret = GST_FLOW_OK;
1696 demux->streams[i]->sent_eos = FALSE;
1698 dur = demux->segment.duration;
1699 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1700 demux->segment.duration = dur;
1704 /* If we are in push mode, and get an EOS before we've seen any streams,
1705 * then error out - we have nowhere to send the EOS */
1706 if (!demux->pullbased) {
1708 gboolean has_valid_stream = FALSE;
1709 for (i = 0; i < demux->n_streams; i++) {
1710 if (demux->streams[i]->pad != NULL) {
1711 has_valid_stream = TRUE;
1715 if (!has_valid_stream)
1716 gst_qtdemux_post_no_playable_stream_error (demux);
1723 res = gst_pad_event_default (demux->sinkpad, parent, event);
1731 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1733 GstQTDemux *demux = GST_QTDEMUX (element);
1735 GST_OBJECT_LOCK (demux);
1736 if (demux->element_index)
1737 gst_object_unref (demux->element_index);
1739 demux->element_index = gst_object_ref (index);
1741 demux->element_index = NULL;
1743 GST_OBJECT_UNLOCK (demux);
1744 /* object lock might be taken again */
1746 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1747 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
1748 demux->element_index, demux->index_id);
1752 gst_qtdemux_get_index (GstElement * element)
1754 GstIndex *result = NULL;
1755 GstQTDemux *demux = GST_QTDEMUX (element);
1757 GST_OBJECT_LOCK (demux);
1758 if (demux->element_index)
1759 result = gst_object_ref (demux->element_index);
1760 GST_OBJECT_UNLOCK (demux);
1762 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1769 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1771 g_free ((gpointer) stream->stco.data);
1772 stream->stco.data = NULL;
1773 g_free ((gpointer) stream->stsz.data);
1774 stream->stsz.data = NULL;
1775 g_free ((gpointer) stream->stsc.data);
1776 stream->stsc.data = NULL;
1777 g_free ((gpointer) stream->stts.data);
1778 stream->stts.data = NULL;
1779 g_free ((gpointer) stream->stss.data);
1780 stream->stss.data = NULL;
1781 g_free ((gpointer) stream->stps.data);
1782 stream->stps.data = NULL;
1783 g_free ((gpointer) stream->ctts.data);
1784 stream->ctts.data = NULL;
1788 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
1790 if (stream->allocator)
1791 gst_allocator_unref (stream->allocator);
1792 while (stream->buffers) {
1793 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1794 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1797 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
1798 g_free (stream->samples);
1800 gst_caps_unref (stream->caps);
1801 g_free (stream->segments);
1802 if (stream->pending_tags)
1803 gst_tag_list_free (stream->pending_tags);
1804 g_free (stream->redirect_uri);
1805 /* free stbl sub-atoms */
1806 gst_qtdemux_stbl_free (stream);
1810 static GstStateChangeReturn
1811 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1813 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1814 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1816 switch (transition) {
1817 case GST_STATE_CHANGE_PAUSED_TO_READY:
1823 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1825 switch (transition) {
1826 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1829 qtdemux->state = QTDEMUX_STATE_INITIAL;
1830 qtdemux->neededbytes = 16;
1831 qtdemux->todrop = 0;
1832 qtdemux->pullbased = FALSE;
1833 qtdemux->posted_redirect = FALSE;
1834 qtdemux->offset = 0;
1835 qtdemux->first_mdat = -1;
1836 qtdemux->header_size = 0;
1837 qtdemux->got_moov = FALSE;
1838 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1839 if (qtdemux->mdatbuffer)
1840 gst_buffer_unref (qtdemux->mdatbuffer);
1841 qtdemux->mdatbuffer = NULL;
1842 if (qtdemux->comp_brands)
1843 gst_buffer_unref (qtdemux->comp_brands);
1844 qtdemux->comp_brands = NULL;
1845 if (qtdemux->tag_list)
1846 gst_tag_list_free (qtdemux->tag_list);
1847 qtdemux->tag_list = NULL;
1849 if (qtdemux->element_index)
1850 gst_object_unref (qtdemux->element_index);
1851 qtdemux->element_index = NULL;
1853 gst_adapter_clear (qtdemux->adapter);
1854 for (n = 0; n < qtdemux->n_streams; n++) {
1855 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1856 qtdemux->streams[n] = NULL;
1858 qtdemux->major_brand = 0;
1859 qtdemux->n_streams = 0;
1860 qtdemux->n_video_streams = 0;
1861 qtdemux->n_audio_streams = 0;
1862 qtdemux->n_sub_streams = 0;
1863 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1864 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1865 qtdemux->seek_offset = 0;
1866 qtdemux->upstream_seekable = FALSE;
1867 qtdemux->upstream_size = 0;
1878 qtdemux_post_global_tags (GstQTDemux * qtdemux)
1880 if (qtdemux->tag_list) {
1881 /* all header tags ready and parsed, push them */
1882 GST_INFO_OBJECT (qtdemux, "posting global tags: %" GST_PTR_FORMAT,
1884 /* post now, send event on pads later */
1885 gst_element_post_message (GST_ELEMENT (qtdemux),
1886 gst_message_new_tag (GST_OBJECT (qtdemux),
1887 gst_tag_list_copy (qtdemux->tag_list)));
1892 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1894 /* counts as header data */
1895 qtdemux->header_size += length;
1897 /* only consider at least a sufficiently complete ftyp atom */
1901 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1902 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1903 GST_FOURCC_ARGS (qtdemux->major_brand));
1904 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1905 _gst_buffer_copy_into_mem (buf, 0, buffer + 16, length - 16);
1910 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
1912 /* Strip out bogus fields */
1914 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
1916 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
1918 if (qtdemux->tag_list) {
1919 /* prioritize native tags using _KEEP mode */
1920 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
1921 gst_tag_list_free (taglist);
1923 qtdemux->tag_list = taglist;
1928 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1930 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
1931 0x97, 0xA9, 0x42, 0xE8,
1932 0x9C, 0x71, 0x99, 0x94,
1933 0x91, 0xE3, 0xAF, 0xAC
1937 /* counts as header data */
1938 qtdemux->header_size += length;
1940 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
1942 if (length <= offset + 16) {
1943 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
1947 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
1949 GstTagList *taglist;
1951 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
1952 length - offset - 16, NULL);
1953 taglist = gst_tag_list_from_xmp_buffer (buf);
1954 gst_buffer_unref (buf);
1956 qtdemux_handle_xmp_taglist (qtdemux, taglist);
1959 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
1963 /* caller verifies at least 8 bytes in buf */
1965 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1966 guint64 * plength, guint32 * pfourcc)
1971 length = QT_UINT32 (data);
1972 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1973 fourcc = QT_FOURCC (data + 4);
1974 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1977 length = G_MAXUINT32;
1978 } else if (length == 1 && size >= 16) {
1979 /* this means we have an extended size, which is the 64 bit value of
1980 * the next 8 bytes */
1981 length = QT_UINT64 (data + 8);
1982 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1992 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
1994 guint32 version = 0;
1995 guint64 duration = 0;
1997 if (!gst_byte_reader_get_uint32_be (br, &version))
2002 if (!gst_byte_reader_get_uint64_be (br, &duration))
2007 if (!gst_byte_reader_get_uint32_be (br, &dur))
2012 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2013 qtdemux->duration = duration;
2019 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2025 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2026 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2028 if (!stream->parsed_trex && qtdemux->moov_node) {
2030 GstByteReader trex_data;
2032 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2034 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2037 guint32 id = 0, dur = 0, size = 0, flags = 0;
2039 /* skip version/flags */
2040 if (!gst_byte_reader_skip (&trex_data, 4))
2042 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2044 if (id != stream->track_id)
2046 /* sample description index; ignore */
2047 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2049 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2051 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2053 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2056 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2057 "duration %d, size %d, flags 0x%x", stream->track_id,
2060 stream->parsed_trex = TRUE;
2061 stream->def_sample_duration = dur;
2062 stream->def_sample_size = size;
2063 stream->def_sample_flags = flags;
2066 /* iterate all siblings */
2067 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2073 *ds_duration = stream->def_sample_duration;
2074 *ds_size = stream->def_sample_size;
2075 *ds_size = stream->def_sample_size;
2077 /* even then, above values are better than random ... */
2078 if (G_UNLIKELY (!stream->parsed_trex)) {
2079 GST_WARNING_OBJECT (qtdemux,
2080 "failed to find fragment defaults for stream %d", stream->track_id);
2088 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2089 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2090 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2091 gint64 * base_offset, gint64 * running_offset)
2094 gint32 data_offset = 0;
2095 guint32 flags = 0, first_flags = 0, samples_count = 0;
2098 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2099 QtDemuxSample *sample;
2100 gboolean ismv = FALSE;
2102 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2103 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2104 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2107 /* presence of stss or not can't really tell us much,
2108 * and flags and so on tend to be marginally reliable in these files */
2109 if (stream->subtype == FOURCC_soun) {
2110 GST_DEBUG_OBJECT (qtdemux,
2111 "sound track in fragmented file; marking all keyframes");
2112 stream->all_keyframe = TRUE;
2115 if (!gst_byte_reader_skip (trun, 1) ||
2116 !gst_byte_reader_get_uint24_be (trun, &flags))
2119 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2122 if (flags & TR_DATA_OFFSET) {
2123 /* note this is really signed */
2124 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2126 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2127 /* default base offset = first byte of moof */
2128 if (*base_offset == -1) {
2129 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2130 *base_offset = moof_offset;
2132 *running_offset = *base_offset + data_offset;
2134 /* if no offset at all, that would mean data starts at moof start,
2135 * which is a bit wrong and is ismv crappy way, so compensate
2136 * assuming data is in mdat following moof */
2137 if (*base_offset == -1) {
2138 *base_offset = moof_offset + moof_length + 8;
2139 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2142 if (*running_offset == -1)
2143 *running_offset = *base_offset;
2146 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2148 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2149 data_offset, flags, samples_count);
2151 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2152 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2153 GST_DEBUG_OBJECT (qtdemux,
2154 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2155 flags ^= TR_FIRST_SAMPLE_FLAGS;
2157 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2159 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2163 /* FIXME ? spec says other bits should also be checked to determine
2164 * entry size (and prefix size for that matter) */
2166 dur_offset = size_offset = 0;
2167 if (flags & TR_SAMPLE_DURATION) {
2168 GST_LOG_OBJECT (qtdemux, "entry duration present");
2169 dur_offset = entry_size;
2172 if (flags & TR_SAMPLE_SIZE) {
2173 GST_LOG_OBJECT (qtdemux, "entry size present");
2174 size_offset = entry_size;
2177 if (flags & TR_SAMPLE_FLAGS) {
2178 GST_LOG_OBJECT (qtdemux, "entry flags present");
2179 flags_offset = entry_size;
2182 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2183 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2184 ct_offset = entry_size;
2188 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2190 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2192 if (stream->n_samples >=
2193 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2196 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2197 stream->n_samples, (guint) sizeof (QtDemuxSample),
2198 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2200 /* create a new array of samples if it's the first sample parsed */
2201 if (stream->n_samples == 0)
2202 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2203 /* or try to reallocate it with space enough to insert the new samples */
2205 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2206 stream->n_samples + samples_count);
2207 if (stream->samples == NULL)
2210 if (G_UNLIKELY (stream->n_samples == 0)) {
2211 /* the timestamp of the first sample is also provided by the tfra entry
2212 * but we shouldn't rely on it as it is at the end of files */
2215 /* subsequent fragments extend stream */
2217 stream->samples[stream->n_samples - 1].timestamp +
2218 stream->samples[stream->n_samples - 1].duration;
2220 sample = stream->samples + stream->n_samples;
2221 for (i = 0; i < samples_count; i++) {
2222 guint32 dur, size, sflags, ct;
2224 /* first read sample data */
2225 if (flags & TR_SAMPLE_DURATION) {
2226 dur = QT_UINT32 (data + dur_offset);
2228 dur = d_sample_duration;
2230 if (flags & TR_SAMPLE_SIZE) {
2231 size = QT_UINT32 (data + size_offset);
2233 size = d_sample_size;
2235 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2237 sflags = first_flags;
2239 sflags = d_sample_flags;
2241 } else if (flags & TR_SAMPLE_FLAGS) {
2242 sflags = QT_UINT32 (data + flags_offset);
2244 sflags = d_sample_flags;
2246 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2247 ct = QT_UINT32 (data + ct_offset);
2253 /* fill the sample information */
2254 sample->offset = *running_offset;
2255 sample->pts_offset = ct;
2256 sample->size = size;
2257 sample->timestamp = timestamp;
2258 sample->duration = dur;
2259 /* sample-is-difference-sample */
2260 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2261 * now idea how it relates to bitfield other than massive LE/BE confusion */
2262 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2263 *running_offset += size;
2268 stream->n_samples += samples_count;
2274 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2279 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2285 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2286 "be larger than %uMB (broken file?)", stream->n_samples,
2287 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2292 /* find stream with @id */
2293 static inline QtDemuxStream *
2294 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2296 QtDemuxStream *stream;
2300 if (G_UNLIKELY (!id)) {
2301 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2305 /* try to get it fast and simple */
2306 if (G_LIKELY (id <= qtdemux->n_streams)) {
2307 stream = qtdemux->streams[id - 1];
2308 if (G_LIKELY (stream->track_id == id))
2312 /* linear search otherwise */
2313 for (i = 0; i < qtdemux->n_streams; i++) {
2314 stream = qtdemux->streams[i];
2315 if (stream->track_id == id)
2323 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2324 QtDemuxStream ** stream, guint32 * default_sample_duration,
2325 guint32 * default_sample_size, guint32 * default_sample_flags,
2326 gint64 * base_offset)
2329 guint32 track_id = 0;
2331 if (!gst_byte_reader_skip (tfhd, 1) ||
2332 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2335 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2338 *stream = qtdemux_find_stream (qtdemux, track_id);
2339 if (G_UNLIKELY (!*stream))
2340 goto unknown_stream;
2342 if (flags & TF_BASE_DATA_OFFSET)
2343 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2346 /* obtain stream defaults */
2347 qtdemux_parse_trex (qtdemux, *stream,
2348 default_sample_duration, default_sample_size, default_sample_flags);
2350 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2351 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2352 if (!gst_byte_reader_skip (tfhd, 4))
2355 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2356 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2359 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2360 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2363 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2364 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2371 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2376 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2382 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2383 guint64 moof_offset, QtDemuxStream * stream)
2385 GNode *moof_node, *traf_node, *tfhd_node, *trun_node;
2386 GstByteReader trun_data, tfhd_data;
2387 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2388 gint64 base_offset, running_offset;
2390 /* NOTE @stream ignored */
2392 moof_node = g_node_new ((guint8 *) buffer);
2393 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2394 qtdemux_node_dump (qtdemux, moof_node);
2396 /* unknown base_offset to start with */
2397 base_offset = running_offset = -1;
2398 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2400 /* Fragment Header node */
2402 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2406 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2407 &ds_size, &ds_flags, &base_offset))
2409 if (G_UNLIKELY (!stream)) {
2410 /* we lost track of offset, we'll need to regain it,
2411 * but can delay complaining until later or avoid doing so altogether */
2415 if (G_UNLIKELY (base_offset < -1))
2417 /* Track Run node */
2419 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2422 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2423 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2425 /* iterate all siblings */
2426 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2429 /* if no new base_offset provided for next traf,
2430 * base is end of current traf */
2431 base_offset = running_offset;
2432 running_offset = -1;
2434 /* iterate all siblings */
2435 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2437 g_node_destroy (moof_node);
2442 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2447 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2452 g_node_destroy (moof_node);
2453 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2454 (_("This file is corrupt and cannot be played.")), (NULL));
2459 /* might be used if some day we actually use mfra & co
2460 * for random access to fragments,
2461 * but that will require quite some modifications and much less relying
2462 * on a sample array */
2465 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2466 QtDemuxStream * stream)
2468 guint64 time = 0, moof_offset = 0;
2469 guint32 ver_flags, track_id, len, num_entries, i;
2470 guint value_size, traf_size, trun_size, sample_size;
2471 GstBuffer *buf = NULL;
2475 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2476 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2478 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2481 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2482 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2483 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2486 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2487 track_id, stream->track_id);
2488 if (track_id != stream->track_id) {
2492 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2493 sample_size = (len & 3) + 1;
2494 trun_size = ((len & 12) >> 2) + 1;
2495 traf_size = ((len & 48) >> 4) + 1;
2497 if (num_entries == 0)
2500 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2501 value_size + value_size + traf_size + trun_size + sample_size))
2504 for (i = 0; i < num_entries; i++) {
2505 qt_atom_parser_get_offset (&tfra, value_size, &time);
2506 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2507 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2508 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2509 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2511 GST_LOG_OBJECT (qtdemux,
2512 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2513 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2514 stream->timescale)), moof_offset);
2516 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2517 if (ret != GST_FLOW_OK)
2519 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2520 moof_offset, stream);
2521 gst_buffer_unref (buf);
2529 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2530 (_("This file is corrupt and cannot be played.")), (NULL));
2535 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2541 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2544 GNode *mfra_node, *tfra_node;
2547 if (!qtdemux->mfra_offset)
2550 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2551 if (ret != GST_FLOW_OK)
2554 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2555 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2556 GST_BUFFER_SIZE (buffer));
2558 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2561 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2562 /* iterate all siblings */
2563 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2565 g_node_destroy (mfra_node);
2566 gst_buffer_unref (buffer);
2572 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2573 (_("This file is corrupt and cannot be played.")), (NULL));
2578 static GstFlowReturn
2579 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2580 guint32 * mfro_size)
2582 GstFlowReturn ret = GST_FLOW_ERROR;
2583 GstBuffer *mfro = NULL;
2586 GstFormat fmt = GST_FORMAT_BYTES;
2588 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, &fmt, &len)) {
2589 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2590 "can not locate mfro");
2594 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2595 if (ret != GST_FLOW_OK)
2598 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2599 if (fourcc != FOURCC_mfro)
2602 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2603 if (GST_BUFFER_SIZE (mfro) >= 16) {
2604 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
2605 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
2606 if (*mfro_size >= len) {
2607 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
2608 ret = GST_FLOW_ERROR;
2611 *mfra_offset = len - *mfro_size;
2616 gst_buffer_unref (mfro);
2622 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
2625 guint32 mfra_size = 0;
2626 guint64 mfra_offset = 0;
2629 qtdemux->fragmented = FALSE;
2631 /* We check here if it is a fragmented mp4 container */
2632 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
2633 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
2634 qtdemux->fragmented = TRUE;
2635 GST_DEBUG_OBJECT (qtdemux,
2636 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
2637 qtdemux->mfra_offset = mfra_offset;
2642 static GstFlowReturn
2643 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
2647 GstBuffer *buf = NULL;
2648 GstFlowReturn ret = GST_FLOW_OK;
2649 guint64 cur_offset = qtdemux->offset;
2652 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
2653 if (G_UNLIKELY (ret != GST_FLOW_OK))
2655 gst_buffer_map (buf, &map, GST_MAP_READ);
2656 if (G_LIKELY (map.size >= 8))
2657 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
2658 gst_buffer_unmap (buf, &map);
2659 gst_buffer_unref (buf);
2661 /* maybe we already got most we needed, so only consider this eof */
2662 if (G_UNLIKELY (length == 0)) {
2663 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
2664 (_("Invalid atom size.")),
2665 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
2666 GST_FOURCC_ARGS (fourcc)));
2673 /* record for later parsing when needed */
2674 if (!qtdemux->moof_offset) {
2675 qtdemux->moof_offset = qtdemux->offset;
2684 GST_LOG_OBJECT (qtdemux,
2685 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
2686 GST_FOURCC_ARGS (fourcc), cur_offset);
2687 qtdemux->offset += length;
2692 GstBuffer *moov = NULL;
2694 if (qtdemux->got_moov) {
2695 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
2696 qtdemux->offset += length;
2700 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
2701 if (ret != GST_FLOW_OK)
2703 gst_buffer_map (moov, &map, GST_MAP_READ);
2704 if (length != map.size) {
2705 /* Some files have a 'moov' atom at the end of the file which contains
2706 * a terminal 'free' atom where the body of the atom is missing.
2707 * Check for, and permit, this special case.
2709 if (map.size >= 8) {
2710 guint8 *final_data = map.data + (map.size - 8);
2711 guint32 final_length = QT_UINT32 (final_data);
2712 guint32 final_fourcc = QT_FOURCC (final_data + 4);
2713 gst_buffer_unmap (moov, &map);
2714 if (final_fourcc == FOURCC_free
2715 && map.size + final_length - 8 == length) {
2716 /* Ok, we've found that special case. Allocate a new buffer with
2717 * that free atom actually present. */
2718 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
2719 gst_buffer_copy_into (newmoov, moov, 0, 0, map.size);
2720 gst_buffer_map (newmoov, &map, GST_MAP_WRITE);
2721 memset (map.data + length - final_length + 8, 0, final_length - 8);
2722 gst_buffer_unref (moov);
2728 if (length != map.size) {
2729 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2730 (_("This file is incomplete and cannot be played.")),
2731 ("We got less than expected (received %" G_GSIZE_FORMAT
2732 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
2733 (guint) length, cur_offset));
2734 gst_buffer_unmap (moov, &map);
2735 gst_buffer_unref (moov);
2736 ret = GST_FLOW_ERROR;
2739 qtdemux->offset += length;
2741 qtdemux_parse_moov (qtdemux, map.data, length);
2742 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
2744 qtdemux_parse_tree (qtdemux);
2745 g_node_destroy (qtdemux->moov_node);
2746 gst_buffer_unmap (moov, &map);
2747 gst_buffer_unref (moov);
2748 qtdemux->moov_node = NULL;
2749 qtdemux->got_moov = TRUE;
2755 GstBuffer *ftyp = NULL;
2757 /* extract major brand; might come in handy for ISO vs QT issues */
2758 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
2759 if (ret != GST_FLOW_OK)
2761 qtdemux->offset += length;
2762 gst_buffer_map (ftyp, &map, GST_MAP_READ);
2763 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
2764 gst_buffer_unmap (ftyp, &map);
2765 gst_buffer_unref (ftyp);
2770 GstBuffer *uuid = NULL;
2772 /* uuid are extension atoms */
2773 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
2774 if (ret != GST_FLOW_OK)
2776 qtdemux->offset += length;
2777 gst_buffer_map (uuid, &map, GST_MAP_READ);
2778 qtdemux_parse_uuid (qtdemux, map.data, map.size);
2779 gst_buffer_unmap (uuid, &map);
2780 gst_buffer_unref (uuid);
2785 GstBuffer *unknown = NULL;
2787 GST_LOG_OBJECT (qtdemux,
2788 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
2789 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
2791 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
2792 if (ret != GST_FLOW_OK)
2794 gst_buffer_map (unknown, &map, GST_MAP_READ);
2795 GST_MEMDUMP ("Unknown tag", map.data, map.size);
2796 gst_buffer_unmap (unknown, &map);
2797 gst_buffer_unref (unknown);
2798 qtdemux->offset += length;
2804 if (ret == GST_FLOW_EOS && qtdemux->got_moov) {
2805 /* digested all data, show what we have */
2806 ret = qtdemux_expose_streams (qtdemux);
2808 /* Only post, event on pads is done after newsegment */
2809 qtdemux_post_global_tags (qtdemux);
2811 qtdemux->state = QTDEMUX_STATE_MOVIE;
2812 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
2819 /* Seeks to the previous keyframe of the indexed stream and
2820 * aligns other streams with respect to the keyframe timestamp
2821 * of indexed stream. Only called in case of Reverse Playback
2823 static GstFlowReturn
2824 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
2827 guint32 seg_idx = 0, k_index = 0;
2828 guint32 ref_seg_idx, ref_k_index;
2829 guint64 k_pos = 0, last_stop = 0;
2830 QtDemuxSegment *seg = NULL;
2831 QtDemuxStream *ref_str = NULL;
2832 guint64 seg_media_start_mov; /* segment media start time in mov format */
2834 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
2835 * and finally align all the other streams on that timestamp with their
2836 * respective keyframes */
2837 for (n = 0; n < qtdemux->n_streams; n++) {
2838 QtDemuxStream *str = qtdemux->streams[n];
2840 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
2841 qtdemux->segment.position);
2843 /* segment not found, continue with normal flow */
2847 /* No candidate yet, take that one */
2853 /* So that stream has a segment, we prefer video streams */
2854 if (str->subtype == FOURCC_vide) {
2860 if (G_UNLIKELY (!ref_str)) {
2861 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
2865 if (G_UNLIKELY (!ref_str->from_sample)) {
2866 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
2870 /* So that stream has been playing from from_sample to to_sample. We will
2871 * get the timestamp of the previous sample and search for a keyframe before
2872 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
2873 if (ref_str->subtype == FOURCC_vide) {
2874 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
2875 ref_str->from_sample - 1);
2877 if (ref_str->from_sample >= 10)
2878 k_index = ref_str->from_sample - 10;
2883 /* get current segment for that stream */
2884 seg = &ref_str->segments[ref_str->segment_index];
2885 /* convert seg->media_start to mov format time for timestamp comparison */
2886 seg_media_start_mov =
2887 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
2888 /* Crawl back through segments to find the one containing this I frame */
2889 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
2890 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
2891 ref_str->segment_index);
2892 if (G_UNLIKELY (!ref_str->segment_index)) {
2893 /* Reached first segment, let's consider it's EOS */
2896 ref_str->segment_index--;
2897 seg = &ref_str->segments[ref_str->segment_index];
2898 /* convert seg->media_start to mov format time for timestamp comparison */
2899 seg_media_start_mov =
2900 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
2903 /* Calculate time position of the keyframe and where we should stop */
2905 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
2906 ref_str->timescale) - seg->media_start) + seg->time;
2908 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
2909 GST_SECOND, ref_str->timescale);
2910 last_stop = (last_stop - seg->media_start) + seg->time;
2912 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
2913 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
2914 k_index, GST_TIME_ARGS (k_pos));
2916 /* Set last_stop with the keyframe timestamp we pushed of that stream */
2917 qtdemux->segment.position = last_stop;
2918 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
2919 GST_TIME_ARGS (last_stop));
2921 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
2922 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
2926 ref_seg_idx = ref_str->segment_index;
2927 ref_k_index = k_index;
2929 /* Align them all on this */
2930 for (n = 0; n < qtdemux->n_streams; n++) {
2932 guint64 media_start = 0, seg_time = 0;
2933 QtDemuxStream *str = qtdemux->streams[n];
2935 /* aligning reference stream again might lead to backing up to yet another
2936 * keyframe (due to timestamp rounding issues),
2937 * potentially putting more load on downstream; so let's try to avoid */
2938 if (str == ref_str) {
2939 seg_idx = ref_seg_idx;
2940 seg = &str->segments[seg_idx];
2941 k_index = ref_k_index;
2942 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
2943 "sample at index %d", ref_str->segment_index, k_index);
2945 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
2946 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
2948 /* segment not found, continue with normal flow */
2952 /* get segment and time in the segment */
2953 seg = &str->segments[seg_idx];
2954 seg_time = k_pos - seg->time;
2956 /* get the media time in the segment */
2957 media_start = seg->media_start + seg_time;
2959 /* get the index of the sample with media time */
2960 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
2961 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
2962 GST_TIME_ARGS (media_start), index);
2964 /* find previous keyframe */
2965 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
2968 /* Remember until where we want to go */
2969 str->to_sample = str->from_sample - 1;
2970 /* Define our time position */
2971 str->time_position =
2972 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
2973 str->timescale) - seg->media_start) + seg->time;
2974 /* Now seek back in time */
2975 gst_qtdemux_move_stream (qtdemux, str, k_index);
2976 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
2977 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
2978 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
2984 return GST_FLOW_EOS;
2987 /* activate the given segment number @seg_idx of @stream at time @offset.
2988 * @offset is an absolute global position over all the segments.
2990 * This will push out a NEWSEGMENT event with the right values and
2991 * position the stream index to the first decodable sample before
2995 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
2996 guint32 seg_idx, guint64 offset)
2999 QtDemuxSegment *segment;
3000 guint32 index, kf_index;
3002 guint64 start, stop, time;
3005 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3008 /* update the current segment */
3009 stream->segment_index = seg_idx;
3011 /* get the segment */
3012 segment = &stream->segments[seg_idx];
3014 if (G_UNLIKELY (offset < segment->time)) {
3015 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3020 /* segment lies beyond total indicated duration */
3021 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3022 segment->time > qtdemux->segment.duration)) {
3023 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3024 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3029 /* get time in this segment */
3030 seg_time = offset - segment->time;
3032 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3033 GST_TIME_ARGS (seg_time));
3035 if (G_UNLIKELY (seg_time > segment->duration)) {
3036 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3037 GST_TIME_ARGS (segment->duration));
3041 /* qtdemux->segment.stop is in outside-time-realm, whereas
3042 * segment->media_stop is in track-time-realm.
3044 * In order to compare the two, we need to bring segment.stop
3045 * into the track-time-realm */
3047 stop = qtdemux->segment.stop;
3049 stop = qtdemux->segment.duration;
3051 stop = segment->media_stop;
3054 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3056 if (qtdemux->segment.rate >= 0) {
3057 start = MIN (segment->media_start + seg_time, stop);
3060 if (segment->media_start >= qtdemux->segment.start) {
3061 start = segment->media_start;
3062 time = segment->time;
3064 start = qtdemux->segment.start;
3065 time = segment->time + (qtdemux->segment.start - segment->media_start);
3068 start = MAX (segment->media_start, qtdemux->segment.start);
3069 stop = MIN (segment->media_start + seg_time, stop);
3072 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3073 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3074 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3076 /* combine global rate with that of the segment */
3077 rate = segment->rate * qtdemux->segment.rate;
3079 /* update the segment values used for clipping */
3080 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
3081 /* accumulate previous segments */
3082 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3083 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3084 ABS (stream->segment.rate);
3085 stream->segment.rate = rate;
3086 stream->segment.start = start;
3087 stream->segment.stop = stop;
3088 stream->segment.time = time;
3090 /* now prepare and send the segment */
3092 event = gst_event_new_segment (&stream->segment);
3093 gst_pad_push_event (stream->pad, event);
3094 /* assume we can send more data now */
3095 stream->last_ret = GST_FLOW_OK;
3096 /* clear to send tags on this pad now */
3097 gst_qtdemux_push_tags (qtdemux, stream);
3100 /* and move to the keyframe before the indicated media time of the
3102 if (qtdemux->segment.rate >= 0) {
3103 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3104 stream->to_sample = G_MAXUINT32;
3105 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3106 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3107 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3108 GST_SECOND, stream->timescale)));
3110 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3111 stream->to_sample = index;
3112 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3113 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3114 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3115 GST_SECOND, stream->timescale)));
3118 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3119 * encountered an error and printed a message so we return appropriately */
3123 /* we're at the right spot */
3124 if (index == stream->sample_index) {
3125 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3129 /* find keyframe of the target index */
3130 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3133 /* indent does stupid stuff with stream->samples[].timestamp */
3135 /* if we move forwards, we don't have to go back to the previous
3136 * keyframe since we already sent that. We can also just jump to
3137 * the keyframe right before the target index if there is one. */
3138 if (index > stream->sample_index) {
3139 /* moving forwards check if we move past a keyframe */
3140 if (kf_index > stream->sample_index) {
3141 GST_DEBUG_OBJECT (qtdemux,
3142 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3143 GST_TIME_ARGS (gst_util_uint64_scale (
3144 stream->samples[kf_index].timestamp,
3145 GST_SECOND, stream->timescale)));
3146 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3148 GST_DEBUG_OBJECT (qtdemux,
3149 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3150 " already sent", kf_index,
3151 GST_TIME_ARGS (gst_util_uint64_scale (
3152 stream->samples[kf_index].timestamp,
3153 GST_SECOND, stream->timescale)));
3156 GST_DEBUG_OBJECT (qtdemux,
3157 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3158 GST_TIME_ARGS (gst_util_uint64_scale (
3159 stream->samples[kf_index].timestamp,
3160 GST_SECOND, stream->timescale)));
3161 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3169 /* prepare to get the current sample of @stream, getting essential values.
3171 * This function will also prepare and send the segment when needed.
3173 * Return FALSE if the stream is EOS.
3176 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3177 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * dts,
3178 guint64 * pts, guint64 * duration, gboolean * keyframe)
3180 QtDemuxSample *sample;
3181 guint64 time_position;
3184 g_return_val_if_fail (stream != NULL, FALSE);
3186 time_position = stream->time_position;
3187 if (G_UNLIKELY (time_position == -1))
3190 seg_idx = stream->segment_index;
3191 if (G_UNLIKELY (seg_idx == -1)) {
3192 /* find segment corresponding to time_position if we are looking
3194 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3196 /* nothing found, we're really eos */
3201 /* different segment, activate it, sample_index will be set. */
3202 if (G_UNLIKELY (stream->segment_index != seg_idx))
3203 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3205 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3206 stream->sample_index, stream->n_samples);
3208 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3211 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3212 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3213 stream->sample_index);
3217 /* now get the info for the sample we're at */
3218 sample = &stream->samples[stream->sample_index];
3220 *dts = QTSAMPLE_DTS (stream, sample);
3221 *pts = QTSAMPLE_PTS (stream, sample);
3222 *offset = sample->offset;
3223 *size = sample->size;
3224 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3225 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3232 stream->time_position = -1;
3237 /* move to the next sample in @stream.
3239 * Moves to the next segment when needed.
3242 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3244 QtDemuxSample *sample;
3245 QtDemuxSegment *segment;
3247 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3248 /* Mark the stream as EOS */
3249 GST_DEBUG_OBJECT (qtdemux,
3250 "reached max allowed sample %u, mark EOS", stream->to_sample);
3251 stream->time_position = -1;
3255 /* move to next sample */
3256 stream->sample_index++;
3258 /* get current segment */
3259 segment = &stream->segments[stream->segment_index];
3261 /* reached the last sample, we need the next segment */
3262 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3265 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3266 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3267 stream->sample_index);
3271 /* get next sample */
3272 sample = &stream->samples[stream->sample_index];
3274 /* see if we are past the segment */
3275 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3276 GST_SECOND, stream->timescale) >= segment->media_stop))
3279 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3280 stream->timescale) >= segment->media_start) {
3281 /* inside the segment, update time_position, looks very familiar to
3282 * GStreamer segments, doesn't it? */
3283 stream->time_position =
3284 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3285 stream->timescale) - segment->media_start) + segment->time;
3287 /* not yet in segment, time does not yet increment. This means
3288 * that we are still prerolling keyframes to the decoder so it can
3289 * decode the first sample of the segment. */
3290 stream->time_position = segment->time;
3294 /* move to the next segment */
3297 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3299 if (stream->segment_index == stream->n_segments - 1) {
3300 /* are we at the end of the last segment, we're EOS */
3301 stream->time_position = -1;
3303 /* else we're only at the end of the current segment */
3304 stream->time_position = segment->stop_time;
3306 /* make sure we select a new segment */
3307 stream->segment_index = -1;
3312 gst_qtdemux_sync_streams (GstQTDemux * demux)
3316 if (demux->n_streams <= 1)
3319 for (i = 0; i < demux->n_streams; i++) {
3320 QtDemuxStream *stream;
3321 GstClockTime end_time;
3323 stream = demux->streams[i];
3328 /* TODO advance time on subtitle streams here, if any some day */
3330 /* some clips/trailers may have unbalanced streams at the end,
3331 * so send EOS on shorter stream to prevent stalling others */
3333 /* do not mess with EOS if SEGMENT seeking */
3334 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3337 if (demux->pullbased) {
3338 /* loop mode is sample time based */
3339 if (stream->time_position != -1)
3342 /* push mode is byte position based */
3343 if (stream->n_samples &&
3344 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3348 if (stream->sent_eos)
3351 /* only act if some gap */
3352 end_time = stream->segments[stream->n_segments - 1].stop_time;
3353 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3354 ", stream end: %" GST_TIME_FORMAT,
3355 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3356 if (end_time + 2 * GST_SECOND < demux->segment.position) {
3357 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3358 GST_PAD_NAME (stream->pad));
3359 stream->sent_eos = TRUE;
3360 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3365 /* EOS and NOT_LINKED need to be combined. This means that we return:
3367 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3368 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
3370 static GstFlowReturn
3371 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3375 gboolean unexpected = FALSE, not_linked = TRUE;
3377 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3379 /* store the value */
3380 stream->last_ret = ret;
3382 /* any other error that is not-linked or eos can be returned right away */
3383 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3386 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3387 for (i = 0; i < demux->n_streams; i++) {
3388 QtDemuxStream *ostream = demux->streams[i];
3390 ret = ostream->last_ret;
3392 /* no unexpected or unlinked, return */
3393 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3396 /* we check to see if we have at least 1 unexpected or all unlinked */
3397 unexpected |= (ret == GST_FLOW_EOS);
3398 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3401 /* when we get here, we all have unlinked or unexpected */
3403 ret = GST_FLOW_NOT_LINKED;
3404 else if (unexpected)
3407 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3411 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3412 * completely cliped */
3414 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3417 guint64 start, stop, cstart, cstop, diff;
3418 GstClockTime pts, dts, duration;
3420 gint num_rate, denom_rate;
3425 osize = size = gst_buffer_get_size (buf);
3428 /* depending on the type, setup the clip parameters */
3429 if (stream->subtype == FOURCC_soun) {
3430 frame_size = stream->bytes_per_frame;
3431 num_rate = GST_SECOND;
3432 denom_rate = (gint) stream->rate;
3434 } else if (stream->subtype == FOURCC_vide) {
3436 num_rate = stream->fps_n;
3437 denom_rate = stream->fps_d;
3442 /* we can only clip if we have a valid pts */
3443 pts = GST_BUFFER_PTS (buf);
3444 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
3447 dts = GST_BUFFER_DTS (buf);
3448 duration = GST_BUFFER_DURATION (buf);
3450 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
3452 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3456 stop = start + duration;
3458 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3459 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3462 /* see if some clipping happened */
3463 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 if (offset != 0 || size != osize)
3498 gst_buffer_resize (buf, offset, size);
3500 GST_BUFFER_DTS (buf) = dts;
3501 GST_BUFFER_PTS (buf) = pts;
3502 GST_BUFFER_DURATION (buf) = duration;
3506 /* dropped buffer */
3509 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3514 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
3519 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3520 gst_buffer_unref (buf);
3525 /* the input buffer metadata must be writable,
3526 * but time/duration etc not yet set and need not be preserved */
3528 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3535 /* not many cases for now */
3536 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3537 /* send a one time dvd clut event */
3538 if (stream->pending_event && stream->pad)
3539 gst_pad_push_event (stream->pad, stream->pending_event);
3540 stream->pending_event = NULL;
3541 /* no further processing needed */
3542 stream->need_process = FALSE;
3545 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
3549 gst_buffer_map (buf, &map, GST_MAP_READ);
3551 if (G_LIKELY (map.size >= 2)) {
3552 nsize = GST_READ_UINT16_BE (map.data);
3553 nsize = MIN (nsize, map.size - 2);
3556 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
3559 /* takes care of UTF-8 validation or UTF-16 recognition,
3560 * no other encoding expected */
3561 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
3562 gst_buffer_unmap (buf, &map);
3564 gst_buffer_unref (buf);
3565 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
3567 /* may be 0-size subtitle, which is also sent to keep pipeline going */
3568 gst_buffer_resize (buf, 2, nsize);
3571 /* FIXME ? convert optional subsequent style info to markup */
3576 /* Sets a buffer's attributes properly and pushes it downstream.
3577 * Also checks for additional actions and custom processing that may
3578 * need to be done first.
3581 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3582 QtDemuxStream * stream, GstBuffer * buf,
3583 guint64 dts, guint64 pts, guint64 duration, gboolean keyframe,
3584 guint64 position, guint64 byte_position)
3586 GstFlowReturn ret = GST_FLOW_OK;
3588 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
3592 gst_buffer_map (buf, &map, GST_MAP_READ);
3593 url = g_strndup ((gchar *) map.data, map.size);
3594 gst_buffer_unmap (buf, &map);
3595 if (url != NULL && strlen (url) != 0) {
3596 /* we have RTSP redirect now */
3597 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3598 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
3599 gst_structure_new ("redirect",
3600 "new-location", G_TYPE_STRING, url, NULL)));
3601 qtdemux->posted_redirect = TRUE;
3603 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
3609 /* position reporting */
3610 if (qtdemux->segment.rate >= 0) {
3611 qtdemux->segment.position = position;
3612 gst_qtdemux_sync_streams (qtdemux);
3615 if (G_UNLIKELY (!stream->pad)) {
3616 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
3617 gst_buffer_unref (buf);
3621 /* send out pending buffers */
3622 while (stream->buffers) {
3623 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
3625 if (G_UNLIKELY (stream->discont)) {
3626 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3627 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
3628 stream->discont = FALSE;
3631 gst_pad_push (stream->pad, buffer);
3633 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
3636 /* we're going to modify the metadata */
3637 buf = gst_buffer_make_writable (buf);
3639 if (G_UNLIKELY (stream->need_process))
3640 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
3642 GST_BUFFER_DTS (buf) = dts;
3643 GST_BUFFER_PTS (buf) = pts;
3644 GST_BUFFER_DURATION (buf) = duration;
3645 GST_BUFFER_OFFSET (buf) = -1;
3646 GST_BUFFER_OFFSET_END (buf) = -1;
3648 if (G_UNLIKELY (stream->padding)) {
3649 gst_buffer_resize (buf, stream->padding, -1);
3652 if (G_UNLIKELY (qtdemux->element_index)) {
3653 GstClockTime stream_time;
3656 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
3658 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
3659 GST_LOG_OBJECT (qtdemux,
3660 "adding association %" GST_TIME_FORMAT "-> %"
3661 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
3662 gst_index_add_association (qtdemux->element_index,
3664 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
3665 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
3666 GST_FORMAT_BYTES, byte_position, NULL);
3671 if (stream->need_clip)
3672 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
3674 if (G_UNLIKELY (buf == NULL))
3677 if (G_UNLIKELY (stream->discont)) {
3678 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3679 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3680 stream->discont = FALSE;
3684 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3686 GST_LOG_OBJECT (qtdemux,
3687 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
3688 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
3689 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
3690 GST_PAD_NAME (stream->pad));
3692 ret = gst_pad_push (stream->pad, buf);
3698 static GstFlowReturn
3699 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
3701 GstFlowReturn ret = GST_FLOW_OK;
3702 GstBuffer *buf = NULL;
3703 QtDemuxStream *stream;
3706 guint64 dts = GST_CLOCK_TIME_NONE;
3707 guint64 pts = GST_CLOCK_TIME_NONE;
3708 guint64 duration = 0;
3709 gboolean keyframe = FALSE;
3714 gst_qtdemux_push_pending_newsegment (qtdemux);
3716 /* Figure out the next stream sample to output, min_time is expressed in
3717 * global time and runs over the edit list segments. */
3718 min_time = G_MAXUINT64;
3720 for (i = 0; i < qtdemux->n_streams; i++) {
3723 stream = qtdemux->streams[i];
3724 position = stream->time_position;
3726 /* position of -1 is EOS */
3727 if (position != -1 && position < min_time) {
3728 min_time = position;
3733 if (G_UNLIKELY (index == -1)) {
3734 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
3738 /* check for segment end */
3739 if (G_UNLIKELY (qtdemux->segment.stop != -1
3740 && qtdemux->segment.stop < min_time)) {
3741 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
3745 stream = qtdemux->streams[index];
3747 /* fetch info for the current sample of this stream */
3748 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
3749 &size, &dts, &pts, &duration, &keyframe)))
3752 GST_LOG_OBJECT (qtdemux,
3753 "pushing from stream %d, offset %" G_GUINT64_FORMAT
3754 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
3755 ", duration %" GST_TIME_FORMAT, index, offset, size,
3756 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
3758 /* hmm, empty sample, skip and move to next sample */
3759 if (G_UNLIKELY (size <= 0))
3762 /* last pushed sample was out of boundary, goto next sample */
3763 if (G_UNLIKELY (stream->last_ret == GST_FLOW_EOS))
3766 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
3769 if (stream->use_allocator) {
3770 /* if we have a per-stream allocator, use it */
3771 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
3774 ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
3775 if (G_UNLIKELY (ret != GST_FLOW_OK))
3778 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
3779 dts, pts, duration, keyframe, min_time, offset);
3782 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
3783 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
3784 * we have no more data for the pad to push */
3785 if (ret == GST_FLOW_EOS)
3789 gst_qtdemux_advance_sample (qtdemux, stream);
3797 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
3803 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
3804 /* EOS will be raised if all are EOS */
3811 gst_qtdemux_loop (GstPad * pad)
3813 GstQTDemux *qtdemux;
3817 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
3819 cur_offset = qtdemux->offset;
3820 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
3821 cur_offset, qtdemux->state);
3823 switch (qtdemux->state) {
3824 case QTDEMUX_STATE_INITIAL:
3825 case QTDEMUX_STATE_HEADER:
3826 ret = gst_qtdemux_loop_state_header (qtdemux);
3828 case QTDEMUX_STATE_MOVIE:
3829 ret = gst_qtdemux_loop_state_movie (qtdemux);
3830 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
3831 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
3839 /* if something went wrong, pause */
3840 if (ret != GST_FLOW_OK)
3844 gst_object_unref (qtdemux);
3850 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3851 (NULL), ("streaming stopped, invalid state"));
3852 gst_pad_pause_task (pad);
3853 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3858 const gchar *reason = gst_flow_get_name (ret);
3860 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
3862 gst_pad_pause_task (pad);
3864 /* fatal errors need special actions */
3866 if (ret == GST_FLOW_EOS) {
3867 if (qtdemux->n_streams == 0) {
3868 /* we have no streams, post an error */
3869 gst_qtdemux_post_no_playable_stream_error (qtdemux);
3871 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3874 if ((stop = qtdemux->segment.stop) == -1)
3875 stop = qtdemux->segment.duration;
3877 if (qtdemux->segment.rate >= 0) {
3878 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
3879 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3880 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3881 GST_FORMAT_TIME, stop));
3883 /* For Reverse Playback */
3884 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
3885 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3886 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3887 GST_FORMAT_TIME, qtdemux->segment.start));
3890 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
3891 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3893 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
3894 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3895 (NULL), ("streaming stopped, reason %s", reason));
3896 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3905 * Returns the size of the first entry at the current offset.
3906 * If -1, there are none (which means EOS or empty file).
3909 next_entry_size (GstQTDemux * demux)
3911 QtDemuxStream *stream;
3914 guint64 smalloffs = (guint64) - 1;
3915 QtDemuxSample *sample;
3917 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
3920 for (i = 0; i < demux->n_streams; i++) {
3921 stream = demux->streams[i];
3923 if (stream->sample_index == -1)
3924 stream->sample_index = 0;
3926 if (stream->sample_index >= stream->n_samples) {
3927 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
3931 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
3932 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
3933 stream->sample_index);
3937 sample = &stream->samples[stream->sample_index];
3939 GST_LOG_OBJECT (demux,
3940 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3941 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
3942 sample->offset, sample->size);
3944 if (((smalloffs == -1)
3945 || (sample->offset < smalloffs)) && (sample->size)) {
3947 smalloffs = sample->offset;
3951 GST_LOG_OBJECT (demux,
3952 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
3953 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
3958 stream = demux->streams[smallidx];
3959 sample = &stream->samples[stream->sample_index];
3961 if (sample->offset >= demux->offset) {
3962 demux->todrop = sample->offset - demux->offset;
3963 return sample->size + demux->todrop;
3966 GST_DEBUG_OBJECT (demux,
3967 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
3972 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
3974 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
3976 gst_element_post_message (GST_ELEMENT_CAST (demux),
3977 gst_message_new_element (GST_OBJECT_CAST (demux),
3978 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
3982 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
3987 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
3990 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
3991 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
3992 GST_SEEK_TYPE_NONE, -1);
3994 res = gst_pad_push_event (demux->sinkpad, event);
3999 /* check for seekable upstream, above and beyond a mere query */
4001 gst_qtdemux_check_seekability (GstQTDemux * demux)
4004 gboolean seekable = FALSE;
4005 gint64 start = -1, stop = -1;
4007 if (demux->upstream_size)
4010 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4011 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4012 GST_DEBUG_OBJECT (demux, "seeking query failed");
4016 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4018 /* try harder to query upstream size if we didn't get it the first time */
4019 if (seekable && stop == -1) {
4020 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4021 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4024 /* if upstream doesn't know the size, it's likely that it's not seekable in
4025 * practice even if it technically may be seekable */
4026 if (seekable && (start != 0 || stop <= start)) {
4027 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4032 gst_query_unref (query);
4034 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4035 G_GUINT64_FORMAT ")", seekable, start, stop);
4036 demux->upstream_seekable = seekable;
4037 demux->upstream_size = seekable ? stop : -1;
4040 /* FIXME, unverified after edit list updates */
4041 static GstFlowReturn
4042 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4045 GstFlowReturn ret = GST_FLOW_OK;
4047 demux = GST_QTDEMUX (parent);
4049 gst_adapter_push (demux->adapter, inbuf);
4051 /* we never really mean to buffer that much */
4052 if (demux->neededbytes == -1)
4055 GST_DEBUG_OBJECT (demux,
4056 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4057 demux->neededbytes, gst_adapter_available (demux->adapter));
4059 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4060 (ret == GST_FLOW_OK)) {
4062 GST_DEBUG_OBJECT (demux,
4063 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4064 demux->state, demux->neededbytes, demux->offset);
4066 switch (demux->state) {
4067 case QTDEMUX_STATE_INITIAL:{
4072 gst_qtdemux_check_seekability (demux);
4074 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4076 /* get fourcc/length, set neededbytes */
4077 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4079 gst_adapter_unmap (demux->adapter);
4081 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4082 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4084 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4085 (_("This file is invalid and cannot be played.")),
4086 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4087 GST_FOURCC_ARGS (fourcc)));
4088 ret = GST_FLOW_ERROR;
4091 if (fourcc == FOURCC_mdat) {
4092 if (demux->n_streams > 0) {
4093 /* we have the headers, start playback */
4094 demux->state = QTDEMUX_STATE_MOVIE;
4095 demux->neededbytes = next_entry_size (demux);
4096 demux->mdatleft = size;
4098 /* Only post, event on pads is done after newsegment */
4099 qtdemux_post_global_tags (demux);
4102 /* no headers yet, try to get them */
4105 guint64 old, target;
4108 old = demux->offset;
4109 target = old + size;
4111 /* try to jump over the atom with a seek */
4112 /* only bother if it seems worth doing so,
4113 * and avoids possible upstream/server problems */
4114 if (demux->upstream_seekable &&
4115 demux->upstream_size > 4 * (1 << 20)) {
4116 res = qtdemux_seek_offset (demux, target);
4118 GST_DEBUG_OBJECT (demux, "skipping seek");
4123 GST_DEBUG_OBJECT (demux, "seek success");
4124 /* remember the offset fo the first mdat so we can seek back to it
4125 * after we have the headers */
4126 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4127 demux->first_mdat = old;
4128 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4131 /* seek worked, continue reading */
4132 demux->offset = target;
4133 demux->neededbytes = 16;
4134 demux->state = QTDEMUX_STATE_INITIAL;
4136 /* seek failed, need to buffer */
4137 demux->offset = old;
4138 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4139 /* there may be multiple mdat (or alike) buffers */
4141 if (demux->mdatbuffer)
4142 bs = gst_buffer_get_size (demux->mdatbuffer);
4145 if (size + bs > 10 * (1 << 20))
4147 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4148 demux->neededbytes = size;
4149 if (!demux->mdatbuffer)
4150 demux->mdatoffset = demux->offset;
4153 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4154 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4155 (_("This file is invalid and cannot be played.")),
4156 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4157 GST_FOURCC_ARGS (fourcc), size));
4158 ret = GST_FLOW_ERROR;
4161 /* this means we already started buffering and still no moov header,
4162 * let's continue buffering everything till we get moov */
4163 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
4165 demux->neededbytes = size;
4166 demux->state = QTDEMUX_STATE_HEADER;
4170 case QTDEMUX_STATE_HEADER:{
4174 GST_DEBUG_OBJECT (demux, "In header");
4176 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4178 /* parse the header */
4179 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4181 if (fourcc == FOURCC_moov) {
4182 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4184 demux->got_moov = TRUE;
4186 /* prepare newsegment to send when streaming actually starts */
4187 if (!demux->pending_newsegment)
4188 demux->pending_newsegment = gst_event_new_segment (&demux->segment);
4190 qtdemux_parse_moov (demux, data, demux->neededbytes);
4191 qtdemux_node_dump (demux, demux->moov_node);
4192 qtdemux_parse_tree (demux);
4193 qtdemux_expose_streams (demux);
4195 g_node_destroy (demux->moov_node);
4196 demux->moov_node = NULL;
4197 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4198 } else if (fourcc == FOURCC_moof) {
4199 if (demux->got_moov && demux->fragmented) {
4200 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4201 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4202 demux->offset, NULL)) {
4203 gst_adapter_unmap (demux->adapter);
4204 ret = GST_FLOW_ERROR;
4208 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4210 } else if (fourcc == FOURCC_ftyp) {
4211 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4212 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4213 } else if (fourcc == FOURCC_uuid) {
4214 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4215 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4217 GST_WARNING_OBJECT (demux,
4218 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4219 GST_FOURCC_ARGS (fourcc));
4220 /* Let's jump that one and go back to initial state */
4222 gst_adapter_unmap (demux->adapter);
4225 if (demux->mdatbuffer && demux->n_streams) {
4226 /* the mdat was before the header */
4227 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4228 demux->n_streams, demux->mdatbuffer);
4229 /* restore our adapter/offset view of things with upstream;
4230 * put preceding buffered data ahead of current moov data.
4231 * This should also handle evil mdat, moov, mdat cases and alike */
4232 gst_adapter_clear (demux->adapter);
4233 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4234 demux->mdatbuffer = NULL;
4235 demux->offset = demux->mdatoffset;
4236 demux->neededbytes = next_entry_size (demux);
4237 demux->state = QTDEMUX_STATE_MOVIE;
4238 demux->mdatleft = gst_adapter_available (demux->adapter);
4240 /* Only post, event on pads is done after newsegment */
4241 qtdemux_post_global_tags (demux);
4244 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4245 gst_adapter_flush (demux->adapter, demux->neededbytes);
4247 if (demux->got_moov && demux->first_mdat != -1) {
4250 /* we need to seek back */
4251 res = qtdemux_seek_offset (demux, demux->first_mdat);
4253 demux->offset = demux->first_mdat;
4255 GST_DEBUG_OBJECT (demux, "Seek back failed");
4258 demux->offset += demux->neededbytes;
4260 demux->neededbytes = 16;
4261 demux->state = QTDEMUX_STATE_INITIAL;
4266 case QTDEMUX_STATE_BUFFER_MDAT:{
4270 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4272 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4273 gst_buffer_extract (buf, 0, fourcc, 4);
4274 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4275 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
4276 if (demux->mdatbuffer)
4277 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
4279 demux->mdatbuffer = buf;
4280 demux->offset += demux->neededbytes;
4281 demux->neededbytes = 16;
4282 demux->state = QTDEMUX_STATE_INITIAL;
4283 gst_qtdemux_post_progress (demux, 1, 1);
4287 case QTDEMUX_STATE_MOVIE:{
4289 QtDemuxStream *stream = NULL;
4290 QtDemuxSample *sample;
4292 guint64 dts, pts, duration;
4295 GST_DEBUG_OBJECT (demux,
4296 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4298 if (demux->fragmented) {
4299 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4301 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4302 /* if needed data starts within this atom,
4303 * then it should not exceed this atom */
4304 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4305 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4306 (_("This file is invalid and cannot be played.")),
4307 ("sample data crosses atom boundary"));
4308 ret = GST_FLOW_ERROR;
4311 demux->mdatleft -= demux->neededbytes;
4313 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4314 /* so we are dropping more than left in this atom */
4315 demux->todrop -= demux->mdatleft;
4316 demux->neededbytes -= demux->mdatleft;
4317 demux->mdatleft = 0;
4318 /* need to resume atom parsing so we do not miss any other pieces */
4319 demux->state = QTDEMUX_STATE_INITIAL;
4320 demux->neededbytes = 16;
4325 if (demux->todrop) {
4326 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4327 gst_adapter_flush (demux->adapter, demux->todrop);
4328 demux->neededbytes -= demux->todrop;
4329 demux->offset += demux->todrop;
4333 /* initial newsegment sent here after having added pads,
4334 * possible others in sink_event */
4335 if (G_UNLIKELY (demux->pending_newsegment)) {
4336 gst_qtdemux_push_event (demux, demux->pending_newsegment);
4337 demux->pending_newsegment = NULL;
4338 /* clear to send tags on all streams */
4339 for (i = 0; i < demux->n_streams; i++) {
4340 gst_qtdemux_push_tags (demux, demux->streams[i]);
4344 /* Figure out which stream this is packet belongs to */
4345 for (i = 0; i < demux->n_streams; i++) {
4346 stream = demux->streams[i];
4347 if (stream->sample_index >= stream->n_samples)
4349 GST_LOG_OBJECT (demux,
4350 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4351 " / size:%d)", i, stream->sample_index,
4352 stream->samples[stream->sample_index].offset,
4353 stream->samples[stream->sample_index].size);
4355 if (stream->samples[stream->sample_index].offset == demux->offset)
4359 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4360 goto unknown_stream;
4362 /* Put data in a buffer, set timestamps, caps, ... */
4363 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4364 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4365 GST_FOURCC_ARGS (stream->fourcc));
4367 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4369 sample = &stream->samples[stream->sample_index];
4371 dts = QTSAMPLE_DTS (stream, sample);
4372 pts = QTSAMPLE_PTS (stream, sample);
4373 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
4374 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4376 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4377 dts, pts, duration, keyframe, dts, demux->offset);
4380 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4382 stream->sample_index++;
4384 /* update current offset and figure out size of next buffer */
4385 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4386 demux->offset, demux->neededbytes);
4387 demux->offset += demux->neededbytes;
4388 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4391 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4392 if (demux->fragmented) {
4393 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4394 /* there may be more to follow, only finish this atom */
4395 demux->todrop = demux->mdatleft;
4396 demux->neededbytes = demux->todrop;
4408 /* when buffering movie data, at least show user something is happening */
4409 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4410 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4411 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4412 demux->neededbytes);
4421 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4422 ret = GST_FLOW_ERROR;
4427 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4433 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4434 (NULL), ("qtdemuxer invalid state %d", demux->state));
4435 ret = GST_FLOW_ERROR;
4440 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4441 (NULL), ("no 'moov' atom within the first 10 MB"));
4442 ret = GST_FLOW_ERROR;
4448 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
4453 query = gst_query_new_scheduling ();
4455 if (!gst_pad_peer_query (sinkpad, query)) {
4456 gst_query_unref (query);
4460 pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
4461 gst_query_unref (query);
4466 GST_DEBUG_OBJECT (sinkpad, "activating pull");
4467 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
4471 GST_DEBUG_OBJECT (sinkpad, "activating push");
4472 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
4477 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
4478 GstPadMode mode, gboolean active)
4481 GstQTDemux *demux = GST_QTDEMUX (parent);
4484 case GST_PAD_MODE_PUSH:
4485 demux->pullbased = FALSE;
4488 case GST_PAD_MODE_PULL:
4490 demux->pullbased = TRUE;
4491 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4494 res = gst_pad_stop_task (sinkpad);
4506 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4508 return g_malloc (items * size);
4512 qtdemux_zfree (void *opaque, void *addr)
4518 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4524 z = g_new0 (z_stream, 1);
4525 z->zalloc = qtdemux_zalloc;
4526 z->zfree = qtdemux_zfree;
4529 z->next_in = z_buffer;
4530 z->avail_in = z_length;
4532 buffer = (guint8 *) g_malloc (length);
4533 ret = inflateInit (z);
4534 while (z->avail_in > 0) {
4535 if (z->avail_out == 0) {
4537 buffer = (guint8 *) g_realloc (buffer, length);
4538 z->next_out = buffer + z->total_out;
4539 z->avail_out = 1024;
4541 ret = inflate (z, Z_SYNC_FLUSH);
4545 if (ret != Z_STREAM_END) {
4546 g_warning ("inflate() returned %d", ret);
4552 #endif /* HAVE_ZLIB */
4555 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4559 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4561 /* counts as header data */
4562 qtdemux->header_size += length;
4564 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4565 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4567 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4573 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4574 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4575 if (dcom == NULL || cmvd == NULL)
4576 goto invalid_compression;
4578 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4581 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4582 guint uncompressed_length;
4583 guint compressed_length;
4586 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4587 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4588 GST_LOG ("length = %u", uncompressed_length);
4591 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4592 compressed_length, uncompressed_length);
4594 qtdemux->moov_node_compressed = qtdemux->moov_node;
4595 qtdemux->moov_node = g_node_new (buf);
4597 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4598 uncompressed_length);
4601 #endif /* HAVE_ZLIB */
4603 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4604 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
4611 invalid_compression:
4613 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
4619 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
4622 while (G_UNLIKELY (buf < end)) {
4626 if (G_UNLIKELY (buf + 4 > end)) {
4627 GST_LOG_OBJECT (qtdemux, "buffer overrun");
4630 len = QT_UINT32 (buf);
4631 if (G_UNLIKELY (len == 0)) {
4632 GST_LOG_OBJECT (qtdemux, "empty container");
4635 if (G_UNLIKELY (len < 8)) {
4636 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
4639 if (G_UNLIKELY (len > (end - buf))) {
4640 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
4641 (gint) (end - buf));
4645 child = g_node_new ((guint8 *) buf);
4646 g_node_append (node, child);
4647 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
4648 qtdemux_parse_node (qtdemux, child, buf, len);
4656 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
4659 int len = QT_UINT32 (xdxt->data);
4660 guint8 *buf = xdxt->data;
4661 guint8 *end = buf + len;
4664 /* skip size and type */
4672 size = QT_UINT32 (buf);
4673 type = QT_FOURCC (buf + 4);
4675 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
4677 if (buf + size > end || size <= 0)
4683 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
4684 GST_FOURCC_ARGS (type));
4688 buffer = gst_buffer_new_and_alloc (size);
4689 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4690 stream->buffers = g_slist_append (stream->buffers, buffer);
4691 GST_LOG_OBJECT (qtdemux, "parsing theora header");
4694 buffer = gst_buffer_new_and_alloc (size);
4695 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4696 stream->buffers = g_slist_append (stream->buffers, buffer);
4697 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
4700 buffer = gst_buffer_new_and_alloc (size);
4701 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4702 stream->buffers = g_slist_append (stream->buffers, buffer);
4703 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
4706 GST_WARNING_OBJECT (qtdemux,
4707 "unknown theora cookie %" GST_FOURCC_FORMAT,
4708 GST_FOURCC_ARGS (type));
4717 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
4721 guint32 node_length = 0;
4722 const QtNodeType *type;
4725 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
4727 if (G_UNLIKELY (length < 8))
4728 goto not_enough_data;
4730 node_length = QT_UINT32 (buffer);
4731 fourcc = QT_FOURCC (buffer + 4);
4733 /* ignore empty nodes */
4734 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
4737 type = qtdemux_type_get (fourcc);
4739 end = buffer + length;
4741 GST_LOG_OBJECT (qtdemux,
4742 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
4743 GST_FOURCC_ARGS (fourcc), node_length, type->name);
4745 if (node_length > length)
4746 goto broken_atom_size;
4748 if (type->flags & QT_FLAG_CONTAINER) {
4749 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
4754 if (node_length < 20) {
4755 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
4758 GST_DEBUG_OBJECT (qtdemux,
4759 "parsing stsd (sample table, sample description) atom");
4760 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
4770 /* also read alac (or whatever) in stead of mp4a in the following,
4771 * since a similar layout is used in other cases as well */
4772 if (fourcc == FOURCC_mp4a)
4777 /* There are two things we might encounter here: a true mp4a atom, and
4778 an mp4a entry in an stsd atom. The latter is what we're interested
4779 in, and it looks like an atom, but isn't really one. The true mp4a
4780 atom is short, so we detect it based on length here. */
4781 if (length < min_size) {
4782 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
4783 GST_FOURCC_ARGS (fourcc));
4787 /* 'version' here is the sound sample description version. Types 0 and
4788 1 are documented in the QTFF reference, but type 2 is not: it's
4789 described in Apple header files instead (struct SoundDescriptionV2
4791 version = QT_UINT16 (buffer + 16);
4793 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
4794 GST_FOURCC_ARGS (fourcc), version);
4796 /* parse any esds descriptors */
4808 GST_WARNING_OBJECT (qtdemux,
4809 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
4810 GST_FOURCC_ARGS (fourcc), version);
4815 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4827 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
4828 GST_FOURCC_ARGS (fourcc));
4829 version = QT_UINT32 (buffer + 16);
4830 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
4831 if (1 || version == 0x00000000) {
4832 buf = buffer + 0x32;
4834 /* FIXME Quicktime uses PASCAL string while
4835 * the iso format uses C strings. Check the file
4836 * type before attempting to parse the string here. */
4837 tlen = QT_UINT8 (buf);
4838 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
4840 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
4841 /* the string has a reserved space of 32 bytes so skip
4842 * the remaining 31 */
4844 buf += 4; /* and 4 bytes reserved */
4846 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
4848 qtdemux_parse_container (qtdemux, node, buf, end);
4854 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
4855 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
4860 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
4865 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
4866 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
4874 version = QT_UINT32 (buffer + 12);
4875 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
4882 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
4887 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4892 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
4896 if (!strcmp (type->name, "unknown"))
4897 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
4901 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
4902 GST_FOURCC_ARGS (fourcc));
4908 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4909 (_("This file is corrupt and cannot be played.")),
4910 ("Not enough data for an atom header, got only %u bytes", length));
4915 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4916 (_("This file is corrupt and cannot be played.")),
4917 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
4918 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
4925 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
4929 guint32 child_fourcc;
4931 for (child = g_node_first_child (node); child;
4932 child = g_node_next_sibling (child)) {
4933 buffer = (guint8 *) child->data;
4935 child_fourcc = QT_FOURCC (buffer + 4);
4937 if (G_UNLIKELY (child_fourcc == fourcc)) {
4945 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
4946 GstByteReader * parser)
4950 guint32 child_fourcc, child_len;
4952 for (child = g_node_first_child (node); child;
4953 child = g_node_next_sibling (child)) {
4954 buffer = (guint8 *) child->data;
4956 child_len = QT_UINT32 (buffer);
4957 child_fourcc = QT_FOURCC (buffer + 4);
4959 if (G_UNLIKELY (child_fourcc == fourcc)) {
4960 if (G_UNLIKELY (child_len < (4 + 4)))
4962 /* FIXME: must verify if atom length < parent atom length */
4963 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4971 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
4972 GstByteReader * parser)
4976 guint32 child_fourcc, child_len;
4978 for (child = g_node_next_sibling (node); child;
4979 child = g_node_next_sibling (child)) {
4980 buffer = (guint8 *) child->data;
4982 child_fourcc = QT_FOURCC (buffer + 4);
4984 if (child_fourcc == fourcc) {
4986 child_len = QT_UINT32 (buffer);
4987 if (G_UNLIKELY (child_len < (4 + 4)))
4989 /* FIXME: must verify if atom length < parent atom length */
4990 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4999 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
5001 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
5005 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
5009 query = gst_query_new_allocation (stream->caps, FALSE);
5011 if (!gst_pad_peer_query (stream->pad, query)) {
5012 /* not a problem, just debug a little */
5013 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
5016 if (stream->allocator)
5017 gst_allocator_unref (stream->allocator);
5019 if (gst_query_get_n_allocation_params (query) > 0) {
5020 /* try the allocator */
5021 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
5023 stream->use_allocator = TRUE;
5025 stream->allocator = NULL;
5026 gst_allocation_params_init (&stream->params);
5027 stream->use_allocator = FALSE;
5029 gst_query_unref (query);
5033 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
5034 QtDemuxStream * stream, GstTagList * list)
5036 /* consistent default for push based mode */
5037 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
5039 if (stream->subtype == FOURCC_vide) {
5040 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5043 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5046 /* fps is calculated base on the duration of the first frames since
5047 * qt does not have a fixed framerate. */
5048 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
5053 stream->fps_n = stream->timescale;
5054 if (stream->min_duration == 0)
5057 stream->fps_d = stream->min_duration;
5062 gint depth, palette_count;
5063 const guint32 *palette_data = NULL;
5065 gst_caps_set_simple (stream->caps,
5066 "width", G_TYPE_INT, stream->width,
5067 "height", G_TYPE_INT, stream->height,
5068 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5070 /* calculate pixel-aspect-ratio using display width and height */
5071 GST_DEBUG_OBJECT (qtdemux,
5072 "video size %dx%d, target display size %dx%d", stream->width,
5073 stream->height, stream->display_width, stream->display_height);
5075 if (stream->display_width > 0 && stream->display_height > 0 &&
5076 stream->width > 0 && stream->height > 0) {
5079 /* calculate the pixel aspect ratio using the display and pixel w/h */
5080 n = stream->display_width * stream->height;
5081 d = stream->display_height * stream->width;
5084 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5085 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5086 GST_TYPE_FRACTION, n, d, NULL);
5089 /* qt file might have pasp atom */
5090 if (stream->par_w > 0 && stream->par_h > 0) {
5091 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5092 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5093 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5096 depth = stream->bits_per_sample;
5098 /* more than 32 bits means grayscale */
5099 gray = (depth > 32);
5100 /* low 32 bits specify the depth */
5103 /* different number of palette entries is determined by depth. */
5105 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
5106 palette_count = (1 << depth);
5108 switch (palette_count) {
5112 palette_data = ff_qt_default_palette_2;
5115 palette_data = ff_qt_default_palette_4;
5119 palette_data = ff_qt_grayscale_palette_16;
5121 palette_data = ff_qt_default_palette_16;
5125 palette_data = ff_qt_grayscale_palette_256;
5127 palette_data = ff_qt_default_palette_256;
5130 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5131 (_("The video in this file might not play correctly.")),
5132 ("unsupported palette depth %d", depth));
5138 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5139 * don't free any of the buffer data. */
5140 palette = _gst_buffer_new_wrapped ((gpointer) palette_data,
5141 palette_count, NULL);
5143 gst_caps_set_simple (stream->caps, "palette_data",
5144 GST_TYPE_BUFFER, palette, NULL);
5145 gst_buffer_unref (palette);
5146 } else if (palette_count != 0) {
5147 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5148 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5150 gst_object_unref (stream->pad);
5154 qtdemux->n_video_streams++;
5155 } else if (stream->subtype == FOURCC_soun) {
5156 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
5159 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5162 /* FIXME: Need to set channel-mask here and maybe reorder */
5163 gst_caps_set_simple (stream->caps,
5164 "rate", G_TYPE_INT, (int) stream->rate,
5165 "channels", G_TYPE_INT, stream->n_channels, NULL);
5167 qtdemux->n_audio_streams++;
5168 } else if (stream->subtype == FOURCC_strm) {
5169 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5170 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
5171 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
5174 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5176 qtdemux->n_sub_streams++;
5178 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5183 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5185 gst_pad_use_fixed_caps (stream->pad);
5186 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5187 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5188 gst_pad_set_active (stream->pad, TRUE);
5190 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5191 gst_pad_set_caps (stream->pad, stream->caps);
5193 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5194 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5195 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5197 if (stream->pending_tags)
5198 gst_tag_list_free (stream->pending_tags);
5199 stream->pending_tags = list;
5200 /* global tags go on each pad anyway */
5201 stream->send_global_tags = TRUE;
5203 qtdemux_do_allocation (qtdemux, stream);
5209 /* find next atom with @fourcc starting at @offset */
5210 static GstFlowReturn
5211 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5212 guint64 * length, guint32 fourcc)
5218 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5219 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5225 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5226 if (G_UNLIKELY (ret != GST_FLOW_OK))
5228 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
5231 gst_buffer_unref (buf);
5234 gst_buffer_map (buf, &map, GST_MAP_READ);
5235 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
5236 gst_buffer_unmap (buf, &map);
5237 gst_buffer_unref (buf);
5239 if (G_UNLIKELY (*length == 0)) {
5240 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5241 ret = GST_FLOW_ERROR;
5245 if (lfourcc == fourcc) {
5246 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5250 GST_LOG_OBJECT (qtdemux,
5251 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5252 GST_FOURCC_ARGS (fourcc), *offset);
5261 /* might simply have had last one */
5262 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5267 /* should only do something in pull mode */
5268 /* call with OBJECT lock */
5269 static GstFlowReturn
5270 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5272 guint64 length, offset;
5273 GstBuffer *buf = NULL;
5274 GstFlowReturn ret = GST_FLOW_OK;
5275 GstFlowReturn res = GST_FLOW_OK;
5278 offset = qtdemux->moof_offset;
5279 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5282 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5283 return GST_FLOW_EOS;
5286 /* best not do pull etc with lock held */
5287 GST_OBJECT_UNLOCK (qtdemux);
5289 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5290 if (ret != GST_FLOW_OK)
5293 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5294 if (G_UNLIKELY (ret != GST_FLOW_OK))
5296 gst_buffer_map (buf, &map, GST_MAP_READ);
5297 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
5298 gst_buffer_unmap (buf, &map);
5299 gst_buffer_unref (buf);
5304 gst_buffer_unmap (buf, &map);
5305 gst_buffer_unref (buf);
5309 /* look for next moof */
5310 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5311 if (G_UNLIKELY (ret != GST_FLOW_OK))
5315 GST_OBJECT_LOCK (qtdemux);
5317 qtdemux->moof_offset = offset;
5323 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5325 res = GST_FLOW_ERROR;
5330 /* maybe upstream temporarily flushing */
5331 if (ret != GST_FLOW_FLUSHING) {
5332 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5335 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5336 /* resume at current position next time */
5343 /* initialise bytereaders for stbl sub-atoms */
5345 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5347 stream->stbl_index = -1; /* no samples have yet been parsed */
5349 /* time-to-sample atom */
5350 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5353 /* copy atom data into a new buffer for later use */
5354 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5356 /* skip version + flags */
5357 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5358 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5360 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5362 /* make sure there's enough data */
5363 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
5364 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
5365 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
5366 stream->n_sample_times);
5367 if (!stream->n_sample_times)
5371 /* sync sample atom */
5372 stream->stps_present = FALSE;
5373 if ((stream->stss_present =
5374 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5375 &stream->stss) ? TRUE : FALSE) == TRUE) {
5376 /* copy atom data into a new buffer for later use */
5377 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5379 /* skip version + flags */
5380 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5381 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5384 if (stream->n_sample_syncs) {
5385 /* make sure there's enough data */
5386 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5390 /* partial sync sample atom */
5391 if ((stream->stps_present =
5392 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5393 &stream->stps) ? TRUE : FALSE) == TRUE) {
5394 /* copy atom data into a new buffer for later use */
5395 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5397 /* skip version + flags */
5398 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5399 !gst_byte_reader_get_uint32_be (&stream->stps,
5400 &stream->n_sample_partial_syncs))
5403 /* if there are no entries, the stss table contains the real
5405 if (stream->n_sample_partial_syncs) {
5406 /* make sure there's enough data */
5407 if (!qt_atom_parser_has_chunks (&stream->stps,
5408 stream->n_sample_partial_syncs, 4))
5415 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5418 /* copy atom data into a new buffer for later use */
5419 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5421 /* skip version + flags */
5422 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5423 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5426 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5429 if (!stream->n_samples)
5432 /* sample-to-chunk atom */
5433 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5436 /* copy atom data into a new buffer for later use */
5437 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5439 /* skip version + flags */
5440 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5441 !gst_byte_reader_get_uint32_be (&stream->stsc,
5442 &stream->n_samples_per_chunk))
5445 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5446 stream->n_samples_per_chunk);
5448 /* make sure there's enough data */
5449 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5455 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5456 stream->co_size = sizeof (guint32);
5457 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5459 stream->co_size = sizeof (guint64);
5463 /* copy atom data into a new buffer for later use */
5464 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5466 /* skip version + flags */
5467 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5470 /* chunks_are_chunks == 0 means treat chunks as samples */
5471 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5472 if (stream->chunks_are_chunks) {
5473 /* skip number of entries */
5474 if (!gst_byte_reader_skip (&stream->stco, 4))
5477 /* make sure there are enough data in the stsz atom */
5478 if (!stream->sample_size) {
5479 /* different sizes for each sample */
5480 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5484 /* treat chunks as samples */
5485 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5489 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5490 stream->n_samples, (guint) sizeof (QtDemuxSample),
5491 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5493 if (stream->n_samples >=
5494 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5495 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5496 "be larger than %uMB (broken file?)", stream->n_samples,
5497 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5501 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5502 if (!stream->samples) {
5503 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5509 /* composition time-to-sample */
5510 if ((stream->ctts_present =
5511 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5512 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5513 /* copy atom data into a new buffer for later use */
5514 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5516 /* skip version + flags */
5517 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5518 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5519 &stream->n_composition_times))
5522 /* make sure there's enough data */
5523 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5532 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5533 (_("This file is corrupt and cannot be played.")), (NULL));
5538 gst_qtdemux_stbl_free (stream);
5539 if (!qtdemux->fragmented) {
5540 /* not quite good */
5541 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5544 /* may pick up samples elsewhere */
5550 /* collect samples from the next sample to be parsed up to sample @n for @stream
5551 * by reading the info from @stbl
5553 * This code can be executed from both the streaming thread and the seeking
5554 * thread so it takes the object lock to protect itself
5557 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
5560 QtDemuxSample *samples, *first, *cur, *last;
5561 guint32 n_samples_per_chunk;
5564 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
5565 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
5566 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
5568 n_samples = stream->n_samples;
5571 goto out_of_samples;
5573 GST_OBJECT_LOCK (qtdemux);
5574 if (n <= stream->stbl_index)
5575 goto already_parsed;
5577 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
5579 if (!stream->stsz.data) {
5580 /* so we already parsed and passed all the moov samples;
5581 * onto fragmented ones */
5582 g_assert (qtdemux->fragmented);
5586 /* pointer to the sample table */
5587 samples = stream->samples;
5589 /* starts from -1, moves to the next sample index to parse */
5590 stream->stbl_index++;
5592 /* keep track of the first and last sample to fill */
5593 first = &samples[stream->stbl_index];
5596 if (stream->chunks_are_chunks) {
5597 /* set the sample sizes */
5598 if (stream->sample_size == 0) {
5599 /* different sizes for each sample */
5600 for (cur = first; cur <= last; cur++) {
5601 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
5602 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
5603 (guint) (cur - samples), cur->size);
5606 /* samples have the same size */
5607 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
5608 for (cur = first; cur <= last; cur++)
5609 cur->size = stream->sample_size;
5613 n_samples_per_chunk = stream->n_samples_per_chunk;
5616 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
5619 if (stream->stsc_chunk_index >= stream->last_chunk
5620 || stream->stsc_chunk_index < stream->first_chunk) {
5621 stream->first_chunk =
5622 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5623 stream->samples_per_chunk =
5624 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5625 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
5627 /* chunk numbers are counted from 1 it seems */
5628 if (G_UNLIKELY (stream->first_chunk == 0))
5631 --stream->first_chunk;
5633 /* the last chunk of each entry is calculated by taking the first chunk
5634 * of the next entry; except if there is no next, where we fake it with
5636 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
5637 stream->last_chunk = G_MAXUINT32;
5639 stream->last_chunk =
5640 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
5641 if (G_UNLIKELY (stream->last_chunk == 0))
5644 --stream->last_chunk;
5647 GST_LOG_OBJECT (qtdemux,
5648 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
5649 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
5651 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
5654 if (stream->last_chunk != G_MAXUINT32) {
5655 if (!qt_atom_parser_peek_sub (&stream->stco,
5656 stream->first_chunk * stream->co_size,
5657 (stream->last_chunk - stream->first_chunk) * stream->co_size,
5662 stream->co_chunk = stream->stco;
5663 if (!gst_byte_reader_skip (&stream->co_chunk,
5664 stream->first_chunk * stream->co_size))
5668 stream->stsc_chunk_index = stream->first_chunk;
5671 last_chunk = stream->last_chunk;
5673 if (stream->chunks_are_chunks) {
5674 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5675 guint32 samples_per_chunk;
5676 guint64 chunk_offset;
5678 if (!stream->stsc_sample_index
5679 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
5680 &stream->chunk_offset))
5683 samples_per_chunk = stream->samples_per_chunk;
5684 chunk_offset = stream->chunk_offset;
5686 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
5687 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
5688 G_GUINT64_FORMAT, (guint) (cur - samples), stream->chunk_offset);
5690 cur->offset = chunk_offset;
5691 chunk_offset += cur->size;
5694 if (G_UNLIKELY (cur > last)) {
5696 stream->stsc_sample_index = k + 1;
5697 stream->chunk_offset = chunk_offset;
5698 stream->stsc_chunk_index = j;
5702 stream->stsc_sample_index = 0;
5704 stream->stsc_chunk_index = j;
5706 cur = &samples[stream->stsc_chunk_index];
5708 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5711 stream->stsc_chunk_index = j;
5716 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
5719 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
5720 "%" G_GUINT64_FORMAT, j, cur->offset);
5722 if (stream->samples_per_frame * stream->bytes_per_frame) {
5724 (stream->samples_per_chunk * stream->n_channels) /
5725 stream->samples_per_frame * stream->bytes_per_frame;
5727 cur->size = stream->samples_per_chunk;
5730 GST_DEBUG_OBJECT (qtdemux,
5731 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
5732 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
5733 GST_SECOND, stream->timescale)), cur->size);
5735 cur->timestamp = stream->stco_sample_index;
5736 cur->duration = stream->samples_per_chunk;
5737 cur->keyframe = TRUE;
5740 stream->stco_sample_index += stream->samples_per_chunk;
5742 stream->stsc_chunk_index = j;
5744 stream->stsc_index++;
5747 if (!stream->chunks_are_chunks)
5751 guint32 n_sample_times;
5753 n_sample_times = stream->n_sample_times;
5756 for (i = stream->stts_index; i < n_sample_times; i++) {
5757 guint32 stts_samples;
5758 gint32 stts_duration;
5761 if (stream->stts_sample_index >= stream->stts_samples
5762 || !stream->stts_sample_index) {
5764 stream->stts_samples =
5765 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5766 stream->stts_duration =
5767 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5769 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
5770 i, stream->stts_samples, stream->stts_duration);
5772 stream->stts_sample_index = 0;
5775 stts_samples = stream->stts_samples;
5776 stts_duration = stream->stts_duration;
5777 stts_time = stream->stts_time;
5779 for (j = stream->stts_sample_index; j < stts_samples; j++) {
5780 GST_DEBUG_OBJECT (qtdemux,
5781 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
5782 (guint) (cur - samples), j,
5783 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
5784 stream->timescale)));
5786 cur->timestamp = stts_time;
5787 cur->duration = stts_duration;
5789 /* avoid 32-bit wrap-around,
5790 * but still mind possible 'negative' duration */
5791 stts_time += (gint64) stts_duration;
5794 if (G_UNLIKELY (cur > last)) {
5796 stream->stts_time = stts_time;
5797 stream->stts_sample_index = j + 1;
5801 stream->stts_sample_index = 0;
5802 stream->stts_time = stts_time;
5803 stream->stts_index++;
5805 /* fill up empty timestamps with the last timestamp, this can happen when
5806 * the last samples do not decode and so we don't have timestamps for them.
5807 * We however look at the last timestamp to estimate the track length so we
5808 * need something in here. */
5809 for (; cur < last; cur++) {
5810 GST_DEBUG_OBJECT (qtdemux,
5811 "fill sample %d: timestamp %" GST_TIME_FORMAT,
5812 (guint) (cur - samples),
5813 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
5814 stream->timescale)));
5815 cur->timestamp = stream->stts_time;
5821 /* sample sync, can be NULL */
5822 if (stream->stss_present == TRUE) {
5823 guint32 n_sample_syncs;
5825 n_sample_syncs = stream->n_sample_syncs;
5827 if (!n_sample_syncs) {
5828 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
5829 stream->all_keyframe = TRUE;
5831 for (i = stream->stss_index; i < n_sample_syncs; i++) {
5832 /* note that the first sample is index 1, not 0 */
5835 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
5837 if (G_LIKELY (index > 0 && index <= n_samples)) {
5839 samples[index].keyframe = TRUE;
5840 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5841 /* and exit if we have enough samples */
5842 if (G_UNLIKELY (index >= n)) {
5849 stream->stss_index = i;
5852 /* stps marks partial sync frames like open GOP I-Frames */
5853 if (stream->stps_present == TRUE) {
5854 guint32 n_sample_partial_syncs;
5856 n_sample_partial_syncs = stream->n_sample_partial_syncs;
5858 /* if there are no entries, the stss table contains the real
5860 if (n_sample_partial_syncs) {
5861 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
5862 /* note that the first sample is index 1, not 0 */
5865 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
5867 if (G_LIKELY (index > 0 && index <= n_samples)) {
5869 samples[index].keyframe = TRUE;
5870 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5871 /* and exit if we have enough samples */
5872 if (G_UNLIKELY (index >= n)) {
5879 stream->stps_index = i;
5883 /* no stss, all samples are keyframes */
5884 stream->all_keyframe = TRUE;
5885 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
5890 /* composition time to sample */
5891 if (stream->ctts_present == TRUE) {
5892 guint32 n_composition_times;
5894 gint32 ctts_soffset;
5896 /* Fill in the pts_offsets */
5898 n_composition_times = stream->n_composition_times;
5900 for (i = stream->ctts_index; i < n_composition_times; i++) {
5901 if (stream->ctts_sample_index >= stream->ctts_count
5902 || !stream->ctts_sample_index) {
5903 stream->ctts_count =
5904 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
5905 stream->ctts_soffset =
5906 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
5907 stream->ctts_sample_index = 0;
5910 ctts_count = stream->ctts_count;
5911 ctts_soffset = stream->ctts_soffset;
5913 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
5914 cur->pts_offset = ctts_soffset;
5917 if (G_UNLIKELY (cur > last)) {
5919 stream->ctts_sample_index = j + 1;
5923 stream->ctts_sample_index = 0;
5924 stream->ctts_index++;
5928 stream->stbl_index = n;
5929 /* if index has been completely parsed, free data that is no-longer needed */
5930 if (n + 1 == stream->n_samples) {
5931 gst_qtdemux_stbl_free (stream);
5932 GST_DEBUG_OBJECT (qtdemux,
5933 "parsed all available samples; checking for more");
5934 while (n + 1 == stream->n_samples)
5935 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
5938 GST_OBJECT_UNLOCK (qtdemux);
5945 GST_LOG_OBJECT (qtdemux,
5946 "Tried to parse up to sample %u but this sample has already been parsed",
5948 /* if fragmented, there may be more */
5949 if (qtdemux->fragmented && n == stream->stbl_index)
5951 GST_OBJECT_UNLOCK (qtdemux);
5957 GST_LOG_OBJECT (qtdemux,
5958 "Tried to parse up to sample %u but there are only %u samples", n + 1,
5960 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5961 (_("This file is corrupt and cannot be played.")), (NULL));
5966 GST_OBJECT_UNLOCK (qtdemux);
5967 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5968 (_("This file is corrupt and cannot be played.")), (NULL));
5973 /* collect all segment info for @stream.
5976 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
5981 /* parse and prepare segment info from the edit list */
5982 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
5983 stream->n_segments = 0;
5984 stream->segments = NULL;
5985 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
5989 guint64 time, stime;
5992 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
5993 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
5996 buffer = elst->data;
5998 n_segments = QT_UINT32 (buffer + 12);
6000 /* we might allocate a bit too much, at least allocate 1 segment */
6001 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
6003 /* segments always start from 0 */
6007 for (i = 0; i < n_segments; i++) {
6010 QtDemuxSegment *segment;
6013 media_time = QT_UINT32 (buffer + 20 + i * 12);
6015 /* -1 media time is an empty segment, just ignore it */
6016 if (media_time == G_MAXUINT32)
6019 duration = QT_UINT32 (buffer + 16 + i * 12);
6021 segment = &stream->segments[count++];
6023 /* time and duration expressed in global timescale */
6024 segment->time = stime;
6025 /* add non scaled values so we don't cause roundoff errors */
6027 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
6028 segment->stop_time = stime;
6029 segment->duration = stime - segment->time;
6030 /* media_time expressed in stream timescale */
6031 segment->media_start =
6032 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
6033 segment->media_stop = segment->media_start + segment->duration;
6034 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
6036 if (rate_int <= 1) {
6037 /* 0 is not allowed, some programs write 1 instead of the floating point
6039 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
6043 segment->rate = rate_int / 65536.0;
6046 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
6047 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
6048 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
6049 GST_TIME_ARGS (segment->duration),
6050 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
6052 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
6053 stream->n_segments = count;
6057 /* push based does not handle segments, so act accordingly here,
6058 * and warn if applicable */
6059 if (!qtdemux->pullbased) {
6060 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
6061 /* remove and use default one below, we stream like it anyway */
6062 g_free (stream->segments);
6063 stream->segments = NULL;
6064 stream->n_segments = 0;
6067 /* no segments, create one to play the complete trak */
6068 if (stream->n_segments == 0) {
6069 GstClockTime stream_duration =
6070 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6072 if (stream->segments == NULL)
6073 stream->segments = g_new (QtDemuxSegment, 1);
6075 /* represent unknown our way */
6076 if (stream_duration == 0)
6077 stream_duration = -1;
6079 stream->segments[0].time = 0;
6080 stream->segments[0].stop_time = stream_duration;
6081 stream->segments[0].duration = stream_duration;
6082 stream->segments[0].media_start = 0;
6083 stream->segments[0].media_stop = stream_duration;
6084 stream->segments[0].rate = 1.0;
6086 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6087 GST_TIME_ARGS (stream_duration));
6088 stream->n_segments = 1;
6090 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6096 * Parses the stsd atom of a svq3 trak looking for
6097 * the SMI and gama atoms.
6100 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6101 guint8 ** gamma, GstBuffer ** seqh)
6103 guint8 *_gamma = NULL;
6104 GstBuffer *_seqh = NULL;
6105 guint8 *stsd_data = stsd->data;
6106 guint32 length = QT_UINT32 (stsd_data);
6110 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6116 version = QT_UINT16 (stsd_data);
6121 while (length > 8) {
6122 guint32 fourcc, size;
6124 size = QT_UINT32 (stsd_data);
6125 fourcc = QT_FOURCC (stsd_data + 4);
6126 data = stsd_data + 8;
6133 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6134 " for gama atom, expected 12", size);
6139 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6141 if (_seqh != NULL) {
6142 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6143 " found, ignoring");
6145 seqh_size = QT_UINT32 (data + 4);
6146 if (seqh_size > 0) {
6147 _seqh = gst_buffer_new_and_alloc (seqh_size);
6148 _gst_buffer_copy_into_mem (_seqh, 0, data + 8, seqh_size);
6155 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6156 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6160 if (size <= length) {
6166 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6169 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6170 G_GUINT16_FORMAT, version);
6181 gst_buffer_unref (_seqh);
6186 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6193 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6194 * atom that might contain a 'data' atom with the rtsp uri.
6195 * This case was reported in bug #597497, some info about
6196 * the hndl atom can be found in TN1195
6198 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6199 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6202 guint32 dref_num_entries = 0;
6203 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6204 gst_byte_reader_skip (&dref, 4) &&
6205 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6208 /* search dref entries for hndl atom */
6209 for (i = 0; i < dref_num_entries; i++) {
6210 guint32 size = 0, type;
6211 guint8 string_len = 0;
6212 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6213 qt_atom_parser_get_fourcc (&dref, &type)) {
6214 if (type == FOURCC_hndl) {
6215 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6217 /* skip data reference handle bytes and the
6218 * following pascal string and some extra 4
6219 * bytes I have no idea what are */
6220 if (!gst_byte_reader_skip (&dref, 4) ||
6221 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6222 !gst_byte_reader_skip (&dref, string_len + 4)) {
6223 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6227 /* iterate over the atoms to find the data atom */
6228 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6232 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6233 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6234 if (atom_type == FOURCC_data) {
6235 const guint8 *uri_aux = NULL;
6237 /* found the data atom that might contain the rtsp uri */
6238 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6239 "hndl atom, interpreting it as an URI");
6240 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6242 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6243 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6245 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6246 "didn't contain a rtsp address");
6248 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6253 /* skipping to the next entry */
6254 gst_byte_reader_skip (&dref, atom_size - 8);
6256 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6263 /* skip to the next entry */
6264 gst_byte_reader_skip (&dref, size - 8);
6266 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6269 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6276 less_than (gconstpointer a, gconstpointer b)
6278 const guint32 *av = a, *bv = b;
6283 #define AMR_NB_ALL_MODES 0x81ff
6284 #define AMR_WB_ALL_MODES 0x83ff
6286 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
6288 /* The 'damr' atom is of the form:
6290 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
6291 * 32 b 8 b 16 b 8 b 8 b
6293 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
6294 * represents the highest mode used in the stream (and thus the maximum
6295 * bitrate), with a couple of special cases as seen below.
6298 /* Map of frame type ID -> bitrate */
6299 static const guint nb_bitrates[] = {
6300 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
6302 static const guint wb_bitrates[] = {
6303 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
6309 gst_buffer_map (buf, &map, GST_MAP_READ);
6311 if (map.size != 0x11) {
6312 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
6316 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
6317 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
6318 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
6322 mode_set = QT_UINT16 (map.data + 13);
6324 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
6325 max_mode = 7 + (wb ? 1 : 0);
6327 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
6328 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
6330 if (max_mode == -1) {
6331 GST_DEBUG ("No mode indication was found (mode set) = %x",
6336 gst_buffer_unmap (buf, &map);
6337 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
6340 gst_buffer_unmap (buf, &map);
6345 * With each track we associate a new QtDemuxStream that contains all the info
6347 * traks that do not decode to something (like strm traks) will not have a pad.
6350 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6365 QtDemuxStream *stream;
6366 GstTagList *list = NULL;
6367 gchar *codec = NULL;
6368 const guint8 *stsd_data;
6369 guint16 lang_code; /* quicktime lang code or packed iso code */
6371 guint32 tkhd_flags = 0;
6372 guint8 tkhd_version = 0;
6374 guint value_size, len;
6376 stream = g_new0 (QtDemuxStream, 1);
6377 /* new streams always need a discont */
6378 stream->discont = TRUE;
6379 /* we enable clipping for raw audio/video streams */
6380 stream->need_clip = FALSE;
6381 stream->need_process = FALSE;
6382 stream->segment_index = -1;
6383 stream->time_position = 0;
6384 stream->sample_index = -1;
6385 stream->last_ret = GST_FLOW_OK;
6387 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6388 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6389 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6392 /* pick between 64 or 32 bits */
6393 value_size = tkhd_version == 1 ? 8 : 4;
6394 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6395 !gst_byte_reader_get_uint32_be (&tkhd, &stream->track_id))
6398 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6399 tkhd_version, tkhd_flags, stream->track_id);
6401 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6404 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6405 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6406 if (qtdemux->major_brand != FOURCC_mjp2 ||
6407 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6411 len = QT_UINT32 ((guint8 *) mdhd->data);
6412 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6413 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6414 if (version == 0x01000000) {
6417 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6418 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6419 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6423 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6424 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6425 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6428 if (lang_code < 0x800) {
6429 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6431 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6432 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6433 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6434 stream->lang_id[3] = 0;
6437 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6439 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6441 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6442 lang_code, stream->lang_id);
6444 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6447 /* fragmented files may have bogus duration in moov */
6448 if (!qtdemux->fragmented &&
6449 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6450 guint64 tdur1, tdur2;
6452 /* don't overflow */
6453 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6454 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6457 * some of those trailers, nowadays, have prologue images that are
6458 * themselves vide tracks as well. I haven't really found a way to
6459 * identify those yet, except for just looking at their duration. */
6460 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6461 GST_WARNING_OBJECT (qtdemux,
6462 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6463 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6464 "found, assuming preview image or something; skipping track",
6465 stream->duration, stream->timescale, qtdemux->duration,
6466 qtdemux->timescale);
6472 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6475 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6476 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6478 len = QT_UINT32 ((guint8 *) hdlr->data);
6480 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6481 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6482 GST_FOURCC_ARGS (stream->subtype));
6484 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6487 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6491 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6493 stsd_data = (const guint8 *) stsd->data;
6495 /* stsd should at least have one entry */
6496 len = QT_UINT32 (stsd_data);
6500 /* and that entry should fit within stsd */
6501 len = QT_UINT32 (stsd_data + 16);
6502 if (len > QT_UINT32 (stsd_data) + 16)
6504 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6506 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6507 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6508 GST_FOURCC_ARGS (stream->fourcc));
6510 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6511 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6512 goto error_encrypted;
6514 if (stream->subtype == FOURCC_vide) {
6515 guint32 w = 0, h = 0;
6517 stream->sampled = TRUE;
6519 /* version 1 uses some 64-bit ints */
6520 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6521 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6522 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6525 stream->display_width = w >> 16;
6526 stream->display_height = h >> 16;
6532 stream->width = QT_UINT16 (stsd_data + offset + 32);
6533 stream->height = QT_UINT16 (stsd_data + offset + 34);
6534 stream->fps_n = 0; /* this is filled in later */
6535 stream->fps_d = 0; /* this is filled in later */
6536 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6537 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6539 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6540 QT_UINT16 (stsd_data + offset + 48));
6543 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6545 list = gst_tag_list_new_empty ();
6546 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6547 GST_TAG_VIDEO_CODEC, codec, NULL);
6554 /* pick 'the' stsd child */
6555 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
6557 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
6558 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
6562 const guint8 *pasp_data = (const guint8 *) pasp->data;
6564 stream->par_w = QT_UINT32 (pasp_data + 8);
6565 stream->par_h = QT_UINT32 (pasp_data + 12);
6572 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
6577 gint len = QT_UINT32 (stsd_data) - 0x66;
6578 const guint8 *avc_data = stsd_data + 0x66;
6581 while (len >= 0x8) {
6584 if (QT_UINT32 (avc_data) <= len)
6585 size = QT_UINT32 (avc_data) - 0x8;
6590 /* No real data, so break out */
6593 switch (QT_FOURCC (avc_data + 0x4)) {
6596 /* parse, if found */
6599 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
6601 /* First 4 bytes are the length of the atom, the next 4 bytes
6602 * are the fourcc, the next 1 byte is the version, and the
6603 * subsequent bytes are sequence parameter set like data. */
6604 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
6605 avc_data + 8 + 1, size - 1);
6607 buf = gst_buffer_new_and_alloc (size);
6608 _gst_buffer_copy_into_mem (buf, 0, avc_data + 0x8, size);
6609 gst_caps_set_simple (stream->caps,
6610 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6611 gst_buffer_unref (buf);
6617 guint avg_bitrate, max_bitrate;
6619 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
6623 max_bitrate = QT_UINT32 (avc_data + 0xc);
6624 avg_bitrate = QT_UINT32 (avc_data + 0x10);
6626 if (!max_bitrate && !avg_bitrate)
6629 /* Some muxers seem to swap the average and maximum bitrates
6630 * (I'm looking at you, YouTube), so we swap for sanity. */
6631 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
6632 guint temp = avg_bitrate;
6634 avg_bitrate = max_bitrate;
6639 list = gst_tag_list_new_empty ();
6641 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6642 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6643 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6645 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6646 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6647 GST_TAG_BITRATE, avg_bitrate, NULL);
6658 avc_data += size + 8;
6670 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
6671 GST_FOURCC_ARGS (fourcc));
6673 /* codec data might be in glbl extension atom */
6675 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
6681 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
6683 len = QT_UINT32 (data);
6686 buf = gst_buffer_new_and_alloc (len);
6687 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
6688 gst_caps_set_simple (stream->caps,
6689 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6690 gst_buffer_unref (buf);
6697 /* see annex I of the jpeg2000 spec */
6698 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
6700 const gchar *colorspace = NULL;
6702 guint32 ncomp_map = 0;
6703 gint32 *comp_map = NULL;
6704 guint32 nchan_def = 0;
6705 gint32 *chan_def = NULL;
6707 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
6708 /* some required atoms */
6709 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
6712 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
6716 /* number of components; redundant with info in codestream, but useful
6718 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
6719 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
6721 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
6723 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
6726 GST_DEBUG_OBJECT (qtdemux, "found colr");
6727 /* extract colour space info */
6728 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
6729 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
6731 colorspace = "sRGB";
6734 colorspace = "GRAY";
6737 colorspace = "sYUV";
6745 /* colr is required, and only values 16, 17, and 18 are specified,
6746 so error if we have no colorspace */
6749 /* extract component mapping */
6750 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
6752 guint32 cmap_len = 0;
6754 cmap_len = QT_UINT32 (cmap->data);
6755 if (cmap_len >= 8) {
6756 /* normal box, subtract off header */
6758 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
6759 if (cmap_len % 4 == 0) {
6760 ncomp_map = (cmap_len / 4);
6761 comp_map = g_new0 (gint32, ncomp_map);
6762 for (i = 0; i < ncomp_map; i++) {
6765 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
6766 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
6767 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
6768 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
6773 /* extract channel definitions */
6774 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
6776 guint32 cdef_len = 0;
6778 cdef_len = QT_UINT32 (cdef->data);
6779 if (cdef_len >= 10) {
6780 /* normal box, subtract off header and len */
6782 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
6783 if (cdef_len % 6 == 0) {
6784 nchan_def = (cdef_len / 6);
6785 chan_def = g_new0 (gint32, nchan_def);
6786 for (i = 0; i < nchan_def; i++)
6788 for (i = 0; i < nchan_def; i++) {
6789 guint16 cn, typ, asoc;
6790 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
6791 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
6792 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
6793 if (cn < nchan_def) {
6796 chan_def[cn] = asoc;
6799 chan_def[cn] = 0; /* alpha */
6802 chan_def[cn] = -typ;
6810 gst_caps_set_simple (stream->caps,
6811 "num-components", G_TYPE_INT, ncomp, NULL);
6812 gst_caps_set_simple (stream->caps,
6813 "colorspace", G_TYPE_STRING, colorspace, NULL);
6816 GValue arr = { 0, };
6817 GValue elt = { 0, };
6819 g_value_init (&arr, GST_TYPE_ARRAY);
6820 g_value_init (&elt, G_TYPE_INT);
6821 for (i = 0; i < ncomp_map; i++) {
6822 g_value_set_int (&elt, comp_map[i]);
6823 gst_value_array_append_value (&arr, &elt);
6825 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6826 "component-map", &arr);
6827 g_value_unset (&elt);
6828 g_value_unset (&arr);
6833 GValue arr = { 0, };
6834 GValue elt = { 0, };
6836 g_value_init (&arr, GST_TYPE_ARRAY);
6837 g_value_init (&elt, G_TYPE_INT);
6838 for (i = 0; i < nchan_def; i++) {
6839 g_value_set_int (&elt, chan_def[i]);
6840 gst_value_array_append_value (&arr, &elt);
6842 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6843 "channel-definitions", &arr);
6844 g_value_unset (&elt);
6845 g_value_unset (&arr);
6849 /* some optional atoms */
6850 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
6851 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
6853 /* indicate possible fields in caps */
6855 data = (guint8 *) field->data + 8;
6857 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
6858 (gint) * data, NULL);
6860 /* add codec_data if provided */
6865 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
6866 data = prefix->data;
6867 len = QT_UINT32 (data);
6870 buf = gst_buffer_new_and_alloc (len);
6871 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
6872 gst_caps_set_simple (stream->caps,
6873 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6874 gst_buffer_unref (buf);
6883 GstBuffer *seqh = NULL;
6884 guint8 *gamma_data = NULL;
6885 gint len = QT_UINT32 (stsd_data);
6887 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
6889 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
6890 QT_FP32 (gamma_data), NULL);
6893 /* sorry for the bad name, but we don't know what this is, other
6894 * than its own fourcc */
6895 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
6899 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
6900 buf = gst_buffer_new_and_alloc (len);
6901 _gst_buffer_copy_into_mem (buf, 0, stsd_data, len);
6902 gst_caps_set_simple (stream->caps,
6903 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6904 gst_buffer_unref (buf);
6909 gst_caps_set_simple (stream->caps,
6910 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
6917 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
6918 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
6922 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
6926 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
6927 /* collect the headers and store them in a stream list so that we can
6928 * send them out first */
6929 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
6939 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
6940 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
6943 ovc1_data = ovc1->data;
6944 ovc1_len = QT_UINT32 (ovc1_data);
6945 if (ovc1_len <= 198) {
6946 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
6949 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
6950 _gst_buffer_copy_into_mem (buf, 0, ovc1_data + 198, ovc1_len - 198);
6951 gst_caps_set_simple (stream->caps,
6952 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6953 gst_buffer_unref (buf);
6961 GST_INFO_OBJECT (qtdemux,
6962 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
6963 GST_FOURCC_ARGS (fourcc), stream->caps);
6965 } else if (stream->subtype == FOURCC_soun) {
6966 int version, samplesize;
6967 guint16 compression_id;
6968 gboolean amrwb = FALSE;
6974 version = QT_UINT32 (stsd_data + offset);
6975 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
6976 samplesize = QT_UINT16 (stsd_data + offset + 10);
6977 compression_id = QT_UINT16 (stsd_data + offset + 12);
6978 stream->rate = QT_FP32 (stsd_data + offset + 16);
6980 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
6981 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
6982 QT_UINT32 (stsd_data + offset + 4));
6983 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
6984 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
6985 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
6986 GST_LOG_OBJECT (qtdemux, "packet size: %d",
6987 QT_UINT16 (stsd_data + offset + 14));
6988 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
6990 if (compression_id == 0xfffe)
6991 stream->sampled = TRUE;
6993 /* first assume uncompressed audio */
6994 stream->bytes_per_sample = samplesize / 8;
6995 stream->samples_per_frame = stream->n_channels;
6996 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
6997 stream->samples_per_packet = stream->samples_per_frame;
6998 stream->bytes_per_packet = stream->bytes_per_sample;
7002 /* Yes, these have to be hard-coded */
7005 stream->samples_per_packet = 6;
7006 stream->bytes_per_packet = 1;
7007 stream->bytes_per_frame = 1 * stream->n_channels;
7008 stream->bytes_per_sample = 1;
7009 stream->samples_per_frame = 6 * stream->n_channels;
7014 stream->samples_per_packet = 3;
7015 stream->bytes_per_packet = 1;
7016 stream->bytes_per_frame = 1 * stream->n_channels;
7017 stream->bytes_per_sample = 1;
7018 stream->samples_per_frame = 3 * stream->n_channels;
7023 stream->samples_per_packet = 64;
7024 stream->bytes_per_packet = 34;
7025 stream->bytes_per_frame = 34 * stream->n_channels;
7026 stream->bytes_per_sample = 2;
7027 stream->samples_per_frame = 64 * stream->n_channels;
7033 stream->samples_per_packet = 1;
7034 stream->bytes_per_packet = 1;
7035 stream->bytes_per_frame = 1 * stream->n_channels;
7036 stream->bytes_per_sample = 1;
7037 stream->samples_per_frame = 1 * stream->n_channels;
7042 stream->samples_per_packet = 160;
7043 stream->bytes_per_packet = 33;
7044 stream->bytes_per_frame = 33 * stream->n_channels;
7045 stream->bytes_per_sample = 2;
7046 stream->samples_per_frame = 160 * stream->n_channels;
7053 if (version == 0x00010000) {
7061 /* only parse extra decoding config for non-pcm audio */
7062 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7063 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
7064 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
7065 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
7067 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7068 stream->samples_per_packet);
7069 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7070 stream->bytes_per_packet);
7071 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
7072 stream->bytes_per_frame);
7073 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
7074 stream->bytes_per_sample);
7076 if (!stream->sampled && stream->bytes_per_packet) {
7077 stream->samples_per_frame = (stream->bytes_per_frame /
7078 stream->bytes_per_packet) * stream->samples_per_packet;
7079 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
7080 stream->samples_per_frame);
7085 } else if (version == 0x00020000) {
7092 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7093 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
7094 stream->rate = qtfp.fp;
7095 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
7097 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7098 stream->samples_per_packet);
7099 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7100 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7103 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
7106 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
7115 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
7117 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
7119 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
7121 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
7124 gst_caps_set_simple (stream->caps,
7125 "format", G_TYPE_STRING, "S24_3LE", NULL);
7132 const guint8 *owma_data;
7133 const gchar *codec_name = NULL;
7137 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
7138 /* FIXME this should also be gst_riff_strf_auds,
7139 * but the latter one is actually missing bits-per-sample :( */
7144 gint32 nSamplesPerSec;
7145 gint32 nAvgBytesPerSec;
7147 gint16 wBitsPerSample;
7152 GST_DEBUG_OBJECT (qtdemux, "parse owma");
7153 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
7156 owma_data = owma->data;
7157 owma_len = QT_UINT32 (owma_data);
7158 if (owma_len <= 54) {
7159 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
7162 wfex = (WAVEFORMATEX *) (owma_data + 36);
7163 buf = gst_buffer_new_and_alloc (owma_len - 54);
7164 _gst_buffer_copy_into_mem (buf, 0, owma_data + 54, owma_len - 54);
7165 if (wfex->wFormatTag == 0x0161) {
7166 codec_name = "Windows Media Audio";
7168 } else if (wfex->wFormatTag == 0x0162) {
7169 codec_name = "Windows Media Audio 9 Pro";
7171 } else if (wfex->wFormatTag == 0x0163) {
7172 codec_name = "Windows Media Audio 9 Lossless";
7173 /* is that correct? gstffmpegcodecmap.c is missing it, but
7174 * fluendo codec seems to support it */
7178 gst_caps_set_simple (stream->caps,
7179 "codec_data", GST_TYPE_BUFFER, buf,
7180 "wmaversion", G_TYPE_INT, version,
7181 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
7182 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
7183 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7184 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7186 gst_buffer_unref (buf);
7190 codec = g_strdup (codec_name);
7202 list = gst_tag_list_new_empty ();
7203 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7204 GST_TAG_AUDIO_CODEC, codec, NULL);
7208 /* some bitrate info may have ended up in caps */
7209 s = gst_caps_get_structure (stream->caps, 0);
7210 gst_structure_get_int (s, "bitrate", &bitrate);
7212 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7216 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7220 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7222 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7224 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7228 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7229 16 bits is a byte-swapped wave-style codec identifier,
7230 and we can find a WAVE header internally to a 'wave' atom here.
7231 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7232 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7235 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7236 if (len < offset + 20) {
7237 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7239 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7240 const guint8 *data = stsd_data + offset + 16;
7242 GNode *waveheadernode;
7244 wavenode = g_node_new ((guint8 *) data);
7245 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7246 const guint8 *waveheader;
7249 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7250 if (waveheadernode) {
7251 waveheader = (const guint8 *) waveheadernode->data;
7252 headerlen = QT_UINT32 (waveheader);
7254 if (headerlen > 8) {
7255 gst_riff_strf_auds *header = NULL;
7256 GstBuffer *headerbuf;
7262 headerbuf = gst_buffer_new_and_alloc (headerlen);
7263 _gst_buffer_copy_into_mem (headerbuf, 0, waveheader, headerlen);
7265 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7266 headerbuf, &header, &extra)) {
7267 gst_caps_unref (stream->caps);
7268 /* FIXME: Need to do something with the channel reorder map */
7269 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7270 header, extra, NULL, NULL, NULL);
7273 gst_buffer_unref (extra);
7277 GST_DEBUG ("Didn't find waveheadernode for this codec");
7279 g_node_destroy (wavenode);
7282 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7286 /* FIXME: what is in the chunk? */
7289 gint len = QT_UINT32 (stsd_data);
7291 /* seems to be always = 116 = 0x74 */
7297 gint len = QT_UINT32 (stsd_data);
7300 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7302 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x4C, len - 0x4C);
7303 gst_caps_set_simple (stream->caps,
7304 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7305 gst_buffer_unref (buf);
7307 gst_caps_set_simple (stream->caps,
7308 "samplesize", G_TYPE_INT, samplesize, NULL);
7313 GNode *alac, *wave = NULL;
7315 /* apparently, m4a has this atom appended directly in the stsd entry,
7316 * while mov has it in a wave atom */
7317 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7319 /* alac now refers to stsd entry atom */
7320 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7322 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7324 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7327 gint len = QT_UINT32 (alac->data);
7331 GST_DEBUG_OBJECT (qtdemux,
7332 "discarding alac atom with unexpected len %d", len);
7334 /* codec-data contains alac atom size and prefix,
7335 * ffmpeg likes it that way, not quite gst-ish though ...*/
7336 buf = gst_buffer_new_and_alloc (len);
7337 _gst_buffer_copy_into_mem (buf, 0, alac->data, len);
7338 gst_caps_set_simple (stream->caps,
7339 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7340 gst_buffer_unref (buf);
7343 gst_caps_set_simple (stream->caps,
7344 "samplesize", G_TYPE_INT, samplesize, NULL);
7352 gint len = QT_UINT32 (stsd_data);
7355 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7358 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x34, len - 0x34);
7360 /* If we have enough data, let's try to get the 'damr' atom. See
7361 * the 3GPP container spec (26.244) for more details. */
7362 if ((len - 0x34) > 8 &&
7363 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
7365 list = gst_tag_list_new_empty ();
7366 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7367 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
7370 gst_caps_set_simple (stream->caps,
7371 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7372 gst_buffer_unref (buf);
7380 GST_INFO_OBJECT (qtdemux,
7381 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7382 GST_FOURCC_ARGS (fourcc), stream->caps);
7384 } else if (stream->subtype == FOURCC_strm) {
7385 if (fourcc == FOURCC_rtsp) {
7386 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7388 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7389 GST_FOURCC_ARGS (fourcc));
7390 goto unknown_stream;
7392 stream->sampled = TRUE;
7393 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
7395 stream->sampled = TRUE;
7400 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7402 list = gst_tag_list_new_empty ();
7403 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7404 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7409 /* hunt for sort-of codec data */
7416 /* look for palette */
7417 /* target mp4s atom */
7418 len = QT_UINT32 (stsd_data + offset);
7419 data = stsd_data + offset;
7420 /* verify sufficient length,
7421 * and esds present with decConfigDescr of expected size and position */
7422 if ((len >= 106 + 8)
7423 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7424 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7429 /* move to decConfigDescr data */
7430 data = data + 8 + 42;
7431 for (i = 0; i < 16; i++) {
7432 clut[i] = QT_UINT32 (data);
7436 s = gst_structure_new ("application/x-gst-dvd", "event",
7437 G_TYPE_STRING, "dvd-spu-clut-change",
7438 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7439 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7440 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7441 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7442 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7443 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7444 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7445 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7448 /* store event and trigger custom processing */
7449 stream->pending_event =
7450 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7451 stream->need_process = TRUE;
7459 goto unknown_stream;
7462 /* promote to sampled format */
7463 if (stream->fourcc == FOURCC_samr) {
7464 /* force mono 8000 Hz for AMR */
7465 stream->sampled = TRUE;
7466 stream->n_channels = 1;
7467 stream->rate = 8000;
7468 } else if (stream->fourcc == FOURCC_sawb) {
7469 /* force mono 16000 Hz for AMR-WB */
7470 stream->sampled = TRUE;
7471 stream->n_channels = 1;
7472 stream->rate = 16000;
7473 } else if (stream->fourcc == FOURCC_mp4a) {
7474 stream->sampled = TRUE;
7477 /* collect sample information */
7478 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7479 goto samples_failed;
7481 if (qtdemux->fragmented) {
7485 /* need all moov samples as basis; probably not many if any at all */
7486 /* prevent moof parsing taking of at this time */
7487 offset = qtdemux->moof_offset;
7488 qtdemux->moof_offset = 0;
7489 if (stream->n_samples &&
7490 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7491 qtdemux->moof_offset = offset;
7492 goto samples_failed;
7494 qtdemux->moof_offset = 0;
7495 /* movie duration more reliable in this case (e.g. mehd) */
7496 if (qtdemux->segment.duration &&
7497 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7498 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7499 stream->timescale, GST_SECOND);
7500 /* need defaults for fragments */
7501 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7504 /* configure segments */
7505 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7506 goto segments_failed;
7508 /* add some language tag, if useful */
7509 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7510 strcmp (stream->lang_id, "und")) {
7511 const gchar *lang_code;
7514 list = gst_tag_list_new_empty ();
7516 /* convert ISO 639-2 code to ISO 639-1 */
7517 lang_code = gst_tag_get_language_code (stream->lang_id);
7518 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7519 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7522 /* now we are ready to add the stream */
7523 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7524 goto too_many_streams;
7526 stream->pending_tags = list;
7527 qtdemux->streams[qtdemux->n_streams] = stream;
7528 qtdemux->n_streams++;
7529 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7536 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7537 (_("This file is corrupt and cannot be played.")), (NULL));
7543 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7550 /* we posted an error already */
7551 /* free stbl sub-atoms */
7552 gst_qtdemux_stbl_free (stream);
7558 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7559 GST_FOURCC_ARGS (stream->subtype));
7565 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7566 (_("This file contains too many streams. Only playing first %d"),
7567 GST_QTDEMUX_MAX_STREAMS), (NULL));
7572 /* If we can estimate the overall bitrate, and don't have information about the
7573 * stream bitrate for exactly one stream, this guesses the stream bitrate as
7574 * the overall bitrate minus the sum of the bitrates of all other streams. This
7575 * should be useful for the common case where we have one audio and one video
7576 * stream and can estimate the bitrate of one, but not the other. */
7578 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
7580 QtDemuxStream *stream = NULL;
7581 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
7585 if (qtdemux->fragmented)
7588 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
7590 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)) {
7591 GST_DEBUG_OBJECT (qtdemux,
7592 "Size in bytes of the stream not known - bailing");
7596 /* Subtract the header size */
7597 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
7598 size, qtdemux->header_size);
7599 g_assert (size >= qtdemux->header_size);
7600 size = size - qtdemux->header_size;
7602 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
7603 duration == GST_CLOCK_TIME_NONE) {
7604 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
7608 for (i = 0; i < qtdemux->n_streams; i++) {
7609 switch (qtdemux->streams[i]->subtype) {
7612 /* retrieve bitrate, prefer avg then max */
7614 if (qtdemux->streams[i]->pending_tags) {
7615 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7616 GST_TAG_MAXIMUM_BITRATE, &bitrate);
7617 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7618 GST_TAG_BITRATE, &bitrate);
7621 sum_bitrate += bitrate;
7624 GST_DEBUG_OBJECT (qtdemux,
7625 ">1 stream with unknown bitrate - bailing");
7628 stream = qtdemux->streams[i];
7632 /* For other subtypes, we assume no significant impact on bitrate */
7638 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
7642 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
7644 if (sys_bitrate < sum_bitrate) {
7645 /* This can happen, since sum_bitrate might be derived from maximum
7646 * bitrates and not average bitrates */
7647 GST_DEBUG_OBJECT (qtdemux,
7648 "System bitrate less than sum bitrate - bailing");
7652 bitrate = sys_bitrate - sum_bitrate;
7653 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
7654 ", Stream bitrate = %u", sys_bitrate, bitrate);
7656 if (!stream->pending_tags)
7657 stream->pending_tags = gst_tag_list_new_empty ();
7659 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
7660 GST_TAG_BITRATE, bitrate, NULL);
7663 static GstFlowReturn
7664 qtdemux_expose_streams (GstQTDemux * qtdemux)
7667 GstFlowReturn ret = GST_FLOW_OK;
7669 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7671 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7672 QtDemuxStream *stream = qtdemux->streams[i];
7673 guint32 sample_num = 0;
7678 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7679 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7681 if (qtdemux->fragmented) {
7682 /* need all moov samples first */
7683 GST_OBJECT_LOCK (qtdemux);
7684 while (stream->n_samples == 0)
7685 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7687 GST_OBJECT_UNLOCK (qtdemux);
7689 /* discard any stray moof */
7690 qtdemux->moof_offset = 0;
7693 /* prepare braking */
7694 if (ret != GST_FLOW_ERROR)
7697 /* in pull mode, we should have parsed some sample info by now;
7698 * and quite some code will not handle no samples.
7699 * in push mode, we'll just have to deal with it */
7700 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7701 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7702 gst_qtdemux_stream_free (qtdemux, stream);
7703 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7704 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7705 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7706 qtdemux->n_streams--;
7711 /* parse number of initial sample to set frame rate cap */
7712 while (sample_num < stream->n_samples && sample_num < samples) {
7713 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7717 /* collect and sort durations */
7718 samples = MIN (stream->stbl_index + 1, samples);
7719 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7721 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7723 while (sample_num < samples) {
7724 g_array_append_val (durations, stream->samples[sample_num].duration);
7727 g_array_sort (durations, less_than);
7728 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7729 g_array_free (durations, TRUE);
7732 /* now we have all info and can expose */
7733 list = stream->pending_tags;
7734 stream->pending_tags = NULL;
7735 gst_qtdemux_add_stream (qtdemux, stream, list);
7738 gst_qtdemux_guess_bitrate (qtdemux);
7740 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7742 /* check if we should post a redirect in case there is a single trak
7743 * and it is a redirecting trak */
7744 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7747 qtdemux_post_global_tags (qtdemux);
7749 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7750 "an external content");
7751 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7752 gst_structure_new ("redirect",
7753 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7755 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7756 qtdemux->posted_redirect = TRUE;
7762 /* check if major or compatible brand is 3GP */
7763 static inline gboolean
7764 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7767 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7768 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7769 } else if (qtdemux->comp_brands != NULL) {
7773 gboolean res = FALSE;
7775 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
7779 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7780 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7784 gst_buffer_unmap (qtdemux->comp_brands, &map);
7791 /* check if tag is a spec'ed 3GP tag keyword storing a string */
7792 static inline gboolean
7793 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
7795 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
7796 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
7797 || fourcc == FOURCC_albm;
7801 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
7802 const char *dummy, GNode * node)
7804 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7808 gdouble longitude, latitude, altitude;
7811 len = QT_UINT32 (node->data);
7818 /* TODO: language code skipped */
7820 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
7823 /* do not alarm in trivial case, but bail out otherwise */
7824 if (*(data + offset) != 0) {
7825 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
7829 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7830 GST_TAG_GEO_LOCATION_NAME, name, NULL);
7831 offset += strlen (name);
7835 if (len < offset + 2 + 4 + 4 + 4)
7838 /* +1 +1 = skip null-terminator and location role byte */
7840 /* table in spec says unsigned, semantics say negative has meaning ... */
7841 longitude = QT_SFP32 (data + offset);
7844 latitude = QT_SFP32 (data + offset);
7847 altitude = QT_SFP32 (data + offset);
7849 /* one invalid means all are invalid */
7850 if (longitude >= -180.0 && longitude <= 180.0 &&
7851 latitude >= -90.0 && latitude <= 90.0) {
7852 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7853 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
7854 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
7855 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
7858 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
7865 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
7872 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7879 len = QT_UINT32 (node->data);
7883 y = QT_UINT16 ((guint8 *) node->data + 12);
7885 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
7888 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
7890 date = g_date_new_dmy (1, 1, y);
7891 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
7896 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
7897 const char *dummy, GNode * node)
7900 char *tag_str = NULL;
7905 len = QT_UINT32 (node->data);
7910 entity = (guint8 *) node->data + offset;
7911 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
7912 GST_DEBUG_OBJECT (qtdemux,
7913 "classification info: %c%c%c%c invalid classification entity",
7914 entity[0], entity[1], entity[2], entity[3]);
7919 table = QT_UINT16 ((guint8 *) node->data + offset);
7921 /* Language code skipped */
7925 /* Tag format: "XXXX://Y[YYYY]/classification info string"
7926 * XXXX: classification entity, fixed length 4 chars.
7927 * Y[YYYY]: classification table, max 5 chars.
7929 tag_str = g_strdup_printf ("----://%u/%s",
7930 table, (char *) node->data + offset);
7932 /* memcpy To be sure we're preserving byte order */
7933 memcpy (tag_str, entity, 4);
7934 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
7936 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
7946 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
7952 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
7953 const char *dummy, GNode * node)
7955 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7961 gboolean ret = TRUE;
7963 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7965 len = QT_UINT32 (data->data);
7966 type = QT_UINT32 ((guint8 *) data->data + 8);
7967 if (type == 0x00000001 && len > 16) {
7968 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
7971 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7972 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
7976 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7980 len = QT_UINT32 (node->data);
7981 type = QT_UINT32 ((guint8 *) node->data + 4);
7982 if ((type >> 24) == 0xa9) {
7983 /* Type starts with the (C) symbol, so the next 32 bits are
7984 * the language code, which we ignore */
7986 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
7987 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
7988 QT_FOURCC ((guint8 *) node->data + 4))) {
7989 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
7991 /* we go for 3GP style encoding if major brands claims so,
7992 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
7993 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
7994 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
7995 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
7997 /* 16-bit Language code is ignored here as well */
7998 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
8005 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
8006 ret = FALSE; /* may have to fallback */
8008 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8009 len - offset, env_vars);
8011 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
8012 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
8016 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
8023 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
8024 const char *dummy, GNode * node)
8026 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
8030 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
8031 const char *dummy, GNode * node)
8033 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8035 char *s, *t, *k = NULL;
8040 /* first try normal string tag if major brand not 3GP */
8041 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
8042 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
8043 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
8044 * let's try it 3gpp way after minor safety check */
8046 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
8052 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
8056 len = QT_UINT32 (data);
8060 count = QT_UINT8 (data + 14);
8062 for (; count; count--) {
8065 if (offset + 1 > len)
8067 slen = QT_UINT8 (data + offset);
8069 if (offset + slen > len)
8071 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8074 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
8076 t = g_strjoin (",", k, s, NULL);
8084 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
8091 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
8092 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
8101 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
8107 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
8108 const char *tag2, GNode * node)
8115 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8117 len = QT_UINT32 (data->data);
8118 type = QT_UINT32 ((guint8 *) data->data + 8);
8119 if (type == 0x00000000 && len >= 22) {
8120 n1 = QT_UINT16 ((guint8 *) data->data + 18);
8121 n2 = QT_UINT16 ((guint8 *) data->data + 20);
8123 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
8124 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8128 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
8129 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8137 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8145 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8147 len = QT_UINT32 (data->data);
8148 type = QT_UINT32 ((guint8 *) data->data + 8);
8149 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
8150 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8151 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
8152 n1 = QT_UINT16 ((guint8 *) data->data + 16);
8154 /* do not add bpm=0 */
8155 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
8156 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8157 tag1, (gdouble) n1, NULL);
8164 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
8165 const char *dummy, GNode * node)
8172 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8174 len = QT_UINT32 (data->data);
8175 type = QT_UINT32 ((guint8 *) data->data + 8);
8176 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
8177 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8178 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
8179 num = QT_UINT32 ((guint8 *) data->data + 16);
8181 /* do not add num=0 */
8182 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
8183 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8191 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8199 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8201 len = QT_UINT32 (data->data);
8202 type = QT_UINT32 ((guint8 *) data->data + 8);
8203 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
8204 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
8206 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
8207 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
8208 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
8209 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8210 tag1, sample, NULL);
8211 gst_sample_unref (sample);
8218 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8226 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8228 len = QT_UINT32 (data->data);
8229 type = QT_UINT32 ((guint8 *) data->data + 8);
8230 if (type == 0x00000001 && len > 16) {
8231 guint y, m = 1, d = 1;
8234 s = g_strndup ((char *) data->data + 16, len - 16);
8235 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
8236 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
8237 if (ret >= 1 && y > 1500 && y < 3000) {
8240 date = g_date_new_dmy (d, m, y);
8241 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
8245 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
8253 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8258 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8260 /* re-route to normal string tag if major brand says so
8261 * or no data atom and compatible brand suggests so */
8262 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8263 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
8264 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
8271 len = QT_UINT32 (data->data);
8272 type = QT_UINT32 ((guint8 *) data->data + 8);
8273 if (type == 0x00000000 && len >= 18) {
8274 n = QT_UINT16 ((guint8 *) data->data + 16);
8278 genre = gst_tag_id3_genre_get (n - 1);
8279 if (genre != NULL) {
8280 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
8281 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8290 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
8291 guint8 * data, guint32 datasize)
8296 /* make a copy to have \0 at the end */
8297 datacopy = g_strndup ((gchar *) data, datasize);
8299 /* convert the str to double */
8300 if (sscanf (datacopy, "%lf", &value) == 1) {
8301 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
8302 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
8304 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
8312 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
8313 const char *tag_bis, GNode * node)
8322 const gchar *meanstr;
8323 const gchar *namestr;
8325 /* checking the whole ---- atom size for consistency */
8326 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8327 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8331 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8333 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8337 meansize = QT_UINT32 (mean->data);
8338 if (meansize <= 12) {
8339 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8342 meanstr = ((gchar *) mean->data) + 12;
8344 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8346 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8350 namesize = QT_UINT32 (name->data);
8351 if (namesize <= 12) {
8352 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8355 namestr = ((gchar *) name->data) + 12;
8362 * uint24 - data type
8366 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8368 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8371 datasize = QT_UINT32 (data->data);
8372 if (datasize <= 16) {
8373 GST_WARNING_OBJECT (demux, "Data atom too small");
8376 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8378 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8381 const gchar name[28];
8382 const gchar tag[28];
8385 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8386 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8387 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8388 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8389 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8390 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8391 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8392 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8396 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8397 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8398 switch (gst_tag_get_type (tags[i].tag)) {
8400 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8401 ((guint8 *) data->data) + 16, datasize - 16);
8404 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8413 if (i == G_N_ELEMENTS (tags))
8427 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8428 namestr_dbg = g_strndup (namestr, namesize - 12);
8430 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8431 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8433 g_free (namestr_dbg);
8434 g_free (meanstr_dbg);
8440 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
8441 const char *tag_bis, GNode * node)
8446 GstTagList *taglist = NULL;
8448 GST_LOG_OBJECT (demux, "parsing ID32");
8451 len = GST_READ_UINT32_BE (data);
8453 /* need at least full box and language tag */
8457 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
8458 gst_buffer_fill (buf, 0, data + 14, len - 14);
8460 taglist = gst_tag_list_from_id3v2_tag (buf);
8462 GST_LOG_OBJECT (demux, "parsing ok");
8463 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
8465 GST_LOG_OBJECT (demux, "parsing failed");
8469 gst_tag_list_free (taglist);
8471 gst_buffer_unref (buf);
8474 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8475 const char *tag, const char *tag_bis, GNode * node);
8478 FOURCC_pcst -> if media is a podcast -> bool
8479 FOURCC_cpil -> if media is part of a compilation -> bool
8480 FOURCC_pgap -> if media is part of a gapless context -> bool
8481 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8487 const gchar *gst_tag;
8488 const gchar *gst_tag_bis;
8489 const GstQTDemuxAddTagFunc func;
8492 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8493 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8494 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8495 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8496 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8497 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8498 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8499 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8500 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8501 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8502 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8503 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8504 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8505 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8506 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8507 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8508 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8509 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8510 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8511 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8512 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8513 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8514 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8515 qtdemux_tag_add_num}, {
8516 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8517 qtdemux_tag_add_num}, {
8518 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8519 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8520 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8521 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8522 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8523 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8524 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8525 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8526 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8527 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8528 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8529 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8530 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8531 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8532 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8533 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8534 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8535 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8536 qtdemux_tag_add_classification}, {
8538 /* This is a special case, some tags are stored in this
8539 * 'reverse dns naming', according to:
8540 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8543 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
8544 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
8545 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
8549 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8561 len = QT_UINT32 (data);
8562 buf = gst_buffer_new_and_alloc (len);
8563 _gst_buffer_copy_into_mem (buf, 0, data, len);
8565 /* heuristic to determine style of tag */
8566 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8567 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8569 else if (demux->major_brand == FOURCC_qt__)
8570 style = "quicktime";
8571 /* fall back to assuming iso/3gp tag style */
8575 /* santize the name for the caps. */
8576 for (i = 0; i < 4; i++) {
8577 guint8 d = data[4 + i];
8578 if (g_ascii_isalnum (d))
8579 ndata[i] = g_ascii_tolower (d);
8584 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8585 ndata[0], ndata[1], ndata[2], ndata[3]);
8586 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8588 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
8589 // TODO conver to metadata or ???
8590 // gst_buffer_set_caps (buf, caps);
8591 gst_caps_unref (caps);
8592 g_free (media_type);
8594 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
8597 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8598 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
8599 gst_buffer_unref (buf);
8603 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8611 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8613 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8615 GST_LOG_OBJECT (qtdemux, "no ilst");
8620 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8623 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8624 if (!qtdemux->tag_list)
8625 qtdemux->tag_list = gst_tag_list_new_empty ();
8628 while (i < G_N_ELEMENTS (add_funcs)) {
8629 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8633 len = QT_UINT32 (node->data);
8635 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8636 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8638 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8639 add_funcs[i].gst_tag_bis, node);
8641 g_node_destroy (node);
8647 /* parsed nodes have been removed, pass along remainder as blob */
8648 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8649 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8651 /* parse up XMP_ node if existing */
8652 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8655 GstTagList *taglist;
8657 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
8658 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
8659 taglist = gst_tag_list_from_xmp_buffer (buf);
8660 gst_buffer_unref (buf);
8662 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8664 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8671 GstStructure *structure; /* helper for sort function */
8673 guint min_req_bitrate;
8674 guint min_req_qt_version;
8678 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8680 GstQtReference *ref_a = (GstQtReference *) a;
8681 GstQtReference *ref_b = (GstQtReference *) b;
8683 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8684 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8686 /* known bitrates go before unknown; higher bitrates go first */
8687 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8690 /* sort the redirects and post a message for the application.
8693 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8695 GstQtReference *best;
8698 GValue list_val = { 0, };
8701 g_assert (references != NULL);
8703 references = g_list_sort (references, qtdemux_redirects_sort_func);
8705 best = (GstQtReference *) references->data;
8707 g_value_init (&list_val, GST_TYPE_LIST);
8709 for (l = references; l != NULL; l = l->next) {
8710 GstQtReference *ref = (GstQtReference *) l->data;
8711 GValue struct_val = { 0, };
8713 ref->structure = gst_structure_new ("redirect",
8714 "new-location", G_TYPE_STRING, ref->location, NULL);
8716 if (ref->min_req_bitrate > 0) {
8717 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8718 ref->min_req_bitrate, NULL);
8721 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8722 g_value_set_boxed (&struct_val, ref->structure);
8723 gst_value_list_append_value (&list_val, &struct_val);
8724 g_value_unset (&struct_val);
8725 /* don't free anything here yet, since we need best->structure below */
8728 g_assert (best != NULL);
8729 s = gst_structure_copy (best->structure);
8731 if (g_list_length (references) > 1) {
8732 gst_structure_set_value (s, "locations", &list_val);
8735 g_value_unset (&list_val);
8737 for (l = references; l != NULL; l = l->next) {
8738 GstQtReference *ref = (GstQtReference *) l->data;
8740 gst_structure_free (ref->structure);
8741 g_free (ref->location);
8744 g_list_free (references);
8746 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8747 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8748 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8749 qtdemux->posted_redirect = TRUE;
8752 /* look for redirect nodes, collect all redirect information and
8756 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8758 GNode *rmra, *rmda, *rdrf;
8760 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8762 GList *redirects = NULL;
8764 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8766 GstQtReference ref = { NULL, NULL, 0, 0 };
8769 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8770 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8771 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8772 ref.min_req_bitrate);
8775 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
8776 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
8777 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
8779 #ifndef GST_DISABLE_GST_DEBUG
8780 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
8782 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
8784 GST_LOG_OBJECT (qtdemux,
8785 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
8786 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
8787 bitmask, check_type);
8788 if (package == FOURCC_qtim && check_type == 0) {
8789 ref.min_req_qt_version = version;
8793 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
8798 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
8799 ref_data = (guint8 *) rdrf->data + 20;
8800 if (ref_type == FOURCC_alis) {
8801 guint record_len, record_version, fn_len;
8803 /* MacOSX alias record, google for alias-layout.txt */
8804 record_len = QT_UINT16 (ref_data + 4);
8805 record_version = QT_UINT16 (ref_data + 4 + 2);
8806 fn_len = QT_UINT8 (ref_data + 50);
8807 if (record_len > 50 && record_version == 2 && fn_len > 0) {
8808 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
8810 } else if (ref_type == FOURCC_url_) {
8811 ref.location = g_strdup ((gchar *) ref_data);
8813 GST_DEBUG_OBJECT (qtdemux,
8814 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
8815 GST_FOURCC_ARGS (ref_type));
8817 if (ref.location != NULL) {
8818 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
8819 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
8821 GST_WARNING_OBJECT (qtdemux,
8822 "Failed to extract redirect location from rdrf atom");
8826 /* look for others */
8827 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
8830 if (redirects != NULL) {
8831 qtdemux_process_redirects (qtdemux, redirects);
8838 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
8843 tags = gst_tag_list_new_empty ();
8845 if (qtdemux->major_brand == FOURCC_mjp2)
8846 fmt = "Motion JPEG 2000";
8847 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
8849 else if (qtdemux->major_brand == FOURCC_qt__)
8851 else if (qtdemux->fragmented)
8854 fmt = "ISO MP4/M4A";
8856 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
8857 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
8859 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
8865 /* we have read th complete moov node now.
8866 * This function parses all of the relevant info, creates the traks and
8867 * prepares all data structures for playback
8870 qtdemux_parse_tree (GstQTDemux * qtdemux)
8877 guint64 creation_time;
8878 GstDateTime *datetime = NULL;
8881 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
8883 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
8884 return qtdemux_parse_redirects (qtdemux);
8887 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
8889 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
8890 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
8891 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
8892 } else if (version == 0) {
8893 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
8894 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
8895 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
8897 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
8901 /* Moving qt creation time (secs since 1904) to unix time */
8902 if (creation_time != 0) {
8903 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
8906 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
8907 /* some data cleansing sanity */
8908 g_get_current_time (&now);
8909 if (now.tv_sec + 24 * 3600 < creation_time) {
8910 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
8912 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
8915 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
8916 "please file a bug at http://bugzilla.gnome.org");
8920 if (!qtdemux->tag_list)
8921 qtdemux->tag_list = gst_tag_list_new_empty ();
8923 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
8924 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
8926 gst_date_time_unref (datetime);
8929 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
8930 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
8932 /* check for fragmented file and get some (default) data */
8933 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
8936 GstByteReader mehd_data;
8938 /* let track parsing or anyone know weird stuff might happen ... */
8939 qtdemux->fragmented = TRUE;
8941 /* compensate for total duration */
8942 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
8944 qtdemux_parse_mehd (qtdemux, &mehd_data);
8947 /* set duration in the segment info */
8948 gst_qtdemux_get_duration (qtdemux, &duration);
8950 qtdemux->segment.duration = duration;
8951 /* also do not exceed duration; stop is set that way post seek anyway,
8952 * and segment activation falls back to duration,
8953 * whereas loop only checks stop, so let's align this here as well */
8954 qtdemux->segment.stop = duration;
8957 /* parse all traks */
8958 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
8960 qtdemux_parse_trak (qtdemux, trak);
8961 /* iterate all siblings */
8962 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
8966 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
8968 qtdemux_parse_udta (qtdemux, udta);
8970 GST_LOG_OBJECT (qtdemux, "No udta node found.");
8973 /* maybe also some tags in meta box */
8974 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
8976 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
8977 qtdemux_parse_udta (qtdemux, udta);
8979 GST_LOG_OBJECT (qtdemux, "No meta node found.");
8982 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
8987 /* taken from ffmpeg */
8989 get_size (guint8 * ptr, guint8 ** end)
8998 len = (len << 7) | (c & 0x7f);
9007 /* this can change the codec originally present in @list */
9009 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
9010 GNode * esds, GstTagList * list)
9012 int len = QT_UINT32 (esds->data);
9013 guint8 *ptr = esds->data;
9014 guint8 *end = ptr + len;
9016 guint8 *data_ptr = NULL;
9018 guint8 object_type_id = 0;
9019 const char *codec_name = NULL;
9020 GstCaps *caps = NULL;
9022 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
9024 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
9027 tag = QT_UINT8 (ptr);
9028 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
9030 len = get_size (ptr, &ptr);
9031 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
9035 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
9036 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
9040 guint max_bitrate, avg_bitrate;
9042 object_type_id = QT_UINT8 (ptr);
9043 max_bitrate = QT_UINT32 (ptr + 5);
9044 avg_bitrate = QT_UINT32 (ptr + 9);
9045 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
9046 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
9047 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
9048 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
9049 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
9050 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9051 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9052 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9054 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9055 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
9062 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
9068 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
9072 GST_ERROR_OBJECT (qtdemux, "parse error");
9077 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
9078 * in use, and should also be used to override some other parameters for some
9080 switch (object_type_id) {
9081 case 0x20: /* MPEG-4 */
9082 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
9083 * profile_and_level_indication */
9084 if (data_ptr != NULL && data_len >= 5 &&
9085 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
9086 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
9087 data_ptr + 4, data_len - 4);
9089 break; /* Nothing special needed here */
9090 case 0x21: /* H.264 */
9091 codec_name = "H.264 / AVC";
9092 caps = gst_caps_new_simple ("video/x-h264",
9093 "stream-format", G_TYPE_STRING, "avc",
9094 "alignment", G_TYPE_STRING, "au", NULL);
9096 case 0x40: /* AAC (any) */
9097 case 0x66: /* AAC Main */
9098 case 0x67: /* AAC LC */
9099 case 0x68: /* AAC SSR */
9100 /* Override channels and rate based on the codec_data, as it's often
9102 /* Only do so for basic setup without HE-AAC extension */
9103 if (data_ptr && data_len == 2) {
9104 guint channels, rateindex, rate;
9106 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
9107 channels = (data_ptr[1] & 0x7f) >> 3;
9108 if (channels > 0 && channels < 7) {
9109 stream->n_channels = channels;
9110 } else if (channels == 7) {
9111 stream->n_channels = 8;
9114 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
9115 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
9117 stream->rate = rate;
9120 /* Set level and profile if possible */
9121 if (data_ptr != NULL && data_len >= 2) {
9122 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
9123 data_ptr, data_len);
9126 case 0x60: /* MPEG-2, various profiles */
9132 codec_name = "MPEG-2 video";
9134 gst_caps_unref (stream->caps);
9135 stream->caps = gst_caps_new_simple ("video/mpeg",
9136 "mpegversion", G_TYPE_INT, 2,
9137 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9139 case 0x69: /* MP3 has two different values, accept either */
9141 /* change to mpeg1 layer 3 audio */
9142 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
9143 "mpegversion", G_TYPE_INT, 1, NULL);
9144 codec_name = "MPEG-1 layer 3";
9146 case 0x6A: /* MPEG-1 */
9147 codec_name = "MPEG-1 video";
9149 gst_caps_unref (stream->caps);
9150 stream->caps = gst_caps_new_simple ("video/mpeg",
9151 "mpegversion", G_TYPE_INT, 1,
9152 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9154 case 0x6C: /* MJPEG */
9155 caps = gst_caps_new_empty_simple ("image/jpeg");
9156 codec_name = "Motion-JPEG";
9158 case 0x6D: /* PNG */
9159 caps = gst_caps_new_empty_simple ("image/png");
9160 codec_name = "PNG still images";
9162 case 0x6E: /* JPEG2000 */
9163 codec_name = "JPEG-2000";
9164 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9166 case 0xA4: /* Dirac */
9167 codec_name = "Dirac";
9168 caps = gst_caps_new_empty_simple ("video/x-dirac");
9170 case 0xA5: /* AC3 */
9171 codec_name = "AC-3 audio";
9172 caps = gst_caps_new_simple ("audio/x-ac3",
9173 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9175 case 0xE1: /* QCELP */
9176 /* QCELP, the codec_data is a riff tag (little endian) with
9177 * 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). */
9178 caps = gst_caps_new_empty_simple ("audio/qcelp");
9179 codec_name = "QCELP";
9185 /* If we have a replacement caps, then change our caps for this stream */
9187 gst_caps_unref (stream->caps);
9188 stream->caps = caps;
9191 if (codec_name && list)
9192 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9193 GST_TAG_AUDIO_CODEC, codec_name, NULL);
9195 /* Add the codec_data attribute to caps, if we have it */
9199 buffer = gst_buffer_new_and_alloc (data_len);
9200 _gst_buffer_copy_into_mem (buffer, 0, data_ptr, data_len);
9202 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
9203 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
9205 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
9207 gst_buffer_unref (buffer);
9212 #define _codec(name) \
9215 *codec_name = g_strdup (name); \
9220 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9221 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9224 const GstStructure *s;
9228 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
9229 _codec ("PNG still images");
9230 caps = gst_caps_new_empty_simple ("image/png");
9232 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
9233 _codec ("JPEG still images");
9234 caps = gst_caps_new_empty_simple ("image/jpeg");
9236 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
9237 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
9238 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
9239 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
9240 _codec ("Motion-JPEG");
9241 caps = gst_caps_new_empty_simple ("image/jpeg");
9243 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
9244 _codec ("Motion-JPEG format B");
9245 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
9247 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
9248 _codec ("JPEG-2000");
9249 /* override to what it should be according to spec, avoid palette_data */
9250 stream->bits_per_sample = 24;
9251 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9253 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
9254 _codec ("Sorensen video v.3");
9255 caps = gst_caps_new_simple ("video/x-svq",
9256 "svqversion", G_TYPE_INT, 3, NULL);
9258 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
9259 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
9260 _codec ("Sorensen video v.1");
9261 caps = gst_caps_new_simple ("video/x-svq",
9262 "svqversion", G_TYPE_INT, 1, NULL);
9264 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9268 _codec ("Raw RGB video");
9269 bps = QT_UINT16 (stsd_data + 98);
9270 /* set common stuff */
9271 caps = gst_caps_new_empty_simple ("video/x-raw");
9275 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB15", NULL);
9278 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB16", NULL);
9281 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB", NULL);
9284 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "ARGB", NULL);
9292 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
9293 _codec ("Raw planar YUV 4:2:0");
9294 caps = gst_caps_new_simple ("video/x-raw",
9295 "format", G_TYPE_STRING, "I420", NULL);
9297 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
9298 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
9299 _codec ("Raw packed YUV 4:2:2");
9300 caps = gst_caps_new_simple ("video/x-raw",
9301 "format", G_TYPE_STRING, "YUY2", NULL);
9303 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
9304 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
9305 _codec ("Raw packed YUV 4:2:2");
9306 caps = gst_caps_new_simple ("video/x-raw",
9307 "format", G_TYPE_STRING, "UYVY", NULL);
9309 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
9310 _codec ("Raw packed YUV 10-bit 4:2:2");
9311 caps = gst_caps_new_simple ("video/x-raw",
9312 "format", G_TYPE_STRING, "v210", NULL);
9314 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
9315 _codec ("Raw packed RGB 10-bit 4:4:4");
9316 caps = gst_caps_new_simple ("video/x-raw",
9317 "format", G_TYPE_STRING, "r210", NULL);
9319 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
9320 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
9321 _codec ("MPEG-1 video");
9322 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9323 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9325 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
9326 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
9327 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
9328 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
9329 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
9330 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
9331 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
9332 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
9333 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
9334 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
9335 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
9336 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
9337 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
9338 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
9339 _codec ("MPEG-2 video");
9340 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
9341 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9343 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
9344 _codec ("GIF still images");
9345 caps = gst_caps_new_empty_simple ("image/gif");
9347 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
9348 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
9349 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
9350 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9352 /* ffmpeg uses the height/width props, don't know why */
9353 caps = gst_caps_new_empty_simple ("video/x-h263");
9355 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9356 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9357 _codec ("MPEG-4 video");
9358 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9359 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9361 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9362 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9363 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9364 caps = gst_caps_new_simple ("video/x-msmpeg",
9365 "msmpegversion", G_TYPE_INT, 43, NULL);
9367 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9368 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9369 _codec ("3ivX video");
9370 caps = gst_caps_new_empty_simple ("video/x-3ivx");
9372 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9374 caps = gst_caps_new_simple ("video/x-divx",
9375 "divxversion", G_TYPE_INT, 3, NULL);
9377 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9378 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9380 caps = gst_caps_new_simple ("video/x-divx",
9381 "divxversion", G_TYPE_INT, 4, NULL);
9383 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9385 caps = gst_caps_new_simple ("video/x-divx",
9386 "divxversion", G_TYPE_INT, 5, NULL);
9388 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9389 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9390 _codec ("XVID MPEG-4");
9391 caps = gst_caps_new_empty_simple ("video/x-xvid");
9394 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9395 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9396 caps = gst_caps_new_simple ("video/mpeg",
9397 "mpegversion", G_TYPE_INT, 4, NULL);
9399 *codec_name = g_strdup ("FFmpeg MPEG-4");
9402 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9404 caps = gst_caps_new_empty_simple ("video/x-cinepak");
9406 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9407 _codec ("Apple QuickDraw");
9408 caps = gst_caps_new_empty_simple ("video/x-qdrw");
9410 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9411 _codec ("Apple video");
9412 caps = gst_caps_new_empty_simple ("video/x-apple-video");
9414 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9415 _codec ("H.264 / AVC");
9416 caps = gst_caps_new_simple ("video/x-h264",
9417 "stream-format", G_TYPE_STRING, "avc",
9418 "alignment", G_TYPE_STRING, "au", NULL);
9420 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9421 _codec ("Run-length encoding");
9422 caps = gst_caps_new_simple ("video/x-rle",
9423 "layout", G_TYPE_STRING, "quicktime", NULL);
9425 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9426 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9427 _codec ("Indeo Video 3");
9428 caps = gst_caps_new_simple ("video/x-indeo",
9429 "indeoversion", G_TYPE_INT, 3, NULL);
9431 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9432 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9433 _codec ("Intel Video 4");
9434 caps = gst_caps_new_simple ("video/x-indeo",
9435 "indeoversion", G_TYPE_INT, 4, NULL);
9437 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9438 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9439 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9440 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9441 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9442 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9443 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9444 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9445 _codec ("DV Video");
9446 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9447 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9449 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9450 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9451 _codec ("DVCPro50 Video");
9452 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9453 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9455 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9456 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9457 _codec ("DVCProHD Video");
9458 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9459 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9461 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9462 _codec ("Apple Graphics (SMC)");
9463 caps = gst_caps_new_empty_simple ("video/x-smc");
9465 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9467 caps = gst_caps_new_empty_simple ("video/x-vp3");
9469 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9471 caps = gst_caps_new_empty_simple ("video/x-theora");
9472 /* theora uses one byte of padding in the data stream because it does not
9473 * allow 0 sized packets while theora does */
9474 stream->padding = 1;
9476 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9478 caps = gst_caps_new_empty_simple ("video/x-dirac");
9480 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9481 _codec ("TIFF still images");
9482 caps = gst_caps_new_empty_simple ("image/tiff");
9484 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9485 _codec ("Apple Intermediate Codec");
9486 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9488 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9489 _codec ("AVID DNxHD");
9490 caps = gst_caps_from_string ("video/x-dnxhd");
9492 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9494 caps = gst_caps_from_string ("video/x-vp8");
9498 caps = gst_caps_new_simple ("video/x-wmv",
9499 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
9501 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9506 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9507 GST_FOURCC_ARGS (fourcc));
9508 caps = gst_caps_new_empty_simple (s);
9513 /* enable clipping for raw video streams */
9514 s = gst_caps_get_structure (caps, 0);
9515 name = gst_structure_get_name (s);
9516 if (g_str_has_prefix (name, "video/x-raw")) {
9517 stream->need_clip = TRUE;
9523 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9524 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9527 const GstStructure *s;
9531 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9534 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9535 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9536 _codec ("Raw 8-bit PCM audio");
9537 caps = gst_caps_new_simple ("audio/x-raw",
9538 "format", G_TYPE_STRING, "U8", NULL);
9540 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9541 endian = G_BIG_ENDIAN;
9543 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9547 GstAudioFormat format;
9550 endian = G_LITTLE_ENDIAN;
9552 depth = stream->bytes_per_packet * 8;
9553 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
9555 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9559 caps = gst_caps_new_simple ("audio/x-raw",
9560 "format", G_TYPE_STRING, gst_audio_format_to_string (format), NULL);
9563 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9564 _codec ("Raw 64-bit floating-point audio");
9565 caps = gst_caps_new_simple ("audio/x-raw",
9566 "format", G_TYPE_STRING, "F64BE", NULL);
9568 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9569 _codec ("Raw 32-bit floating-point audio");
9570 caps = gst_caps_new_simple ("audio/x-raw",
9571 "format", G_TYPE_STRING, "F32BE", NULL);
9574 _codec ("Raw 24-bit PCM audio");
9575 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9577 caps = gst_caps_new_simple ("audio/x-raw",
9578 "format", G_TYPE_STRING, "S24BE", NULL);
9580 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9581 _codec ("Raw 32-bit PCM audio");
9582 caps = gst_caps_new_simple ("audio/x-raw",
9583 "format", G_TYPE_STRING, "S32BE", NULL);
9585 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9586 _codec ("Mu-law audio");
9587 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
9589 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9590 _codec ("A-law audio");
9591 caps = gst_caps_new_empty_simple ("audio/x-alaw");
9595 _codec ("Microsoft ADPCM");
9596 /* Microsoft ADPCM-ACM code 2 */
9597 caps = gst_caps_new_simple ("audio/x-adpcm",
9598 "layout", G_TYPE_STRING, "microsoft", NULL);
9602 _codec ("DVI/IMA ADPCM");
9603 caps = gst_caps_new_simple ("audio/x-adpcm",
9604 "layout", G_TYPE_STRING, "dvi", NULL);
9608 _codec ("DVI/Intel IMA ADPCM");
9609 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9610 caps = gst_caps_new_simple ("audio/x-adpcm",
9611 "layout", G_TYPE_STRING, "quicktime", NULL);
9615 /* MPEG layer 3, CBR only (pre QT4.1) */
9616 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9617 _codec ("MPEG-1 layer 3");
9618 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9619 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9620 "mpegversion", G_TYPE_INT, 1, NULL);
9623 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9624 _codec ("EAC-3 audio");
9625 caps = gst_caps_new_simple ("audio/x-eac3",
9626 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9627 stream->sampled = TRUE;
9629 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9630 _codec ("AC-3 audio");
9631 caps = gst_caps_new_simple ("audio/x-ac3",
9632 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9633 stream->sampled = TRUE;
9635 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9637 caps = gst_caps_new_simple ("audio/x-mace",
9638 "maceversion", G_TYPE_INT, 3, NULL);
9640 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9642 caps = gst_caps_new_simple ("audio/x-mace",
9643 "maceversion", G_TYPE_INT, 6, NULL);
9645 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9647 caps = gst_caps_new_empty_simple ("application/ogg");
9649 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9650 _codec ("DV audio");
9651 caps = gst_caps_new_empty_simple ("audio/x-dv");
9653 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9654 _codec ("MPEG-4 AAC audio");
9655 caps = gst_caps_new_simple ("audio/mpeg",
9656 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9657 "stream-format", G_TYPE_STRING, "raw", NULL);
9659 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9660 _codec ("QDesign Music");
9661 caps = gst_caps_new_empty_simple ("audio/x-qdm");
9663 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9664 _codec ("QDesign Music v.2");
9665 /* FIXME: QDesign music version 2 (no constant) */
9667 caps = gst_caps_new_simple ("audio/x-qdm2",
9668 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9669 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9670 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9672 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
9675 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9676 _codec ("GSM audio");
9677 caps = gst_caps_new_empty_simple ("audio/x-gsm");
9679 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9680 _codec ("AMR audio");
9681 caps = gst_caps_new_empty_simple ("audio/AMR");
9683 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9684 _codec ("AMR-WB audio");
9685 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
9687 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9688 _codec ("Quicktime IMA ADPCM");
9689 caps = gst_caps_new_simple ("audio/x-adpcm",
9690 "layout", G_TYPE_STRING, "quicktime", NULL);
9692 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9693 _codec ("Apple lossless audio");
9694 caps = gst_caps_new_empty_simple ("audio/x-alac");
9696 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9697 _codec ("QualComm PureVoice");
9698 caps = gst_caps_from_string ("audio/qcelp");
9702 caps = gst_caps_new_empty_simple ("audio/x-wma");
9704 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
9710 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9711 GST_FOURCC_ARGS (fourcc));
9712 caps = gst_caps_new_empty_simple (s);
9718 GstCaps *templ_caps =
9719 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
9720 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
9721 gst_caps_unref (caps);
9722 gst_caps_unref (templ_caps);
9723 caps = intersection;
9726 /* enable clipping for raw audio streams */
9727 s = gst_caps_get_structure (caps, 0);
9728 name = gst_structure_get_name (s);
9729 if (g_str_has_prefix (name, "audio/x-raw")) {
9730 stream->need_clip = TRUE;
9736 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9737 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9741 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9744 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
9745 _codec ("DVD subtitle");
9746 caps = gst_caps_new_empty_simple ("video/x-dvd-subpicture");
9748 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
9749 _codec ("Quicktime timed text");
9751 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
9752 _codec ("3GPP timed text");
9754 caps = gst_caps_new_empty_simple ("text/plain");
9755 /* actual text piece needs to be extracted */
9756 stream->need_process = TRUE;
9762 s = g_strdup_printf ("text/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9763 GST_FOURCC_ARGS (fourcc));
9764 caps = gst_caps_new_empty_simple (s);