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., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, 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-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! 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 GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
435 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
436 gchar ** codec_name);
438 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
439 QtDemuxStream * stream, guint32 n);
440 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
443 gst_qtdemux_class_init (GstQTDemuxClass * klass)
445 GObjectClass *gobject_class;
446 GstElementClass *gstelement_class;
448 gobject_class = (GObjectClass *) klass;
449 gstelement_class = (GstElementClass *) klass;
451 parent_class = g_type_class_peek_parent (klass);
453 gobject_class->dispose = gst_qtdemux_dispose;
455 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
457 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
458 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
461 gst_tag_register_musicbrainz_tags ();
463 gst_element_class_add_pad_template (gstelement_class,
464 gst_static_pad_template_get (&gst_qtdemux_sink_template));
465 gst_element_class_add_pad_template (gstelement_class,
466 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
467 gst_element_class_add_pad_template (gstelement_class,
468 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
469 gst_element_class_add_pad_template (gstelement_class,
470 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
471 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
473 "Demultiplex a QuickTime file into audio and video streams",
474 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
476 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
481 gst_qtdemux_init (GstQTDemux * qtdemux)
484 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
485 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
486 gst_pad_set_activatemode_function (qtdemux->sinkpad,
487 qtdemux_sink_activate_mode);
488 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
489 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
490 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
492 qtdemux->state = QTDEMUX_STATE_INITIAL;
493 qtdemux->pullbased = FALSE;
494 qtdemux->posted_redirect = FALSE;
495 qtdemux->neededbytes = 16;
497 qtdemux->adapter = gst_adapter_new ();
499 qtdemux->first_mdat = -1;
500 qtdemux->got_moov = FALSE;
501 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
502 qtdemux->mdatbuffer = NULL;
503 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
505 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
509 gst_qtdemux_dispose (GObject * object)
511 GstQTDemux *qtdemux = GST_QTDEMUX (object);
513 if (qtdemux->adapter) {
514 g_object_unref (G_OBJECT (qtdemux->adapter));
515 qtdemux->adapter = NULL;
518 G_OBJECT_CLASS (parent_class)->dispose (object);
522 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
524 if (qtdemux->posted_redirect) {
525 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
526 (_("This file contains no playable streams.")),
527 ("no known streams found, a redirect message has been posted"));
529 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
530 (_("This file contains no playable streams.")),
531 ("no known streams found"));
536 _gst_buffer_copy_into_mem (GstBuffer * dest, gsize offset, const guint8 * src,
541 g_return_if_fail (gst_buffer_is_writable (dest));
543 bsize = gst_buffer_get_size (dest);
544 g_return_if_fail (bsize >= offset + size);
546 gst_buffer_fill (dest, offset, src, size);
550 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
554 buf = gst_buffer_new ();
555 gst_buffer_append_memory (buf,
556 gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
557 mem, size, 0, size, mem, free_func));
563 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
570 if (G_UNLIKELY (size == 0)) {
572 GstBuffer *tmp = NULL;
574 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
575 if (ret != GST_FLOW_OK)
578 gst_buffer_map (tmp, &map, GST_MAP_READ);
579 size = QT_UINT32 (map.data);
580 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
582 gst_buffer_unmap (tmp, &map);
583 gst_buffer_unref (tmp);
586 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
587 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
588 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
589 /* we're pulling header but already got most interesting bits,
590 * so never mind the rest (e.g. tags) (that much) */
591 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
595 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
596 (_("This file is invalid and cannot be played.")),
597 ("atom has bogus size %" G_GUINT64_FORMAT, size));
598 return GST_FLOW_ERROR;
602 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
604 if (G_UNLIKELY (flow != GST_FLOW_OK))
607 bsize = gst_buffer_get_size (*buf);
608 /* Catch short reads - we don't want any partial atoms */
609 if (G_UNLIKELY (bsize < size)) {
610 GST_WARNING_OBJECT (qtdemux,
611 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
612 gst_buffer_unref (*buf);
622 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
623 GstFormat dest_format, gint64 * dest_value)
626 QtDemuxStream *stream = gst_pad_get_element_private (pad);
627 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
630 if (stream->subtype != FOURCC_vide) {
635 switch (src_format) {
636 case GST_FORMAT_TIME:
637 switch (dest_format) {
638 case GST_FORMAT_BYTES:{
639 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
643 *dest_value = stream->samples[index].offset;
645 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
646 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
647 GST_TIME_ARGS (src_value), *dest_value);
655 case GST_FORMAT_BYTES:
656 switch (dest_format) {
657 case GST_FORMAT_TIME:{
659 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
666 gst_util_uint64_scale (stream->samples[index].timestamp,
667 GST_SECOND, stream->timescale);
668 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
669 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
670 src_value, GST_TIME_ARGS (*dest_value));
683 gst_object_unref (qtdemux);
690 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
694 *duration = GST_CLOCK_TIME_NONE;
696 if (qtdemux->duration != 0) {
697 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
698 *duration = gst_util_uint64_scale (qtdemux->duration,
699 GST_SECOND, qtdemux->timescale);
706 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
709 gboolean res = FALSE;
710 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
712 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
714 switch (GST_QUERY_TYPE (query)) {
715 case GST_QUERY_POSITION:
716 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
717 gst_query_set_position (query, GST_FORMAT_TIME,
718 qtdemux->segment.position);
722 case GST_QUERY_DURATION:{
725 gst_query_parse_duration (query, &fmt, NULL);
726 if (fmt == GST_FORMAT_TIME) {
727 /* First try to query upstream */
728 res = gst_pad_query_default (pad, parent, query);
730 gint64 duration = -1;
732 gst_qtdemux_get_duration (qtdemux, &duration);
734 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
741 case GST_QUERY_CONVERT:{
742 GstFormat src_fmt, dest_fmt;
743 gint64 src_value, dest_value = 0;
745 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
747 res = gst_qtdemux_src_convert (pad,
748 src_fmt, src_value, dest_fmt, &dest_value);
750 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
755 case GST_QUERY_FORMATS:
756 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
759 case GST_QUERY_SEEKING:{
763 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
764 if (fmt == GST_FORMAT_TIME) {
765 gint64 duration = -1;
767 gst_qtdemux_get_duration (qtdemux, &duration);
769 if (!qtdemux->pullbased) {
772 /* we might be able with help from upstream */
774 q = gst_query_new_seeking (GST_FORMAT_BYTES);
775 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
776 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
777 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
781 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
787 res = gst_pad_query_default (pad, parent, query);
795 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
797 if (G_LIKELY (stream->pad)) {
798 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
799 GST_DEBUG_PAD_NAME (stream->pad));
801 if (G_UNLIKELY (stream->pending_tags)) {
802 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
803 stream->pending_tags);
804 gst_pad_push_event (stream->pad,
805 gst_event_new_tag (stream->pending_tags));
806 stream->pending_tags = NULL;
809 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
810 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
812 gst_pad_push_event (stream->pad,
813 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
814 stream->send_global_tags = FALSE;
819 /* push event on all source pads; takes ownership of the event */
821 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
824 gboolean has_valid_stream = FALSE;
825 GstEventType etype = GST_EVENT_TYPE (event);
827 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
828 GST_EVENT_TYPE_NAME (event));
830 for (n = 0; n < qtdemux->n_streams; n++) {
832 QtDemuxStream *stream = qtdemux->streams[n];
834 if ((pad = stream->pad)) {
835 has_valid_stream = TRUE;
837 if (etype == GST_EVENT_EOS) {
838 /* let's not send twice */
839 if (stream->sent_eos)
841 stream->sent_eos = TRUE;
844 gst_pad_push_event (pad, gst_event_ref (event));
848 gst_event_unref (event);
850 /* if it is EOS and there are no pads, post an error */
851 if (!has_valid_stream && etype == GST_EVENT_EOS) {
852 gst_qtdemux_post_no_playable_stream_error (qtdemux);
856 /* push a pending newsegment event, if any from the streaming thread */
858 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
860 if (qtdemux->pending_newsegment) {
861 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
862 qtdemux->pending_newsegment = NULL;
872 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
874 if (s1->timestamp > *media_time)
880 /* find the index of the sample that includes the data for @media_time using a
881 * binary search. Only to be called in optimized cases of linear search below.
883 * Returns the index of the sample.
886 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
889 QtDemuxSample *result;
892 /* convert media_time to mov format */
894 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
896 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
897 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
898 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
900 if (G_LIKELY (result))
901 index = result - str->samples;
910 /* find the index of the sample that includes the data for @media_offset using a
913 * Returns the index of the sample.
916 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
917 QtDemuxStream * str, gint64 media_offset)
919 QtDemuxSample *result = str->samples;
922 if (result == NULL || str->n_samples == 0)
925 if (media_offset == result->offset)
929 while (index < str->n_samples - 1) {
930 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
933 if (media_offset < result->offset)
944 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
949 /* find the index of the sample that includes the data for @media_time using a
950 * linear search, and keeping in mind that not all samples may have been parsed
951 * yet. If possible, it will delegate to binary search.
953 * Returns the index of the sample.
956 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
962 /* convert media_time to mov format */
964 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
966 if (mov_time == str->samples[0].timestamp)
969 /* use faster search if requested time in already parsed range */
970 if (str->stbl_index >= 0 &&
971 mov_time <= str->samples[str->stbl_index].timestamp)
972 return gst_qtdemux_find_index (qtdemux, str, media_time);
974 while (index < str->n_samples - 1) {
975 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
978 if (mov_time < str->samples[index + 1].timestamp)
988 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
993 /* find the index of the keyframe needed to decode the sample at @index
996 * Returns the index of the keyframe.
999 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1002 guint32 new_index = index;
1004 if (index >= str->n_samples) {
1005 new_index = str->n_samples;
1009 /* all keyframes, return index */
1010 if (str->all_keyframe) {
1015 /* else go back until we have a keyframe */
1017 if (str->samples[new_index].keyframe)
1027 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1028 "gave %u", index, new_index);
1033 /* find the segment for @time_position for @stream
1035 * Returns -1 if the segment cannot be found.
1038 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1039 guint64 time_position)
1044 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1045 GST_TIME_ARGS (time_position));
1047 /* find segment corresponding to time_position if we are looking
1050 for (i = 0; i < stream->n_segments; i++) {
1051 QtDemuxSegment *segment = &stream->segments[i];
1053 GST_LOG_OBJECT (qtdemux,
1054 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1055 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1057 /* For the last segment we include stop_time in the last segment */
1058 if (i < stream->n_segments - 1) {
1059 if (segment->time <= time_position && time_position < segment->stop_time) {
1060 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1065 if (segment->time <= time_position && time_position <= segment->stop_time) {
1066 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1075 /* move the stream @str to the sample position @index.
1077 * Updates @str->sample_index and marks discontinuity if needed.
1080 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1083 /* no change needed */
1084 if (index == str->sample_index)
1087 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1090 /* position changed, we have a discont */
1091 str->sample_index = index;
1092 /* Each time we move in the stream we store the position where we are
1094 str->from_sample = index;
1095 str->discont = TRUE;
1099 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1100 gint64 * key_time, gint64 * key_offset)
1103 gint64 min_byte_offset = -1;
1106 min_offset = desired_time;
1108 /* for each stream, find the index of the sample in the segment
1109 * and move back to the previous keyframe. */
1110 for (n = 0; n < qtdemux->n_streams; n++) {
1112 guint32 index, kindex;
1114 guint64 media_start;
1117 QtDemuxSegment *seg;
1119 str = qtdemux->streams[n];
1121 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1122 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1124 /* segment not found, continue with normal flow */
1128 /* get segment and time in the segment */
1129 seg = &str->segments[seg_idx];
1130 seg_time = desired_time - seg->time;
1132 /* get the media time in the segment */
1133 media_start = seg->media_start + seg_time;
1135 /* get the index of the sample with media time */
1136 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1137 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1138 " at offset %" G_GUINT64_FORMAT,
1139 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1141 /* find previous keyframe */
1142 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1144 /* if the keyframe is at a different position, we need to update the
1145 * requested seek time */
1146 if (index != kindex) {
1149 /* get timestamp of keyframe */
1151 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1153 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT
1154 " at offset %" G_GUINT64_FORMAT,
1155 kindex, GST_TIME_ARGS (media_time), str->samples[kindex].offset);
1157 /* keyframes in the segment get a chance to change the
1158 * desired_offset. keyframes out of the segment are
1160 if (media_time >= seg->media_start) {
1163 /* this keyframe is inside the segment, convert back to
1165 seg_time = (media_time - seg->media_start) + seg->time;
1166 if (seg_time < min_offset)
1167 min_offset = seg_time;
1171 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1172 min_byte_offset = str->samples[index].offset;
1176 *key_time = min_offset;
1178 *key_offset = min_byte_offset;
1182 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1183 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1187 g_return_val_if_fail (format != NULL, FALSE);
1188 g_return_val_if_fail (cur != NULL, FALSE);
1189 g_return_val_if_fail (stop != NULL, FALSE);
1191 if (*format == GST_FORMAT_TIME)
1195 if (cur_type != GST_SEEK_TYPE_NONE)
1196 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1197 if (res && stop_type != GST_SEEK_TYPE_NONE)
1198 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1201 *format = GST_FORMAT_TIME;
1206 /* perform seek in push based mode:
1207 find BYTE position to move to based on time and delegate to upstream
1210 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1215 GstSeekType cur_type, stop_type;
1220 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1222 gst_event_parse_seek (event, &rate, &format, &flags,
1223 &cur_type, &cur, &stop_type, &stop);
1225 /* FIXME, always play to the end */
1228 /* only forward streaming and seeking is possible */
1230 goto unsupported_seek;
1232 /* convert to TIME if needed and possible */
1233 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1237 /* find reasonable corresponding BYTE position,
1238 * also try to mind about keyframes, since we can not go back a bit for them
1240 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1245 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1246 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1249 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1250 GST_DEBUG_OBJECT (qtdemux,
1251 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1252 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1253 GST_OBJECT_LOCK (qtdemux);
1254 qtdemux->requested_seek_time = cur;
1255 qtdemux->seek_offset = byte_cur;
1256 GST_OBJECT_UNLOCK (qtdemux);
1259 /* BYTE seek event */
1260 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1262 res = gst_pad_push_event (qtdemux->sinkpad, event);
1269 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1275 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1280 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1285 /* perform the seek.
1287 * We set all segment_indexes in the streams to unknown and
1288 * adjust the time_position to the desired position. this is enough
1289 * to trigger a segment switch in the streaming thread to start
1290 * streaming from the desired position.
1292 * Keyframe seeking is a little more complicated when dealing with
1293 * segments. Ideally we want to move to the previous keyframe in
1294 * the segment but there might not be a keyframe in the segment. In
1295 * fact, none of the segments could contain a keyframe. We take a
1296 * practical approach: seek to the previous keyframe in the segment,
1297 * if there is none, seek to the beginning of the segment.
1299 * Called with STREAM_LOCK
1302 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1304 gint64 desired_offset;
1307 desired_offset = segment->position;
1309 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1310 GST_TIME_ARGS (desired_offset));
1312 /* may not have enough fragmented info to do this adjustment,
1313 * and we can't scan (and probably should not) at this time with
1314 * possibly flushing upstream */
1315 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1318 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1319 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1320 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1321 desired_offset = min_offset;
1324 /* and set all streams to the final position */
1325 for (n = 0; n < qtdemux->n_streams; n++) {
1326 QtDemuxStream *stream = qtdemux->streams[n];
1328 stream->time_position = desired_offset;
1329 stream->sample_index = -1;
1330 stream->segment_index = -1;
1331 stream->last_ret = GST_FLOW_OK;
1332 stream->sent_eos = FALSE;
1334 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1335 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1337 segment->position = desired_offset;
1338 segment->time = desired_offset;
1340 /* we stop at the end */
1341 if (segment->stop == -1)
1342 segment->stop = segment->duration;
1347 /* do a seek in pull based mode */
1349 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1354 GstSeekType cur_type, stop_type;
1358 GstSegment seeksegment;
1362 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1364 gst_event_parse_seek (event, &rate, &format, &flags,
1365 &cur_type, &cur, &stop_type, &stop);
1367 /* we have to have a format as the segment format. Try to convert
1369 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1373 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1375 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1379 flush = flags & GST_SEEK_FLAG_FLUSH;
1381 /* stop streaming, either by flushing or by pausing the task */
1383 /* unlock upstream pull_range */
1384 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1385 /* make sure out loop function exits */
1386 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1388 /* non flushing seek, pause the task */
1389 gst_pad_pause_task (qtdemux->sinkpad);
1392 /* wait for streaming to finish */
1393 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1395 /* copy segment, we need this because we still need the old
1396 * segment when we close the current segment. */
1397 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1400 /* configure the segment with the seek variables */
1401 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1402 gst_segment_do_seek (&seeksegment, rate, format, flags,
1403 cur_type, cur, stop_type, stop, &update);
1406 /* now do the seek, this actually never returns FALSE */
1407 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1409 /* prepare for streaming again */
1411 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop (TRUE));
1412 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop (TRUE));
1415 /* commit the new segment */
1416 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1418 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1419 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1420 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1421 qtdemux->segment.format, qtdemux->segment.position));
1424 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1425 for (i = 0; i < qtdemux->n_streams; i++)
1426 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1428 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1429 qtdemux->sinkpad, NULL);
1431 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1438 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1444 qtdemux_ensure_index (GstQTDemux * qtdemux)
1448 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1450 /* Build complete index */
1451 for (i = 0; i < qtdemux->n_streams; i++) {
1452 QtDemuxStream *stream = qtdemux->streams[i];
1454 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1462 GST_LOG_OBJECT (qtdemux,
1463 "Building complete index of stream %u for seeking failed!", i);
1469 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1472 gboolean res = TRUE;
1473 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1475 switch (GST_EVENT_TYPE (event)) {
1476 case GST_EVENT_SEEK:
1478 #ifndef GST_DISABLE_GST_DEBUG
1479 GstClockTime ts = gst_util_get_timestamp ();
1481 /* Build complete index for seeking;
1482 * if not a fragmented file at least */
1483 if (!qtdemux->fragmented)
1484 if (!qtdemux_ensure_index (qtdemux))
1486 #ifndef GST_DISABLE_GST_DEBUG
1487 ts = gst_util_get_timestamp () - ts;
1488 GST_INFO_OBJECT (qtdemux,
1489 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1492 if (qtdemux->pullbased) {
1493 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1494 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1495 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1497 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1498 && !qtdemux->fragmented) {
1499 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1501 GST_DEBUG_OBJECT (qtdemux,
1502 "ignoring seek in push mode in current state");
1505 gst_event_unref (event);
1508 case GST_EVENT_NAVIGATION:
1510 gst_event_unref (event);
1513 res = gst_pad_event_default (pad, parent, event);
1523 GST_ERROR_OBJECT (qtdemux, "Index failed");
1524 gst_event_unref (event);
1530 /* stream/index return sample that is min/max w.r.t. byte position,
1531 * time is min/max w.r.t. time of samples,
1532 * the latter need not be time of the former sample */
1534 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1535 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1538 gint64 time, min_time;
1539 QtDemuxStream *stream;
1545 for (n = 0; n < qtdemux->n_streams; ++n) {
1548 gboolean set_sample;
1550 str = qtdemux->streams[n];
1557 i = str->n_samples - 1;
1560 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1561 if (str->samples[i].size &&
1562 ((fw && (str->samples[i].offset >= byte_pos)) ||
1564 (str->samples[i].offset + str->samples[i].size <=
1566 /* move stream to first available sample */
1568 gst_qtdemux_move_stream (qtdemux, str, i);
1571 /* determine min/max time */
1572 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1573 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1574 if (min_time == -1 || (!fw && time > min_time) ||
1575 (fw && time < min_time)) {
1578 /* determine stream with leading sample, to get its position */
1580 && (str->samples[i].offset < stream->samples[index].offset))
1582 && (str->samples[i].offset > stream->samples[index].offset))) {
1589 /* no sample for this stream, mark eos */
1591 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1603 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1606 GstQTDemux *demux = GST_QTDEMUX (parent);
1609 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1611 switch (GST_EVENT_TYPE (event)) {
1612 case GST_EVENT_SEGMENT:
1615 QtDemuxStream *stream;
1619 /* some debug output */
1620 gst_event_copy_segment (event, &segment);
1621 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1624 /* chain will send initial newsegment after pads have been added */
1625 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1626 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1630 /* we only expect a BYTE segment, e.g. following a seek */
1631 if (segment.format == GST_FORMAT_BYTES) {
1632 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1633 gint64 requested_seek_time;
1634 guint64 seek_offset;
1636 offset = segment.start;
1638 GST_OBJECT_LOCK (demux);
1639 requested_seek_time = demux->requested_seek_time;
1640 seek_offset = demux->seek_offset;
1641 demux->requested_seek_time = -1;
1642 demux->seek_offset = -1;
1643 GST_OBJECT_UNLOCK (demux);
1645 if (offset == seek_offset) {
1646 segment.start = requested_seek_time;
1648 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1649 NULL, (gint64 *) & segment.start);
1650 if ((gint64) segment.start < 0)
1654 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1655 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1656 NULL, (gint64 *) & segment.stop);
1657 /* keyframe seeking should already arrange for start >= stop,
1658 * but make sure in other rare cases */
1659 segment.stop = MAX (segment.stop, segment.start);
1662 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1666 /* accept upstream's notion of segment and distribute along */
1667 segment.format = GST_FORMAT_TIME;
1668 segment.position = segment.time = segment.start;
1669 segment.duration = demux->segment.duration;
1670 segment.base = gst_segment_to_running_time (&demux->segment,
1671 GST_FORMAT_TIME, demux->segment.position);
1673 gst_segment_copy_into (&segment, &demux->segment);
1674 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
1675 gst_qtdemux_push_event (demux, gst_event_new_segment (&segment));
1677 /* clear leftover in current segment, if any */
1678 gst_adapter_clear (demux->adapter);
1679 /* set up streaming thread */
1680 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1681 demux->offset = offset;
1683 demux->todrop = stream->samples[idx].offset - offset;
1684 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1686 /* set up for EOS */
1687 demux->neededbytes = -1;
1691 gst_event_unref (event);
1696 case GST_EVENT_FLUSH_STOP:
1701 /* clean up, force EOS if no more info follows */
1702 gst_adapter_clear (demux->adapter);
1704 demux->neededbytes = -1;
1705 /* reset flow return, e.g. following seek */
1706 for (i = 0; i < demux->n_streams; i++) {
1707 demux->streams[i]->last_ret = GST_FLOW_OK;
1708 demux->streams[i]->sent_eos = FALSE;
1710 dur = demux->segment.duration;
1711 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1712 demux->segment.duration = dur;
1716 /* If we are in push mode, and get an EOS before we've seen any streams,
1717 * then error out - we have nowhere to send the EOS */
1718 if (!demux->pullbased) {
1720 gboolean has_valid_stream = FALSE;
1721 for (i = 0; i < demux->n_streams; i++) {
1722 if (demux->streams[i]->pad != NULL) {
1723 has_valid_stream = TRUE;
1727 if (!has_valid_stream)
1728 gst_qtdemux_post_no_playable_stream_error (demux);
1735 res = gst_pad_event_default (demux->sinkpad, parent, event);
1743 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1745 GstQTDemux *demux = GST_QTDEMUX (element);
1747 GST_OBJECT_LOCK (demux);
1748 if (demux->element_index)
1749 gst_object_unref (demux->element_index);
1751 demux->element_index = gst_object_ref (index);
1753 demux->element_index = NULL;
1755 GST_OBJECT_UNLOCK (demux);
1756 /* object lock might be taken again */
1758 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1759 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
1760 demux->element_index, demux->index_id);
1764 gst_qtdemux_get_index (GstElement * element)
1766 GstIndex *result = NULL;
1767 GstQTDemux *demux = GST_QTDEMUX (element);
1769 GST_OBJECT_LOCK (demux);
1770 if (demux->element_index)
1771 result = gst_object_ref (demux->element_index);
1772 GST_OBJECT_UNLOCK (demux);
1774 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1781 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1783 g_free ((gpointer) stream->stco.data);
1784 stream->stco.data = NULL;
1785 g_free ((gpointer) stream->stsz.data);
1786 stream->stsz.data = NULL;
1787 g_free ((gpointer) stream->stsc.data);
1788 stream->stsc.data = NULL;
1789 g_free ((gpointer) stream->stts.data);
1790 stream->stts.data = NULL;
1791 g_free ((gpointer) stream->stss.data);
1792 stream->stss.data = NULL;
1793 g_free ((gpointer) stream->stps.data);
1794 stream->stps.data = NULL;
1795 g_free ((gpointer) stream->ctts.data);
1796 stream->ctts.data = NULL;
1800 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
1802 if (stream->allocator)
1803 gst_object_unref (stream->allocator);
1804 while (stream->buffers) {
1805 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1806 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1809 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
1810 g_free (stream->samples);
1812 gst_caps_unref (stream->caps);
1813 g_free (stream->segments);
1814 if (stream->pending_tags)
1815 gst_tag_list_unref (stream->pending_tags);
1816 g_free (stream->redirect_uri);
1817 /* free stbl sub-atoms */
1818 gst_qtdemux_stbl_free (stream);
1822 static GstStateChangeReturn
1823 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1825 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1826 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1828 switch (transition) {
1829 case GST_STATE_CHANGE_PAUSED_TO_READY:
1835 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1837 switch (transition) {
1838 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1841 qtdemux->state = QTDEMUX_STATE_INITIAL;
1842 qtdemux->neededbytes = 16;
1843 qtdemux->todrop = 0;
1844 qtdemux->pullbased = FALSE;
1845 qtdemux->posted_redirect = FALSE;
1846 qtdemux->offset = 0;
1847 qtdemux->first_mdat = -1;
1848 qtdemux->header_size = 0;
1849 qtdemux->got_moov = FALSE;
1850 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1851 if (qtdemux->mdatbuffer)
1852 gst_buffer_unref (qtdemux->mdatbuffer);
1853 qtdemux->mdatbuffer = NULL;
1854 if (qtdemux->comp_brands)
1855 gst_buffer_unref (qtdemux->comp_brands);
1856 qtdemux->comp_brands = NULL;
1857 if (qtdemux->tag_list)
1858 gst_tag_list_unref (qtdemux->tag_list);
1859 qtdemux->tag_list = NULL;
1861 if (qtdemux->element_index)
1862 gst_object_unref (qtdemux->element_index);
1863 qtdemux->element_index = NULL;
1865 gst_adapter_clear (qtdemux->adapter);
1866 for (n = 0; n < qtdemux->n_streams; n++) {
1867 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1868 qtdemux->streams[n] = NULL;
1870 qtdemux->major_brand = 0;
1871 qtdemux->n_streams = 0;
1872 qtdemux->n_video_streams = 0;
1873 qtdemux->n_audio_streams = 0;
1874 qtdemux->n_sub_streams = 0;
1875 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1876 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1877 qtdemux->seek_offset = 0;
1878 qtdemux->upstream_seekable = FALSE;
1879 qtdemux->upstream_size = 0;
1890 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1892 /* counts as header data */
1893 qtdemux->header_size += length;
1895 /* only consider at least a sufficiently complete ftyp atom */
1899 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1900 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1901 GST_FOURCC_ARGS (qtdemux->major_brand));
1902 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1903 _gst_buffer_copy_into_mem (buf, 0, buffer + 16, length - 16);
1908 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
1910 /* Strip out bogus fields */
1912 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
1914 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
1916 if (qtdemux->tag_list) {
1917 /* prioritize native tags using _KEEP mode */
1918 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
1919 gst_tag_list_unref (taglist);
1921 qtdemux->tag_list = taglist;
1926 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1928 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
1929 0x97, 0xA9, 0x42, 0xE8,
1930 0x9C, 0x71, 0x99, 0x94,
1931 0x91, 0xE3, 0xAF, 0xAC
1935 /* counts as header data */
1936 qtdemux->header_size += length;
1938 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
1940 if (length <= offset + 16) {
1941 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
1945 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
1947 GstTagList *taglist;
1949 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
1950 length - offset - 16, NULL);
1951 taglist = gst_tag_list_from_xmp_buffer (buf);
1952 gst_buffer_unref (buf);
1954 qtdemux_handle_xmp_taglist (qtdemux, taglist);
1957 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
1961 /* caller verifies at least 8 bytes in buf */
1963 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1964 guint64 * plength, guint32 * pfourcc)
1969 length = QT_UINT32 (data);
1970 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1971 fourcc = QT_FOURCC (data + 4);
1972 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1975 length = G_MAXUINT32;
1976 } else if (length == 1 && size >= 16) {
1977 /* this means we have an extended size, which is the 64 bit value of
1978 * the next 8 bytes */
1979 length = QT_UINT64 (data + 8);
1980 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1990 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
1992 guint32 version = 0;
1993 guint64 duration = 0;
1995 if (!gst_byte_reader_get_uint32_be (br, &version))
2000 if (!gst_byte_reader_get_uint64_be (br, &duration))
2005 if (!gst_byte_reader_get_uint32_be (br, &dur))
2010 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2011 qtdemux->duration = duration;
2017 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2023 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2024 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2026 if (!stream->parsed_trex && qtdemux->moov_node) {
2028 GstByteReader trex_data;
2030 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2032 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2035 guint32 id = 0, dur = 0, size = 0, flags = 0;
2037 /* skip version/flags */
2038 if (!gst_byte_reader_skip (&trex_data, 4))
2040 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2042 if (id != stream->track_id)
2044 /* sample description index; ignore */
2045 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2047 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2049 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2051 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2054 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2055 "duration %d, size %d, flags 0x%x", stream->track_id,
2058 stream->parsed_trex = TRUE;
2059 stream->def_sample_duration = dur;
2060 stream->def_sample_size = size;
2061 stream->def_sample_flags = flags;
2064 /* iterate all siblings */
2065 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2071 *ds_duration = stream->def_sample_duration;
2072 *ds_size = stream->def_sample_size;
2073 *ds_size = stream->def_sample_size;
2075 /* even then, above values are better than random ... */
2076 if (G_UNLIKELY (!stream->parsed_trex)) {
2077 GST_WARNING_OBJECT (qtdemux,
2078 "failed to find fragment defaults for stream %d", stream->track_id);
2086 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2087 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2088 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2089 gint64 * base_offset, gint64 * running_offset)
2092 gint32 data_offset = 0;
2093 guint32 flags = 0, first_flags = 0, samples_count = 0;
2096 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2097 QtDemuxSample *sample;
2098 gboolean ismv = FALSE;
2100 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2101 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2102 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2105 /* presence of stss or not can't really tell us much,
2106 * and flags and so on tend to be marginally reliable in these files */
2107 if (stream->subtype == FOURCC_soun) {
2108 GST_DEBUG_OBJECT (qtdemux,
2109 "sound track in fragmented file; marking all keyframes");
2110 stream->all_keyframe = TRUE;
2113 if (!gst_byte_reader_skip (trun, 1) ||
2114 !gst_byte_reader_get_uint24_be (trun, &flags))
2117 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2120 if (flags & TR_DATA_OFFSET) {
2121 /* note this is really signed */
2122 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2124 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2125 /* default base offset = first byte of moof */
2126 if (*base_offset == -1) {
2127 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2128 *base_offset = moof_offset;
2130 *running_offset = *base_offset + data_offset;
2132 /* if no offset at all, that would mean data starts at moof start,
2133 * which is a bit wrong and is ismv crappy way, so compensate
2134 * assuming data is in mdat following moof */
2135 if (*base_offset == -1) {
2136 *base_offset = moof_offset + moof_length + 8;
2137 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2140 if (*running_offset == -1)
2141 *running_offset = *base_offset;
2144 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2146 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2147 data_offset, flags, samples_count);
2149 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2150 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2151 GST_DEBUG_OBJECT (qtdemux,
2152 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2153 flags ^= TR_FIRST_SAMPLE_FLAGS;
2155 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2157 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2161 /* FIXME ? spec says other bits should also be checked to determine
2162 * entry size (and prefix size for that matter) */
2164 dur_offset = size_offset = 0;
2165 if (flags & TR_SAMPLE_DURATION) {
2166 GST_LOG_OBJECT (qtdemux, "entry duration present");
2167 dur_offset = entry_size;
2170 if (flags & TR_SAMPLE_SIZE) {
2171 GST_LOG_OBJECT (qtdemux, "entry size present");
2172 size_offset = entry_size;
2175 if (flags & TR_SAMPLE_FLAGS) {
2176 GST_LOG_OBJECT (qtdemux, "entry flags present");
2177 flags_offset = entry_size;
2180 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2181 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2182 ct_offset = entry_size;
2186 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2188 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2190 if (stream->n_samples >=
2191 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2194 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2195 stream->n_samples, (guint) sizeof (QtDemuxSample),
2196 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2198 /* create a new array of samples if it's the first sample parsed */
2199 if (stream->n_samples == 0)
2200 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2201 /* or try to reallocate it with space enough to insert the new samples */
2203 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2204 stream->n_samples + samples_count);
2205 if (stream->samples == NULL)
2208 if (G_UNLIKELY (stream->n_samples == 0)) {
2209 /* the timestamp of the first sample is also provided by the tfra entry
2210 * but we shouldn't rely on it as it is at the end of files */
2213 /* subsequent fragments extend stream */
2215 stream->samples[stream->n_samples - 1].timestamp +
2216 stream->samples[stream->n_samples - 1].duration;
2218 sample = stream->samples + stream->n_samples;
2219 for (i = 0; i < samples_count; i++) {
2220 guint32 dur, size, sflags, ct;
2222 /* first read sample data */
2223 if (flags & TR_SAMPLE_DURATION) {
2224 dur = QT_UINT32 (data + dur_offset);
2226 dur = d_sample_duration;
2228 if (flags & TR_SAMPLE_SIZE) {
2229 size = QT_UINT32 (data + size_offset);
2231 size = d_sample_size;
2233 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2235 sflags = first_flags;
2237 sflags = d_sample_flags;
2239 } else if (flags & TR_SAMPLE_FLAGS) {
2240 sflags = QT_UINT32 (data + flags_offset);
2242 sflags = d_sample_flags;
2244 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2245 ct = QT_UINT32 (data + ct_offset);
2251 /* fill the sample information */
2252 sample->offset = *running_offset;
2253 sample->pts_offset = ct;
2254 sample->size = size;
2255 sample->timestamp = timestamp;
2256 sample->duration = dur;
2257 /* sample-is-difference-sample */
2258 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2259 * now idea how it relates to bitfield other than massive LE/BE confusion */
2260 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2261 *running_offset += size;
2266 stream->n_samples += samples_count;
2272 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2277 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2283 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2284 "be larger than %uMB (broken file?)", stream->n_samples,
2285 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2290 /* find stream with @id */
2291 static inline QtDemuxStream *
2292 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2294 QtDemuxStream *stream;
2298 if (G_UNLIKELY (!id)) {
2299 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2303 /* try to get it fast and simple */
2304 if (G_LIKELY (id <= qtdemux->n_streams)) {
2305 stream = qtdemux->streams[id - 1];
2306 if (G_LIKELY (stream->track_id == id))
2310 /* linear search otherwise */
2311 for (i = 0; i < qtdemux->n_streams; i++) {
2312 stream = qtdemux->streams[i];
2313 if (stream->track_id == id)
2321 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2322 QtDemuxStream ** stream, guint32 * default_sample_duration,
2323 guint32 * default_sample_size, guint32 * default_sample_flags,
2324 gint64 * base_offset)
2327 guint32 track_id = 0;
2329 if (!gst_byte_reader_skip (tfhd, 1) ||
2330 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2333 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2336 *stream = qtdemux_find_stream (qtdemux, track_id);
2337 if (G_UNLIKELY (!*stream))
2338 goto unknown_stream;
2340 if (flags & TF_BASE_DATA_OFFSET)
2341 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2344 /* obtain stream defaults */
2345 qtdemux_parse_trex (qtdemux, *stream,
2346 default_sample_duration, default_sample_size, default_sample_flags);
2348 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2349 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2350 if (!gst_byte_reader_skip (tfhd, 4))
2353 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2354 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2357 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2358 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2361 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2362 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2369 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2374 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2380 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
2381 guint64 * decode_time)
2383 guint32 version = 0;
2385 if (!gst_byte_reader_get_uint32_be (br, &version))
2390 if (!gst_byte_reader_get_uint64_be (br, decode_time))
2393 guint32 dec_time = 0;
2394 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
2396 *decode_time = dec_time;
2399 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
2406 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
2412 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2413 guint64 moof_offset, QtDemuxStream * stream)
2415 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node;
2416 GstByteReader trun_data, tfhd_data, tfdt_data;
2417 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2418 gint64 base_offset, running_offset;
2420 /* NOTE @stream ignored */
2422 moof_node = g_node_new ((guint8 *) buffer);
2423 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2424 qtdemux_node_dump (qtdemux, moof_node);
2426 /* unknown base_offset to start with */
2427 base_offset = running_offset = -1;
2428 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2430 /* Fragment Header node */
2432 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2436 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2437 &ds_size, &ds_flags, &base_offset))
2440 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
2443 guint64 decode_time = 0;
2444 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
2445 /* If there is a new segment pending, update the time/position */
2446 if (qtdemux->pending_newsegment) {
2449 gst_segment_init (&segment, GST_FORMAT_TIME);
2450 segment.time = gst_util_uint64_scale (decode_time,
2451 GST_SECOND, stream->timescale);
2452 gst_event_replace (&qtdemux->pending_newsegment,
2453 gst_event_new_segment (&segment));
2454 /* ref added when replaced, release the original _new one */
2455 gst_event_unref (qtdemux->pending_newsegment);
2459 if (G_UNLIKELY (!stream)) {
2460 /* we lost track of offset, we'll need to regain it,
2461 * but can delay complaining until later or avoid doing so altogether */
2465 if (G_UNLIKELY (base_offset < -1))
2467 /* Track Run node */
2469 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2472 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2473 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2475 /* iterate all siblings */
2476 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2479 /* if no new base_offset provided for next traf,
2480 * base is end of current traf */
2481 base_offset = running_offset;
2482 running_offset = -1;
2484 /* iterate all siblings */
2485 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2487 g_node_destroy (moof_node);
2492 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2497 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2502 g_node_destroy (moof_node);
2503 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2504 (_("This file is corrupt and cannot be played.")), (NULL));
2509 /* might be used if some day we actually use mfra & co
2510 * for random access to fragments,
2511 * but that will require quite some modifications and much less relying
2512 * on a sample array */
2515 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2516 QtDemuxStream * stream)
2518 guint64 time = 0, moof_offset = 0;
2519 guint32 ver_flags, track_id, len, num_entries, i;
2520 guint value_size, traf_size, trun_size, sample_size;
2521 GstBuffer *buf = NULL;
2525 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2526 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2528 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2531 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2532 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2533 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2536 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2537 track_id, stream->track_id);
2538 if (track_id != stream->track_id) {
2542 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2543 sample_size = (len & 3) + 1;
2544 trun_size = ((len & 12) >> 2) + 1;
2545 traf_size = ((len & 48) >> 4) + 1;
2547 if (num_entries == 0)
2550 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2551 value_size + value_size + traf_size + trun_size + sample_size))
2554 for (i = 0; i < num_entries; i++) {
2555 qt_atom_parser_get_offset (&tfra, value_size, &time);
2556 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2557 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2558 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2559 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2561 GST_LOG_OBJECT (qtdemux,
2562 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2563 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2564 stream->timescale)), moof_offset);
2566 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2567 if (ret != GST_FLOW_OK)
2569 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2570 moof_offset, stream);
2571 gst_buffer_unref (buf);
2579 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2580 (_("This file is corrupt and cannot be played.")), (NULL));
2585 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2591 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2594 GNode *mfra_node, *tfra_node;
2597 if (!qtdemux->mfra_offset)
2600 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2601 if (ret != GST_FLOW_OK)
2604 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2605 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2606 GST_BUFFER_SIZE (buffer));
2608 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2611 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2612 /* iterate all siblings */
2613 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2615 g_node_destroy (mfra_node);
2616 gst_buffer_unref (buffer);
2622 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2623 (_("This file is corrupt and cannot be played.")), (NULL));
2628 static GstFlowReturn
2629 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2630 guint32 * mfro_size)
2632 GstFlowReturn ret = GST_FLOW_ERROR;
2633 GstBuffer *mfro = NULL;
2636 GstFormat fmt = GST_FORMAT_BYTES;
2638 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, &fmt, &len)) {
2639 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2640 "can not locate mfro");
2644 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2645 if (ret != GST_FLOW_OK)
2648 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2649 if (fourcc != FOURCC_mfro)
2652 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2653 if (GST_BUFFER_SIZE (mfro) >= 16) {
2654 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
2655 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
2656 if (*mfro_size >= len) {
2657 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
2658 ret = GST_FLOW_ERROR;
2661 *mfra_offset = len - *mfro_size;
2666 gst_buffer_unref (mfro);
2672 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
2675 guint32 mfra_size = 0;
2676 guint64 mfra_offset = 0;
2679 qtdemux->fragmented = FALSE;
2681 /* We check here if it is a fragmented mp4 container */
2682 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
2683 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
2684 qtdemux->fragmented = TRUE;
2685 GST_DEBUG_OBJECT (qtdemux,
2686 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
2687 qtdemux->mfra_offset = mfra_offset;
2692 static GstFlowReturn
2693 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
2697 GstBuffer *buf = NULL;
2698 GstFlowReturn ret = GST_FLOW_OK;
2699 guint64 cur_offset = qtdemux->offset;
2702 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
2703 if (G_UNLIKELY (ret != GST_FLOW_OK))
2705 gst_buffer_map (buf, &map, GST_MAP_READ);
2706 if (G_LIKELY (map.size >= 8))
2707 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
2708 gst_buffer_unmap (buf, &map);
2709 gst_buffer_unref (buf);
2711 /* maybe we already got most we needed, so only consider this eof */
2712 if (G_UNLIKELY (length == 0)) {
2713 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
2714 (_("Invalid atom size.")),
2715 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
2716 GST_FOURCC_ARGS (fourcc)));
2723 /* record for later parsing when needed */
2724 if (!qtdemux->moof_offset) {
2725 qtdemux->moof_offset = qtdemux->offset;
2734 GST_LOG_OBJECT (qtdemux,
2735 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
2736 GST_FOURCC_ARGS (fourcc), cur_offset);
2737 qtdemux->offset += length;
2742 GstBuffer *moov = NULL;
2744 if (qtdemux->got_moov) {
2745 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
2746 qtdemux->offset += length;
2750 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
2751 if (ret != GST_FLOW_OK)
2753 gst_buffer_map (moov, &map, GST_MAP_READ);
2754 if (length != map.size) {
2755 /* Some files have a 'moov' atom at the end of the file which contains
2756 * a terminal 'free' atom where the body of the atom is missing.
2757 * Check for, and permit, this special case.
2759 if (map.size >= 8) {
2760 guint8 *final_data = map.data + (map.size - 8);
2761 guint32 final_length = QT_UINT32 (final_data);
2762 guint32 final_fourcc = QT_FOURCC (final_data + 4);
2763 gst_buffer_unmap (moov, &map);
2764 if (final_fourcc == FOURCC_free
2765 && map.size + final_length - 8 == length) {
2766 /* Ok, we've found that special case. Allocate a new buffer with
2767 * that free atom actually present. */
2768 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
2769 gst_buffer_copy_into (newmoov, moov, 0, 0, map.size);
2770 gst_buffer_map (newmoov, &map, GST_MAP_WRITE);
2771 memset (map.data + length - final_length + 8, 0, final_length - 8);
2772 gst_buffer_unref (moov);
2778 if (length != map.size) {
2779 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2780 (_("This file is incomplete and cannot be played.")),
2781 ("We got less than expected (received %" G_GSIZE_FORMAT
2782 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
2783 (guint) length, cur_offset));
2784 gst_buffer_unmap (moov, &map);
2785 gst_buffer_unref (moov);
2786 ret = GST_FLOW_ERROR;
2789 qtdemux->offset += length;
2791 qtdemux_parse_moov (qtdemux, map.data, length);
2792 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
2794 qtdemux_parse_tree (qtdemux);
2795 g_node_destroy (qtdemux->moov_node);
2796 gst_buffer_unmap (moov, &map);
2797 gst_buffer_unref (moov);
2798 qtdemux->moov_node = NULL;
2799 qtdemux->got_moov = TRUE;
2805 GstBuffer *ftyp = NULL;
2807 /* extract major brand; might come in handy for ISO vs QT issues */
2808 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
2809 if (ret != GST_FLOW_OK)
2811 qtdemux->offset += length;
2812 gst_buffer_map (ftyp, &map, GST_MAP_READ);
2813 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
2814 gst_buffer_unmap (ftyp, &map);
2815 gst_buffer_unref (ftyp);
2820 GstBuffer *uuid = NULL;
2822 /* uuid are extension atoms */
2823 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
2824 if (ret != GST_FLOW_OK)
2826 qtdemux->offset += length;
2827 gst_buffer_map (uuid, &map, GST_MAP_READ);
2828 qtdemux_parse_uuid (qtdemux, map.data, map.size);
2829 gst_buffer_unmap (uuid, &map);
2830 gst_buffer_unref (uuid);
2835 GstBuffer *unknown = NULL;
2837 GST_LOG_OBJECT (qtdemux,
2838 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
2839 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
2841 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
2842 if (ret != GST_FLOW_OK)
2844 gst_buffer_map (unknown, &map, GST_MAP_READ);
2845 GST_MEMDUMP ("Unknown tag", map.data, map.size);
2846 gst_buffer_unmap (unknown, &map);
2847 gst_buffer_unref (unknown);
2848 qtdemux->offset += length;
2854 if (ret == GST_FLOW_EOS && qtdemux->got_moov) {
2855 /* digested all data, show what we have */
2856 ret = qtdemux_expose_streams (qtdemux);
2858 qtdemux->state = QTDEMUX_STATE_MOVIE;
2859 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
2866 /* Seeks to the previous keyframe of the indexed stream and
2867 * aligns other streams with respect to the keyframe timestamp
2868 * of indexed stream. Only called in case of Reverse Playback
2870 static GstFlowReturn
2871 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
2874 guint32 seg_idx = 0, k_index = 0;
2875 guint32 ref_seg_idx, ref_k_index;
2876 guint64 k_pos = 0, last_stop = 0;
2877 QtDemuxSegment *seg = NULL;
2878 QtDemuxStream *ref_str = NULL;
2879 guint64 seg_media_start_mov; /* segment media start time in mov format */
2881 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
2882 * and finally align all the other streams on that timestamp with their
2883 * respective keyframes */
2884 for (n = 0; n < qtdemux->n_streams; n++) {
2885 QtDemuxStream *str = qtdemux->streams[n];
2887 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
2888 qtdemux->segment.position);
2890 /* segment not found, continue with normal flow */
2894 /* No candidate yet, take that one */
2900 /* So that stream has a segment, we prefer video streams */
2901 if (str->subtype == FOURCC_vide) {
2907 if (G_UNLIKELY (!ref_str)) {
2908 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
2912 if (G_UNLIKELY (!ref_str->from_sample)) {
2913 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
2917 /* So that stream has been playing from from_sample to to_sample. We will
2918 * get the timestamp of the previous sample and search for a keyframe before
2919 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
2920 if (ref_str->subtype == FOURCC_vide) {
2921 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
2922 ref_str->from_sample - 1);
2924 if (ref_str->from_sample >= 10)
2925 k_index = ref_str->from_sample - 10;
2930 /* get current segment for that stream */
2931 seg = &ref_str->segments[ref_str->segment_index];
2932 /* convert seg->media_start to mov format time for timestamp comparison */
2933 seg_media_start_mov =
2934 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
2935 /* Crawl back through segments to find the one containing this I frame */
2936 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
2937 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
2938 ref_str->segment_index);
2939 if (G_UNLIKELY (!ref_str->segment_index)) {
2940 /* Reached first segment, let's consider it's EOS */
2943 ref_str->segment_index--;
2944 seg = &ref_str->segments[ref_str->segment_index];
2945 /* convert seg->media_start to mov format time for timestamp comparison */
2946 seg_media_start_mov =
2947 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
2950 /* Calculate time position of the keyframe and where we should stop */
2952 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
2953 ref_str->timescale) - seg->media_start) + seg->time;
2955 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
2956 GST_SECOND, ref_str->timescale);
2957 last_stop = (last_stop - seg->media_start) + seg->time;
2959 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
2960 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
2961 k_index, GST_TIME_ARGS (k_pos));
2963 /* Set last_stop with the keyframe timestamp we pushed of that stream */
2964 qtdemux->segment.position = last_stop;
2965 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
2966 GST_TIME_ARGS (last_stop));
2968 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
2969 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
2973 ref_seg_idx = ref_str->segment_index;
2974 ref_k_index = k_index;
2976 /* Align them all on this */
2977 for (n = 0; n < qtdemux->n_streams; n++) {
2979 guint64 media_start = 0, seg_time = 0;
2980 QtDemuxStream *str = qtdemux->streams[n];
2982 /* aligning reference stream again might lead to backing up to yet another
2983 * keyframe (due to timestamp rounding issues),
2984 * potentially putting more load on downstream; so let's try to avoid */
2985 if (str == ref_str) {
2986 seg_idx = ref_seg_idx;
2987 seg = &str->segments[seg_idx];
2988 k_index = ref_k_index;
2989 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
2990 "sample at index %d", ref_str->segment_index, k_index);
2992 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
2993 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
2995 /* segment not found, continue with normal flow */
2999 /* get segment and time in the segment */
3000 seg = &str->segments[seg_idx];
3001 seg_time = k_pos - seg->time;
3003 /* get the media time in the segment */
3004 media_start = seg->media_start + seg_time;
3006 /* get the index of the sample with media time */
3007 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
3008 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
3009 GST_TIME_ARGS (media_start), index);
3011 /* find previous keyframe */
3012 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
3015 /* Remember until where we want to go */
3016 str->to_sample = str->from_sample - 1;
3017 /* Define our time position */
3018 str->time_position =
3019 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
3020 str->timescale) - seg->media_start) + seg->time;
3021 /* Now seek back in time */
3022 gst_qtdemux_move_stream (qtdemux, str, k_index);
3023 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
3024 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
3025 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
3031 return GST_FLOW_EOS;
3034 /* activate the given segment number @seg_idx of @stream at time @offset.
3035 * @offset is an absolute global position over all the segments.
3037 * This will push out a NEWSEGMENT event with the right values and
3038 * position the stream index to the first decodable sample before
3042 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
3043 guint32 seg_idx, guint64 offset)
3046 QtDemuxSegment *segment;
3047 guint32 index, kf_index;
3049 guint64 start, stop, time;
3052 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3055 /* update the current segment */
3056 stream->segment_index = seg_idx;
3058 /* get the segment */
3059 segment = &stream->segments[seg_idx];
3061 if (G_UNLIKELY (offset < segment->time)) {
3062 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3067 /* segment lies beyond total indicated duration */
3068 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3069 segment->time > qtdemux->segment.duration)) {
3070 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3071 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3076 /* get time in this segment */
3077 seg_time = offset - segment->time;
3079 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3080 GST_TIME_ARGS (seg_time));
3082 if (G_UNLIKELY (seg_time > segment->duration)) {
3083 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3084 GST_TIME_ARGS (segment->duration));
3088 /* qtdemux->segment.stop is in outside-time-realm, whereas
3089 * segment->media_stop is in track-time-realm.
3091 * In order to compare the two, we need to bring segment.stop
3092 * into the track-time-realm */
3094 stop = qtdemux->segment.stop;
3096 stop = qtdemux->segment.duration;
3098 stop = segment->media_stop;
3101 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3103 if (qtdemux->segment.rate >= 0) {
3104 start = MIN (segment->media_start + seg_time, stop);
3107 if (segment->media_start >= qtdemux->segment.start) {
3108 start = segment->media_start;
3109 time = segment->time;
3111 start = qtdemux->segment.start;
3112 time = segment->time + (qtdemux->segment.start - segment->media_start);
3115 start = MAX (segment->media_start, qtdemux->segment.start);
3116 stop = MIN (segment->media_start + seg_time, stop);
3119 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3120 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3121 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3123 /* combine global rate with that of the segment */
3124 rate = segment->rate * qtdemux->segment.rate;
3126 /* update the segment values used for clipping */
3127 /* accumulate previous segments */
3128 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3129 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3130 ABS (stream->segment.rate);
3131 stream->segment.rate = rate;
3132 stream->segment.start = start;
3133 stream->segment.stop = stop;
3134 stream->segment.time = time;
3136 /* now prepare and send the segment */
3138 event = gst_event_new_segment (&stream->segment);
3139 gst_pad_push_event (stream->pad, event);
3140 /* assume we can send more data now */
3141 stream->last_ret = GST_FLOW_OK;
3142 /* clear to send tags on this pad now */
3143 gst_qtdemux_push_tags (qtdemux, stream);
3146 /* and move to the keyframe before the indicated media time of the
3148 if (qtdemux->segment.rate >= 0) {
3149 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3150 stream->to_sample = G_MAXUINT32;
3151 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3152 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3153 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3154 GST_SECOND, stream->timescale)));
3156 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3157 stream->to_sample = index;
3158 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3159 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3160 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3161 GST_SECOND, stream->timescale)));
3164 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3165 * encountered an error and printed a message so we return appropriately */
3169 /* we're at the right spot */
3170 if (index == stream->sample_index) {
3171 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3175 /* find keyframe of the target index */
3176 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3179 /* indent does stupid stuff with stream->samples[].timestamp */
3181 /* if we move forwards, we don't have to go back to the previous
3182 * keyframe since we already sent that. We can also just jump to
3183 * the keyframe right before the target index if there is one. */
3184 if (index > stream->sample_index) {
3185 /* moving forwards check if we move past a keyframe */
3186 if (kf_index > stream->sample_index) {
3187 GST_DEBUG_OBJECT (qtdemux,
3188 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3189 GST_TIME_ARGS (gst_util_uint64_scale (
3190 stream->samples[kf_index].timestamp,
3191 GST_SECOND, stream->timescale)));
3192 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3194 GST_DEBUG_OBJECT (qtdemux,
3195 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3196 " already sent", kf_index,
3197 GST_TIME_ARGS (gst_util_uint64_scale (
3198 stream->samples[kf_index].timestamp,
3199 GST_SECOND, stream->timescale)));
3202 GST_DEBUG_OBJECT (qtdemux,
3203 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3204 GST_TIME_ARGS (gst_util_uint64_scale (
3205 stream->samples[kf_index].timestamp,
3206 GST_SECOND, stream->timescale)));
3207 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3215 /* prepare to get the current sample of @stream, getting essential values.
3217 * This function will also prepare and send the segment when needed.
3219 * Return FALSE if the stream is EOS.
3222 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3223 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * dts,
3224 guint64 * pts, guint64 * duration, gboolean * keyframe)
3226 QtDemuxSample *sample;
3227 guint64 time_position;
3230 g_return_val_if_fail (stream != NULL, FALSE);
3232 time_position = stream->time_position;
3233 if (G_UNLIKELY (time_position == -1))
3236 seg_idx = stream->segment_index;
3237 if (G_UNLIKELY (seg_idx == -1)) {
3238 /* find segment corresponding to time_position if we are looking
3240 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3242 /* nothing found, we're really eos */
3247 /* different segment, activate it, sample_index will be set. */
3248 if (G_UNLIKELY (stream->segment_index != seg_idx))
3249 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3251 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3252 stream->sample_index, stream->n_samples);
3254 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3257 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3258 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3259 stream->sample_index);
3263 /* now get the info for the sample we're at */
3264 sample = &stream->samples[stream->sample_index];
3266 *dts = QTSAMPLE_DTS (stream, sample);
3267 *pts = QTSAMPLE_PTS (stream, sample);
3268 *offset = sample->offset;
3269 *size = sample->size;
3270 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3271 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3278 stream->time_position = -1;
3283 /* move to the next sample in @stream.
3285 * Moves to the next segment when needed.
3288 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3290 QtDemuxSample *sample;
3291 QtDemuxSegment *segment;
3293 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3294 /* Mark the stream as EOS */
3295 GST_DEBUG_OBJECT (qtdemux,
3296 "reached max allowed sample %u, mark EOS", stream->to_sample);
3297 stream->time_position = -1;
3301 /* move to next sample */
3302 stream->sample_index++;
3304 /* get current segment */
3305 segment = &stream->segments[stream->segment_index];
3307 /* reached the last sample, we need the next segment */
3308 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3311 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3312 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3313 stream->sample_index);
3317 /* get next sample */
3318 sample = &stream->samples[stream->sample_index];
3320 /* see if we are past the segment */
3321 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3322 GST_SECOND, stream->timescale) >= segment->media_stop))
3325 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3326 stream->timescale) >= segment->media_start) {
3327 /* inside the segment, update time_position, looks very familiar to
3328 * GStreamer segments, doesn't it? */
3329 stream->time_position =
3330 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3331 stream->timescale) - segment->media_start) + segment->time;
3333 /* not yet in segment, time does not yet increment. This means
3334 * that we are still prerolling keyframes to the decoder so it can
3335 * decode the first sample of the segment. */
3336 stream->time_position = segment->time;
3340 /* move to the next segment */
3343 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3345 if (stream->segment_index == stream->n_segments - 1) {
3346 /* are we at the end of the last segment, we're EOS */
3347 stream->time_position = -1;
3349 /* else we're only at the end of the current segment */
3350 stream->time_position = segment->stop_time;
3352 /* make sure we select a new segment */
3353 stream->segment_index = -1;
3358 gst_qtdemux_sync_streams (GstQTDemux * demux)
3362 if (demux->n_streams <= 1)
3365 for (i = 0; i < demux->n_streams; i++) {
3366 QtDemuxStream *stream;
3367 GstClockTime end_time;
3369 stream = demux->streams[i];
3374 /* TODO advance time on subtitle streams here, if any some day */
3376 /* some clips/trailers may have unbalanced streams at the end,
3377 * so send EOS on shorter stream to prevent stalling others */
3379 /* do not mess with EOS if SEGMENT seeking */
3380 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3383 if (demux->pullbased) {
3384 /* loop mode is sample time based */
3385 if (stream->time_position != -1)
3388 /* push mode is byte position based */
3389 if (stream->n_samples &&
3390 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3394 if (stream->sent_eos)
3397 /* only act if some gap */
3398 end_time = stream->segments[stream->n_segments - 1].stop_time;
3399 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3400 ", stream end: %" GST_TIME_FORMAT,
3401 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3402 if (end_time + 2 * GST_SECOND < demux->segment.position) {
3403 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3404 GST_PAD_NAME (stream->pad));
3405 stream->sent_eos = TRUE;
3406 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3411 /* EOS and NOT_LINKED need to be combined. This means that we return:
3413 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3414 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
3416 static GstFlowReturn
3417 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3421 gboolean unexpected = FALSE, not_linked = TRUE;
3423 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3425 /* store the value */
3426 stream->last_ret = ret;
3428 /* any other error that is not-linked or eos can be returned right away */
3429 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3432 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3433 for (i = 0; i < demux->n_streams; i++) {
3434 QtDemuxStream *ostream = demux->streams[i];
3436 ret = ostream->last_ret;
3438 /* no unexpected or unlinked, return */
3439 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3442 /* we check to see if we have at least 1 unexpected or all unlinked */
3443 unexpected |= (ret == GST_FLOW_EOS);
3444 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3447 /* when we get here, we all have unlinked or unexpected */
3449 ret = GST_FLOW_NOT_LINKED;
3450 else if (unexpected)
3453 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3457 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3458 * completely cliped */
3460 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3463 guint64 start, stop, cstart, cstop, diff;
3464 GstClockTime pts, dts, duration;
3466 gint num_rate, denom_rate;
3471 osize = size = gst_buffer_get_size (buf);
3474 /* depending on the type, setup the clip parameters */
3475 if (stream->subtype == FOURCC_soun) {
3476 frame_size = stream->bytes_per_frame;
3477 num_rate = GST_SECOND;
3478 denom_rate = (gint) stream->rate;
3480 } else if (stream->subtype == FOURCC_vide) {
3482 num_rate = stream->fps_n;
3483 denom_rate = stream->fps_d;
3488 /* we can only clip if we have a valid pts */
3489 pts = GST_BUFFER_PTS (buf);
3490 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
3493 dts = GST_BUFFER_DTS (buf);
3494 duration = GST_BUFFER_DURATION (buf);
3496 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
3498 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3502 stop = start + duration;
3504 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3505 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3508 /* see if some clipping happened */
3509 diff = cstart - start;
3516 /* bring clipped time to samples and to bytes */
3517 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3520 GST_DEBUG_OBJECT (qtdemux,
3521 "clipping start to %" GST_TIME_FORMAT " %"
3522 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3528 diff = stop - cstop;
3533 /* bring clipped time to samples and then to bytes */
3534 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3536 GST_DEBUG_OBJECT (qtdemux,
3537 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3538 " bytes", GST_TIME_ARGS (cstop), diff);
3543 if (offset != 0 || size != osize)
3544 gst_buffer_resize (buf, offset, size);
3546 GST_BUFFER_DTS (buf) = dts;
3547 GST_BUFFER_PTS (buf) = pts;
3548 GST_BUFFER_DURATION (buf) = duration;
3552 /* dropped buffer */
3555 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3560 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
3565 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3566 gst_buffer_unref (buf);
3571 /* the input buffer metadata must be writable,
3572 * but time/duration etc not yet set and need not be preserved */
3574 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3581 /* not many cases for now */
3582 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3583 /* send a one time dvd clut event */
3584 if (stream->pending_event && stream->pad)
3585 gst_pad_push_event (stream->pad, stream->pending_event);
3586 stream->pending_event = NULL;
3587 /* no further processing needed */
3588 stream->need_process = FALSE;
3591 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
3595 gst_buffer_map (buf, &map, GST_MAP_READ);
3597 if (G_LIKELY (map.size >= 2)) {
3598 nsize = GST_READ_UINT16_BE (map.data);
3599 nsize = MIN (nsize, map.size - 2);
3602 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
3605 /* takes care of UTF-8 validation or UTF-16 recognition,
3606 * no other encoding expected */
3607 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
3608 gst_buffer_unmap (buf, &map);
3610 gst_buffer_unref (buf);
3611 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
3613 /* may be 0-size subtitle, which is also sent to keep pipeline going */
3614 gst_buffer_resize (buf, 2, nsize);
3617 /* FIXME ? convert optional subsequent style info to markup */
3622 /* Sets a buffer's attributes properly and pushes it downstream.
3623 * Also checks for additional actions and custom processing that may
3624 * need to be done first.
3627 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3628 QtDemuxStream * stream, GstBuffer * buf,
3629 guint64 dts, guint64 pts, guint64 duration, gboolean keyframe,
3630 guint64 position, guint64 byte_position)
3632 GstFlowReturn ret = GST_FLOW_OK;
3634 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
3638 gst_buffer_map (buf, &map, GST_MAP_READ);
3639 url = g_strndup ((gchar *) map.data, map.size);
3640 gst_buffer_unmap (buf, &map);
3641 if (url != NULL && strlen (url) != 0) {
3642 /* we have RTSP redirect now */
3643 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3644 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
3645 gst_structure_new ("redirect",
3646 "new-location", G_TYPE_STRING, url, NULL)));
3647 qtdemux->posted_redirect = TRUE;
3649 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
3655 /* position reporting */
3656 if (qtdemux->segment.rate >= 0) {
3657 qtdemux->segment.position = position;
3658 gst_qtdemux_sync_streams (qtdemux);
3661 if (G_UNLIKELY (!stream->pad)) {
3662 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
3663 gst_buffer_unref (buf);
3667 /* send out pending buffers */
3668 while (stream->buffers) {
3669 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
3671 if (G_UNLIKELY (stream->discont)) {
3672 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3673 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
3674 stream->discont = FALSE;
3677 gst_pad_push (stream->pad, buffer);
3679 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
3682 /* we're going to modify the metadata */
3683 buf = gst_buffer_make_writable (buf);
3685 if (G_UNLIKELY (stream->need_process))
3686 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
3688 GST_BUFFER_DTS (buf) = dts;
3689 GST_BUFFER_PTS (buf) = pts;
3690 GST_BUFFER_DURATION (buf) = duration;
3691 GST_BUFFER_OFFSET (buf) = -1;
3692 GST_BUFFER_OFFSET_END (buf) = -1;
3694 if (G_UNLIKELY (stream->padding)) {
3695 gst_buffer_resize (buf, stream->padding, -1);
3698 if (G_UNLIKELY (qtdemux->element_index)) {
3699 GstClockTime stream_time;
3702 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
3704 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
3705 GST_LOG_OBJECT (qtdemux,
3706 "adding association %" GST_TIME_FORMAT "-> %"
3707 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
3708 gst_index_add_association (qtdemux->element_index,
3710 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
3711 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
3712 GST_FORMAT_BYTES, byte_position, NULL);
3717 if (stream->need_clip)
3718 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
3720 if (G_UNLIKELY (buf == NULL))
3723 if (G_UNLIKELY (stream->discont)) {
3724 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3725 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3726 stream->discont = FALSE;
3730 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3732 GST_LOG_OBJECT (qtdemux,
3733 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
3734 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
3735 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
3736 GST_PAD_NAME (stream->pad));
3738 ret = gst_pad_push (stream->pad, buf);
3744 static GstFlowReturn
3745 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
3747 GstFlowReturn ret = GST_FLOW_OK;
3748 GstBuffer *buf = NULL;
3749 QtDemuxStream *stream;
3752 guint64 dts = GST_CLOCK_TIME_NONE;
3753 guint64 pts = GST_CLOCK_TIME_NONE;
3754 guint64 duration = 0;
3755 gboolean keyframe = FALSE;
3760 gst_qtdemux_push_pending_newsegment (qtdemux);
3762 /* Figure out the next stream sample to output, min_time is expressed in
3763 * global time and runs over the edit list segments. */
3764 min_time = G_MAXUINT64;
3766 for (i = 0; i < qtdemux->n_streams; i++) {
3769 stream = qtdemux->streams[i];
3770 position = stream->time_position;
3772 /* position of -1 is EOS */
3773 if (position != -1 && position < min_time) {
3774 min_time = position;
3779 if (G_UNLIKELY (index == -1)) {
3780 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
3784 /* check for segment end */
3785 if (G_UNLIKELY (qtdemux->segment.stop != -1
3786 && qtdemux->segment.stop < min_time)) {
3787 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
3791 stream = qtdemux->streams[index];
3793 /* fetch info for the current sample of this stream */
3794 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
3795 &size, &dts, &pts, &duration, &keyframe)))
3798 GST_LOG_OBJECT (qtdemux,
3799 "pushing from stream %d, offset %" G_GUINT64_FORMAT
3800 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
3801 ", duration %" GST_TIME_FORMAT, index, offset, size,
3802 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
3804 /* hmm, empty sample, skip and move to next sample */
3805 if (G_UNLIKELY (size <= 0))
3808 /* last pushed sample was out of boundary, goto next sample */
3809 if (G_UNLIKELY (stream->last_ret == GST_FLOW_EOS))
3812 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
3815 if (stream->use_allocator) {
3816 /* if we have a per-stream allocator, use it */
3817 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
3820 ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
3821 if (G_UNLIKELY (ret != GST_FLOW_OK))
3824 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
3825 dts, pts, duration, keyframe, min_time, offset);
3828 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
3829 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
3830 * we have no more data for the pad to push */
3831 if (ret == GST_FLOW_EOS)
3835 gst_qtdemux_advance_sample (qtdemux, stream);
3843 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
3849 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
3850 /* EOS will be raised if all are EOS */
3857 gst_qtdemux_loop (GstPad * pad)
3859 GstQTDemux *qtdemux;
3863 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
3865 cur_offset = qtdemux->offset;
3866 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
3867 cur_offset, qtdemux->state);
3869 switch (qtdemux->state) {
3870 case QTDEMUX_STATE_INITIAL:
3871 case QTDEMUX_STATE_HEADER:
3872 ret = gst_qtdemux_loop_state_header (qtdemux);
3874 case QTDEMUX_STATE_MOVIE:
3875 ret = gst_qtdemux_loop_state_movie (qtdemux);
3876 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
3877 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
3885 /* if something went wrong, pause */
3886 if (ret != GST_FLOW_OK)
3890 gst_object_unref (qtdemux);
3896 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3897 (NULL), ("streaming stopped, invalid state"));
3898 gst_pad_pause_task (pad);
3899 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3904 const gchar *reason = gst_flow_get_name (ret);
3906 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
3908 gst_pad_pause_task (pad);
3910 /* fatal errors need special actions */
3912 if (ret == GST_FLOW_EOS) {
3913 if (qtdemux->n_streams == 0) {
3914 /* we have no streams, post an error */
3915 gst_qtdemux_post_no_playable_stream_error (qtdemux);
3917 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3920 if ((stop = qtdemux->segment.stop) == -1)
3921 stop = qtdemux->segment.duration;
3923 if (qtdemux->segment.rate >= 0) {
3924 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
3925 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3926 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3927 GST_FORMAT_TIME, stop));
3928 gst_qtdemux_push_event (qtdemux,
3929 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
3931 /* For Reverse Playback */
3932 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
3933 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3934 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3935 GST_FORMAT_TIME, qtdemux->segment.start));
3936 gst_qtdemux_push_event (qtdemux,
3937 gst_event_new_segment_done (GST_FORMAT_TIME,
3938 qtdemux->segment.start));
3941 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
3942 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3944 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
3945 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3946 (NULL), ("streaming stopped, reason %s", reason));
3947 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3956 * Returns the size of the first entry at the current offset.
3957 * If -1, there are none (which means EOS or empty file).
3960 next_entry_size (GstQTDemux * demux)
3962 QtDemuxStream *stream;
3965 guint64 smalloffs = (guint64) - 1;
3966 QtDemuxSample *sample;
3968 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
3971 for (i = 0; i < demux->n_streams; i++) {
3972 stream = demux->streams[i];
3974 if (stream->sample_index == -1)
3975 stream->sample_index = 0;
3977 if (stream->sample_index >= stream->n_samples) {
3978 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
3982 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
3983 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
3984 stream->sample_index);
3988 sample = &stream->samples[stream->sample_index];
3990 GST_LOG_OBJECT (demux,
3991 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3992 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
3993 sample->offset, sample->size);
3995 if (((smalloffs == -1)
3996 || (sample->offset < smalloffs)) && (sample->size)) {
3998 smalloffs = sample->offset;
4002 GST_LOG_OBJECT (demux,
4003 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
4004 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
4009 stream = demux->streams[smallidx];
4010 sample = &stream->samples[stream->sample_index];
4012 if (sample->offset >= demux->offset) {
4013 demux->todrop = sample->offset - demux->offset;
4014 return sample->size + demux->todrop;
4017 GST_DEBUG_OBJECT (demux,
4018 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
4023 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
4025 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
4027 gst_element_post_message (GST_ELEMENT_CAST (demux),
4028 gst_message_new_element (GST_OBJECT_CAST (demux),
4029 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
4033 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
4038 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
4041 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
4042 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
4043 GST_SEEK_TYPE_NONE, -1);
4045 res = gst_pad_push_event (demux->sinkpad, event);
4050 /* check for seekable upstream, above and beyond a mere query */
4052 gst_qtdemux_check_seekability (GstQTDemux * demux)
4055 gboolean seekable = FALSE;
4056 gint64 start = -1, stop = -1;
4058 if (demux->upstream_size)
4061 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4062 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4063 GST_DEBUG_OBJECT (demux, "seeking query failed");
4067 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4069 /* try harder to query upstream size if we didn't get it the first time */
4070 if (seekable && stop == -1) {
4071 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4072 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4075 /* if upstream doesn't know the size, it's likely that it's not seekable in
4076 * practice even if it technically may be seekable */
4077 if (seekable && (start != 0 || stop <= start)) {
4078 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4083 gst_query_unref (query);
4085 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4086 G_GUINT64_FORMAT ")", seekable, start, stop);
4087 demux->upstream_seekable = seekable;
4088 demux->upstream_size = seekable ? stop : -1;
4091 /* FIXME, unverified after edit list updates */
4092 static GstFlowReturn
4093 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4096 GstFlowReturn ret = GST_FLOW_OK;
4098 demux = GST_QTDEMUX (parent);
4100 gst_adapter_push (demux->adapter, inbuf);
4102 /* we never really mean to buffer that much */
4103 if (demux->neededbytes == -1)
4106 GST_DEBUG_OBJECT (demux,
4107 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4108 demux->neededbytes, gst_adapter_available (demux->adapter));
4110 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4111 (ret == GST_FLOW_OK)) {
4113 GST_DEBUG_OBJECT (demux,
4114 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4115 demux->state, demux->neededbytes, demux->offset);
4117 switch (demux->state) {
4118 case QTDEMUX_STATE_INITIAL:{
4123 gst_qtdemux_check_seekability (demux);
4125 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4127 /* get fourcc/length, set neededbytes */
4128 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4130 gst_adapter_unmap (demux->adapter);
4132 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4133 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4135 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4136 (_("This file is invalid and cannot be played.")),
4137 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4138 GST_FOURCC_ARGS (fourcc)));
4139 ret = GST_FLOW_ERROR;
4142 if (fourcc == FOURCC_mdat) {
4143 if (demux->n_streams > 0) {
4144 /* we have the headers, start playback */
4145 demux->state = QTDEMUX_STATE_MOVIE;
4146 demux->neededbytes = next_entry_size (demux);
4147 demux->mdatleft = size;
4149 /* no headers yet, try to get them */
4152 guint64 old, target;
4155 old = demux->offset;
4156 target = old + size;
4158 /* try to jump over the atom with a seek */
4159 /* only bother if it seems worth doing so,
4160 * and avoids possible upstream/server problems */
4161 if (demux->upstream_seekable &&
4162 demux->upstream_size > 4 * (1 << 20)) {
4163 res = qtdemux_seek_offset (demux, target);
4165 GST_DEBUG_OBJECT (demux, "skipping seek");
4170 GST_DEBUG_OBJECT (demux, "seek success");
4171 /* remember the offset fo the first mdat so we can seek back to it
4172 * after we have the headers */
4173 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4174 demux->first_mdat = old;
4175 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4178 /* seek worked, continue reading */
4179 demux->offset = target;
4180 demux->neededbytes = 16;
4181 demux->state = QTDEMUX_STATE_INITIAL;
4183 /* seek failed, need to buffer */
4184 demux->offset = old;
4185 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4186 /* there may be multiple mdat (or alike) buffers */
4188 if (demux->mdatbuffer)
4189 bs = gst_buffer_get_size (demux->mdatbuffer);
4192 if (size + bs > 10 * (1 << 20))
4194 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4195 demux->neededbytes = size;
4196 if (!demux->mdatbuffer)
4197 demux->mdatoffset = demux->offset;
4200 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4201 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4202 (_("This file is invalid and cannot be played.")),
4203 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4204 GST_FOURCC_ARGS (fourcc), size));
4205 ret = GST_FLOW_ERROR;
4208 /* this means we already started buffering and still no moov header,
4209 * let's continue buffering everything till we get moov */
4210 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
4212 demux->neededbytes = size;
4213 demux->state = QTDEMUX_STATE_HEADER;
4217 case QTDEMUX_STATE_HEADER:{
4221 GST_DEBUG_OBJECT (demux, "In header");
4223 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4225 /* parse the header */
4226 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4228 if (fourcc == FOURCC_moov) {
4229 /* in usual fragmented setup we could try to scan for more
4230 * and end up at the the moov (after mdat) again */
4231 if (demux->got_moov && demux->n_streams > 0) {
4232 GST_DEBUG_OBJECT (demux,
4233 "Skipping moov atom as we have one already");
4235 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4237 demux->got_moov = TRUE;
4239 /* prepare newsegment to send when streaming actually starts */
4240 if (!demux->pending_newsegment)
4241 demux->pending_newsegment =
4242 gst_event_new_segment (&demux->segment);
4244 qtdemux_parse_moov (demux, data, demux->neededbytes);
4245 qtdemux_node_dump (demux, demux->moov_node);
4246 qtdemux_parse_tree (demux);
4247 qtdemux_expose_streams (demux);
4249 g_node_destroy (demux->moov_node);
4250 demux->moov_node = NULL;
4251 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4253 } else if (fourcc == FOURCC_moof) {
4254 if (demux->got_moov && demux->fragmented) {
4255 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4256 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4257 demux->offset, NULL)) {
4258 gst_adapter_unmap (demux->adapter);
4259 ret = GST_FLOW_ERROR;
4263 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4265 } else if (fourcc == FOURCC_ftyp) {
4266 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4267 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4268 } else if (fourcc == FOURCC_uuid) {
4269 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4270 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4272 GST_WARNING_OBJECT (demux,
4273 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4274 GST_FOURCC_ARGS (fourcc));
4275 /* Let's jump that one and go back to initial state */
4277 gst_adapter_unmap (demux->adapter);
4280 if (demux->mdatbuffer && demux->n_streams) {
4281 /* the mdat was before the header */
4282 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4283 demux->n_streams, demux->mdatbuffer);
4284 /* restore our adapter/offset view of things with upstream;
4285 * put preceding buffered data ahead of current moov data.
4286 * This should also handle evil mdat, moov, mdat cases and alike */
4287 gst_adapter_clear (demux->adapter);
4288 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4289 demux->mdatbuffer = NULL;
4290 demux->offset = demux->mdatoffset;
4291 demux->neededbytes = next_entry_size (demux);
4292 demux->state = QTDEMUX_STATE_MOVIE;
4293 demux->mdatleft = gst_adapter_available (demux->adapter);
4295 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4296 gst_adapter_flush (demux->adapter, demux->neededbytes);
4298 if (demux->got_moov && demux->first_mdat != -1) {
4301 /* we need to seek back */
4302 res = qtdemux_seek_offset (demux, demux->first_mdat);
4304 demux->offset = demux->first_mdat;
4306 GST_DEBUG_OBJECT (demux, "Seek back failed");
4309 demux->offset += demux->neededbytes;
4311 demux->neededbytes = 16;
4312 demux->state = QTDEMUX_STATE_INITIAL;
4317 case QTDEMUX_STATE_BUFFER_MDAT:{
4321 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4323 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4324 gst_buffer_extract (buf, 0, fourcc, 4);
4325 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4326 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
4327 if (demux->mdatbuffer)
4328 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
4330 demux->mdatbuffer = buf;
4331 demux->offset += demux->neededbytes;
4332 demux->neededbytes = 16;
4333 demux->state = QTDEMUX_STATE_INITIAL;
4334 gst_qtdemux_post_progress (demux, 1, 1);
4338 case QTDEMUX_STATE_MOVIE:{
4340 QtDemuxStream *stream = NULL;
4341 QtDemuxSample *sample;
4343 guint64 dts, pts, duration;
4346 GST_DEBUG_OBJECT (demux,
4347 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4349 if (demux->fragmented) {
4350 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4352 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4353 /* if needed data starts within this atom,
4354 * then it should not exceed this atom */
4355 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4356 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4357 (_("This file is invalid and cannot be played.")),
4358 ("sample data crosses atom boundary"));
4359 ret = GST_FLOW_ERROR;
4362 demux->mdatleft -= demux->neededbytes;
4364 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4365 /* so we are dropping more than left in this atom */
4366 demux->todrop -= demux->mdatleft;
4367 demux->neededbytes -= demux->mdatleft;
4368 demux->mdatleft = 0;
4369 /* need to resume atom parsing so we do not miss any other pieces */
4370 demux->state = QTDEMUX_STATE_INITIAL;
4371 demux->neededbytes = 16;
4376 if (demux->todrop) {
4377 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4378 gst_adapter_flush (demux->adapter, demux->todrop);
4379 demux->neededbytes -= demux->todrop;
4380 demux->offset += demux->todrop;
4384 /* initial newsegment sent here after having added pads,
4385 * possible others in sink_event */
4386 if (G_UNLIKELY (demux->pending_newsegment)) {
4387 gst_qtdemux_push_event (demux, demux->pending_newsegment);
4388 demux->pending_newsegment = NULL;
4389 /* clear to send tags on all streams */
4390 for (i = 0; i < demux->n_streams; i++) {
4391 gst_qtdemux_push_tags (demux, demux->streams[i]);
4395 /* Figure out which stream this is packet belongs to */
4396 for (i = 0; i < demux->n_streams; i++) {
4397 stream = demux->streams[i];
4398 if (stream->sample_index >= stream->n_samples)
4400 GST_LOG_OBJECT (demux,
4401 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4402 " / size:%d)", i, stream->sample_index,
4403 stream->samples[stream->sample_index].offset,
4404 stream->samples[stream->sample_index].size);
4406 if (stream->samples[stream->sample_index].offset == demux->offset)
4410 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4411 goto unknown_stream;
4413 /* Put data in a buffer, set timestamps, caps, ... */
4414 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4415 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4416 GST_FOURCC_ARGS (stream->fourcc));
4418 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4420 sample = &stream->samples[stream->sample_index];
4422 dts = QTSAMPLE_DTS (stream, sample);
4423 pts = QTSAMPLE_PTS (stream, sample);
4424 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
4425 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4427 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4428 dts, pts, duration, keyframe, dts, demux->offset);
4431 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4433 stream->sample_index++;
4435 /* update current offset and figure out size of next buffer */
4436 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4437 demux->offset, demux->neededbytes);
4438 demux->offset += demux->neededbytes;
4439 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4442 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4443 if (demux->fragmented) {
4444 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4445 /* there may be more to follow, only finish this atom */
4446 demux->todrop = demux->mdatleft;
4447 demux->neededbytes = demux->todrop;
4459 /* when buffering movie data, at least show user something is happening */
4460 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4461 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4462 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4463 demux->neededbytes);
4472 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4473 ret = GST_FLOW_ERROR;
4478 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4484 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4485 (NULL), ("qtdemuxer invalid state %d", demux->state));
4486 ret = GST_FLOW_ERROR;
4491 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4492 (NULL), ("no 'moov' atom within the first 10 MB"));
4493 ret = GST_FLOW_ERROR;
4499 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
4504 query = gst_query_new_scheduling ();
4506 if (!gst_pad_peer_query (sinkpad, query)) {
4507 gst_query_unref (query);
4511 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
4512 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
4513 gst_query_unref (query);
4518 GST_DEBUG_OBJECT (sinkpad, "activating pull");
4519 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
4523 GST_DEBUG_OBJECT (sinkpad, "activating push");
4524 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
4529 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
4530 GstPadMode mode, gboolean active)
4533 GstQTDemux *demux = GST_QTDEMUX (parent);
4536 case GST_PAD_MODE_PUSH:
4537 demux->pullbased = FALSE;
4540 case GST_PAD_MODE_PULL:
4542 demux->pullbased = TRUE;
4543 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4546 res = gst_pad_stop_task (sinkpad);
4558 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4560 return g_malloc (items * size);
4564 qtdemux_zfree (void *opaque, void *addr)
4570 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4576 z = g_new0 (z_stream, 1);
4577 z->zalloc = qtdemux_zalloc;
4578 z->zfree = qtdemux_zfree;
4581 z->next_in = z_buffer;
4582 z->avail_in = z_length;
4584 buffer = (guint8 *) g_malloc (length);
4585 ret = inflateInit (z);
4586 while (z->avail_in > 0) {
4587 if (z->avail_out == 0) {
4589 buffer = (guint8 *) g_realloc (buffer, length);
4590 z->next_out = buffer + z->total_out;
4591 z->avail_out = 1024;
4593 ret = inflate (z, Z_SYNC_FLUSH);
4597 if (ret != Z_STREAM_END) {
4598 g_warning ("inflate() returned %d", ret);
4604 #endif /* HAVE_ZLIB */
4607 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4611 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4613 /* counts as header data */
4614 qtdemux->header_size += length;
4616 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4617 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4619 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4625 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4626 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4627 if (dcom == NULL || cmvd == NULL)
4628 goto invalid_compression;
4630 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4633 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4634 guint uncompressed_length;
4635 guint compressed_length;
4638 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4639 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4640 GST_LOG ("length = %u", uncompressed_length);
4643 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4644 compressed_length, uncompressed_length);
4646 qtdemux->moov_node_compressed = qtdemux->moov_node;
4647 qtdemux->moov_node = g_node_new (buf);
4649 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4650 uncompressed_length);
4653 #endif /* HAVE_ZLIB */
4655 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4656 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
4663 invalid_compression:
4665 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
4671 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
4674 while (G_UNLIKELY (buf < end)) {
4678 if (G_UNLIKELY (buf + 4 > end)) {
4679 GST_LOG_OBJECT (qtdemux, "buffer overrun");
4682 len = QT_UINT32 (buf);
4683 if (G_UNLIKELY (len == 0)) {
4684 GST_LOG_OBJECT (qtdemux, "empty container");
4687 if (G_UNLIKELY (len < 8)) {
4688 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
4691 if (G_UNLIKELY (len > (end - buf))) {
4692 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
4693 (gint) (end - buf));
4697 child = g_node_new ((guint8 *) buf);
4698 g_node_append (node, child);
4699 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
4700 qtdemux_parse_node (qtdemux, child, buf, len);
4708 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
4711 int len = QT_UINT32 (xdxt->data);
4712 guint8 *buf = xdxt->data;
4713 guint8 *end = buf + len;
4716 /* skip size and type */
4724 size = QT_UINT32 (buf);
4725 type = QT_FOURCC (buf + 4);
4727 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
4729 if (buf + size > end || size <= 0)
4735 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
4736 GST_FOURCC_ARGS (type));
4740 buffer = gst_buffer_new_and_alloc (size);
4741 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4742 stream->buffers = g_slist_append (stream->buffers, buffer);
4743 GST_LOG_OBJECT (qtdemux, "parsing theora header");
4746 buffer = gst_buffer_new_and_alloc (size);
4747 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4748 stream->buffers = g_slist_append (stream->buffers, buffer);
4749 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
4752 buffer = gst_buffer_new_and_alloc (size);
4753 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4754 stream->buffers = g_slist_append (stream->buffers, buffer);
4755 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
4758 GST_WARNING_OBJECT (qtdemux,
4759 "unknown theora cookie %" GST_FOURCC_FORMAT,
4760 GST_FOURCC_ARGS (type));
4769 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
4773 guint32 node_length = 0;
4774 const QtNodeType *type;
4777 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
4779 if (G_UNLIKELY (length < 8))
4780 goto not_enough_data;
4782 node_length = QT_UINT32 (buffer);
4783 fourcc = QT_FOURCC (buffer + 4);
4785 /* ignore empty nodes */
4786 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
4789 type = qtdemux_type_get (fourcc);
4791 end = buffer + length;
4793 GST_LOG_OBJECT (qtdemux,
4794 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
4795 GST_FOURCC_ARGS (fourcc), node_length, type->name);
4797 if (node_length > length)
4798 goto broken_atom_size;
4800 if (type->flags & QT_FLAG_CONTAINER) {
4801 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
4806 if (node_length < 20) {
4807 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
4810 GST_DEBUG_OBJECT (qtdemux,
4811 "parsing stsd (sample table, sample description) atom");
4812 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
4822 /* also read alac (or whatever) in stead of mp4a in the following,
4823 * since a similar layout is used in other cases as well */
4824 if (fourcc == FOURCC_mp4a)
4829 /* There are two things we might encounter here: a true mp4a atom, and
4830 an mp4a entry in an stsd atom. The latter is what we're interested
4831 in, and it looks like an atom, but isn't really one. The true mp4a
4832 atom is short, so we detect it based on length here. */
4833 if (length < min_size) {
4834 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
4835 GST_FOURCC_ARGS (fourcc));
4839 /* 'version' here is the sound sample description version. Types 0 and
4840 1 are documented in the QTFF reference, but type 2 is not: it's
4841 described in Apple header files instead (struct SoundDescriptionV2
4843 version = QT_UINT16 (buffer + 16);
4845 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
4846 GST_FOURCC_ARGS (fourcc), version);
4848 /* parse any esds descriptors */
4860 GST_WARNING_OBJECT (qtdemux,
4861 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
4862 GST_FOURCC_ARGS (fourcc), version);
4867 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4884 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
4885 GST_FOURCC_ARGS (fourcc));
4886 version = QT_UINT32 (buffer + 16);
4887 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
4888 if (1 || version == 0x00000000) {
4889 buf = buffer + 0x32;
4891 /* FIXME Quicktime uses PASCAL string while
4892 * the iso format uses C strings. Check the file
4893 * type before attempting to parse the string here. */
4894 tlen = QT_UINT8 (buf);
4895 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
4897 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
4898 /* the string has a reserved space of 32 bytes so skip
4899 * the remaining 31 */
4901 buf += 4; /* and 4 bytes reserved */
4903 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
4905 qtdemux_parse_container (qtdemux, node, buf, end);
4911 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
4912 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
4917 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
4922 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
4923 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
4931 version = QT_UINT32 (buffer + 12);
4932 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
4939 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
4944 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4949 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
4953 if (!strcmp (type->name, "unknown"))
4954 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
4958 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
4959 GST_FOURCC_ARGS (fourcc));
4965 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4966 (_("This file is corrupt and cannot be played.")),
4967 ("Not enough data for an atom header, got only %u bytes", length));
4972 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4973 (_("This file is corrupt and cannot be played.")),
4974 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
4975 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
4982 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
4986 guint32 child_fourcc;
4988 for (child = g_node_first_child (node); child;
4989 child = g_node_next_sibling (child)) {
4990 buffer = (guint8 *) child->data;
4992 child_fourcc = QT_FOURCC (buffer + 4);
4994 if (G_UNLIKELY (child_fourcc == fourcc)) {
5002 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
5003 GstByteReader * parser)
5007 guint32 child_fourcc, child_len;
5009 for (child = g_node_first_child (node); child;
5010 child = g_node_next_sibling (child)) {
5011 buffer = (guint8 *) child->data;
5013 child_len = QT_UINT32 (buffer);
5014 child_fourcc = QT_FOURCC (buffer + 4);
5016 if (G_UNLIKELY (child_fourcc == fourcc)) {
5017 if (G_UNLIKELY (child_len < (4 + 4)))
5019 /* FIXME: must verify if atom length < parent atom length */
5020 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
5028 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
5029 GstByteReader * parser)
5033 guint32 child_fourcc, child_len;
5035 for (child = g_node_next_sibling (node); child;
5036 child = g_node_next_sibling (child)) {
5037 buffer = (guint8 *) child->data;
5039 child_fourcc = QT_FOURCC (buffer + 4);
5041 if (child_fourcc == fourcc) {
5043 child_len = QT_UINT32 (buffer);
5044 if (G_UNLIKELY (child_len < (4 + 4)))
5046 /* FIXME: must verify if atom length < parent atom length */
5047 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
5056 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
5058 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
5062 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
5066 query = gst_query_new_allocation (stream->caps, FALSE);
5068 if (!gst_pad_peer_query (stream->pad, query)) {
5069 /* not a problem, just debug a little */
5070 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
5073 if (stream->allocator)
5074 gst_object_unref (stream->allocator);
5076 if (gst_query_get_n_allocation_params (query) > 0) {
5077 /* try the allocator */
5078 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
5080 stream->use_allocator = TRUE;
5082 stream->allocator = NULL;
5083 gst_allocation_params_init (&stream->params);
5084 stream->use_allocator = FALSE;
5086 gst_query_unref (query);
5090 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
5091 QtDemuxStream * stream, GstTagList * list)
5093 /* consistent default for push based mode */
5094 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
5096 if (stream->subtype == FOURCC_vide) {
5097 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5100 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5103 /* fps is calculated base on the duration of the first frames since
5104 * qt does not have a fixed framerate. */
5105 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
5110 stream->fps_n = stream->timescale;
5111 if (stream->min_duration == 0)
5114 stream->fps_d = stream->min_duration;
5119 gint depth, palette_count;
5120 const guint32 *palette_data = NULL;
5122 gst_caps_set_simple (stream->caps,
5123 "width", G_TYPE_INT, stream->width,
5124 "height", G_TYPE_INT, stream->height,
5125 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5127 /* calculate pixel-aspect-ratio using display width and height */
5128 GST_DEBUG_OBJECT (qtdemux,
5129 "video size %dx%d, target display size %dx%d", stream->width,
5130 stream->height, stream->display_width, stream->display_height);
5132 if (stream->display_width > 0 && stream->display_height > 0 &&
5133 stream->width > 0 && stream->height > 0) {
5136 /* calculate the pixel aspect ratio using the display and pixel w/h */
5137 n = stream->display_width * stream->height;
5138 d = stream->display_height * stream->width;
5141 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5142 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5143 GST_TYPE_FRACTION, n, d, NULL);
5146 /* qt file might have pasp atom */
5147 if (stream->par_w > 0 && stream->par_h > 0) {
5148 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5149 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5150 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5153 depth = stream->bits_per_sample;
5155 /* more than 32 bits means grayscale */
5156 gray = (depth > 32);
5157 /* low 32 bits specify the depth */
5160 /* different number of palette entries is determined by depth. */
5162 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
5163 palette_count = (1 << depth);
5165 switch (palette_count) {
5169 palette_data = ff_qt_default_palette_2;
5172 palette_data = ff_qt_default_palette_4;
5176 palette_data = ff_qt_grayscale_palette_16;
5178 palette_data = ff_qt_default_palette_16;
5182 palette_data = ff_qt_grayscale_palette_256;
5184 palette_data = ff_qt_default_palette_256;
5187 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5188 (_("The video in this file might not play correctly.")),
5189 ("unsupported palette depth %d", depth));
5195 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5196 * don't free any of the buffer data. */
5197 palette = _gst_buffer_new_wrapped ((gpointer) palette_data,
5198 palette_count * 4, NULL);
5200 gst_caps_set_simple (stream->caps, "palette_data",
5201 GST_TYPE_BUFFER, palette, NULL);
5202 gst_buffer_unref (palette);
5203 } else if (palette_count != 0) {
5204 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5205 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5207 gst_object_unref (stream->pad);
5211 qtdemux->n_video_streams++;
5212 } else if (stream->subtype == FOURCC_soun) {
5213 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
5216 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5219 gst_caps_set_simple (stream->caps,
5220 "rate", G_TYPE_INT, (int) stream->rate,
5221 "channels", G_TYPE_INT, stream->n_channels, NULL);
5223 if (stream->n_channels > 2) {
5224 /* FIXME: Need to parse the 'chan' atom to get channel layouts
5225 * correctly; this is just the minimum we can do - assume
5226 * we don't actually have any channel positions. */
5227 gst_caps_set_simple (stream->caps,
5228 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
5231 qtdemux->n_audio_streams++;
5232 } else if (stream->subtype == FOURCC_strm) {
5233 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5234 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
5235 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
5238 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5240 qtdemux->n_sub_streams++;
5241 } else if (stream->caps) {
5242 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5245 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5247 qtdemux->n_video_streams++;
5249 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5256 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5258 gst_pad_use_fixed_caps (stream->pad);
5259 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5260 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5261 gst_pad_set_active (stream->pad, TRUE);
5263 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5265 gst_pad_create_stream_id_printf (stream->pad,
5266 GST_ELEMENT_CAST (qtdemux), "%u", stream->track_id);
5267 gst_pad_push_event (stream->pad, gst_event_new_stream_start (stream_id));
5269 gst_pad_set_caps (stream->pad, stream->caps);
5271 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5272 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5273 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5275 if (stream->pending_tags)
5276 gst_tag_list_unref (stream->pending_tags);
5277 stream->pending_tags = list;
5278 /* global tags go on each pad anyway */
5279 stream->send_global_tags = TRUE;
5281 qtdemux_do_allocation (qtdemux, stream);
5287 /* find next atom with @fourcc starting at @offset */
5288 static GstFlowReturn
5289 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5290 guint64 * length, guint32 fourcc)
5296 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5297 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5303 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5304 if (G_UNLIKELY (ret != GST_FLOW_OK))
5306 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
5309 gst_buffer_unref (buf);
5312 gst_buffer_map (buf, &map, GST_MAP_READ);
5313 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
5314 gst_buffer_unmap (buf, &map);
5315 gst_buffer_unref (buf);
5317 if (G_UNLIKELY (*length == 0)) {
5318 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5319 ret = GST_FLOW_ERROR;
5323 if (lfourcc == fourcc) {
5324 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5328 GST_LOG_OBJECT (qtdemux,
5329 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5330 GST_FOURCC_ARGS (fourcc), *offset);
5339 /* might simply have had last one */
5340 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5345 /* should only do something in pull mode */
5346 /* call with OBJECT lock */
5347 static GstFlowReturn
5348 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5350 guint64 length, offset;
5351 GstBuffer *buf = NULL;
5352 GstFlowReturn ret = GST_FLOW_OK;
5353 GstFlowReturn res = GST_FLOW_OK;
5356 offset = qtdemux->moof_offset;
5357 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5360 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5361 return GST_FLOW_EOS;
5364 /* best not do pull etc with lock held */
5365 GST_OBJECT_UNLOCK (qtdemux);
5367 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5368 if (ret != GST_FLOW_OK)
5371 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5372 if (G_UNLIKELY (ret != GST_FLOW_OK))
5374 gst_buffer_map (buf, &map, GST_MAP_READ);
5375 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
5376 gst_buffer_unmap (buf, &map);
5377 gst_buffer_unref (buf);
5382 gst_buffer_unmap (buf, &map);
5383 gst_buffer_unref (buf);
5387 /* look for next moof */
5388 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5389 if (G_UNLIKELY (ret != GST_FLOW_OK))
5393 GST_OBJECT_LOCK (qtdemux);
5395 qtdemux->moof_offset = offset;
5401 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5403 res = GST_FLOW_ERROR;
5408 /* maybe upstream temporarily flushing */
5409 if (ret != GST_FLOW_FLUSHING) {
5410 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5413 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5414 /* resume at current position next time */
5421 /* initialise bytereaders for stbl sub-atoms */
5423 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5425 stream->stbl_index = -1; /* no samples have yet been parsed */
5427 /* time-to-sample atom */
5428 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5431 /* copy atom data into a new buffer for later use */
5432 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5434 /* skip version + flags */
5435 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5436 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5438 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5440 /* make sure there's enough data */
5441 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
5442 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
5443 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
5444 stream->n_sample_times);
5445 if (!stream->n_sample_times)
5449 /* sync sample atom */
5450 stream->stps_present = FALSE;
5451 if ((stream->stss_present =
5452 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5453 &stream->stss) ? TRUE : FALSE) == TRUE) {
5454 /* copy atom data into a new buffer for later use */
5455 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5457 /* skip version + flags */
5458 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5459 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5462 if (stream->n_sample_syncs) {
5463 /* make sure there's enough data */
5464 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5468 /* partial sync sample atom */
5469 if ((stream->stps_present =
5470 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5471 &stream->stps) ? TRUE : FALSE) == TRUE) {
5472 /* copy atom data into a new buffer for later use */
5473 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5475 /* skip version + flags */
5476 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5477 !gst_byte_reader_get_uint32_be (&stream->stps,
5478 &stream->n_sample_partial_syncs))
5481 /* if there are no entries, the stss table contains the real
5483 if (stream->n_sample_partial_syncs) {
5484 /* make sure there's enough data */
5485 if (!qt_atom_parser_has_chunks (&stream->stps,
5486 stream->n_sample_partial_syncs, 4))
5493 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5496 /* copy atom data into a new buffer for later use */
5497 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5499 /* skip version + flags */
5500 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5501 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5504 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5507 if (!stream->n_samples)
5510 /* sample-to-chunk atom */
5511 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5514 /* copy atom data into a new buffer for later use */
5515 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5517 /* skip version + flags */
5518 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5519 !gst_byte_reader_get_uint32_be (&stream->stsc,
5520 &stream->n_samples_per_chunk))
5523 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5524 stream->n_samples_per_chunk);
5526 /* make sure there's enough data */
5527 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5533 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5534 stream->co_size = sizeof (guint32);
5535 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5537 stream->co_size = sizeof (guint64);
5541 /* copy atom data into a new buffer for later use */
5542 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5544 /* skip version + flags */
5545 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5548 /* chunks_are_chunks == 0 means treat chunks as samples */
5549 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5550 if (stream->chunks_are_chunks) {
5551 /* skip number of entries */
5552 if (!gst_byte_reader_skip (&stream->stco, 4))
5555 /* make sure there are enough data in the stsz atom */
5556 if (!stream->sample_size) {
5557 /* different sizes for each sample */
5558 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5562 /* treat chunks as samples */
5563 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5567 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5568 stream->n_samples, (guint) sizeof (QtDemuxSample),
5569 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5571 if (stream->n_samples >=
5572 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5573 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5574 "be larger than %uMB (broken file?)", stream->n_samples,
5575 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5579 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5580 if (!stream->samples) {
5581 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5587 /* composition time-to-sample */
5588 if ((stream->ctts_present =
5589 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5590 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5591 /* copy atom data into a new buffer for later use */
5592 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5594 /* skip version + flags */
5595 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5596 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5597 &stream->n_composition_times))
5600 /* make sure there's enough data */
5601 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5610 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5611 (_("This file is corrupt and cannot be played.")), (NULL));
5616 gst_qtdemux_stbl_free (stream);
5617 if (!qtdemux->fragmented) {
5618 /* not quite good */
5619 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5622 /* may pick up samples elsewhere */
5628 /* collect samples from the next sample to be parsed up to sample @n for @stream
5629 * by reading the info from @stbl
5631 * This code can be executed from both the streaming thread and the seeking
5632 * thread so it takes the object lock to protect itself
5635 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
5638 QtDemuxSample *samples, *first, *cur, *last;
5639 guint32 n_samples_per_chunk;
5642 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
5643 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
5644 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
5646 n_samples = stream->n_samples;
5649 goto out_of_samples;
5651 GST_OBJECT_LOCK (qtdemux);
5652 if (n <= stream->stbl_index)
5653 goto already_parsed;
5655 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
5657 if (!stream->stsz.data) {
5658 /* so we already parsed and passed all the moov samples;
5659 * onto fragmented ones */
5660 g_assert (qtdemux->fragmented);
5664 /* pointer to the sample table */
5665 samples = stream->samples;
5667 /* starts from -1, moves to the next sample index to parse */
5668 stream->stbl_index++;
5670 /* keep track of the first and last sample to fill */
5671 first = &samples[stream->stbl_index];
5674 if (stream->chunks_are_chunks) {
5675 /* set the sample sizes */
5676 if (stream->sample_size == 0) {
5677 /* different sizes for each sample */
5678 for (cur = first; cur <= last; cur++) {
5679 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
5680 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
5681 (guint) (cur - samples), cur->size);
5684 /* samples have the same size */
5685 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
5686 for (cur = first; cur <= last; cur++)
5687 cur->size = stream->sample_size;
5691 n_samples_per_chunk = stream->n_samples_per_chunk;
5694 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
5697 if (stream->stsc_chunk_index >= stream->last_chunk
5698 || stream->stsc_chunk_index < stream->first_chunk) {
5699 stream->first_chunk =
5700 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5701 stream->samples_per_chunk =
5702 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5703 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
5705 /* chunk numbers are counted from 1 it seems */
5706 if (G_UNLIKELY (stream->first_chunk == 0))
5709 --stream->first_chunk;
5711 /* the last chunk of each entry is calculated by taking the first chunk
5712 * of the next entry; except if there is no next, where we fake it with
5714 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
5715 stream->last_chunk = G_MAXUINT32;
5717 stream->last_chunk =
5718 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
5719 if (G_UNLIKELY (stream->last_chunk == 0))
5722 --stream->last_chunk;
5725 GST_LOG_OBJECT (qtdemux,
5726 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
5727 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
5729 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
5732 if (stream->last_chunk != G_MAXUINT32) {
5733 if (!qt_atom_parser_peek_sub (&stream->stco,
5734 stream->first_chunk * stream->co_size,
5735 (stream->last_chunk - stream->first_chunk) * stream->co_size,
5740 stream->co_chunk = stream->stco;
5741 if (!gst_byte_reader_skip (&stream->co_chunk,
5742 stream->first_chunk * stream->co_size))
5746 stream->stsc_chunk_index = stream->first_chunk;
5749 last_chunk = stream->last_chunk;
5751 if (stream->chunks_are_chunks) {
5752 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5753 guint32 samples_per_chunk;
5754 guint64 chunk_offset;
5756 if (!stream->stsc_sample_index
5757 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
5758 &stream->chunk_offset))
5761 samples_per_chunk = stream->samples_per_chunk;
5762 chunk_offset = stream->chunk_offset;
5764 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
5765 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
5766 G_GUINT64_FORMAT, (guint) (cur - samples), stream->chunk_offset);
5768 cur->offset = chunk_offset;
5769 chunk_offset += cur->size;
5772 if (G_UNLIKELY (cur > last)) {
5774 stream->stsc_sample_index = k + 1;
5775 stream->chunk_offset = chunk_offset;
5776 stream->stsc_chunk_index = j;
5780 stream->stsc_sample_index = 0;
5782 stream->stsc_chunk_index = j;
5784 cur = &samples[stream->stsc_chunk_index];
5786 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5789 stream->stsc_chunk_index = j;
5794 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
5797 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
5798 "%" G_GUINT64_FORMAT, j, cur->offset);
5800 if (stream->samples_per_frame * stream->bytes_per_frame) {
5802 (stream->samples_per_chunk * stream->n_channels) /
5803 stream->samples_per_frame * stream->bytes_per_frame;
5805 cur->size = stream->samples_per_chunk;
5808 GST_DEBUG_OBJECT (qtdemux,
5809 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
5810 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
5811 GST_SECOND, stream->timescale)), cur->size);
5813 cur->timestamp = stream->stco_sample_index;
5814 cur->duration = stream->samples_per_chunk;
5815 cur->keyframe = TRUE;
5818 stream->stco_sample_index += stream->samples_per_chunk;
5820 stream->stsc_chunk_index = j;
5822 stream->stsc_index++;
5825 if (!stream->chunks_are_chunks)
5829 guint32 n_sample_times;
5831 n_sample_times = stream->n_sample_times;
5834 for (i = stream->stts_index; i < n_sample_times; i++) {
5835 guint32 stts_samples;
5836 gint32 stts_duration;
5839 if (stream->stts_sample_index >= stream->stts_samples
5840 || !stream->stts_sample_index) {
5842 stream->stts_samples =
5843 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5844 stream->stts_duration =
5845 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5847 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
5848 i, stream->stts_samples, stream->stts_duration);
5850 stream->stts_sample_index = 0;
5853 stts_samples = stream->stts_samples;
5854 stts_duration = stream->stts_duration;
5855 stts_time = stream->stts_time;
5857 for (j = stream->stts_sample_index; j < stts_samples; j++) {
5858 GST_DEBUG_OBJECT (qtdemux,
5859 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
5860 (guint) (cur - samples), j,
5861 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
5862 stream->timescale)));
5864 cur->timestamp = stts_time;
5865 cur->duration = stts_duration;
5867 /* avoid 32-bit wrap-around,
5868 * but still mind possible 'negative' duration */
5869 stts_time += (gint64) stts_duration;
5872 if (G_UNLIKELY (cur > last)) {
5874 stream->stts_time = stts_time;
5875 stream->stts_sample_index = j + 1;
5879 stream->stts_sample_index = 0;
5880 stream->stts_time = stts_time;
5881 stream->stts_index++;
5883 /* fill up empty timestamps with the last timestamp, this can happen when
5884 * the last samples do not decode and so we don't have timestamps for them.
5885 * We however look at the last timestamp to estimate the track length so we
5886 * need something in here. */
5887 for (; cur < last; cur++) {
5888 GST_DEBUG_OBJECT (qtdemux,
5889 "fill sample %d: timestamp %" GST_TIME_FORMAT,
5890 (guint) (cur - samples),
5891 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
5892 stream->timescale)));
5893 cur->timestamp = stream->stts_time;
5899 /* sample sync, can be NULL */
5900 if (stream->stss_present == TRUE) {
5901 guint32 n_sample_syncs;
5903 n_sample_syncs = stream->n_sample_syncs;
5905 if (!n_sample_syncs) {
5906 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
5907 stream->all_keyframe = TRUE;
5909 for (i = stream->stss_index; i < n_sample_syncs; i++) {
5910 /* note that the first sample is index 1, not 0 */
5913 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
5915 if (G_LIKELY (index > 0 && index <= n_samples)) {
5917 samples[index].keyframe = TRUE;
5918 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5919 /* and exit if we have enough samples */
5920 if (G_UNLIKELY (index >= n)) {
5927 stream->stss_index = i;
5930 /* stps marks partial sync frames like open GOP I-Frames */
5931 if (stream->stps_present == TRUE) {
5932 guint32 n_sample_partial_syncs;
5934 n_sample_partial_syncs = stream->n_sample_partial_syncs;
5936 /* if there are no entries, the stss table contains the real
5938 if (n_sample_partial_syncs) {
5939 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
5940 /* note that the first sample is index 1, not 0 */
5943 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
5945 if (G_LIKELY (index > 0 && index <= n_samples)) {
5947 samples[index].keyframe = TRUE;
5948 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5949 /* and exit if we have enough samples */
5950 if (G_UNLIKELY (index >= n)) {
5957 stream->stps_index = i;
5961 /* no stss, all samples are keyframes */
5962 stream->all_keyframe = TRUE;
5963 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
5968 /* composition time to sample */
5969 if (stream->ctts_present == TRUE) {
5970 guint32 n_composition_times;
5972 gint32 ctts_soffset;
5974 /* Fill in the pts_offsets */
5976 n_composition_times = stream->n_composition_times;
5978 for (i = stream->ctts_index; i < n_composition_times; i++) {
5979 if (stream->ctts_sample_index >= stream->ctts_count
5980 || !stream->ctts_sample_index) {
5981 stream->ctts_count =
5982 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
5983 stream->ctts_soffset =
5984 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
5985 stream->ctts_sample_index = 0;
5988 ctts_count = stream->ctts_count;
5989 ctts_soffset = stream->ctts_soffset;
5991 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
5992 cur->pts_offset = ctts_soffset;
5995 if (G_UNLIKELY (cur > last)) {
5997 stream->ctts_sample_index = j + 1;
6001 stream->ctts_sample_index = 0;
6002 stream->ctts_index++;
6006 stream->stbl_index = n;
6007 /* if index has been completely parsed, free data that is no-longer needed */
6008 if (n + 1 == stream->n_samples) {
6009 gst_qtdemux_stbl_free (stream);
6010 GST_DEBUG_OBJECT (qtdemux,
6011 "parsed all available samples; checking for more");
6012 while (n + 1 == stream->n_samples)
6013 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
6016 GST_OBJECT_UNLOCK (qtdemux);
6023 GST_LOG_OBJECT (qtdemux,
6024 "Tried to parse up to sample %u but this sample has already been parsed",
6026 /* if fragmented, there may be more */
6027 if (qtdemux->fragmented && n == stream->stbl_index)
6029 GST_OBJECT_UNLOCK (qtdemux);
6035 GST_LOG_OBJECT (qtdemux,
6036 "Tried to parse up to sample %u but there are only %u samples", n + 1,
6038 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6039 (_("This file is corrupt and cannot be played.")), (NULL));
6044 GST_OBJECT_UNLOCK (qtdemux);
6045 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6046 (_("This file is corrupt and cannot be played.")), (NULL));
6051 /* collect all segment info for @stream.
6054 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
6059 /* parse and prepare segment info from the edit list */
6060 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
6061 stream->n_segments = 0;
6062 stream->segments = NULL;
6063 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
6067 guint64 time, stime;
6070 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
6071 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
6074 buffer = elst->data;
6076 n_segments = QT_UINT32 (buffer + 12);
6078 /* we might allocate a bit too much, at least allocate 1 segment */
6079 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
6081 /* segments always start from 0 */
6085 for (i = 0; i < n_segments; i++) {
6088 QtDemuxSegment *segment;
6091 media_time = QT_UINT32 (buffer + 20 + i * 12);
6093 /* -1 media time is an empty segment, just ignore it */
6094 if (media_time == G_MAXUINT32)
6097 duration = QT_UINT32 (buffer + 16 + i * 12);
6099 segment = &stream->segments[count++];
6101 /* time and duration expressed in global timescale */
6102 segment->time = stime;
6103 /* add non scaled values so we don't cause roundoff errors */
6105 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
6106 segment->stop_time = stime;
6107 segment->duration = stime - segment->time;
6108 /* media_time expressed in stream timescale */
6109 segment->media_start =
6110 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
6111 segment->media_stop = segment->media_start + segment->duration;
6112 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
6114 if (rate_int <= 1) {
6115 /* 0 is not allowed, some programs write 1 instead of the floating point
6117 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
6121 segment->rate = rate_int / 65536.0;
6124 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
6125 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
6126 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
6127 GST_TIME_ARGS (segment->duration),
6128 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
6130 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
6131 stream->n_segments = count;
6135 /* push based does not handle segments, so act accordingly here,
6136 * and warn if applicable */
6137 if (!qtdemux->pullbased) {
6138 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
6139 /* remove and use default one below, we stream like it anyway */
6140 g_free (stream->segments);
6141 stream->segments = NULL;
6142 stream->n_segments = 0;
6145 /* no segments, create one to play the complete trak */
6146 if (stream->n_segments == 0) {
6147 GstClockTime stream_duration =
6148 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6150 if (stream->segments == NULL)
6151 stream->segments = g_new (QtDemuxSegment, 1);
6153 /* represent unknown our way */
6154 if (stream_duration == 0)
6155 stream_duration = -1;
6157 stream->segments[0].time = 0;
6158 stream->segments[0].stop_time = stream_duration;
6159 stream->segments[0].duration = stream_duration;
6160 stream->segments[0].media_start = 0;
6161 stream->segments[0].media_stop = stream_duration;
6162 stream->segments[0].rate = 1.0;
6164 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6165 GST_TIME_ARGS (stream_duration));
6166 stream->n_segments = 1;
6168 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6174 * Parses the stsd atom of a svq3 trak looking for
6175 * the SMI and gama atoms.
6178 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6179 guint8 ** gamma, GstBuffer ** seqh)
6181 guint8 *_gamma = NULL;
6182 GstBuffer *_seqh = NULL;
6183 guint8 *stsd_data = stsd->data;
6184 guint32 length = QT_UINT32 (stsd_data);
6188 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6194 version = QT_UINT16 (stsd_data);
6199 while (length > 8) {
6200 guint32 fourcc, size;
6202 size = QT_UINT32 (stsd_data);
6203 fourcc = QT_FOURCC (stsd_data + 4);
6204 data = stsd_data + 8;
6211 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6212 " for gama atom, expected 12", size);
6217 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6219 if (_seqh != NULL) {
6220 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6221 " found, ignoring");
6223 seqh_size = QT_UINT32 (data + 4);
6224 if (seqh_size > 0) {
6225 _seqh = gst_buffer_new_and_alloc (seqh_size);
6226 _gst_buffer_copy_into_mem (_seqh, 0, data + 8, seqh_size);
6233 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6234 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6238 if (size <= length) {
6244 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6247 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6248 G_GUINT16_FORMAT, version);
6259 gst_buffer_unref (_seqh);
6264 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6271 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6272 * atom that might contain a 'data' atom with the rtsp uri.
6273 * This case was reported in bug #597497, some info about
6274 * the hndl atom can be found in TN1195
6276 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6277 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6280 guint32 dref_num_entries = 0;
6281 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6282 gst_byte_reader_skip (&dref, 4) &&
6283 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6286 /* search dref entries for hndl atom */
6287 for (i = 0; i < dref_num_entries; i++) {
6288 guint32 size = 0, type;
6289 guint8 string_len = 0;
6290 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6291 qt_atom_parser_get_fourcc (&dref, &type)) {
6292 if (type == FOURCC_hndl) {
6293 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6295 /* skip data reference handle bytes and the
6296 * following pascal string and some extra 4
6297 * bytes I have no idea what are */
6298 if (!gst_byte_reader_skip (&dref, 4) ||
6299 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6300 !gst_byte_reader_skip (&dref, string_len + 4)) {
6301 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6305 /* iterate over the atoms to find the data atom */
6306 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6310 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6311 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6312 if (atom_type == FOURCC_data) {
6313 const guint8 *uri_aux = NULL;
6315 /* found the data atom that might contain the rtsp uri */
6316 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6317 "hndl atom, interpreting it as an URI");
6318 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6320 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6321 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6323 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6324 "didn't contain a rtsp address");
6326 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6331 /* skipping to the next entry */
6332 if (!gst_byte_reader_skip (&dref, atom_size - 8))
6335 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6342 /* skip to the next entry */
6343 if (!gst_byte_reader_skip (&dref, size - 8))
6346 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6349 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6356 less_than (gconstpointer a, gconstpointer b)
6358 const guint32 *av = a, *bv = b;
6363 #define AMR_NB_ALL_MODES 0x81ff
6364 #define AMR_WB_ALL_MODES 0x83ff
6366 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
6368 /* The 'damr' atom is of the form:
6370 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
6371 * 32 b 8 b 16 b 8 b 8 b
6373 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
6374 * represents the highest mode used in the stream (and thus the maximum
6375 * bitrate), with a couple of special cases as seen below.
6378 /* Map of frame type ID -> bitrate */
6379 static const guint nb_bitrates[] = {
6380 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
6382 static const guint wb_bitrates[] = {
6383 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
6389 gst_buffer_map (buf, &map, GST_MAP_READ);
6391 if (map.size != 0x11) {
6392 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
6396 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
6397 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
6398 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
6402 mode_set = QT_UINT16 (map.data + 13);
6404 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
6405 max_mode = 7 + (wb ? 1 : 0);
6407 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
6408 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
6410 if (max_mode == -1) {
6411 GST_DEBUG ("No mode indication was found (mode set) = %x",
6416 gst_buffer_unmap (buf, &map);
6417 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
6420 gst_buffer_unmap (buf, &map);
6425 * With each track we associate a new QtDemuxStream that contains all the info
6427 * traks that do not decode to something (like strm traks) will not have a pad.
6430 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6445 QtDemuxStream *stream;
6446 GstTagList *list = NULL;
6447 gchar *codec = NULL;
6448 const guint8 *stsd_data;
6449 guint16 lang_code; /* quicktime lang code or packed iso code */
6451 guint32 tkhd_flags = 0;
6452 guint8 tkhd_version = 0;
6454 guint value_size, len;
6456 stream = g_new0 (QtDemuxStream, 1);
6457 /* new streams always need a discont */
6458 stream->discont = TRUE;
6459 /* we enable clipping for raw audio/video streams */
6460 stream->need_clip = FALSE;
6461 stream->need_process = FALSE;
6462 stream->segment_index = -1;
6463 stream->time_position = 0;
6464 stream->sample_index = -1;
6465 stream->last_ret = GST_FLOW_OK;
6467 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6468 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6469 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6472 /* pick between 64 or 32 bits */
6473 value_size = tkhd_version == 1 ? 8 : 4;
6474 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6475 !gst_byte_reader_get_uint32_be (&tkhd, &stream->track_id))
6478 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6479 tkhd_version, tkhd_flags, stream->track_id);
6481 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6484 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6485 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6486 if (qtdemux->major_brand != FOURCC_mjp2 ||
6487 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6491 len = QT_UINT32 ((guint8 *) mdhd->data);
6492 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6493 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6494 if (version == 0x01000000) {
6497 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6498 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6499 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6503 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6504 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6505 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6508 if (lang_code < 0x800) {
6509 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6511 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6512 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6513 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6514 stream->lang_id[3] = 0;
6517 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6519 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6521 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6522 lang_code, stream->lang_id);
6524 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6527 /* fragmented files may have bogus duration in moov */
6528 if (!qtdemux->fragmented &&
6529 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6530 guint64 tdur1, tdur2;
6532 /* don't overflow */
6533 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6534 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6537 * some of those trailers, nowadays, have prologue images that are
6538 * themselves vide tracks as well. I haven't really found a way to
6539 * identify those yet, except for just looking at their duration. */
6540 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6541 GST_WARNING_OBJECT (qtdemux,
6542 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6543 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6544 "found, assuming preview image or something; skipping track",
6545 stream->duration, stream->timescale, qtdemux->duration,
6546 qtdemux->timescale);
6552 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6555 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6556 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6558 len = QT_UINT32 ((guint8 *) hdlr->data);
6560 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6561 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6562 GST_FOURCC_ARGS (stream->subtype));
6564 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6567 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6571 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6573 stsd_data = (const guint8 *) stsd->data;
6575 /* stsd should at least have one entry */
6576 len = QT_UINT32 (stsd_data);
6580 /* and that entry should fit within stsd */
6581 len = QT_UINT32 (stsd_data + 16);
6582 if (len > QT_UINT32 (stsd_data) + 16)
6584 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6586 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6587 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6588 GST_FOURCC_ARGS (stream->fourcc));
6590 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6591 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6592 goto error_encrypted;
6594 if (stream->subtype == FOURCC_vide) {
6595 guint32 w = 0, h = 0;
6597 stream->sampled = TRUE;
6599 /* version 1 uses some 64-bit ints */
6600 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6601 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6602 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6605 stream->display_width = w >> 16;
6606 stream->display_height = h >> 16;
6612 stream->width = QT_UINT16 (stsd_data + offset + 32);
6613 stream->height = QT_UINT16 (stsd_data + offset + 34);
6614 stream->fps_n = 0; /* this is filled in later */
6615 stream->fps_d = 0; /* this is filled in later */
6616 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6617 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6619 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6620 QT_UINT16 (stsd_data + offset + 48));
6623 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6625 list = gst_tag_list_new_empty ();
6626 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6627 GST_TAG_VIDEO_CODEC, codec, NULL);
6634 /* pick 'the' stsd child */
6635 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
6637 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
6638 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
6642 const guint8 *pasp_data = (const guint8 *) pasp->data;
6644 stream->par_w = QT_UINT32 (pasp_data + 8);
6645 stream->par_h = QT_UINT32 (pasp_data + 12);
6652 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
6657 gint len = QT_UINT32 (stsd_data) - 0x66;
6658 const guint8 *avc_data = stsd_data + 0x66;
6661 while (len >= 0x8) {
6664 if (QT_UINT32 (avc_data) <= len)
6665 size = QT_UINT32 (avc_data) - 0x8;
6670 /* No real data, so break out */
6673 switch (QT_FOURCC (avc_data + 0x4)) {
6676 /* parse, if found */
6679 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
6681 /* First 4 bytes are the length of the atom, the next 4 bytes
6682 * are the fourcc, the next 1 byte is the version, and the
6683 * subsequent bytes are sequence parameter set like data. */
6684 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
6685 avc_data + 8 + 1, size - 1);
6687 buf = gst_buffer_new_and_alloc (size);
6688 _gst_buffer_copy_into_mem (buf, 0, avc_data + 0x8, size);
6689 gst_caps_set_simple (stream->caps,
6690 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6691 gst_buffer_unref (buf);
6697 guint avg_bitrate, max_bitrate;
6699 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
6703 max_bitrate = QT_UINT32 (avc_data + 0xc);
6704 avg_bitrate = QT_UINT32 (avc_data + 0x10);
6706 if (!max_bitrate && !avg_bitrate)
6709 /* Some muxers seem to swap the average and maximum bitrates
6710 * (I'm looking at you, YouTube), so we swap for sanity. */
6711 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
6712 guint temp = avg_bitrate;
6714 avg_bitrate = max_bitrate;
6719 list = gst_tag_list_new_empty ();
6721 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6722 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6723 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6725 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6726 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6727 GST_TAG_BITRATE, avg_bitrate, NULL);
6738 avc_data += size + 8;
6750 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
6751 GST_FOURCC_ARGS (fourcc));
6753 /* codec data might be in glbl extension atom */
6755 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
6761 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
6763 len = QT_UINT32 (data);
6766 buf = gst_buffer_new_and_alloc (len);
6767 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
6768 gst_caps_set_simple (stream->caps,
6769 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6770 gst_buffer_unref (buf);
6777 /* see annex I of the jpeg2000 spec */
6778 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
6780 const gchar *colorspace = NULL;
6782 guint32 ncomp_map = 0;
6783 gint32 *comp_map = NULL;
6784 guint32 nchan_def = 0;
6785 gint32 *chan_def = NULL;
6787 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
6788 /* some required atoms */
6789 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
6792 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
6796 /* number of components; redundant with info in codestream, but useful
6798 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
6799 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
6801 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
6803 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
6806 GST_DEBUG_OBJECT (qtdemux, "found colr");
6807 /* extract colour space info */
6808 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
6809 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
6811 colorspace = "sRGB";
6814 colorspace = "GRAY";
6817 colorspace = "sYUV";
6825 /* colr is required, and only values 16, 17, and 18 are specified,
6826 so error if we have no colorspace */
6829 /* extract component mapping */
6830 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
6832 guint32 cmap_len = 0;
6834 cmap_len = QT_UINT32 (cmap->data);
6835 if (cmap_len >= 8) {
6836 /* normal box, subtract off header */
6838 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
6839 if (cmap_len % 4 == 0) {
6840 ncomp_map = (cmap_len / 4);
6841 comp_map = g_new0 (gint32, ncomp_map);
6842 for (i = 0; i < ncomp_map; i++) {
6845 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
6846 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
6847 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
6848 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
6853 /* extract channel definitions */
6854 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
6856 guint32 cdef_len = 0;
6858 cdef_len = QT_UINT32 (cdef->data);
6859 if (cdef_len >= 10) {
6860 /* normal box, subtract off header and len */
6862 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
6863 if (cdef_len % 6 == 0) {
6864 nchan_def = (cdef_len / 6);
6865 chan_def = g_new0 (gint32, nchan_def);
6866 for (i = 0; i < nchan_def; i++)
6868 for (i = 0; i < nchan_def; i++) {
6869 guint16 cn, typ, asoc;
6870 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
6871 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
6872 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
6873 if (cn < nchan_def) {
6876 chan_def[cn] = asoc;
6879 chan_def[cn] = 0; /* alpha */
6882 chan_def[cn] = -typ;
6890 gst_caps_set_simple (stream->caps,
6891 "num-components", G_TYPE_INT, ncomp, NULL);
6892 gst_caps_set_simple (stream->caps,
6893 "colorspace", G_TYPE_STRING, colorspace, NULL);
6896 GValue arr = { 0, };
6897 GValue elt = { 0, };
6899 g_value_init (&arr, GST_TYPE_ARRAY);
6900 g_value_init (&elt, G_TYPE_INT);
6901 for (i = 0; i < ncomp_map; i++) {
6902 g_value_set_int (&elt, comp_map[i]);
6903 gst_value_array_append_value (&arr, &elt);
6905 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6906 "component-map", &arr);
6907 g_value_unset (&elt);
6908 g_value_unset (&arr);
6913 GValue arr = { 0, };
6914 GValue elt = { 0, };
6916 g_value_init (&arr, GST_TYPE_ARRAY);
6917 g_value_init (&elt, G_TYPE_INT);
6918 for (i = 0; i < nchan_def; i++) {
6919 g_value_set_int (&elt, chan_def[i]);
6920 gst_value_array_append_value (&arr, &elt);
6922 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6923 "channel-definitions", &arr);
6924 g_value_unset (&elt);
6925 g_value_unset (&arr);
6929 /* some optional atoms */
6930 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
6931 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
6933 /* indicate possible fields in caps */
6935 data = (guint8 *) field->data + 8;
6937 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
6938 (gint) * data, NULL);
6940 /* add codec_data if provided */
6945 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
6946 data = prefix->data;
6947 len = QT_UINT32 (data);
6950 buf = gst_buffer_new_and_alloc (len);
6951 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
6952 gst_caps_set_simple (stream->caps,
6953 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6954 gst_buffer_unref (buf);
6963 GstBuffer *seqh = NULL;
6964 guint8 *gamma_data = NULL;
6965 gint len = QT_UINT32 (stsd_data);
6967 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
6969 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
6970 QT_FP32 (gamma_data), NULL);
6973 /* sorry for the bad name, but we don't know what this is, other
6974 * than its own fourcc */
6975 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
6979 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
6980 buf = gst_buffer_new_and_alloc (len);
6981 _gst_buffer_copy_into_mem (buf, 0, stsd_data, len);
6982 gst_caps_set_simple (stream->caps,
6983 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6984 gst_buffer_unref (buf);
6989 gst_caps_set_simple (stream->caps,
6990 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
6997 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
6998 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
7002 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
7006 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
7007 /* collect the headers and store them in a stream list so that we can
7008 * send them out first */
7009 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
7019 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
7020 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
7023 ovc1_data = ovc1->data;
7024 ovc1_len = QT_UINT32 (ovc1_data);
7025 if (ovc1_len <= 198) {
7026 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
7029 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
7030 _gst_buffer_copy_into_mem (buf, 0, ovc1_data + 198, ovc1_len - 198);
7031 gst_caps_set_simple (stream->caps,
7032 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7033 gst_buffer_unref (buf);
7041 GST_INFO_OBJECT (qtdemux,
7042 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7043 GST_FOURCC_ARGS (fourcc), stream->caps);
7045 } else if (stream->subtype == FOURCC_soun) {
7046 int version, samplesize;
7047 guint16 compression_id;
7048 gboolean amrwb = FALSE;
7054 version = QT_UINT32 (stsd_data + offset);
7055 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
7056 samplesize = QT_UINT16 (stsd_data + offset + 10);
7057 compression_id = QT_UINT16 (stsd_data + offset + 12);
7058 stream->rate = QT_FP32 (stsd_data + offset + 16);
7060 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
7061 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
7062 QT_UINT32 (stsd_data + offset + 4));
7063 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7064 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
7065 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
7066 GST_LOG_OBJECT (qtdemux, "packet size: %d",
7067 QT_UINT16 (stsd_data + offset + 14));
7068 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7070 if (compression_id == 0xfffe)
7071 stream->sampled = TRUE;
7073 /* first assume uncompressed audio */
7074 stream->bytes_per_sample = samplesize / 8;
7075 stream->samples_per_frame = stream->n_channels;
7076 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
7077 stream->samples_per_packet = stream->samples_per_frame;
7078 stream->bytes_per_packet = stream->bytes_per_sample;
7082 /* Yes, these have to be hard-coded */
7085 stream->samples_per_packet = 6;
7086 stream->bytes_per_packet = 1;
7087 stream->bytes_per_frame = 1 * stream->n_channels;
7088 stream->bytes_per_sample = 1;
7089 stream->samples_per_frame = 6 * stream->n_channels;
7094 stream->samples_per_packet = 3;
7095 stream->bytes_per_packet = 1;
7096 stream->bytes_per_frame = 1 * stream->n_channels;
7097 stream->bytes_per_sample = 1;
7098 stream->samples_per_frame = 3 * stream->n_channels;
7103 stream->samples_per_packet = 64;
7104 stream->bytes_per_packet = 34;
7105 stream->bytes_per_frame = 34 * stream->n_channels;
7106 stream->bytes_per_sample = 2;
7107 stream->samples_per_frame = 64 * stream->n_channels;
7113 stream->samples_per_packet = 1;
7114 stream->bytes_per_packet = 1;
7115 stream->bytes_per_frame = 1 * stream->n_channels;
7116 stream->bytes_per_sample = 1;
7117 stream->samples_per_frame = 1 * stream->n_channels;
7122 stream->samples_per_packet = 160;
7123 stream->bytes_per_packet = 33;
7124 stream->bytes_per_frame = 33 * stream->n_channels;
7125 stream->bytes_per_sample = 2;
7126 stream->samples_per_frame = 160 * stream->n_channels;
7133 if (version == 0x00010000) {
7141 /* only parse extra decoding config for non-pcm audio */
7142 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7143 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
7144 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
7145 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
7147 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7148 stream->samples_per_packet);
7149 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7150 stream->bytes_per_packet);
7151 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
7152 stream->bytes_per_frame);
7153 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
7154 stream->bytes_per_sample);
7156 if (!stream->sampled && stream->bytes_per_packet) {
7157 stream->samples_per_frame = (stream->bytes_per_frame /
7158 stream->bytes_per_packet) * stream->samples_per_packet;
7159 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
7160 stream->samples_per_frame);
7165 } else if (version == 0x00020000) {
7172 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7173 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
7174 stream->rate = qtfp.fp;
7175 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
7177 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7178 stream->samples_per_packet);
7179 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7180 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7183 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
7186 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
7195 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
7197 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
7199 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
7201 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
7204 gst_caps_set_simple (stream->caps,
7205 "format", G_TYPE_STRING, "S24LE", NULL);
7212 const guint8 *owma_data;
7213 const gchar *codec_name = NULL;
7217 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
7218 /* FIXME this should also be gst_riff_strf_auds,
7219 * but the latter one is actually missing bits-per-sample :( */
7224 gint32 nSamplesPerSec;
7225 gint32 nAvgBytesPerSec;
7227 gint16 wBitsPerSample;
7232 GST_DEBUG_OBJECT (qtdemux, "parse owma");
7233 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
7236 owma_data = owma->data;
7237 owma_len = QT_UINT32 (owma_data);
7238 if (owma_len <= 54) {
7239 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
7242 wfex = (WAVEFORMATEX *) (owma_data + 36);
7243 buf = gst_buffer_new_and_alloc (owma_len - 54);
7244 _gst_buffer_copy_into_mem (buf, 0, owma_data + 54, owma_len - 54);
7245 if (wfex->wFormatTag == 0x0161) {
7246 codec_name = "Windows Media Audio";
7248 } else if (wfex->wFormatTag == 0x0162) {
7249 codec_name = "Windows Media Audio 9 Pro";
7251 } else if (wfex->wFormatTag == 0x0163) {
7252 codec_name = "Windows Media Audio 9 Lossless";
7253 /* is that correct? gstffmpegcodecmap.c is missing it, but
7254 * fluendo codec seems to support it */
7258 gst_caps_set_simple (stream->caps,
7259 "codec_data", GST_TYPE_BUFFER, buf,
7260 "wmaversion", G_TYPE_INT, version,
7261 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
7262 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
7263 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7264 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7266 gst_buffer_unref (buf);
7270 codec = g_strdup (codec_name);
7282 list = gst_tag_list_new_empty ();
7283 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7284 GST_TAG_AUDIO_CODEC, codec, NULL);
7288 /* some bitrate info may have ended up in caps */
7289 s = gst_caps_get_structure (stream->caps, 0);
7290 gst_structure_get_int (s, "bitrate", &bitrate);
7292 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7296 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7300 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7302 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7304 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7308 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7309 16 bits is a byte-swapped wave-style codec identifier,
7310 and we can find a WAVE header internally to a 'wave' atom here.
7311 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7312 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7315 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7316 if (len < offset + 20) {
7317 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7319 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7320 const guint8 *data = stsd_data + offset + 16;
7322 GNode *waveheadernode;
7324 wavenode = g_node_new ((guint8 *) data);
7325 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7326 const guint8 *waveheader;
7329 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7330 if (waveheadernode) {
7331 waveheader = (const guint8 *) waveheadernode->data;
7332 headerlen = QT_UINT32 (waveheader);
7334 if (headerlen > 8) {
7335 gst_riff_strf_auds *header = NULL;
7336 GstBuffer *headerbuf;
7342 headerbuf = gst_buffer_new_and_alloc (headerlen);
7343 _gst_buffer_copy_into_mem (headerbuf, 0, waveheader, headerlen);
7345 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7346 headerbuf, &header, &extra)) {
7347 gst_caps_unref (stream->caps);
7348 /* FIXME: Need to do something with the channel reorder map */
7349 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7350 header, extra, NULL, NULL, NULL);
7353 gst_buffer_unref (extra);
7358 GST_DEBUG ("Didn't find waveheadernode for this codec");
7360 g_node_destroy (wavenode);
7363 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7367 /* FIXME: what is in the chunk? */
7370 gint len = QT_UINT32 (stsd_data);
7372 /* seems to be always = 116 = 0x74 */
7378 gint len = QT_UINT32 (stsd_data);
7381 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7383 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x4C, len - 0x4C);
7384 gst_caps_set_simple (stream->caps,
7385 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7386 gst_buffer_unref (buf);
7388 gst_caps_set_simple (stream->caps,
7389 "samplesize", G_TYPE_INT, samplesize, NULL);
7394 GNode *alac, *wave = NULL;
7396 /* apparently, m4a has this atom appended directly in the stsd entry,
7397 * while mov has it in a wave atom */
7398 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7400 /* alac now refers to stsd entry atom */
7401 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7403 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7405 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7408 gint len = QT_UINT32 (alac->data);
7412 GST_DEBUG_OBJECT (qtdemux,
7413 "discarding alac atom with unexpected len %d", len);
7415 /* codec-data contains alac atom size and prefix,
7416 * ffmpeg likes it that way, not quite gst-ish though ...*/
7417 buf = gst_buffer_new_and_alloc (len);
7418 _gst_buffer_copy_into_mem (buf, 0, alac->data, len);
7419 gst_caps_set_simple (stream->caps,
7420 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7421 gst_buffer_unref (buf);
7424 gst_caps_set_simple (stream->caps,
7425 "samplesize", G_TYPE_INT, samplesize, NULL);
7433 gint len = QT_UINT32 (stsd_data);
7436 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7439 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x34, len - 0x34);
7441 /* If we have enough data, let's try to get the 'damr' atom. See
7442 * the 3GPP container spec (26.244) for more details. */
7443 if ((len - 0x34) > 8 &&
7444 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
7446 list = gst_tag_list_new_empty ();
7447 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7448 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
7451 gst_caps_set_simple (stream->caps,
7452 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7453 gst_buffer_unref (buf);
7461 GST_INFO_OBJECT (qtdemux,
7462 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7463 GST_FOURCC_ARGS (fourcc), stream->caps);
7465 } else if (stream->subtype == FOURCC_strm) {
7466 if (fourcc == FOURCC_rtsp) {
7467 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7469 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7470 GST_FOURCC_ARGS (fourcc));
7471 goto unknown_stream;
7473 stream->sampled = TRUE;
7474 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
7476 stream->sampled = TRUE;
7481 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7483 list = gst_tag_list_new_empty ();
7484 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7485 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7490 /* hunt for sort-of codec data */
7497 /* look for palette */
7498 /* target mp4s atom */
7499 len = QT_UINT32 (stsd_data + offset);
7500 data = stsd_data + offset;
7501 /* verify sufficient length,
7502 * and esds present with decConfigDescr of expected size and position */
7503 if ((len >= 106 + 8)
7504 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7505 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7510 /* move to decConfigDescr data */
7511 data = data + 8 + 42;
7512 for (i = 0; i < 16; i++) {
7513 clut[i] = QT_UINT32 (data);
7517 s = gst_structure_new ("application/x-gst-dvd", "event",
7518 G_TYPE_STRING, "dvd-spu-clut-change",
7519 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7520 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7521 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7522 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7523 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7524 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7525 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7526 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7529 /* store event and trigger custom processing */
7530 stream->pending_event =
7531 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7532 stream->need_process = TRUE;
7540 /* everything in 1 sample */
7541 stream->sampled = TRUE;
7544 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7546 if (stream->caps == NULL)
7547 goto unknown_stream;
7550 list = gst_tag_list_new_empty ();
7551 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7552 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7558 /* promote to sampled format */
7559 if (stream->fourcc == FOURCC_samr) {
7560 /* force mono 8000 Hz for AMR */
7561 stream->sampled = TRUE;
7562 stream->n_channels = 1;
7563 stream->rate = 8000;
7564 } else if (stream->fourcc == FOURCC_sawb) {
7565 /* force mono 16000 Hz for AMR-WB */
7566 stream->sampled = TRUE;
7567 stream->n_channels = 1;
7568 stream->rate = 16000;
7569 } else if (stream->fourcc == FOURCC_mp4a) {
7570 stream->sampled = TRUE;
7573 /* collect sample information */
7574 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7575 goto samples_failed;
7577 if (qtdemux->fragmented) {
7581 /* need all moov samples as basis; probably not many if any at all */
7582 /* prevent moof parsing taking of at this time */
7583 offset = qtdemux->moof_offset;
7584 qtdemux->moof_offset = 0;
7585 if (stream->n_samples &&
7586 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7587 qtdemux->moof_offset = offset;
7588 goto samples_failed;
7590 qtdemux->moof_offset = 0;
7591 /* movie duration more reliable in this case (e.g. mehd) */
7592 if (qtdemux->segment.duration &&
7593 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7594 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7595 stream->timescale, GST_SECOND);
7596 /* need defaults for fragments */
7597 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7600 /* configure segments */
7601 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7602 goto segments_failed;
7604 /* add some language tag, if useful */
7605 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7606 strcmp (stream->lang_id, "und")) {
7607 const gchar *lang_code;
7610 list = gst_tag_list_new_empty ();
7612 /* convert ISO 639-2 code to ISO 639-1 */
7613 lang_code = gst_tag_get_language_code (stream->lang_id);
7614 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7615 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7618 /* now we are ready to add the stream */
7619 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7620 goto too_many_streams;
7622 stream->pending_tags = list;
7623 qtdemux->streams[qtdemux->n_streams] = stream;
7624 qtdemux->n_streams++;
7625 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7632 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7633 (_("This file is corrupt and cannot be played.")), (NULL));
7639 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7646 /* we posted an error already */
7647 /* free stbl sub-atoms */
7648 gst_qtdemux_stbl_free (stream);
7654 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7655 GST_FOURCC_ARGS (stream->subtype));
7661 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7662 (_("This file contains too many streams. Only playing first %d"),
7663 GST_QTDEMUX_MAX_STREAMS), (NULL));
7668 /* If we can estimate the overall bitrate, and don't have information about the
7669 * stream bitrate for exactly one stream, this guesses the stream bitrate as
7670 * the overall bitrate minus the sum of the bitrates of all other streams. This
7671 * should be useful for the common case where we have one audio and one video
7672 * stream and can estimate the bitrate of one, but not the other. */
7674 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
7676 QtDemuxStream *stream = NULL;
7677 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
7681 if (qtdemux->fragmented)
7684 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
7686 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
7688 GST_DEBUG_OBJECT (qtdemux,
7689 "Size in bytes of the stream not known - bailing");
7693 /* Subtract the header size */
7694 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
7695 size, qtdemux->header_size);
7697 if (size < qtdemux->header_size)
7700 size = size - qtdemux->header_size;
7702 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
7703 duration == GST_CLOCK_TIME_NONE) {
7704 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
7708 for (i = 0; i < qtdemux->n_streams; i++) {
7709 switch (qtdemux->streams[i]->subtype) {
7712 /* retrieve bitrate, prefer avg then max */
7714 if (qtdemux->streams[i]->pending_tags) {
7715 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7716 GST_TAG_MAXIMUM_BITRATE, &bitrate);
7717 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7718 GST_TAG_BITRATE, &bitrate);
7721 sum_bitrate += bitrate;
7724 GST_DEBUG_OBJECT (qtdemux,
7725 ">1 stream with unknown bitrate - bailing");
7728 stream = qtdemux->streams[i];
7732 /* For other subtypes, we assume no significant impact on bitrate */
7738 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
7742 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
7744 if (sys_bitrate < sum_bitrate) {
7745 /* This can happen, since sum_bitrate might be derived from maximum
7746 * bitrates and not average bitrates */
7747 GST_DEBUG_OBJECT (qtdemux,
7748 "System bitrate less than sum bitrate - bailing");
7752 bitrate = sys_bitrate - sum_bitrate;
7753 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
7754 ", Stream bitrate = %u", sys_bitrate, bitrate);
7756 if (!stream->pending_tags)
7757 stream->pending_tags = gst_tag_list_new_empty ();
7759 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
7760 GST_TAG_BITRATE, bitrate, NULL);
7763 static GstFlowReturn
7764 qtdemux_expose_streams (GstQTDemux * qtdemux)
7767 GstFlowReturn ret = GST_FLOW_OK;
7769 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7771 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7772 QtDemuxStream *stream = qtdemux->streams[i];
7773 guint32 sample_num = 0;
7778 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7779 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7781 if (qtdemux->fragmented) {
7782 /* need all moov samples first */
7783 GST_OBJECT_LOCK (qtdemux);
7784 while (stream->n_samples == 0)
7785 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7787 GST_OBJECT_UNLOCK (qtdemux);
7789 /* discard any stray moof */
7790 qtdemux->moof_offset = 0;
7793 /* prepare braking */
7794 if (ret != GST_FLOW_ERROR)
7797 /* in pull mode, we should have parsed some sample info by now;
7798 * and quite some code will not handle no samples.
7799 * in push mode, we'll just have to deal with it */
7800 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7801 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7802 gst_qtdemux_stream_free (qtdemux, stream);
7803 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7804 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7805 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7806 qtdemux->n_streams--;
7811 /* parse number of initial sample to set frame rate cap */
7812 while (sample_num < stream->n_samples && sample_num < samples) {
7813 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7817 /* collect and sort durations */
7818 samples = MIN (stream->stbl_index + 1, samples);
7819 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7821 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7823 while (sample_num < samples) {
7824 g_array_append_val (durations, stream->samples[sample_num].duration);
7827 g_array_sort (durations, less_than);
7828 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7829 g_array_free (durations, TRUE);
7832 /* now we have all info and can expose */
7833 list = stream->pending_tags;
7834 stream->pending_tags = NULL;
7835 gst_qtdemux_add_stream (qtdemux, stream, list);
7838 gst_qtdemux_guess_bitrate (qtdemux);
7840 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7842 /* check if we should post a redirect in case there is a single trak
7843 * and it is a redirecting trak */
7844 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7847 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7848 "an external content");
7849 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7850 gst_structure_new ("redirect",
7851 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7853 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7854 qtdemux->posted_redirect = TRUE;
7860 /* check if major or compatible brand is 3GP */
7861 static inline gboolean
7862 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7865 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7866 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7867 } else if (qtdemux->comp_brands != NULL) {
7871 gboolean res = FALSE;
7873 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
7877 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7878 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7882 gst_buffer_unmap (qtdemux->comp_brands, &map);
7889 /* check if tag is a spec'ed 3GP tag keyword storing a string */
7890 static inline gboolean
7891 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
7893 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
7894 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
7895 || fourcc == FOURCC_albm;
7899 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
7900 const char *dummy, GNode * node)
7902 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7906 gdouble longitude, latitude, altitude;
7909 len = QT_UINT32 (node->data);
7916 /* TODO: language code skipped */
7918 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
7921 /* do not alarm in trivial case, but bail out otherwise */
7922 if (*(data + offset) != 0) {
7923 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
7927 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7928 GST_TAG_GEO_LOCATION_NAME, name, NULL);
7929 offset += strlen (name);
7933 if (len < offset + 2 + 4 + 4 + 4)
7936 /* +1 +1 = skip null-terminator and location role byte */
7938 /* table in spec says unsigned, semantics say negative has meaning ... */
7939 longitude = QT_SFP32 (data + offset);
7942 latitude = QT_SFP32 (data + offset);
7945 altitude = QT_SFP32 (data + offset);
7947 /* one invalid means all are invalid */
7948 if (longitude >= -180.0 && longitude <= 180.0 &&
7949 latitude >= -90.0 && latitude <= 90.0) {
7950 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7951 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
7952 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
7953 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
7956 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
7963 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
7970 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7977 len = QT_UINT32 (node->data);
7981 y = QT_UINT16 ((guint8 *) node->data + 12);
7983 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
7986 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
7988 date = g_date_new_dmy (1, 1, y);
7989 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
7994 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
7995 const char *dummy, GNode * node)
7998 char *tag_str = NULL;
8003 len = QT_UINT32 (node->data);
8008 entity = (guint8 *) node->data + offset;
8009 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
8010 GST_DEBUG_OBJECT (qtdemux,
8011 "classification info: %c%c%c%c invalid classification entity",
8012 entity[0], entity[1], entity[2], entity[3]);
8017 table = QT_UINT16 ((guint8 *) node->data + offset);
8019 /* Language code skipped */
8023 /* Tag format: "XXXX://Y[YYYY]/classification info string"
8024 * XXXX: classification entity, fixed length 4 chars.
8025 * Y[YYYY]: classification table, max 5 chars.
8027 tag_str = g_strdup_printf ("----://%u/%s",
8028 table, (char *) node->data + offset);
8030 /* memcpy To be sure we're preserving byte order */
8031 memcpy (tag_str, entity, 4);
8032 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
8034 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
8044 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
8050 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
8051 const char *dummy, GNode * node)
8053 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8059 gboolean ret = TRUE;
8061 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8063 len = QT_UINT32 (data->data);
8064 type = QT_UINT32 ((guint8 *) data->data + 8);
8065 if (type == 0x00000001 && len > 16) {
8066 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
8069 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
8070 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
8074 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
8078 len = QT_UINT32 (node->data);
8079 type = QT_UINT32 ((guint8 *) node->data + 4);
8080 if ((type >> 24) == 0xa9) {
8081 /* Type starts with the (C) symbol, so the next 32 bits are
8082 * the language code, which we ignore */
8084 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
8085 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
8086 QT_FOURCC ((guint8 *) node->data + 4))) {
8087 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
8089 /* we go for 3GP style encoding if major brands claims so,
8090 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
8091 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8092 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
8093 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
8095 /* 16-bit Language code is ignored here as well */
8096 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
8103 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
8104 ret = FALSE; /* may have to fallback */
8106 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8107 len - offset, env_vars);
8109 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
8110 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
8114 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
8121 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
8122 const char *dummy, GNode * node)
8124 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
8128 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
8129 const char *dummy, GNode * node)
8131 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8133 char *s, *t, *k = NULL;
8138 /* first try normal string tag if major brand not 3GP */
8139 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
8140 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
8141 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
8142 * let's try it 3gpp way after minor safety check */
8144 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
8150 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
8154 len = QT_UINT32 (data);
8158 count = QT_UINT8 (data + 14);
8160 for (; count; count--) {
8163 if (offset + 1 > len)
8165 slen = QT_UINT8 (data + offset);
8167 if (offset + slen > len)
8169 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8172 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
8174 t = g_strjoin (",", k, s, NULL);
8182 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
8189 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
8190 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
8199 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
8205 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
8206 const char *tag2, GNode * node)
8213 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8215 len = QT_UINT32 (data->data);
8216 type = QT_UINT32 ((guint8 *) data->data + 8);
8217 if (type == 0x00000000 && len >= 22) {
8218 n1 = QT_UINT16 ((guint8 *) data->data + 18);
8219 n2 = QT_UINT16 ((guint8 *) data->data + 20);
8221 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
8222 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8226 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
8227 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8235 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8243 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8245 len = QT_UINT32 (data->data);
8246 type = QT_UINT32 ((guint8 *) data->data + 8);
8247 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
8248 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8249 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
8250 n1 = QT_UINT16 ((guint8 *) data->data + 16);
8252 /* do not add bpm=0 */
8253 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
8254 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8255 tag1, (gdouble) n1, NULL);
8262 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
8263 const char *dummy, GNode * node)
8270 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8272 len = QT_UINT32 (data->data);
8273 type = QT_UINT32 ((guint8 *) data->data + 8);
8274 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
8275 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8276 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
8277 num = QT_UINT32 ((guint8 *) data->data + 16);
8279 /* do not add num=0 */
8280 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
8281 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8289 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8297 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8299 len = QT_UINT32 (data->data);
8300 type = QT_UINT32 ((guint8 *) data->data + 8);
8301 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
8302 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
8304 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
8305 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
8306 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
8307 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8308 tag1, sample, NULL);
8309 gst_sample_unref (sample);
8316 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8324 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8326 len = QT_UINT32 (data->data);
8327 type = QT_UINT32 ((guint8 *) data->data + 8);
8328 if (type == 0x00000001 && len > 16) {
8329 guint y, m = 1, d = 1;
8332 s = g_strndup ((char *) data->data + 16, len - 16);
8333 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
8334 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
8335 if (ret >= 1 && y > 1500 && y < 3000) {
8338 date = g_date_new_dmy (d, m, y);
8339 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
8343 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
8351 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8356 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8358 /* re-route to normal string tag if major brand says so
8359 * or no data atom and compatible brand suggests so */
8360 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8361 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
8362 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
8369 len = QT_UINT32 (data->data);
8370 type = QT_UINT32 ((guint8 *) data->data + 8);
8371 if (type == 0x00000000 && len >= 18) {
8372 n = QT_UINT16 ((guint8 *) data->data + 16);
8376 genre = gst_tag_id3_genre_get (n - 1);
8377 if (genre != NULL) {
8378 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
8379 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8388 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
8389 guint8 * data, guint32 datasize)
8394 /* make a copy to have \0 at the end */
8395 datacopy = g_strndup ((gchar *) data, datasize);
8397 /* convert the str to double */
8398 if (sscanf (datacopy, "%lf", &value) == 1) {
8399 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
8400 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
8402 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
8410 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
8411 const char *tag_bis, GNode * node)
8420 const gchar *meanstr;
8421 const gchar *namestr;
8423 /* checking the whole ---- atom size for consistency */
8424 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8425 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8429 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8431 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8435 meansize = QT_UINT32 (mean->data);
8436 if (meansize <= 12) {
8437 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8440 meanstr = ((gchar *) mean->data) + 12;
8442 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8444 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8448 namesize = QT_UINT32 (name->data);
8449 if (namesize <= 12) {
8450 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8453 namestr = ((gchar *) name->data) + 12;
8460 * uint24 - data type
8464 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8466 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8469 datasize = QT_UINT32 (data->data);
8470 if (datasize <= 16) {
8471 GST_WARNING_OBJECT (demux, "Data atom too small");
8474 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8476 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8479 const gchar name[28];
8480 const gchar tag[28];
8483 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8484 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8485 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8486 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8487 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8488 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8489 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8490 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8494 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8495 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8496 switch (gst_tag_get_type (tags[i].tag)) {
8498 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8499 ((guint8 *) data->data) + 16, datasize - 16);
8502 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8511 if (i == G_N_ELEMENTS (tags))
8525 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8526 namestr_dbg = g_strndup (namestr, namesize - 12);
8528 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8529 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8531 g_free (namestr_dbg);
8532 g_free (meanstr_dbg);
8538 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
8539 const char *tag_bis, GNode * node)
8544 GstTagList *taglist = NULL;
8546 GST_LOG_OBJECT (demux, "parsing ID32");
8549 len = GST_READ_UINT32_BE (data);
8551 /* need at least full box and language tag */
8555 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
8556 gst_buffer_fill (buf, 0, data + 14, len - 14);
8558 taglist = gst_tag_list_from_id3v2_tag (buf);
8560 GST_LOG_OBJECT (demux, "parsing ok");
8561 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
8563 GST_LOG_OBJECT (demux, "parsing failed");
8567 gst_tag_list_unref (taglist);
8569 gst_buffer_unref (buf);
8572 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8573 const char *tag, const char *tag_bis, GNode * node);
8576 FOURCC_pcst -> if media is a podcast -> bool
8577 FOURCC_cpil -> if media is part of a compilation -> bool
8578 FOURCC_pgap -> if media is part of a gapless context -> bool
8579 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8585 const gchar *gst_tag;
8586 const gchar *gst_tag_bis;
8587 const GstQTDemuxAddTagFunc func;
8590 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8591 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8592 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8593 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8594 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8595 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8596 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8597 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8598 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8599 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8600 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8601 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8602 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8603 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8604 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8605 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8606 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8607 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8608 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8609 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8610 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8611 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8612 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8613 qtdemux_tag_add_num}, {
8614 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8615 qtdemux_tag_add_num}, {
8616 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8617 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8618 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8619 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8620 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8621 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8622 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8623 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8624 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8625 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8626 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8627 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8628 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8629 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8630 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8631 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8632 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8633 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8634 qtdemux_tag_add_classification}, {
8636 /* This is a special case, some tags are stored in this
8637 * 'reverse dns naming', according to:
8638 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8641 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
8642 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
8643 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
8647 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8660 len = QT_UINT32 (data);
8661 buf = gst_buffer_new_and_alloc (len);
8662 _gst_buffer_copy_into_mem (buf, 0, data, len);
8664 /* heuristic to determine style of tag */
8665 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8666 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8668 else if (demux->major_brand == FOURCC_qt__)
8669 style = "quicktime";
8670 /* fall back to assuming iso/3gp tag style */
8674 /* santize the name for the caps. */
8675 for (i = 0; i < 4; i++) {
8676 guint8 d = data[4 + i];
8677 if (g_ascii_isalnum (d))
8678 ndata[i] = g_ascii_tolower (d);
8683 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8684 ndata[0], ndata[1], ndata[2], ndata[3]);
8685 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8687 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
8688 sample = gst_sample_new (buf, NULL, NULL, s);
8689 gst_buffer_unref (buf);
8690 g_free (media_type);
8692 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
8695 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8696 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
8700 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8708 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8710 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8712 GST_LOG_OBJECT (qtdemux, "no ilst");
8717 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8720 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8721 if (!qtdemux->tag_list) {
8722 qtdemux->tag_list = gst_tag_list_new_empty ();
8723 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
8727 while (i < G_N_ELEMENTS (add_funcs)) {
8728 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8732 len = QT_UINT32 (node->data);
8734 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8735 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8737 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8738 add_funcs[i].gst_tag_bis, node);
8740 g_node_destroy (node);
8746 /* parsed nodes have been removed, pass along remainder as blob */
8747 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8748 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8750 /* parse up XMP_ node if existing */
8751 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8754 GstTagList *taglist;
8756 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
8757 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
8758 taglist = gst_tag_list_from_xmp_buffer (buf);
8759 gst_buffer_unref (buf);
8761 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8763 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8770 GstStructure *structure; /* helper for sort function */
8772 guint min_req_bitrate;
8773 guint min_req_qt_version;
8777 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8779 GstQtReference *ref_a = (GstQtReference *) a;
8780 GstQtReference *ref_b = (GstQtReference *) b;
8782 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8783 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8785 /* known bitrates go before unknown; higher bitrates go first */
8786 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8789 /* sort the redirects and post a message for the application.
8792 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8794 GstQtReference *best;
8797 GValue list_val = { 0, };
8800 g_assert (references != NULL);
8802 references = g_list_sort (references, qtdemux_redirects_sort_func);
8804 best = (GstQtReference *) references->data;
8806 g_value_init (&list_val, GST_TYPE_LIST);
8808 for (l = references; l != NULL; l = l->next) {
8809 GstQtReference *ref = (GstQtReference *) l->data;
8810 GValue struct_val = { 0, };
8812 ref->structure = gst_structure_new ("redirect",
8813 "new-location", G_TYPE_STRING, ref->location, NULL);
8815 if (ref->min_req_bitrate > 0) {
8816 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8817 ref->min_req_bitrate, NULL);
8820 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8821 g_value_set_boxed (&struct_val, ref->structure);
8822 gst_value_list_append_value (&list_val, &struct_val);
8823 g_value_unset (&struct_val);
8824 /* don't free anything here yet, since we need best->structure below */
8827 g_assert (best != NULL);
8828 s = gst_structure_copy (best->structure);
8830 if (g_list_length (references) > 1) {
8831 gst_structure_set_value (s, "locations", &list_val);
8834 g_value_unset (&list_val);
8836 for (l = references; l != NULL; l = l->next) {
8837 GstQtReference *ref = (GstQtReference *) l->data;
8839 gst_structure_free (ref->structure);
8840 g_free (ref->location);
8843 g_list_free (references);
8845 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8846 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8847 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8848 qtdemux->posted_redirect = TRUE;
8851 /* look for redirect nodes, collect all redirect information and
8855 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8857 GNode *rmra, *rmda, *rdrf;
8859 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8861 GList *redirects = NULL;
8863 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8865 GstQtReference ref = { NULL, NULL, 0, 0 };
8868 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8869 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8870 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8871 ref.min_req_bitrate);
8874 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
8875 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
8876 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
8878 #ifndef GST_DISABLE_GST_DEBUG
8879 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
8881 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
8883 GST_LOG_OBJECT (qtdemux,
8884 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
8885 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
8886 bitmask, check_type);
8887 if (package == FOURCC_qtim && check_type == 0) {
8888 ref.min_req_qt_version = version;
8892 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
8897 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
8898 ref_data = (guint8 *) rdrf->data + 20;
8899 if (ref_type == FOURCC_alis) {
8900 guint record_len, record_version, fn_len;
8902 /* MacOSX alias record, google for alias-layout.txt */
8903 record_len = QT_UINT16 (ref_data + 4);
8904 record_version = QT_UINT16 (ref_data + 4 + 2);
8905 fn_len = QT_UINT8 (ref_data + 50);
8906 if (record_len > 50 && record_version == 2 && fn_len > 0) {
8907 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
8909 } else if (ref_type == FOURCC_url_) {
8910 ref.location = g_strdup ((gchar *) ref_data);
8912 GST_DEBUG_OBJECT (qtdemux,
8913 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
8914 GST_FOURCC_ARGS (ref_type));
8916 if (ref.location != NULL) {
8917 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
8918 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
8920 GST_WARNING_OBJECT (qtdemux,
8921 "Failed to extract redirect location from rdrf atom");
8925 /* look for others */
8926 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
8929 if (redirects != NULL) {
8930 qtdemux_process_redirects (qtdemux, redirects);
8937 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
8942 tags = gst_tag_list_new_empty ();
8943 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
8946 if (qtdemux->major_brand == FOURCC_mjp2)
8947 fmt = "Motion JPEG 2000";
8948 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
8950 else if (qtdemux->major_brand == FOURCC_qt__)
8952 else if (qtdemux->fragmented)
8955 fmt = "ISO MP4/M4A";
8957 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
8958 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
8960 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
8966 /* we have read th complete moov node now.
8967 * This function parses all of the relevant info, creates the traks and
8968 * prepares all data structures for playback
8971 qtdemux_parse_tree (GstQTDemux * qtdemux)
8978 guint64 creation_time;
8979 GstDateTime *datetime = NULL;
8982 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
8984 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
8985 return qtdemux_parse_redirects (qtdemux);
8988 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
8990 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
8991 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
8992 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
8993 } else if (version == 0) {
8994 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
8995 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
8996 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
8998 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
9002 /* Moving qt creation time (secs since 1904) to unix time */
9003 if (creation_time != 0) {
9004 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
9007 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
9008 /* some data cleansing sanity */
9009 g_get_current_time (&now);
9010 if (now.tv_sec + 24 * 3600 < creation_time) {
9011 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
9013 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
9016 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
9017 "please file a bug at http://bugzilla.gnome.org");
9021 if (!qtdemux->tag_list) {
9022 qtdemux->tag_list = gst_tag_list_new_empty ();
9023 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
9026 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
9027 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
9029 gst_date_time_unref (datetime);
9032 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
9033 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
9035 /* check for fragmented file and get some (default) data */
9036 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
9039 GstByteReader mehd_data;
9041 /* let track parsing or anyone know weird stuff might happen ... */
9042 qtdemux->fragmented = TRUE;
9044 /* compensate for total duration */
9045 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
9047 qtdemux_parse_mehd (qtdemux, &mehd_data);
9050 /* set duration in the segment info */
9051 gst_qtdemux_get_duration (qtdemux, &duration);
9053 qtdemux->segment.duration = duration;
9054 /* also do not exceed duration; stop is set that way post seek anyway,
9055 * and segment activation falls back to duration,
9056 * whereas loop only checks stop, so let's align this here as well */
9057 qtdemux->segment.stop = duration;
9060 /* parse all traks */
9061 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
9063 qtdemux_parse_trak (qtdemux, trak);
9064 /* iterate all siblings */
9065 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
9069 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
9071 qtdemux_parse_udta (qtdemux, udta);
9073 GST_LOG_OBJECT (qtdemux, "No udta node found.");
9076 /* maybe also some tags in meta box */
9077 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
9079 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
9080 qtdemux_parse_udta (qtdemux, udta);
9082 GST_LOG_OBJECT (qtdemux, "No meta node found.");
9085 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
9090 /* taken from ffmpeg */
9092 get_size (guint8 * ptr, guint8 ** end)
9101 len = (len << 7) | (c & 0x7f);
9110 /* this can change the codec originally present in @list */
9112 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
9113 GNode * esds, GstTagList * list)
9115 int len = QT_UINT32 (esds->data);
9116 guint8 *ptr = esds->data;
9117 guint8 *end = ptr + len;
9119 guint8 *data_ptr = NULL;
9121 guint8 object_type_id = 0;
9122 const char *codec_name = NULL;
9123 GstCaps *caps = NULL;
9125 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
9127 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
9130 tag = QT_UINT8 (ptr);
9131 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
9133 len = get_size (ptr, &ptr);
9134 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
9138 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
9139 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
9143 guint max_bitrate, avg_bitrate;
9145 object_type_id = QT_UINT8 (ptr);
9146 max_bitrate = QT_UINT32 (ptr + 5);
9147 avg_bitrate = QT_UINT32 (ptr + 9);
9148 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
9149 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
9150 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
9151 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
9152 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
9153 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9154 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9155 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9157 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9158 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
9165 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
9171 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
9175 GST_ERROR_OBJECT (qtdemux, "parse error");
9180 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
9181 * in use, and should also be used to override some other parameters for some
9183 switch (object_type_id) {
9184 case 0x20: /* MPEG-4 */
9185 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
9186 * profile_and_level_indication */
9187 if (data_ptr != NULL && data_len >= 5 &&
9188 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
9189 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
9190 data_ptr + 4, data_len - 4);
9192 break; /* Nothing special needed here */
9193 case 0x21: /* H.264 */
9194 codec_name = "H.264 / AVC";
9195 caps = gst_caps_new_simple ("video/x-h264",
9196 "stream-format", G_TYPE_STRING, "avc",
9197 "alignment", G_TYPE_STRING, "au", NULL);
9199 case 0x40: /* AAC (any) */
9200 case 0x66: /* AAC Main */
9201 case 0x67: /* AAC LC */
9202 case 0x68: /* AAC SSR */
9203 /* Override channels and rate based on the codec_data, as it's often
9205 /* Only do so for basic setup without HE-AAC extension */
9206 if (data_ptr && data_len == 2) {
9207 guint channels, rateindex, rate;
9209 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
9210 channels = (data_ptr[1] & 0x7f) >> 3;
9211 if (channels > 0 && channels < 7) {
9212 stream->n_channels = channels;
9213 } else if (channels == 7) {
9214 stream->n_channels = 8;
9217 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
9218 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
9220 stream->rate = rate;
9223 /* Set level and profile if possible */
9224 if (data_ptr != NULL && data_len >= 2) {
9225 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
9226 data_ptr, data_len);
9229 case 0x60: /* MPEG-2, various profiles */
9235 codec_name = "MPEG-2 video";
9237 gst_caps_unref (stream->caps);
9238 stream->caps = gst_caps_new_simple ("video/mpeg",
9239 "mpegversion", G_TYPE_INT, 2,
9240 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9242 case 0x69: /* MP3 has two different values, accept either */
9244 /* change to mpeg1 layer 3 audio */
9245 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
9246 "mpegversion", G_TYPE_INT, 1, NULL);
9247 codec_name = "MPEG-1 layer 3";
9249 case 0x6A: /* MPEG-1 */
9250 codec_name = "MPEG-1 video";
9252 gst_caps_unref (stream->caps);
9253 stream->caps = gst_caps_new_simple ("video/mpeg",
9254 "mpegversion", G_TYPE_INT, 1,
9255 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9257 case 0x6C: /* MJPEG */
9258 caps = gst_caps_new_empty_simple ("image/jpeg");
9259 codec_name = "Motion-JPEG";
9261 case 0x6D: /* PNG */
9262 caps = gst_caps_new_empty_simple ("image/png");
9263 codec_name = "PNG still images";
9265 case 0x6E: /* JPEG2000 */
9266 codec_name = "JPEG-2000";
9267 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9269 case 0xA4: /* Dirac */
9270 codec_name = "Dirac";
9271 caps = gst_caps_new_empty_simple ("video/x-dirac");
9273 case 0xA5: /* AC3 */
9274 codec_name = "AC-3 audio";
9275 caps = gst_caps_new_simple ("audio/x-ac3",
9276 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9278 case 0xE1: /* QCELP */
9279 /* QCELP, the codec_data is a riff tag (little endian) with
9280 * 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). */
9281 caps = gst_caps_new_empty_simple ("audio/qcelp");
9282 codec_name = "QCELP";
9288 /* If we have a replacement caps, then change our caps for this stream */
9290 gst_caps_unref (stream->caps);
9291 stream->caps = caps;
9294 if (codec_name && list)
9295 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9296 GST_TAG_AUDIO_CODEC, codec_name, NULL);
9298 /* Add the codec_data attribute to caps, if we have it */
9302 buffer = gst_buffer_new_and_alloc (data_len);
9303 _gst_buffer_copy_into_mem (buffer, 0, data_ptr, data_len);
9305 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
9306 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
9308 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
9310 gst_buffer_unref (buffer);
9315 #define _codec(name) \
9318 *codec_name = g_strdup (name); \
9323 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9324 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9327 const GstStructure *s;
9331 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
9332 _codec ("PNG still images");
9333 caps = gst_caps_new_empty_simple ("image/png");
9335 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
9336 _codec ("JPEG still images");
9337 caps = gst_caps_new_empty_simple ("image/jpeg");
9339 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
9340 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
9341 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
9342 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
9343 _codec ("Motion-JPEG");
9344 caps = gst_caps_new_empty_simple ("image/jpeg");
9346 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
9347 _codec ("Motion-JPEG format B");
9348 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
9350 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
9351 _codec ("JPEG-2000");
9352 /* override to what it should be according to spec, avoid palette_data */
9353 stream->bits_per_sample = 24;
9354 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9356 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
9357 _codec ("Sorensen video v.3");
9358 caps = gst_caps_new_simple ("video/x-svq",
9359 "svqversion", G_TYPE_INT, 3, NULL);
9361 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
9362 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
9363 _codec ("Sorensen video v.1");
9364 caps = gst_caps_new_simple ("video/x-svq",
9365 "svqversion", G_TYPE_INT, 1, NULL);
9367 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9371 _codec ("Raw RGB video");
9372 bps = QT_UINT16 (stsd_data + 98);
9373 /* set common stuff */
9374 caps = gst_caps_new_empty_simple ("video/x-raw");
9378 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB15", NULL);
9381 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB16", NULL);
9384 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB", NULL);
9387 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "ARGB", NULL);
9395 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
9396 _codec ("Raw planar YUV 4:2:0");
9397 caps = gst_caps_new_simple ("video/x-raw",
9398 "format", G_TYPE_STRING, "I420", NULL);
9400 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
9401 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
9402 _codec ("Raw packed YUV 4:2:2");
9403 caps = gst_caps_new_simple ("video/x-raw",
9404 "format", G_TYPE_STRING, "YUY2", NULL);
9406 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
9407 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
9408 _codec ("Raw packed YUV 4:2:2");
9409 caps = gst_caps_new_simple ("video/x-raw",
9410 "format", G_TYPE_STRING, "UYVY", NULL);
9412 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
9413 _codec ("Raw packed YUV 10-bit 4:2:2");
9414 caps = gst_caps_new_simple ("video/x-raw",
9415 "format", G_TYPE_STRING, "v210", NULL);
9417 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
9418 _codec ("Raw packed RGB 10-bit 4:4:4");
9419 caps = gst_caps_new_simple ("video/x-raw",
9420 "format", G_TYPE_STRING, "r210", NULL);
9422 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
9423 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
9424 _codec ("MPEG-1 video");
9425 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9426 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9428 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
9429 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
9430 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
9431 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
9432 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
9433 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
9434 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
9435 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
9436 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
9437 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
9438 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
9439 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
9440 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
9441 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
9442 _codec ("MPEG-2 video");
9443 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
9444 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9446 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
9447 _codec ("GIF still images");
9448 caps = gst_caps_new_empty_simple ("image/gif");
9450 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
9451 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
9452 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
9453 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9455 /* ffmpeg uses the height/width props, don't know why */
9456 caps = gst_caps_new_empty_simple ("video/x-h263");
9458 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9459 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9460 _codec ("MPEG-4 video");
9461 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9462 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9464 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9465 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9466 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9467 caps = gst_caps_new_simple ("video/x-msmpeg",
9468 "msmpegversion", G_TYPE_INT, 43, NULL);
9470 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9472 caps = gst_caps_new_simple ("video/x-divx",
9473 "divxversion", G_TYPE_INT, 3, NULL);
9475 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9476 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9478 caps = gst_caps_new_simple ("video/x-divx",
9479 "divxversion", G_TYPE_INT, 4, NULL);
9481 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9483 caps = gst_caps_new_simple ("video/x-divx",
9484 "divxversion", G_TYPE_INT, 5, NULL);
9487 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9488 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9489 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9490 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9491 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9492 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9493 caps = gst_caps_new_simple ("video/mpeg",
9494 "mpegversion", G_TYPE_INT, 4, NULL);
9496 *codec_name = g_strdup ("MPEG-4");
9499 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9501 caps = gst_caps_new_empty_simple ("video/x-cinepak");
9503 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9504 _codec ("Apple QuickDraw");
9505 caps = gst_caps_new_empty_simple ("video/x-qdrw");
9507 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9508 _codec ("Apple video");
9509 caps = gst_caps_new_empty_simple ("video/x-apple-video");
9511 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9512 _codec ("H.264 / AVC");
9513 caps = gst_caps_new_simple ("video/x-h264",
9514 "stream-format", G_TYPE_STRING, "avc",
9515 "alignment", G_TYPE_STRING, "au", NULL);
9517 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9518 _codec ("Run-length encoding");
9519 caps = gst_caps_new_simple ("video/x-rle",
9520 "layout", G_TYPE_STRING, "quicktime", NULL);
9522 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9523 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9524 _codec ("Indeo Video 3");
9525 caps = gst_caps_new_simple ("video/x-indeo",
9526 "indeoversion", G_TYPE_INT, 3, NULL);
9528 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9529 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9530 _codec ("Intel Video 4");
9531 caps = gst_caps_new_simple ("video/x-indeo",
9532 "indeoversion", G_TYPE_INT, 4, NULL);
9534 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9535 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9536 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9537 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9538 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9539 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9540 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9541 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9542 _codec ("DV Video");
9543 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9544 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9546 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9547 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9548 _codec ("DVCPro50 Video");
9549 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9550 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9552 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9553 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9554 _codec ("DVCProHD Video");
9555 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9556 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9558 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9559 _codec ("Apple Graphics (SMC)");
9560 caps = gst_caps_new_empty_simple ("video/x-smc");
9562 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9564 caps = gst_caps_new_empty_simple ("video/x-vp3");
9566 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9568 caps = gst_caps_new_empty_simple ("video/x-theora");
9569 /* theora uses one byte of padding in the data stream because it does not
9570 * allow 0 sized packets while theora does */
9571 stream->padding = 1;
9573 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9575 caps = gst_caps_new_empty_simple ("video/x-dirac");
9577 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9578 _codec ("TIFF still images");
9579 caps = gst_caps_new_empty_simple ("image/tiff");
9581 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9582 _codec ("Apple Intermediate Codec");
9583 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9585 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9586 _codec ("AVID DNxHD");
9587 caps = gst_caps_from_string ("video/x-dnxhd");
9589 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9591 caps = gst_caps_from_string ("video/x-vp8");
9593 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
9594 _codec ("Apple ProRes LT");
9596 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
9599 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
9600 _codec ("Apple ProRes HQ");
9602 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
9605 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
9606 _codec ("Apple ProRes");
9608 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
9611 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
9612 _codec ("Apple ProRes Proxy");
9614 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
9617 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
9618 _codec ("Apple ProRes 4444");
9620 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
9625 caps = gst_caps_new_simple ("video/x-wmv",
9626 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
9628 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9631 char *s, fourstr[5];
9633 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9634 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
9635 caps = gst_caps_new_empty_simple (s);
9640 /* enable clipping for raw video streams */
9641 s = gst_caps_get_structure (caps, 0);
9642 name = gst_structure_get_name (s);
9643 if (g_str_has_prefix (name, "video/x-raw")) {
9644 stream->need_clip = TRUE;
9650 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9651 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9654 const GstStructure *s;
9658 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9661 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9662 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9663 _codec ("Raw 8-bit PCM audio");
9664 caps = gst_caps_new_simple ("audio/x-raw",
9665 "format", G_TYPE_STRING, "U8",
9666 "layout", G_TYPE_STRING, "interleaved", NULL);
9668 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9669 endian = G_BIG_ENDIAN;
9671 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9675 GstAudioFormat format;
9678 endian = G_LITTLE_ENDIAN;
9680 depth = stream->bytes_per_packet * 8;
9681 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
9683 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9687 caps = gst_caps_new_simple ("audio/x-raw",
9688 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
9689 "layout", G_TYPE_STRING, "interleaved", NULL);
9692 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9693 _codec ("Raw 64-bit floating-point audio");
9694 caps = gst_caps_new_simple ("audio/x-raw",
9695 "format", G_TYPE_STRING, "F64BE",
9696 "layout", G_TYPE_STRING, "interleaved", NULL);
9698 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9699 _codec ("Raw 32-bit floating-point audio");
9700 caps = gst_caps_new_simple ("audio/x-raw",
9701 "format", G_TYPE_STRING, "F32BE",
9702 "layout", G_TYPE_STRING, "interleaved", NULL);
9705 _codec ("Raw 24-bit PCM audio");
9706 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9708 caps = gst_caps_new_simple ("audio/x-raw",
9709 "format", G_TYPE_STRING, "S24BE",
9710 "layout", G_TYPE_STRING, "interleaved", NULL);
9712 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9713 _codec ("Raw 32-bit PCM audio");
9714 caps = gst_caps_new_simple ("audio/x-raw",
9715 "format", G_TYPE_STRING, "S32BE",
9716 "layout", G_TYPE_STRING, "interleaved", NULL);
9718 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9719 _codec ("Mu-law audio");
9720 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
9722 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9723 _codec ("A-law audio");
9724 caps = gst_caps_new_empty_simple ("audio/x-alaw");
9728 _codec ("Microsoft ADPCM");
9729 /* Microsoft ADPCM-ACM code 2 */
9730 caps = gst_caps_new_simple ("audio/x-adpcm",
9731 "layout", G_TYPE_STRING, "microsoft", NULL);
9735 _codec ("DVI/IMA ADPCM");
9736 caps = gst_caps_new_simple ("audio/x-adpcm",
9737 "layout", G_TYPE_STRING, "dvi", NULL);
9741 _codec ("DVI/Intel IMA ADPCM");
9742 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9743 caps = gst_caps_new_simple ("audio/x-adpcm",
9744 "layout", G_TYPE_STRING, "quicktime", NULL);
9748 /* MPEG layer 3, CBR only (pre QT4.1) */
9749 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9750 _codec ("MPEG-1 layer 3");
9751 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9752 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9753 "mpegversion", G_TYPE_INT, 1, NULL);
9756 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9757 _codec ("EAC-3 audio");
9758 caps = gst_caps_new_simple ("audio/x-eac3",
9759 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9760 stream->sampled = TRUE;
9762 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9763 _codec ("AC-3 audio");
9764 caps = gst_caps_new_simple ("audio/x-ac3",
9765 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9766 stream->sampled = TRUE;
9768 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9770 caps = gst_caps_new_simple ("audio/x-mace",
9771 "maceversion", G_TYPE_INT, 3, NULL);
9773 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9775 caps = gst_caps_new_simple ("audio/x-mace",
9776 "maceversion", G_TYPE_INT, 6, NULL);
9778 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9780 caps = gst_caps_new_empty_simple ("application/ogg");
9782 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9783 _codec ("DV audio");
9784 caps = gst_caps_new_empty_simple ("audio/x-dv");
9786 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9787 _codec ("MPEG-4 AAC audio");
9788 caps = gst_caps_new_simple ("audio/mpeg",
9789 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9790 "stream-format", G_TYPE_STRING, "raw", NULL);
9792 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9793 _codec ("QDesign Music");
9794 caps = gst_caps_new_empty_simple ("audio/x-qdm");
9796 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9797 _codec ("QDesign Music v.2");
9798 /* FIXME: QDesign music version 2 (no constant) */
9800 caps = gst_caps_new_simple ("audio/x-qdm2",
9801 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9802 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9803 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9805 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
9808 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9809 _codec ("GSM audio");
9810 caps = gst_caps_new_empty_simple ("audio/x-gsm");
9812 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9813 _codec ("AMR audio");
9814 caps = gst_caps_new_empty_simple ("audio/AMR");
9816 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9817 _codec ("AMR-WB audio");
9818 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
9820 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9821 _codec ("Quicktime IMA ADPCM");
9822 caps = gst_caps_new_simple ("audio/x-adpcm",
9823 "layout", G_TYPE_STRING, "quicktime", NULL);
9825 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9826 _codec ("Apple lossless audio");
9827 caps = gst_caps_new_empty_simple ("audio/x-alac");
9829 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9830 _codec ("QualComm PureVoice");
9831 caps = gst_caps_from_string ("audio/qcelp");
9835 caps = gst_caps_new_empty_simple ("audio/x-wma");
9837 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
9841 char *s, fourstr[5];
9843 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9844 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
9845 caps = gst_caps_new_empty_simple (s);
9851 GstCaps *templ_caps =
9852 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
9853 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
9854 gst_caps_unref (caps);
9855 gst_caps_unref (templ_caps);
9856 caps = intersection;
9859 /* enable clipping for raw audio streams */
9860 s = gst_caps_get_structure (caps, 0);
9861 name = gst_structure_get_name (s);
9862 if (g_str_has_prefix (name, "audio/x-raw")) {
9863 stream->need_clip = TRUE;
9869 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9870 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9874 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9877 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
9878 _codec ("DVD subtitle");
9879 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
9881 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
9882 _codec ("Quicktime timed text");
9884 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
9885 _codec ("3GPP timed text");
9887 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
9889 /* actual text piece needs to be extracted */
9890 stream->need_process = TRUE;
9894 char *s, fourstr[5];
9896 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9897 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
9898 caps = gst_caps_new_empty_simple (s);
9906 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9907 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9912 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
9913 _codec ("MPEG 1 video");
9914 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9915 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);