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;
7051 /* sample description entry (16) + sound sample description v0 (20) */
7055 version = QT_UINT32 (stsd_data + offset);
7056 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
7057 samplesize = QT_UINT16 (stsd_data + offset + 10);
7058 compression_id = QT_UINT16 (stsd_data + offset + 12);
7059 stream->rate = QT_FP32 (stsd_data + offset + 16);
7061 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
7062 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
7063 QT_UINT32 (stsd_data + offset + 4));
7064 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7065 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
7066 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
7067 GST_LOG_OBJECT (qtdemux, "packet size: %d",
7068 QT_UINT16 (stsd_data + offset + 14));
7069 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7071 if (compression_id == 0xfffe)
7072 stream->sampled = TRUE;
7074 /* first assume uncompressed audio */
7075 stream->bytes_per_sample = samplesize / 8;
7076 stream->samples_per_frame = stream->n_channels;
7077 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
7078 stream->samples_per_packet = stream->samples_per_frame;
7079 stream->bytes_per_packet = stream->bytes_per_sample;
7083 /* Yes, these have to be hard-coded */
7086 stream->samples_per_packet = 6;
7087 stream->bytes_per_packet = 1;
7088 stream->bytes_per_frame = 1 * stream->n_channels;
7089 stream->bytes_per_sample = 1;
7090 stream->samples_per_frame = 6 * stream->n_channels;
7095 stream->samples_per_packet = 3;
7096 stream->bytes_per_packet = 1;
7097 stream->bytes_per_frame = 1 * stream->n_channels;
7098 stream->bytes_per_sample = 1;
7099 stream->samples_per_frame = 3 * stream->n_channels;
7104 stream->samples_per_packet = 64;
7105 stream->bytes_per_packet = 34;
7106 stream->bytes_per_frame = 34 * stream->n_channels;
7107 stream->bytes_per_sample = 2;
7108 stream->samples_per_frame = 64 * stream->n_channels;
7114 stream->samples_per_packet = 1;
7115 stream->bytes_per_packet = 1;
7116 stream->bytes_per_frame = 1 * stream->n_channels;
7117 stream->bytes_per_sample = 1;
7118 stream->samples_per_frame = 1 * stream->n_channels;
7123 stream->samples_per_packet = 160;
7124 stream->bytes_per_packet = 33;
7125 stream->bytes_per_frame = 33 * stream->n_channels;
7126 stream->bytes_per_sample = 2;
7127 stream->samples_per_frame = 160 * stream->n_channels;
7134 if (version == 0x00010000) {
7135 /* sample description entry (16) + sound sample description v1 (20+16) */
7146 /* only parse extra decoding config for non-pcm audio */
7147 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7148 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
7149 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
7150 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
7152 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7153 stream->samples_per_packet);
7154 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7155 stream->bytes_per_packet);
7156 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
7157 stream->bytes_per_frame);
7158 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
7159 stream->bytes_per_sample);
7161 if (!stream->sampled && stream->bytes_per_packet) {
7162 stream->samples_per_frame = (stream->bytes_per_frame /
7163 stream->bytes_per_packet) * stream->samples_per_packet;
7164 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
7165 stream->samples_per_frame);
7170 } else if (version == 0x00020000) {
7177 /* sample description entry (16) + sound sample description v2 (56) */
7181 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
7182 stream->rate = qtfp.fp;
7183 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
7185 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
7186 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7187 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7188 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
7189 QT_UINT32 (stsd_data + offset + 20));
7190 GST_LOG_OBJECT (qtdemux, "format flags: %X",
7191 QT_UINT32 (stsd_data + offset + 24));
7192 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7193 QT_UINT32 (stsd_data + offset + 28));
7194 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
7195 QT_UINT32 (stsd_data + offset + 32));
7197 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
7200 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
7201 stsd_data + 32, len - 16, &codec);
7209 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
7211 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
7213 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
7215 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
7218 gst_caps_set_simple (stream->caps,
7219 "format", G_TYPE_STRING, "S24LE", NULL);
7226 const guint8 *owma_data;
7227 const gchar *codec_name = NULL;
7231 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
7232 /* FIXME this should also be gst_riff_strf_auds,
7233 * but the latter one is actually missing bits-per-sample :( */
7238 gint32 nSamplesPerSec;
7239 gint32 nAvgBytesPerSec;
7241 gint16 wBitsPerSample;
7246 GST_DEBUG_OBJECT (qtdemux, "parse owma");
7247 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
7250 owma_data = owma->data;
7251 owma_len = QT_UINT32 (owma_data);
7252 if (owma_len <= 54) {
7253 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
7256 wfex = (WAVEFORMATEX *) (owma_data + 36);
7257 buf = gst_buffer_new_and_alloc (owma_len - 54);
7258 _gst_buffer_copy_into_mem (buf, 0, owma_data + 54, owma_len - 54);
7259 if (wfex->wFormatTag == 0x0161) {
7260 codec_name = "Windows Media Audio";
7262 } else if (wfex->wFormatTag == 0x0162) {
7263 codec_name = "Windows Media Audio 9 Pro";
7265 } else if (wfex->wFormatTag == 0x0163) {
7266 codec_name = "Windows Media Audio 9 Lossless";
7267 /* is that correct? gstffmpegcodecmap.c is missing it, but
7268 * fluendo codec seems to support it */
7272 gst_caps_set_simple (stream->caps,
7273 "codec_data", GST_TYPE_BUFFER, buf,
7274 "wmaversion", G_TYPE_INT, version,
7275 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
7276 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
7277 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7278 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7280 gst_buffer_unref (buf);
7284 codec = g_strdup (codec_name);
7296 list = gst_tag_list_new_empty ();
7297 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7298 GST_TAG_AUDIO_CODEC, codec, NULL);
7302 /* some bitrate info may have ended up in caps */
7303 s = gst_caps_get_structure (stream->caps, 0);
7304 gst_structure_get_int (s, "bitrate", &bitrate);
7306 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7310 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7314 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7316 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7318 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7322 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7323 16 bits is a byte-swapped wave-style codec identifier,
7324 and we can find a WAVE header internally to a 'wave' atom here.
7325 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7326 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7329 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7330 if (len < offset + 20) {
7331 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7333 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7334 const guint8 *data = stsd_data + offset + 16;
7336 GNode *waveheadernode;
7338 wavenode = g_node_new ((guint8 *) data);
7339 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7340 const guint8 *waveheader;
7343 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7344 if (waveheadernode) {
7345 waveheader = (const guint8 *) waveheadernode->data;
7346 headerlen = QT_UINT32 (waveheader);
7348 if (headerlen > 8) {
7349 gst_riff_strf_auds *header = NULL;
7350 GstBuffer *headerbuf;
7356 headerbuf = gst_buffer_new_and_alloc (headerlen);
7357 _gst_buffer_copy_into_mem (headerbuf, 0, waveheader, headerlen);
7359 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7360 headerbuf, &header, &extra)) {
7361 gst_caps_unref (stream->caps);
7362 /* FIXME: Need to do something with the channel reorder map */
7363 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7364 header, extra, NULL, NULL, NULL);
7367 gst_buffer_unref (extra);
7372 GST_DEBUG ("Didn't find waveheadernode for this codec");
7374 g_node_destroy (wavenode);
7377 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7381 /* FIXME: what is in the chunk? */
7384 gint len = QT_UINT32 (stsd_data);
7386 /* seems to be always = 116 = 0x74 */
7392 gint len = QT_UINT32 (stsd_data);
7395 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7397 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x4C, len - 0x4C);
7398 gst_caps_set_simple (stream->caps,
7399 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7400 gst_buffer_unref (buf);
7402 gst_caps_set_simple (stream->caps,
7403 "samplesize", G_TYPE_INT, samplesize, NULL);
7408 GNode *alac, *wave = NULL;
7410 /* apparently, m4a has this atom appended directly in the stsd entry,
7411 * while mov has it in a wave atom */
7412 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7414 /* alac now refers to stsd entry atom */
7415 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7417 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7419 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7422 gint len = QT_UINT32 (alac->data);
7426 GST_DEBUG_OBJECT (qtdemux,
7427 "discarding alac atom with unexpected len %d", len);
7429 /* codec-data contains alac atom size and prefix,
7430 * ffmpeg likes it that way, not quite gst-ish though ...*/
7431 buf = gst_buffer_new_and_alloc (len);
7432 _gst_buffer_copy_into_mem (buf, 0, alac->data, len);
7433 gst_caps_set_simple (stream->caps,
7434 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7435 gst_buffer_unref (buf);
7438 gst_caps_set_simple (stream->caps,
7439 "samplesize", G_TYPE_INT, samplesize, NULL);
7447 gint len = QT_UINT32 (stsd_data);
7450 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7453 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x34, len - 0x34);
7455 /* If we have enough data, let's try to get the 'damr' atom. See
7456 * the 3GPP container spec (26.244) for more details. */
7457 if ((len - 0x34) > 8 &&
7458 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
7460 list = gst_tag_list_new_empty ();
7461 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7462 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
7465 gst_caps_set_simple (stream->caps,
7466 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7467 gst_buffer_unref (buf);
7475 GST_INFO_OBJECT (qtdemux,
7476 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7477 GST_FOURCC_ARGS (fourcc), stream->caps);
7479 } else if (stream->subtype == FOURCC_strm) {
7480 if (fourcc == FOURCC_rtsp) {
7481 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7483 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7484 GST_FOURCC_ARGS (fourcc));
7485 goto unknown_stream;
7487 stream->sampled = TRUE;
7488 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
7490 stream->sampled = TRUE;
7495 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7497 list = gst_tag_list_new_empty ();
7498 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7499 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7504 /* hunt for sort-of codec data */
7511 /* look for palette */
7512 /* target mp4s atom */
7513 len = QT_UINT32 (stsd_data + offset);
7514 data = stsd_data + offset;
7515 /* verify sufficient length,
7516 * and esds present with decConfigDescr of expected size and position */
7517 if ((len >= 106 + 8)
7518 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7519 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7524 /* move to decConfigDescr data */
7525 data = data + 8 + 42;
7526 for (i = 0; i < 16; i++) {
7527 clut[i] = QT_UINT32 (data);
7531 s = gst_structure_new ("application/x-gst-dvd", "event",
7532 G_TYPE_STRING, "dvd-spu-clut-change",
7533 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7534 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7535 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7536 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7537 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7538 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7539 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7540 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7543 /* store event and trigger custom processing */
7544 stream->pending_event =
7545 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7546 stream->need_process = TRUE;
7554 /* everything in 1 sample */
7555 stream->sampled = TRUE;
7558 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7560 if (stream->caps == NULL)
7561 goto unknown_stream;
7564 list = gst_tag_list_new_empty ();
7565 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7566 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7572 /* promote to sampled format */
7573 if (stream->fourcc == FOURCC_samr) {
7574 /* force mono 8000 Hz for AMR */
7575 stream->sampled = TRUE;
7576 stream->n_channels = 1;
7577 stream->rate = 8000;
7578 } else if (stream->fourcc == FOURCC_sawb) {
7579 /* force mono 16000 Hz for AMR-WB */
7580 stream->sampled = TRUE;
7581 stream->n_channels = 1;
7582 stream->rate = 16000;
7583 } else if (stream->fourcc == FOURCC_mp4a) {
7584 stream->sampled = TRUE;
7587 /* collect sample information */
7588 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7589 goto samples_failed;
7591 if (qtdemux->fragmented) {
7595 /* need all moov samples as basis; probably not many if any at all */
7596 /* prevent moof parsing taking of at this time */
7597 offset = qtdemux->moof_offset;
7598 qtdemux->moof_offset = 0;
7599 if (stream->n_samples &&
7600 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7601 qtdemux->moof_offset = offset;
7602 goto samples_failed;
7604 qtdemux->moof_offset = 0;
7605 /* movie duration more reliable in this case (e.g. mehd) */
7606 if (qtdemux->segment.duration &&
7607 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7608 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7609 stream->timescale, GST_SECOND);
7610 /* need defaults for fragments */
7611 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7614 /* configure segments */
7615 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7616 goto segments_failed;
7618 /* add some language tag, if useful */
7619 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7620 strcmp (stream->lang_id, "und")) {
7621 const gchar *lang_code;
7624 list = gst_tag_list_new_empty ();
7626 /* convert ISO 639-2 code to ISO 639-1 */
7627 lang_code = gst_tag_get_language_code (stream->lang_id);
7628 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7629 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7632 /* now we are ready to add the stream */
7633 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7634 goto too_many_streams;
7636 stream->pending_tags = list;
7637 qtdemux->streams[qtdemux->n_streams] = stream;
7638 qtdemux->n_streams++;
7639 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7646 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7647 (_("This file is corrupt and cannot be played.")), (NULL));
7653 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7660 /* we posted an error already */
7661 /* free stbl sub-atoms */
7662 gst_qtdemux_stbl_free (stream);
7668 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7669 GST_FOURCC_ARGS (stream->subtype));
7675 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7676 (_("This file contains too many streams. Only playing first %d"),
7677 GST_QTDEMUX_MAX_STREAMS), (NULL));
7682 /* If we can estimate the overall bitrate, and don't have information about the
7683 * stream bitrate for exactly one stream, this guesses the stream bitrate as
7684 * the overall bitrate minus the sum of the bitrates of all other streams. This
7685 * should be useful for the common case where we have one audio and one video
7686 * stream and can estimate the bitrate of one, but not the other. */
7688 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
7690 QtDemuxStream *stream = NULL;
7691 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
7695 if (qtdemux->fragmented)
7698 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
7700 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
7702 GST_DEBUG_OBJECT (qtdemux,
7703 "Size in bytes of the stream not known - bailing");
7707 /* Subtract the header size */
7708 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
7709 size, qtdemux->header_size);
7711 if (size < qtdemux->header_size)
7714 size = size - qtdemux->header_size;
7716 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
7717 duration == GST_CLOCK_TIME_NONE) {
7718 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
7722 for (i = 0; i < qtdemux->n_streams; i++) {
7723 switch (qtdemux->streams[i]->subtype) {
7726 /* retrieve bitrate, prefer avg then max */
7728 if (qtdemux->streams[i]->pending_tags) {
7729 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7730 GST_TAG_MAXIMUM_BITRATE, &bitrate);
7731 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7732 GST_TAG_BITRATE, &bitrate);
7735 sum_bitrate += bitrate;
7738 GST_DEBUG_OBJECT (qtdemux,
7739 ">1 stream with unknown bitrate - bailing");
7742 stream = qtdemux->streams[i];
7746 /* For other subtypes, we assume no significant impact on bitrate */
7752 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
7756 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
7758 if (sys_bitrate < sum_bitrate) {
7759 /* This can happen, since sum_bitrate might be derived from maximum
7760 * bitrates and not average bitrates */
7761 GST_DEBUG_OBJECT (qtdemux,
7762 "System bitrate less than sum bitrate - bailing");
7766 bitrate = sys_bitrate - sum_bitrate;
7767 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
7768 ", Stream bitrate = %u", sys_bitrate, bitrate);
7770 if (!stream->pending_tags)
7771 stream->pending_tags = gst_tag_list_new_empty ();
7773 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
7774 GST_TAG_BITRATE, bitrate, NULL);
7777 static GstFlowReturn
7778 qtdemux_expose_streams (GstQTDemux * qtdemux)
7781 GstFlowReturn ret = GST_FLOW_OK;
7783 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7785 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7786 QtDemuxStream *stream = qtdemux->streams[i];
7787 guint32 sample_num = 0;
7792 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7793 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7795 if (qtdemux->fragmented) {
7796 /* need all moov samples first */
7797 GST_OBJECT_LOCK (qtdemux);
7798 while (stream->n_samples == 0)
7799 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7801 GST_OBJECT_UNLOCK (qtdemux);
7803 /* discard any stray moof */
7804 qtdemux->moof_offset = 0;
7807 /* prepare braking */
7808 if (ret != GST_FLOW_ERROR)
7811 /* in pull mode, we should have parsed some sample info by now;
7812 * and quite some code will not handle no samples.
7813 * in push mode, we'll just have to deal with it */
7814 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7815 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7816 gst_qtdemux_stream_free (qtdemux, stream);
7817 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7818 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7819 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7820 qtdemux->n_streams--;
7825 /* parse number of initial sample to set frame rate cap */
7826 while (sample_num < stream->n_samples && sample_num < samples) {
7827 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7831 /* collect and sort durations */
7832 samples = MIN (stream->stbl_index + 1, samples);
7833 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7835 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7837 while (sample_num < samples) {
7838 g_array_append_val (durations, stream->samples[sample_num].duration);
7841 g_array_sort (durations, less_than);
7842 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7843 g_array_free (durations, TRUE);
7846 /* now we have all info and can expose */
7847 list = stream->pending_tags;
7848 stream->pending_tags = NULL;
7849 gst_qtdemux_add_stream (qtdemux, stream, list);
7852 gst_qtdemux_guess_bitrate (qtdemux);
7854 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7856 /* check if we should post a redirect in case there is a single trak
7857 * and it is a redirecting trak */
7858 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7861 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7862 "an external content");
7863 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7864 gst_structure_new ("redirect",
7865 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7867 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7868 qtdemux->posted_redirect = TRUE;
7874 /* check if major or compatible brand is 3GP */
7875 static inline gboolean
7876 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7879 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7880 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7881 } else if (qtdemux->comp_brands != NULL) {
7885 gboolean res = FALSE;
7887 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
7891 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7892 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7896 gst_buffer_unmap (qtdemux->comp_brands, &map);
7903 /* check if tag is a spec'ed 3GP tag keyword storing a string */
7904 static inline gboolean
7905 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
7907 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
7908 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
7909 || fourcc == FOURCC_albm;
7913 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
7914 const char *dummy, GNode * node)
7916 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7920 gdouble longitude, latitude, altitude;
7923 len = QT_UINT32 (node->data);
7930 /* TODO: language code skipped */
7932 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
7935 /* do not alarm in trivial case, but bail out otherwise */
7936 if (*(data + offset) != 0) {
7937 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
7941 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7942 GST_TAG_GEO_LOCATION_NAME, name, NULL);
7943 offset += strlen (name);
7947 if (len < offset + 2 + 4 + 4 + 4)
7950 /* +1 +1 = skip null-terminator and location role byte */
7952 /* table in spec says unsigned, semantics say negative has meaning ... */
7953 longitude = QT_SFP32 (data + offset);
7956 latitude = QT_SFP32 (data + offset);
7959 altitude = QT_SFP32 (data + offset);
7961 /* one invalid means all are invalid */
7962 if (longitude >= -180.0 && longitude <= 180.0 &&
7963 latitude >= -90.0 && latitude <= 90.0) {
7964 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7965 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
7966 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
7967 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
7970 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
7977 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
7984 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7991 len = QT_UINT32 (node->data);
7995 y = QT_UINT16 ((guint8 *) node->data + 12);
7997 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
8000 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
8002 date = g_date_new_dmy (1, 1, y);
8003 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
8008 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
8009 const char *dummy, GNode * node)
8012 char *tag_str = NULL;
8017 len = QT_UINT32 (node->data);
8022 entity = (guint8 *) node->data + offset;
8023 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
8024 GST_DEBUG_OBJECT (qtdemux,
8025 "classification info: %c%c%c%c invalid classification entity",
8026 entity[0], entity[1], entity[2], entity[3]);
8031 table = QT_UINT16 ((guint8 *) node->data + offset);
8033 /* Language code skipped */
8037 /* Tag format: "XXXX://Y[YYYY]/classification info string"
8038 * XXXX: classification entity, fixed length 4 chars.
8039 * Y[YYYY]: classification table, max 5 chars.
8041 tag_str = g_strdup_printf ("----://%u/%s",
8042 table, (char *) node->data + offset);
8044 /* memcpy To be sure we're preserving byte order */
8045 memcpy (tag_str, entity, 4);
8046 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
8048 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
8058 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
8064 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
8065 const char *dummy, GNode * node)
8067 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8073 gboolean ret = TRUE;
8075 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8077 len = QT_UINT32 (data->data);
8078 type = QT_UINT32 ((guint8 *) data->data + 8);
8079 if (type == 0x00000001 && len > 16) {
8080 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
8083 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
8084 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
8088 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
8092 len = QT_UINT32 (node->data);
8093 type = QT_UINT32 ((guint8 *) node->data + 4);
8094 if ((type >> 24) == 0xa9) {
8095 /* Type starts with the (C) symbol, so the next 32 bits are
8096 * the language code, which we ignore */
8098 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
8099 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
8100 QT_FOURCC ((guint8 *) node->data + 4))) {
8101 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
8103 /* we go for 3GP style encoding if major brands claims so,
8104 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
8105 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8106 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
8107 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
8109 /* 16-bit Language code is ignored here as well */
8110 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
8117 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
8118 ret = FALSE; /* may have to fallback */
8120 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8121 len - offset, env_vars);
8123 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
8124 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
8128 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
8135 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
8136 const char *dummy, GNode * node)
8138 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
8142 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
8143 const char *dummy, GNode * node)
8145 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8147 char *s, *t, *k = NULL;
8152 /* first try normal string tag if major brand not 3GP */
8153 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
8154 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
8155 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
8156 * let's try it 3gpp way after minor safety check */
8158 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
8164 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
8168 len = QT_UINT32 (data);
8172 count = QT_UINT8 (data + 14);
8174 for (; count; count--) {
8177 if (offset + 1 > len)
8179 slen = QT_UINT8 (data + offset);
8181 if (offset + slen > len)
8183 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8186 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
8188 t = g_strjoin (",", k, s, NULL);
8196 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
8203 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
8204 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
8213 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
8219 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
8220 const char *tag2, GNode * node)
8227 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8229 len = QT_UINT32 (data->data);
8230 type = QT_UINT32 ((guint8 *) data->data + 8);
8231 if (type == 0x00000000 && len >= 22) {
8232 n1 = QT_UINT16 ((guint8 *) data->data + 18);
8233 n2 = QT_UINT16 ((guint8 *) data->data + 20);
8235 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
8236 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8240 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
8241 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8249 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8257 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8259 len = QT_UINT32 (data->data);
8260 type = QT_UINT32 ((guint8 *) data->data + 8);
8261 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
8262 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8263 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
8264 n1 = QT_UINT16 ((guint8 *) data->data + 16);
8266 /* do not add bpm=0 */
8267 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
8268 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8269 tag1, (gdouble) n1, NULL);
8276 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
8277 const char *dummy, GNode * node)
8284 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8286 len = QT_UINT32 (data->data);
8287 type = QT_UINT32 ((guint8 *) data->data + 8);
8288 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
8289 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8290 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
8291 num = QT_UINT32 ((guint8 *) data->data + 16);
8293 /* do not add num=0 */
8294 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
8295 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8303 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8311 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8313 len = QT_UINT32 (data->data);
8314 type = QT_UINT32 ((guint8 *) data->data + 8);
8315 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
8316 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
8318 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
8319 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
8320 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
8321 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8322 tag1, sample, NULL);
8323 gst_sample_unref (sample);
8330 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8338 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8340 len = QT_UINT32 (data->data);
8341 type = QT_UINT32 ((guint8 *) data->data + 8);
8342 if (type == 0x00000001 && len > 16) {
8343 guint y, m = 1, d = 1;
8346 s = g_strndup ((char *) data->data + 16, len - 16);
8347 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
8348 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
8349 if (ret >= 1 && y > 1500 && y < 3000) {
8352 date = g_date_new_dmy (d, m, y);
8353 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
8357 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
8365 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8370 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8372 /* re-route to normal string tag if major brand says so
8373 * or no data atom and compatible brand suggests so */
8374 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8375 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
8376 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
8383 len = QT_UINT32 (data->data);
8384 type = QT_UINT32 ((guint8 *) data->data + 8);
8385 if (type == 0x00000000 && len >= 18) {
8386 n = QT_UINT16 ((guint8 *) data->data + 16);
8390 genre = gst_tag_id3_genre_get (n - 1);
8391 if (genre != NULL) {
8392 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
8393 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8402 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
8403 guint8 * data, guint32 datasize)
8408 /* make a copy to have \0 at the end */
8409 datacopy = g_strndup ((gchar *) data, datasize);
8411 /* convert the str to double */
8412 if (sscanf (datacopy, "%lf", &value) == 1) {
8413 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
8414 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
8416 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
8424 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
8425 const char *tag_bis, GNode * node)
8434 const gchar *meanstr;
8435 const gchar *namestr;
8437 /* checking the whole ---- atom size for consistency */
8438 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8439 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8443 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8445 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8449 meansize = QT_UINT32 (mean->data);
8450 if (meansize <= 12) {
8451 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8454 meanstr = ((gchar *) mean->data) + 12;
8456 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8458 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8462 namesize = QT_UINT32 (name->data);
8463 if (namesize <= 12) {
8464 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8467 namestr = ((gchar *) name->data) + 12;
8474 * uint24 - data type
8478 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8480 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8483 datasize = QT_UINT32 (data->data);
8484 if (datasize <= 16) {
8485 GST_WARNING_OBJECT (demux, "Data atom too small");
8488 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8490 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8493 const gchar name[28];
8494 const gchar tag[28];
8497 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8498 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8499 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8500 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8501 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8502 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8503 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8504 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8508 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8509 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8510 switch (gst_tag_get_type (tags[i].tag)) {
8512 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8513 ((guint8 *) data->data) + 16, datasize - 16);
8516 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8525 if (i == G_N_ELEMENTS (tags))
8539 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8540 namestr_dbg = g_strndup (namestr, namesize - 12);
8542 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8543 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8545 g_free (namestr_dbg);
8546 g_free (meanstr_dbg);
8552 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
8553 const char *tag_bis, GNode * node)
8558 GstTagList *taglist = NULL;
8560 GST_LOG_OBJECT (demux, "parsing ID32");
8563 len = GST_READ_UINT32_BE (data);
8565 /* need at least full box and language tag */
8569 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
8570 gst_buffer_fill (buf, 0, data + 14, len - 14);
8572 taglist = gst_tag_list_from_id3v2_tag (buf);
8574 GST_LOG_OBJECT (demux, "parsing ok");
8575 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
8577 GST_LOG_OBJECT (demux, "parsing failed");
8581 gst_tag_list_unref (taglist);
8583 gst_buffer_unref (buf);
8586 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8587 const char *tag, const char *tag_bis, GNode * node);
8590 FOURCC_pcst -> if media is a podcast -> bool
8591 FOURCC_cpil -> if media is part of a compilation -> bool
8592 FOURCC_pgap -> if media is part of a gapless context -> bool
8593 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8599 const gchar *gst_tag;
8600 const gchar *gst_tag_bis;
8601 const GstQTDemuxAddTagFunc func;
8604 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8605 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8606 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8607 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8608 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8609 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8610 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8611 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8612 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8613 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8614 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8615 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8616 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8617 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8618 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8619 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8620 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8621 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8622 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8623 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8624 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8625 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8626 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8627 qtdemux_tag_add_num}, {
8628 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8629 qtdemux_tag_add_num}, {
8630 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8631 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8632 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8633 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8634 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8635 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8636 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8637 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8638 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8639 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8640 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8641 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8642 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8643 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8644 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8645 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8646 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8647 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8648 qtdemux_tag_add_classification}, {
8650 /* This is a special case, some tags are stored in this
8651 * 'reverse dns naming', according to:
8652 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8655 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
8656 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
8657 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
8661 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8674 len = QT_UINT32 (data);
8675 buf = gst_buffer_new_and_alloc (len);
8676 _gst_buffer_copy_into_mem (buf, 0, data, len);
8678 /* heuristic to determine style of tag */
8679 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8680 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8682 else if (demux->major_brand == FOURCC_qt__)
8683 style = "quicktime";
8684 /* fall back to assuming iso/3gp tag style */
8688 /* santize the name for the caps. */
8689 for (i = 0; i < 4; i++) {
8690 guint8 d = data[4 + i];
8691 if (g_ascii_isalnum (d))
8692 ndata[i] = g_ascii_tolower (d);
8697 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8698 ndata[0], ndata[1], ndata[2], ndata[3]);
8699 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8701 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
8702 sample = gst_sample_new (buf, NULL, NULL, s);
8703 gst_buffer_unref (buf);
8704 g_free (media_type);
8706 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
8709 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8710 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
8714 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8722 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8724 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8726 GST_LOG_OBJECT (qtdemux, "no ilst");
8731 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8734 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8735 if (!qtdemux->tag_list) {
8736 qtdemux->tag_list = gst_tag_list_new_empty ();
8737 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
8741 while (i < G_N_ELEMENTS (add_funcs)) {
8742 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8746 len = QT_UINT32 (node->data);
8748 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8749 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8751 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8752 add_funcs[i].gst_tag_bis, node);
8754 g_node_destroy (node);
8760 /* parsed nodes have been removed, pass along remainder as blob */
8761 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8762 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8764 /* parse up XMP_ node if existing */
8765 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8768 GstTagList *taglist;
8770 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
8771 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
8772 taglist = gst_tag_list_from_xmp_buffer (buf);
8773 gst_buffer_unref (buf);
8775 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8777 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8784 GstStructure *structure; /* helper for sort function */
8786 guint min_req_bitrate;
8787 guint min_req_qt_version;
8791 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8793 GstQtReference *ref_a = (GstQtReference *) a;
8794 GstQtReference *ref_b = (GstQtReference *) b;
8796 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8797 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8799 /* known bitrates go before unknown; higher bitrates go first */
8800 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8803 /* sort the redirects and post a message for the application.
8806 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8808 GstQtReference *best;
8811 GValue list_val = { 0, };
8814 g_assert (references != NULL);
8816 references = g_list_sort (references, qtdemux_redirects_sort_func);
8818 best = (GstQtReference *) references->data;
8820 g_value_init (&list_val, GST_TYPE_LIST);
8822 for (l = references; l != NULL; l = l->next) {
8823 GstQtReference *ref = (GstQtReference *) l->data;
8824 GValue struct_val = { 0, };
8826 ref->structure = gst_structure_new ("redirect",
8827 "new-location", G_TYPE_STRING, ref->location, NULL);
8829 if (ref->min_req_bitrate > 0) {
8830 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8831 ref->min_req_bitrate, NULL);
8834 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8835 g_value_set_boxed (&struct_val, ref->structure);
8836 gst_value_list_append_value (&list_val, &struct_val);
8837 g_value_unset (&struct_val);
8838 /* don't free anything here yet, since we need best->structure below */
8841 g_assert (best != NULL);
8842 s = gst_structure_copy (best->structure);
8844 if (g_list_length (references) > 1) {
8845 gst_structure_set_value (s, "locations", &list_val);
8848 g_value_unset (&list_val);
8850 for (l = references; l != NULL; l = l->next) {
8851 GstQtReference *ref = (GstQtReference *) l->data;
8853 gst_structure_free (ref->structure);
8854 g_free (ref->location);
8857 g_list_free (references);
8859 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8860 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8861 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8862 qtdemux->posted_redirect = TRUE;
8865 /* look for redirect nodes, collect all redirect information and
8869 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8871 GNode *rmra, *rmda, *rdrf;
8873 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8875 GList *redirects = NULL;
8877 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8879 GstQtReference ref = { NULL, NULL, 0, 0 };
8882 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8883 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8884 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8885 ref.min_req_bitrate);
8888 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
8889 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
8890 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
8892 #ifndef GST_DISABLE_GST_DEBUG
8893 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
8895 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
8897 GST_LOG_OBJECT (qtdemux,
8898 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
8899 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
8900 bitmask, check_type);
8901 if (package == FOURCC_qtim && check_type == 0) {
8902 ref.min_req_qt_version = version;
8906 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
8911 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
8912 ref_data = (guint8 *) rdrf->data + 20;
8913 if (ref_type == FOURCC_alis) {
8914 guint record_len, record_version, fn_len;
8916 /* MacOSX alias record, google for alias-layout.txt */
8917 record_len = QT_UINT16 (ref_data + 4);
8918 record_version = QT_UINT16 (ref_data + 4 + 2);
8919 fn_len = QT_UINT8 (ref_data + 50);
8920 if (record_len > 50 && record_version == 2 && fn_len > 0) {
8921 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
8923 } else if (ref_type == FOURCC_url_) {
8924 ref.location = g_strdup ((gchar *) ref_data);
8926 GST_DEBUG_OBJECT (qtdemux,
8927 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
8928 GST_FOURCC_ARGS (ref_type));
8930 if (ref.location != NULL) {
8931 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
8932 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
8934 GST_WARNING_OBJECT (qtdemux,
8935 "Failed to extract redirect location from rdrf atom");
8939 /* look for others */
8940 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
8943 if (redirects != NULL) {
8944 qtdemux_process_redirects (qtdemux, redirects);
8951 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
8956 tags = gst_tag_list_new_empty ();
8957 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
8960 if (qtdemux->major_brand == FOURCC_mjp2)
8961 fmt = "Motion JPEG 2000";
8962 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
8964 else if (qtdemux->major_brand == FOURCC_qt__)
8966 else if (qtdemux->fragmented)
8969 fmt = "ISO MP4/M4A";
8971 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
8972 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
8974 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
8980 /* we have read th complete moov node now.
8981 * This function parses all of the relevant info, creates the traks and
8982 * prepares all data structures for playback
8985 qtdemux_parse_tree (GstQTDemux * qtdemux)
8992 guint64 creation_time;
8993 GstDateTime *datetime = NULL;
8996 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
8998 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
8999 return qtdemux_parse_redirects (qtdemux);
9002 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
9004 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
9005 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
9006 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
9007 } else if (version == 0) {
9008 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
9009 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
9010 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
9012 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
9016 /* Moving qt creation time (secs since 1904) to unix time */
9017 if (creation_time != 0) {
9018 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
9021 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
9022 /* some data cleansing sanity */
9023 g_get_current_time (&now);
9024 if (now.tv_sec + 24 * 3600 < creation_time) {
9025 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
9027 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
9030 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
9031 "please file a bug at http://bugzilla.gnome.org");
9035 if (!qtdemux->tag_list) {
9036 qtdemux->tag_list = gst_tag_list_new_empty ();
9037 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
9040 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
9041 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
9043 gst_date_time_unref (datetime);
9046 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
9047 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
9049 /* check for fragmented file and get some (default) data */
9050 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
9053 GstByteReader mehd_data;
9055 /* let track parsing or anyone know weird stuff might happen ... */
9056 qtdemux->fragmented = TRUE;
9058 /* compensate for total duration */
9059 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
9061 qtdemux_parse_mehd (qtdemux, &mehd_data);
9064 /* set duration in the segment info */
9065 gst_qtdemux_get_duration (qtdemux, &duration);
9067 qtdemux->segment.duration = duration;
9068 /* also do not exceed duration; stop is set that way post seek anyway,
9069 * and segment activation falls back to duration,
9070 * whereas loop only checks stop, so let's align this here as well */
9071 qtdemux->segment.stop = duration;
9074 /* parse all traks */
9075 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
9077 qtdemux_parse_trak (qtdemux, trak);
9078 /* iterate all siblings */
9079 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
9083 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
9085 qtdemux_parse_udta (qtdemux, udta);
9087 GST_LOG_OBJECT (qtdemux, "No udta node found.");
9090 /* maybe also some tags in meta box */
9091 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
9093 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
9094 qtdemux_parse_udta (qtdemux, udta);
9096 GST_LOG_OBJECT (qtdemux, "No meta node found.");
9099 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
9104 /* taken from ffmpeg */
9106 get_size (guint8 * ptr, guint8 ** end)
9115 len = (len << 7) | (c & 0x7f);
9124 /* this can change the codec originally present in @list */
9126 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
9127 GNode * esds, GstTagList * list)
9129 int len = QT_UINT32 (esds->data);
9130 guint8 *ptr = esds->data;
9131 guint8 *end = ptr + len;
9133 guint8 *data_ptr = NULL;
9135 guint8 object_type_id = 0;
9136 const char *codec_name = NULL;
9137 GstCaps *caps = NULL;
9139 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
9141 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
9144 tag = QT_UINT8 (ptr);
9145 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
9147 len = get_size (ptr, &ptr);
9148 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
9152 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
9153 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
9157 guint max_bitrate, avg_bitrate;
9159 object_type_id = QT_UINT8 (ptr);
9160 max_bitrate = QT_UINT32 (ptr + 5);
9161 avg_bitrate = QT_UINT32 (ptr + 9);
9162 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
9163 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
9164 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
9165 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
9166 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
9167 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9168 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9169 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9171 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9172 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
9179 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
9185 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
9189 GST_ERROR_OBJECT (qtdemux, "parse error");
9194 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
9195 * in use, and should also be used to override some other parameters for some
9197 switch (object_type_id) {
9198 case 0x20: /* MPEG-4 */
9199 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
9200 * profile_and_level_indication */
9201 if (data_ptr != NULL && data_len >= 5 &&
9202 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
9203 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
9204 data_ptr + 4, data_len - 4);
9206 break; /* Nothing special needed here */
9207 case 0x21: /* H.264 */
9208 codec_name = "H.264 / AVC";
9209 caps = gst_caps_new_simple ("video/x-h264",
9210 "stream-format", G_TYPE_STRING, "avc",
9211 "alignment", G_TYPE_STRING, "au", NULL);
9213 case 0x40: /* AAC (any) */
9214 case 0x66: /* AAC Main */
9215 case 0x67: /* AAC LC */
9216 case 0x68: /* AAC SSR */
9217 /* Override channels and rate based on the codec_data, as it's often
9219 /* Only do so for basic setup without HE-AAC extension */
9220 if (data_ptr && data_len == 2) {
9221 guint channels, rateindex, rate;
9223 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
9224 channels = (data_ptr[1] & 0x7f) >> 3;
9225 if (channels > 0 && channels < 7) {
9226 stream->n_channels = channels;
9227 } else if (channels == 7) {
9228 stream->n_channels = 8;
9231 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
9232 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
9234 stream->rate = rate;
9237 /* Set level and profile if possible */
9238 if (data_ptr != NULL && data_len >= 2) {
9239 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
9240 data_ptr, data_len);
9243 case 0x60: /* MPEG-2, various profiles */
9249 codec_name = "MPEG-2 video";
9251 gst_caps_unref (stream->caps);
9252 stream->caps = gst_caps_new_simple ("video/mpeg",
9253 "mpegversion", G_TYPE_INT, 2,
9254 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9256 case 0x69: /* MP3 has two different values, accept either */
9258 /* change to mpeg1 layer 3 audio */
9259 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
9260 "mpegversion", G_TYPE_INT, 1, NULL);
9261 codec_name = "MPEG-1 layer 3";
9263 case 0x6A: /* MPEG-1 */
9264 codec_name = "MPEG-1 video";
9266 gst_caps_unref (stream->caps);
9267 stream->caps = gst_caps_new_simple ("video/mpeg",
9268 "mpegversion", G_TYPE_INT, 1,
9269 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9271 case 0x6C: /* MJPEG */
9272 caps = gst_caps_new_empty_simple ("image/jpeg");
9273 codec_name = "Motion-JPEG";
9275 case 0x6D: /* PNG */
9276 caps = gst_caps_new_empty_simple ("image/png");
9277 codec_name = "PNG still images";
9279 case 0x6E: /* JPEG2000 */
9280 codec_name = "JPEG-2000";
9281 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9283 case 0xA4: /* Dirac */
9284 codec_name = "Dirac";
9285 caps = gst_caps_new_empty_simple ("video/x-dirac");
9287 case 0xA5: /* AC3 */
9288 codec_name = "AC-3 audio";
9289 caps = gst_caps_new_simple ("audio/x-ac3",
9290 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9292 case 0xE1: /* QCELP */
9293 /* QCELP, the codec_data is a riff tag (little endian) with
9294 * 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). */
9295 caps = gst_caps_new_empty_simple ("audio/qcelp");
9296 codec_name = "QCELP";
9302 /* If we have a replacement caps, then change our caps for this stream */
9304 gst_caps_unref (stream->caps);
9305 stream->caps = caps;
9308 if (codec_name && list)
9309 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9310 GST_TAG_AUDIO_CODEC, codec_name, NULL);
9312 /* Add the codec_data attribute to caps, if we have it */
9316 buffer = gst_buffer_new_and_alloc (data_len);
9317 _gst_buffer_copy_into_mem (buffer, 0, data_ptr, data_len);
9319 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
9320 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
9322 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
9324 gst_buffer_unref (buffer);
9329 #define _codec(name) \
9332 *codec_name = g_strdup (name); \
9337 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9338 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9341 const GstStructure *s;
9345 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
9346 _codec ("PNG still images");
9347 caps = gst_caps_new_empty_simple ("image/png");
9349 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
9350 _codec ("JPEG still images");
9351 caps = gst_caps_new_empty_simple ("image/jpeg");
9353 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
9354 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
9355 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
9356 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
9357 _codec ("Motion-JPEG");
9358 caps = gst_caps_new_empty_simple ("image/jpeg");
9360 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
9361 _codec ("Motion-JPEG format B");
9362 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
9364 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
9365 _codec ("JPEG-2000");
9366 /* override to what it should be according to spec, avoid palette_data */
9367 stream->bits_per_sample = 24;
9368 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9370 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
9371 _codec ("Sorensen video v.3");
9372 caps = gst_caps_new_simple ("video/x-svq",
9373 "svqversion", G_TYPE_INT, 3, NULL);
9375 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
9376 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
9377 _codec ("Sorensen video v.1");
9378 caps = gst_caps_new_simple ("video/x-svq",
9379 "svqversion", G_TYPE_INT, 1, NULL);
9381 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9385 _codec ("Raw RGB video");
9386 bps = QT_UINT16 (stsd_data + 98);
9387 /* set common stuff */
9388 caps = gst_caps_new_empty_simple ("video/x-raw");
9392 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB15", NULL);
9395 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB16", NULL);
9398 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB", NULL);
9401 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "ARGB", NULL);
9409 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
9410 _codec ("Raw planar YUV 4:2:0");
9411 caps = gst_caps_new_simple ("video/x-raw",
9412 "format", G_TYPE_STRING, "I420", NULL);
9414 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
9415 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
9416 _codec ("Raw packed YUV 4:2:2");
9417 caps = gst_caps_new_simple ("video/x-raw",
9418 "format", G_TYPE_STRING, "YUY2", NULL);
9420 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
9421 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
9422 _codec ("Raw packed YUV 4:2:2");
9423 caps = gst_caps_new_simple ("video/x-raw",
9424 "format", G_TYPE_STRING, "UYVY", NULL);
9426 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
9427 _codec ("Raw packed YUV 10-bit 4:2:2");
9428 caps = gst_caps_new_simple ("video/x-raw",
9429 "format", G_TYPE_STRING, "v210", NULL);
9431 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
9432 _codec ("Raw packed RGB 10-bit 4:4:4");
9433 caps = gst_caps_new_simple ("video/x-raw",
9434 "format", G_TYPE_STRING, "r210", NULL);
9436 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
9437 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
9438 _codec ("MPEG-1 video");
9439 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9440 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9442 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
9443 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
9444 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
9445 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
9446 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
9447 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
9448 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
9449 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
9450 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
9451 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
9452 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
9453 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
9454 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
9455 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
9456 _codec ("MPEG-2 video");
9457 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
9458 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9460 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
9461 _codec ("GIF still images");
9462 caps = gst_caps_new_empty_simple ("image/gif");
9464 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
9465 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
9466 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
9467 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9469 /* ffmpeg uses the height/width props, don't know why */
9470 caps = gst_caps_new_empty_simple ("video/x-h263");
9472 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9473 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9474 _codec ("MPEG-4 video");
9475 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9476 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9478 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9479 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9480 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9481 caps = gst_caps_new_simple ("video/x-msmpeg",
9482 "msmpegversion", G_TYPE_INT, 43, NULL);
9484 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9486 caps = gst_caps_new_simple ("video/x-divx",
9487 "divxversion", G_TYPE_INT, 3, NULL);
9489 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9490 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9492 caps = gst_caps_new_simple ("video/x-divx",
9493 "divxversion", G_TYPE_INT, 4, NULL);
9495 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9497 caps = gst_caps_new_simple ("video/x-divx",
9498 "divxversion", G_TYPE_INT, 5, NULL);
9501 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9502 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9503 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9504 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9505 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9506 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9507 caps = gst_caps_new_simple ("video/mpeg",
9508 "mpegversion", G_TYPE_INT, 4, NULL);
9510 *codec_name = g_strdup ("MPEG-4");
9513 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9515 caps = gst_caps_new_empty_simple ("video/x-cinepak");
9517 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9518 _codec ("Apple QuickDraw");
9519 caps = gst_caps_new_empty_simple ("video/x-qdrw");
9521 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9522 _codec ("Apple video");
9523 caps = gst_caps_new_empty_simple ("video/x-apple-video");
9525 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9526 _codec ("H.264 / AVC");
9527 caps = gst_caps_new_simple ("video/x-h264",
9528 "stream-format", G_TYPE_STRING, "avc",
9529 "alignment", G_TYPE_STRING, "au", NULL);
9531 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9532 _codec ("Run-length encoding");
9533 caps = gst_caps_new_simple ("video/x-rle",
9534 "layout", G_TYPE_STRING, "quicktime", NULL);
9536 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9537 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9538 _codec ("Indeo Video 3");
9539 caps = gst_caps_new_simple ("video/x-indeo",
9540 "indeoversion", G_TYPE_INT, 3, NULL);
9542 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9543 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9544 _codec ("Intel Video 4");
9545 caps = gst_caps_new_simple ("video/x-indeo",
9546 "indeoversion", G_TYPE_INT, 4, NULL);
9548 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9549 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9550 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9551 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9552 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9553 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9554 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9555 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9556 _codec ("DV Video");
9557 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9558 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9560 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9561 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9562 _codec ("DVCPro50 Video");
9563 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9564 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9566 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9567 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9568 _codec ("DVCProHD Video");
9569 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9570 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9572 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9573 _codec ("Apple Graphics (SMC)");
9574 caps = gst_caps_new_empty_simple ("video/x-smc");
9576 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9578 caps = gst_caps_new_empty_simple ("video/x-vp3");
9580 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9582 caps = gst_caps_new_empty_simple ("video/x-theora");
9583 /* theora uses one byte of padding in the data stream because it does not
9584 * allow 0 sized packets while theora does */
9585 stream->padding = 1;
9587 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9589 caps = gst_caps_new_empty_simple ("video/x-dirac");
9591 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9592 _codec ("TIFF still images");
9593 caps = gst_caps_new_empty_simple ("image/tiff");
9595 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9596 _codec ("Apple Intermediate Codec");
9597 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9599 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9600 _codec ("AVID DNxHD");
9601 caps = gst_caps_from_string ("video/x-dnxhd");
9603 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9605 caps = gst_caps_from_string ("video/x-vp8");
9607 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
9608 _codec ("Apple ProRes LT");
9610 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
9613 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
9614 _codec ("Apple ProRes HQ");
9616 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
9619 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
9620 _codec ("Apple ProRes");
9622 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
9625 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
9626 _codec ("Apple ProRes Proxy");
9628 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
9631 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
9632 _codec ("Apple ProRes 4444");
9634 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
9639 caps = gst_caps_new_simple ("video/x-wmv",
9640 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
9642 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9645 char *s, fourstr[5];
9647 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9648 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
9649 caps = gst_caps_new_empty_simple (s);
9654 /* enable clipping for raw video streams */
9655 s = gst_caps_get_structure (caps, 0);
9656 name = gst_structure_get_name (s);
9657 if (g_str_has_prefix (name, "video/x-raw")) {
9658 stream->need_clip = TRUE;
9664 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9665 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9668 const GstStructure *s;
9672 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9675 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9676 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9677 _codec ("Raw 8-bit PCM audio");
9678 caps = gst_caps_new_simple ("audio/x-raw",
9679 "format", G_TYPE_STRING, "U8",
9680 "layout", G_TYPE_STRING, "interleaved", NULL);
9682 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9683 endian = G_BIG_ENDIAN;
9685 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9689 GstAudioFormat format;
9692 endian = G_LITTLE_ENDIAN;
9694 depth = stream->bytes_per_packet * 8;
9695 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
9697 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9701 caps = gst_caps_new_simple ("audio/x-raw",
9702 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
9703 "layout", G_TYPE_STRING, "interleaved", NULL);
9706 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9707 _codec ("Raw 64-bit floating-point audio");
9708 caps = gst_caps_new_simple ("audio/x-raw",
9709 "format", G_TYPE_STRING, "F64BE",
9710 "layout", G_TYPE_STRING, "interleaved", NULL);
9712 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9713 _codec ("Raw 32-bit floating-point audio");
9714 caps = gst_caps_new_simple ("audio/x-raw",
9715 "format", G_TYPE_STRING, "F32BE",
9716 "layout", G_TYPE_STRING, "interleaved", NULL);
9719 _codec ("Raw 24-bit PCM audio");
9720 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9722 caps = gst_caps_new_simple ("audio/x-raw",
9723 "format", G_TYPE_STRING, "S24BE",
9724 "layout", G_TYPE_STRING, "interleaved", NULL);
9726 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9727 _codec ("Raw 32-bit PCM audio");
9728 caps = gst_caps_new_simple ("audio/x-raw",
9729 "format", G_TYPE_STRING, "S32BE",
9730 "layout", G_TYPE_STRING, "interleaved", NULL);
9732 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9733 _codec ("Mu-law audio");
9734 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
9736 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9737 _codec ("A-law audio");
9738 caps = gst_caps_new_empty_simple ("audio/x-alaw");
9742 _codec ("Microsoft ADPCM");
9743 /* Microsoft ADPCM-ACM code 2 */
9744 caps = gst_caps_new_simple ("audio/x-adpcm",
9745 "layout", G_TYPE_STRING, "microsoft", NULL);
9749 _codec ("DVI/IMA ADPCM");
9750 caps = gst_caps_new_simple ("audio/x-adpcm",
9751 "layout", G_TYPE_STRING, "dvi", NULL);
9755 _codec ("DVI/Intel IMA ADPCM");
9756 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9757 caps = gst_caps_new_simple ("audio/x-adpcm",
9758 "layout", G_TYPE_STRING, "quicktime", NULL);
9762 /* MPEG layer 3, CBR only (pre QT4.1) */
9763 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9764 _codec ("MPEG-1 layer 3");
9765 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9766 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9767 "mpegversion", G_TYPE_INT, 1, NULL);
9770 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9771 _codec ("EAC-3 audio");
9772 caps = gst_caps_new_simple ("audio/x-eac3",
9773 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9774 stream->sampled = TRUE;
9776 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9777 _codec ("AC-3 audio");
9778 caps = gst_caps_new_simple ("audio/x-ac3",
9779 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9780 stream->sampled = TRUE;
9782 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9784 caps = gst_caps_new_simple ("audio/x-mace",
9785 "maceversion", G_TYPE_INT, 3, NULL);
9787 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9789 caps = gst_caps_new_simple ("audio/x-mace",
9790 "maceversion", G_TYPE_INT, 6, NULL);
9792 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9794 caps = gst_caps_new_empty_simple ("application/ogg");
9796 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9797 _codec ("DV audio");
9798 caps = gst_caps_new_empty_simple ("audio/x-dv");
9800 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9801 _codec ("MPEG-4 AAC audio");
9802 caps = gst_caps_new_simple ("audio/mpeg",
9803 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9804 "stream-format", G_TYPE_STRING, "raw", NULL);
9806 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9807 _codec ("QDesign Music");
9808 caps = gst_caps_new_empty_simple ("audio/x-qdm");
9810 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9811 _codec ("QDesign Music v.2");
9812 /* FIXME: QDesign music version 2 (no constant) */
9813 if (FALSE && data) {
9814 caps = gst_caps_new_simple ("audio/x-qdm2",
9815 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9816 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9817 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9819 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
9822 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9823 _codec ("GSM audio");
9824 caps = gst_caps_new_empty_simple ("audio/x-gsm");
9826 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9827 _codec ("AMR audio");
9828 caps = gst_caps_new_empty_simple ("audio/AMR");
9830 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9831 _codec ("AMR-WB audio");
9832 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
9834 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9835 _codec ("Quicktime IMA ADPCM");
9836 caps = gst_caps_new_simple ("audio/x-adpcm",
9837 "layout", G_TYPE_STRING, "quicktime", NULL);
9839 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9840 _codec ("Apple lossless audio");
9841 caps = gst_caps_new_empty_simple ("audio/x-alac");
9843 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9844 _codec ("QualComm PureVoice");
9845 caps = gst_caps_from_string ("audio/qcelp");
9849 caps = gst_caps_new_empty_simple ("audio/x-wma");
9851 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
9856 GstAudioFormat format;
9859 FLAG_IS_FLOAT = 0x1,
9860 FLAG_IS_BIG_ENDIAN = 0x2,
9861 FLAG_IS_SIGNED = 0x4,
9862 FLAG_IS_PACKED = 0x8,
9863 FLAG_IS_ALIGNED_HIGH = 0x10,
9864 FLAG_IS_NON_INTERLEAVED = 0x20
9866 _codec ("Raw LPCM audio");
9868 if (data && len >= 56) {
9869 depth = QT_UINT32 (data + 40);
9870 flags = QT_UINT32 (data + 44);
9871 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
9873 if ((flags & FLAG_IS_FLOAT) == 0) {
9878 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
9879 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
9880 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
9881 // FIXME: check FLAG_IS_NON_INTERLEAVED flag for layout
9882 caps = gst_caps_new_simple ("audio/x-raw",
9883 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
9884 "layout", G_TYPE_STRING, "interleaved", NULL);
9891 if (flags & FLAG_IS_BIG_ENDIAN)
9892 format = GST_AUDIO_FORMAT_F64BE;
9894 format = GST_AUDIO_FORMAT_F64LE;
9896 if (flags & FLAG_IS_BIG_ENDIAN)
9897 format = GST_AUDIO_FORMAT_F32BE;
9899 format = GST_AUDIO_FORMAT_F32LE;
9901 caps = gst_caps_new_simple ("audio/x-raw",
9902 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
9903 "layout", G_TYPE_STRING, "interleaved", NULL);
9907 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
9911 char *s, fourstr[5];
9913 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9914 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
9915 caps = gst_caps_new_empty_simple (s);
9921 GstCaps *templ_caps =
9922 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
9923 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
9924 gst_caps_unref (caps);
9925 gst_caps_unref (templ_caps);
9926 caps = intersection;
9929 /* enable clipping for raw audio streams */
9930 s = gst_caps_get_structure (caps, 0);
9931 name = gst_structure_get_name (s);
9932 if (g_str_has_prefix (name, "audio/x-raw")) {
9933 stream->need_clip = TRUE;
9939 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9940 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9944 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9947 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
9948 _codec ("DVD subtitle");
9949 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
9951 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
9952 _codec ("Quicktime timed text");
9954 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
9955 _codec ("3GPP timed text");
9957 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
9959 /* actual text piece needs to be extracted */
9960 stream->need_process = TRUE;
9964 char *s, fourstr[5];
9966 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9967 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
9968 caps = gst_caps_new_empty_simple (s);
9976 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9977 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9982 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
9983 _codec ("MPEG 1 video");
9984 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9985 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);