2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 * SECTION:element-qtdemux
28 * Demuxes a .mov file into raw or compressed audio and/or video streams.
30 * This element supports both push and pull-based scheduling, depending on the
31 * capabilities of the upstream elements.
34 * <title>Example launch line</title>
36 * gst-launch filesrc location=test.mov ! qtdemux name=demux demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
37 * ]| Play (parse and decode) a .mov file and try to output it to
38 * an automatically detected soundcard and videosink. If the MOV file contains
39 * compressed audio or video data, this will only work if you have the
40 * right decoder elements/plugins installed.
43 * Last reviewed on 2006-12-29 (0.10.5)
50 #include "gst/gst-i18n-plugin.h"
52 #include <gst/tag/tag.h>
54 #include "qtatomparser.h"
55 #include "qtdemux_types.h"
56 #include "qtdemux_dump.h"
57 #include "qtdemux_fourcc.h"
59 #include "qtpalette.h"
61 #include "gst/riff/riff-media.h"
62 #include "gst/riff/riff-read.h"
72 /* max. size considered 'sane' for non-mdat atoms */
73 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
75 /* if the sample index is larger than this, something is likely wrong */
76 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
78 GST_DEBUG_CATEGORY (qtdemux_debug);
80 /*typedef struct _QtNode QtNode; */
81 typedef struct _QtDemuxSegment QtDemuxSegment;
82 typedef struct _QtDemuxSample QtDemuxSample;
94 gint32 pts_offset; /* Add this value to timestamp to get the pts */
96 guint64 timestamp; /* DTS In mov time */
97 guint32 duration; /* In mov time */
98 gboolean keyframe; /* TRUE when this packet is a keyframe */
101 /* timestamp is the DTS */
102 #define QTSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
103 GST_SECOND, (stream)->timescale)
104 /* timestamp + offset is the PTS */
105 #define QTSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
106 (sample)->pts_offset, GST_SECOND, (stream)->timescale)
107 /* timestamp + duration - dts is the duration */
108 #define QTSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
109 (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
110 /* timestamp + offset + duration - pts is the duration */
111 #define QTSAMPLE_DUR_PTS(stream,sample,pts) (gst_util_uint64_scale ((sample)->timestamp + \
112 (sample)->pts_offset + (sample)->duration, GST_SECOND, (stream)->timescale) - (pts));
114 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
117 * Quicktime has tracks and segments. A track is a continuous piece of
118 * multimedia content. The track is not always played from start to finish but
119 * instead, pieces of the track are 'cut out' and played in sequence. This is
120 * what the segments do.
122 * Inside the track we have keyframes (K) and delta frames. The track has its
123 * own timing, which starts from 0 and extends to end. The position in the track
124 * is called the media_time.
126 * The segments now describe the pieces that should be played from this track
127 * and are basically tupples of media_time/duration/rate entries. We can have
128 * multiple segments and they are all played after one another. An example:
130 * segment 1: media_time: 1 second, duration: 1 second, rate 1
131 * segment 2: media_time: 3 second, duration: 2 second, rate 2
133 * To correctly play back this track, one must play: 1 second of media starting
134 * from media_time 1 followed by 2 seconds of media starting from media_time 3
137 * Each of the segments will be played at a specific time, the first segment at
138 * time 0, the second one after the duration of the first one, etc.. Note that
139 * the time in resulting playback is not identical to the media_time of the
142 * Visually, assuming the track has 4 second of media_time:
145 * .-----------------------------------------------------------.
146 * track: | K.....K.........K........K.......K.......K...........K... |
147 * '-----------------------------------------------------------'
149 * .------------^ ^ .----------^ ^
150 * / .-------------' / .------------------'
152 * .--------------. .--------------.
153 * | segment 1 | | segment 2 |
154 * '--------------' '--------------'
156 * The challenge here is to cut out the right pieces of the track for each of
157 * the playback segments. This fortunatly can easily be done with the SEGMENT
158 * events of gstreamer.
160 * For playback of segment 1, we need to provide the decoder with the keyframe
161 * (a), in the above figure, but we must instruct it only to output the decoded
162 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
163 * position set to the time of the segment: 0.
165 * We then proceed to push data from keyframe (a) to frame (b). The decoder
166 * decodes but clips all before media_time 1.
168 * After finishing a segment, we push out a new SEGMENT event with the clipping
169 * boundaries of the new data.
171 * This is a good usecase for the GStreamer accumulated SEGMENT events.
174 struct _QtDemuxSegment
176 /* global time and duration, all gst time */
180 /* media time of trak, all gst time */
186 struct _QtDemuxStream
196 guint64 duration; /* in timescale */
201 gchar lang_id[4]; /* in ISO 639-2 */
205 QtDemuxSample *samples;
206 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
207 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
208 the framerate, in timescale units */
210 /* if we use chunks or samples */
222 /* Numerator/denominator framerate */
225 guint16 bits_per_sample;
226 guint16 color_table_id;
231 guint samples_per_packet;
232 guint samples_per_frame;
233 guint bytes_per_packet;
234 guint bytes_per_sample;
235 guint bytes_per_frame;
238 /* when a discontinuity is pending */
241 /* list of buffers to push first */
244 /* if we need to clip this buffer. This is only needed for uncompressed
248 /* buffer needs some custom processing, e.g. subtitles */
249 gboolean need_process;
251 /* current position */
252 guint32 segment_index;
253 guint32 sample_index;
254 guint64 time_position; /* in gst time */
256 /* the Gst segment we are processing out, used for clipping */
259 /* last GstFlowReturn */
260 GstFlowReturn last_ret;
262 /* quicktime segments */
264 QtDemuxSegment *segments;
269 GstTagList *pending_tags;
270 gboolean send_global_tags;
272 GstEvent *pending_event;
282 gboolean chunks_are_chunks;
286 GstByteReader co_chunk;
288 guint32 current_chunk;
290 guint32 samples_per_chunk;
291 guint32 stco_sample_index;
293 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
296 guint32 n_samples_per_chunk;
297 guint32 stsc_chunk_index;
298 guint32 stsc_sample_index;
299 guint64 chunk_offset;
302 guint32 stts_samples;
303 guint32 n_sample_times;
304 guint32 stts_sample_index;
306 guint64 stts_duration;
308 gboolean stss_present;
309 guint32 n_sample_syncs;
312 gboolean stps_present;
313 guint32 n_sample_partial_syncs;
316 gboolean ctts_present;
317 guint32 n_composition_times;
319 guint32 ctts_sample_index;
326 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
327 QTDEMUX_STATE_HEADER, /* Parsing the header */
328 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
329 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
332 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
333 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
334 guint32 fourcc, GstByteReader * parser);
335 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
337 static const GstElementDetails gst_qtdemux_details =
338 GST_ELEMENT_DETAILS ("QuickTime demuxer",
340 "Demultiplex a QuickTime file into audio and video streams",
341 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
343 static GstStaticPadTemplate gst_qtdemux_sink_template =
344 GST_STATIC_PAD_TEMPLATE ("sink",
347 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
351 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
352 GST_STATIC_PAD_TEMPLATE ("video_%02d",
355 GST_STATIC_CAPS_ANY);
357 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
358 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
361 GST_STATIC_CAPS_ANY);
363 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
364 GST_STATIC_PAD_TEMPLATE ("subtitle_%02d",
367 GST_STATIC_CAPS_ANY);
369 static GstElementClass *parent_class = NULL;
371 static void gst_qtdemux_class_init (GstQTDemuxClass * klass);
372 static void gst_qtdemux_base_init (GstQTDemuxClass * klass);
373 static void gst_qtdemux_init (GstQTDemux * quicktime_demux);
374 static void gst_qtdemux_dispose (GObject * object);
376 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
377 static GstIndex *gst_qtdemux_get_index (GstElement * element);
378 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
379 GstStateChange transition);
380 static gboolean qtdemux_sink_activate (GstPad * sinkpad);
381 static gboolean qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active);
382 static gboolean qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active);
384 static void gst_qtdemux_loop (GstPad * pad);
385 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf);
386 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstEvent * event);
388 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer,
390 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
391 const guint8 * buffer, guint length);
392 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
394 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
395 QtDemuxStream * stream, GNode * esds, GstTagList * list);
396 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
397 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
398 gchar ** codec_name);
399 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
400 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
401 gchar ** codec_name);
402 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
403 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
404 gchar ** codec_name);
405 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
406 QtDemuxStream * stream, guint32 n);
409 gst_qtdemux_get_type (void)
411 static GType qtdemux_type = 0;
413 if (G_UNLIKELY (!qtdemux_type)) {
414 static const GTypeInfo qtdemux_info = {
415 sizeof (GstQTDemuxClass),
416 (GBaseInitFunc) gst_qtdemux_base_init, NULL,
417 (GClassInitFunc) gst_qtdemux_class_init,
418 NULL, NULL, sizeof (GstQTDemux), 0,
419 (GInstanceInitFunc) gst_qtdemux_init,
423 g_type_register_static (GST_TYPE_ELEMENT, "GstQTDemux", &qtdemux_info,
430 gst_qtdemux_base_init (GstQTDemuxClass * klass)
432 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
434 gst_element_class_add_pad_template (element_class,
435 gst_static_pad_template_get (&gst_qtdemux_sink_template));
436 gst_element_class_add_pad_template (element_class,
437 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
438 gst_element_class_add_pad_template (element_class,
439 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
440 gst_element_class_add_pad_template (element_class,
441 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
442 gst_element_class_set_details (element_class, &gst_qtdemux_details);
444 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
448 gst_qtdemux_class_init (GstQTDemuxClass * klass)
450 GObjectClass *gobject_class;
451 GstElementClass *gstelement_class;
453 gobject_class = (GObjectClass *) klass;
454 gstelement_class = (GstElementClass *) klass;
456 parent_class = g_type_class_peek_parent (klass);
458 gobject_class->dispose = gst_qtdemux_dispose;
460 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
462 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
463 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
467 gst_qtdemux_init (GstQTDemux * qtdemux)
470 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
471 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
472 gst_pad_set_activatepull_function (qtdemux->sinkpad,
473 qtdemux_sink_activate_pull);
474 gst_pad_set_activatepush_function (qtdemux->sinkpad,
475 qtdemux_sink_activate_push);
476 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
477 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
478 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
480 qtdemux->state = QTDEMUX_STATE_INITIAL;
481 qtdemux->pullbased = FALSE;
482 qtdemux->neededbytes = 16;
484 qtdemux->adapter = gst_adapter_new ();
486 qtdemux->first_mdat = -1;
487 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
488 qtdemux->mdatbuffer = NULL;
489 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
493 gst_qtdemux_dispose (GObject * object)
495 GstQTDemux *qtdemux = GST_QTDEMUX (object);
497 if (qtdemux->adapter) {
498 g_object_unref (G_OBJECT (qtdemux->adapter));
499 qtdemux->adapter = NULL;
502 G_OBJECT_CLASS (parent_class)->dispose (object);
506 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
511 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
512 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
513 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
514 (_("This file is invalid and cannot be played.")),
515 ("atom has bogus size %" G_GUINT64_FORMAT, size));
516 return GST_FLOW_ERROR;
519 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
521 if (G_UNLIKELY (flow != GST_FLOW_OK))
524 /* Catch short reads - we don't want any partial atoms */
525 if (G_UNLIKELY (GST_BUFFER_SIZE (*buf) < size)) {
526 GST_WARNING_OBJECT (qtdemux, "short read: %u < %" G_GUINT64_FORMAT,
527 GST_BUFFER_SIZE (*buf), size);
528 gst_buffer_unref (*buf);
530 return GST_FLOW_UNEXPECTED;
538 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
539 GstFormat * dest_format, gint64 * dest_value)
542 QtDemuxStream *stream = gst_pad_get_element_private (pad);
544 if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e') &&
545 (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
548 switch (src_format) {
549 case GST_FORMAT_TIME:
550 switch (*dest_format) {
551 case GST_FORMAT_BYTES:
552 *dest_value = src_value * 1; /* FIXME */
554 case GST_FORMAT_DEFAULT:
555 *dest_value = src_value * 1; /* FIXME */
562 case GST_FORMAT_BYTES:
563 switch (*dest_format) {
564 case GST_FORMAT_TIME:
565 *dest_value = src_value * 1; /* FIXME */
572 case GST_FORMAT_DEFAULT:
573 switch (*dest_format) {
574 case GST_FORMAT_TIME:
575 *dest_value = src_value * 1; /* FIXME */
590 static const GstQueryType *
591 gst_qtdemux_get_src_query_types (GstPad * pad)
593 static const GstQueryType src_types[] = {
604 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
608 *duration = GST_CLOCK_TIME_NONE;
610 if (qtdemux->duration != 0) {
611 if (qtdemux->duration != G_MAXINT32 && qtdemux->timescale != 0) {
612 *duration = gst_util_uint64_scale (qtdemux->duration,
613 GST_SECOND, qtdemux->timescale);
620 gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
622 gboolean res = FALSE;
623 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
625 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
627 switch (GST_QUERY_TYPE (query)) {
628 case GST_QUERY_POSITION:
629 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.last_stop)) {
630 gst_query_set_position (query, GST_FORMAT_TIME,
631 qtdemux->segment.last_stop);
635 case GST_QUERY_DURATION:{
638 gst_query_parse_duration (query, &fmt, NULL);
639 if (fmt == GST_FORMAT_TIME) {
640 gint64 duration = -1;
642 gst_qtdemux_get_duration (qtdemux, &duration);
644 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
650 case GST_QUERY_SEEKING:{
654 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
655 if (fmt == GST_FORMAT_TIME) {
656 gint64 duration = -1;
658 gst_qtdemux_get_duration (qtdemux, &duration);
660 if (!qtdemux->pullbased) {
663 /* we might be able with help from upstream */
665 q = gst_query_new_seeking (GST_FORMAT_BYTES);
666 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
667 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
668 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
672 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
678 res = gst_pad_query_default (pad, query);
682 gst_object_unref (qtdemux);
688 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
690 if (G_LIKELY (stream->pad)) {
691 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
692 GST_DEBUG_PAD_NAME (stream->pad));
694 if (G_UNLIKELY (stream->pending_tags)) {
695 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
696 stream->pending_tags);
697 gst_pad_push_event (stream->pad,
698 gst_event_new_tag (stream->pending_tags));
699 stream->pending_tags = NULL;
702 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
703 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
705 gst_pad_push_event (stream->pad,
706 gst_event_new_tag (gst_tag_list_copy (qtdemux->tag_list)));
707 stream->send_global_tags = FALSE;
712 /* push event on all source pads; takes ownership of the event */
714 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
718 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
719 GST_EVENT_TYPE_NAME (event));
721 for (n = 0; n < qtdemux->n_streams; n++) {
724 if ((pad = qtdemux->streams[n]->pad))
725 gst_pad_push_event (pad, gst_event_ref (event));
727 gst_event_unref (event);
730 /* push a pending newsegment event, if any from the streaming thread */
732 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
734 if (qtdemux->pending_newsegment) {
735 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
736 qtdemux->pending_newsegment = NULL;
746 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
748 if (s1->timestamp > *media_time)
754 /* find the index of the sample that includes the data for @media_time using a
757 * Returns the index of the sample.
760 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
763 QtDemuxSample *result;
766 /* convert media_time to mov format */
767 media_time = gst_util_uint64_scale (media_time, str->timescale, GST_SECOND);
769 result = gst_util_array_binary_search (str->samples, str->n_samples,
770 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
771 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
773 if (G_LIKELY (result))
774 index = result - str->samples;
781 /* find the index of the sample that includes the data for @media_time using a
784 * Returns the index of the sample.
787 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
790 QtDemuxSample *result = str->samples;
793 /* convert media_time to mov format */
794 media_time = gst_util_uint64_scale (media_time, str->timescale, GST_SECOND);
796 if (media_time == result->timestamp)
800 while (index < str->n_samples - 1) {
801 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
804 if (media_time < result->timestamp)
815 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
820 /* find the index of the keyframe needed to decode the sample at @index
823 * Returns the index of the keyframe.
826 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
829 guint32 new_index = index;
831 if (index >= str->n_samples) {
832 new_index = str->n_samples;
836 /* all keyframes, return index */
837 if (str->all_keyframe) {
842 /* else go back until we have a keyframe */
844 if (str->samples[new_index].keyframe)
854 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
855 "gave %u", index, new_index);
860 /* find the segment for @time_position for @stream
862 * Returns -1 if the segment cannot be found.
865 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
866 guint64 time_position)
871 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
872 GST_TIME_ARGS (time_position));
874 /* find segment corresponding to time_position if we are looking
877 for (i = 0; i < stream->n_segments; i++) {
878 QtDemuxSegment *segment = &stream->segments[i];
880 GST_LOG_OBJECT (qtdemux,
881 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
882 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
884 /* For the last segment we include stop_time in the last segment */
885 if (i < stream->n_segments - 1) {
886 if (segment->time <= time_position && time_position < segment->stop_time) {
887 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
892 if (segment->time <= time_position && time_position <= segment->stop_time) {
893 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
902 /* move the stream @str to the sample position @index.
904 * Updates @str->sample_index and marks discontinuity if needed.
907 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
910 /* no change needed */
911 if (index == str->sample_index)
914 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
917 /* position changed, we have a discont */
918 str->sample_index = index;
919 /* Each time we move in the stream we store the position where we are
921 str->from_sample = index;
926 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
927 gint64 * key_time, gint64 * key_offset)
930 gint64 min_byte_offset = -1;
933 min_offset = desired_time;
935 /* for each stream, find the index of the sample in the segment
936 * and move back to the previous keyframe. */
937 for (n = 0; n < qtdemux->n_streams; n++) {
939 guint32 index, kindex;
946 str = qtdemux->streams[n];
948 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
949 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
951 /* segment not found, continue with normal flow */
955 /* get segment and time in the segment */
956 seg = &str->segments[seg_idx];
957 seg_time = desired_time - seg->time;
959 /* get the media time in the segment */
960 media_start = seg->media_start + seg_time;
962 /* get the index of the sample with media time */
963 index = gst_qtdemux_find_index (qtdemux, str, media_start);
964 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
965 GST_TIME_ARGS (media_start), index);
967 /* find previous keyframe */
968 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
970 /* if the keyframe is at a different position, we need to update the
971 * requested seek time */
972 if (index != kindex) {
975 /* get timestamp of keyframe */
977 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
979 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT,
980 kindex, GST_TIME_ARGS (media_time));
982 /* keyframes in the segment get a chance to change the
983 * desired_offset. keyframes out of the segment are
985 if (media_time >= seg->media_start) {
988 /* this keyframe is inside the segment, convert back to
990 seg_time = (media_time - seg->media_start) + seg->time;
991 if (seg_time < min_offset)
992 min_offset = seg_time;
996 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
997 min_byte_offset = str->samples[index].offset;
1001 *key_time = min_offset;
1003 *key_offset = min_byte_offset;
1007 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1008 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1013 g_return_val_if_fail (format != NULL, FALSE);
1014 g_return_val_if_fail (cur != NULL, FALSE);
1015 g_return_val_if_fail (stop != NULL, FALSE);
1017 if (*format == GST_FORMAT_TIME)
1020 fmt = GST_FORMAT_TIME;
1022 if (cur_type != GST_SEEK_TYPE_NONE)
1023 res = gst_pad_query_convert (pad, *format, *cur, &fmt, cur);
1024 if (res && stop_type != GST_SEEK_TYPE_NONE)
1025 res = gst_pad_query_convert (pad, *format, *stop, &fmt, stop);
1028 *format = GST_FORMAT_TIME;
1033 /* perform seek in push based mode:
1034 find BYTE position to move to based on time and delegate to upstream
1037 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1042 GstSeekType cur_type, stop_type;
1047 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1049 gst_event_parse_seek (event, &rate, &format, &flags,
1050 &cur_type, &cur, &stop_type, &stop);
1052 /* FIXME, always play to the end */
1055 /* only forward streaming and seeking is possible */
1057 goto unsupported_seek;
1059 /* convert to TIME if needed and possible */
1060 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1064 /* find reasonable corresponding BYTE position,
1065 * also try to mind about keyframes, since we can not go back a bit for them
1067 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1072 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1073 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1076 /* BYTE seek event */
1077 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1079 res = gst_pad_push_event (qtdemux->sinkpad, event);
1086 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1092 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1097 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1102 /* perform the seek.
1104 * We set all segment_indexes in the streams to unknown and
1105 * adjust the time_position to the desired position. this is enough
1106 * to trigger a segment switch in the streaming thread to start
1107 * streaming from the desired position.
1109 * Keyframe seeking is a little more complicated when dealing with
1110 * segments. Ideally we want to move to the previous keyframe in
1111 * the segment but there might not be a keyframe in the segment. In
1112 * fact, none of the segments could contain a keyframe. We take a
1113 * practical approach: seek to the previous keyframe in the segment,
1114 * if there is none, seek to the beginning of the segment.
1116 * Called with STREAM_LOCK
1119 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1121 gint64 desired_offset;
1124 desired_offset = segment->last_stop;
1126 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1127 GST_TIME_ARGS (desired_offset));
1129 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
1132 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1133 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1134 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1135 desired_offset = min_offset;
1138 /* and set all streams to the final position */
1139 for (n = 0; n < qtdemux->n_streams; n++) {
1140 QtDemuxStream *stream = qtdemux->streams[n];
1142 stream->time_position = desired_offset;
1143 stream->sample_index = -1;
1144 stream->segment_index = -1;
1145 stream->last_ret = GST_FLOW_OK;
1146 stream->sent_eos = FALSE;
1148 segment->last_stop = desired_offset;
1149 segment->time = desired_offset;
1151 /* we stop at the end */
1152 if (segment->stop == -1)
1153 segment->stop = segment->duration;
1158 /* do a seek in pull based mode */
1160 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1165 GstSeekType cur_type, stop_type;
1169 GstSegment seeksegment;
1173 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1175 gst_event_parse_seek (event, &rate, &format, &flags,
1176 &cur_type, &cur, &stop_type, &stop);
1178 /* we have to have a format as the segment format. Try to convert
1180 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1184 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1186 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1190 flush = flags & GST_SEEK_FLAG_FLUSH;
1192 /* stop streaming, either by flushing or by pausing the task */
1194 /* unlock upstream pull_range */
1195 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1196 /* make sure out loop function exits */
1197 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1199 /* non flushing seek, pause the task */
1200 gst_pad_pause_task (qtdemux->sinkpad);
1203 /* wait for streaming to finish */
1204 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1206 /* copy segment, we need this because we still need the old
1207 * segment when we close the current segment. */
1208 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1211 /* configure the segment with the seek variables */
1212 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1213 gst_segment_set_seek (&seeksegment, rate, format, flags,
1214 cur_type, cur, stop_type, stop, &update);
1217 /* now do the seek, this actually never returns FALSE */
1218 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1220 /* prepare for streaming again */
1222 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop ());
1223 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop ());
1224 } else if (qtdemux->segment_running) {
1225 /* we are running the current segment and doing a non-flushing seek,
1226 * close the segment first based on the last_stop. */
1227 GST_DEBUG_OBJECT (qtdemux, "closing running segment %" G_GINT64_FORMAT
1228 " to %" G_GINT64_FORMAT, qtdemux->segment.start,
1229 qtdemux->segment.last_stop);
1231 if (qtdemux->segment.rate >= 0) {
1232 /* FIXME, rate is the product of the global rate and the (quicktime)
1234 qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
1235 qtdemux->segment.rate, qtdemux->segment.format,
1236 qtdemux->segment.start, qtdemux->segment.last_stop,
1237 qtdemux->segment.time);
1238 } else { /* For Reverse Playback */
1241 if ((stop = qtdemux->segment.stop) == -1)
1242 stop = qtdemux->segment.duration;
1243 /* for reverse playback, we played from stop to last_stop. */
1244 qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
1245 qtdemux->segment.rate, qtdemux->segment.format,
1246 qtdemux->segment.last_stop, stop, qtdemux->segment.last_stop);
1250 /* commit the new segment */
1251 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1253 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1254 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1255 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1256 qtdemux->segment.format, qtdemux->segment.last_stop));
1259 /* restart streaming, NEWSEGMENT will be sent from the streaming
1261 qtdemux->segment_running = TRUE;
1262 for (i = 0; i < qtdemux->n_streams; i++)
1263 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1265 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1268 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1275 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1281 qtdemux_ensure_index (GstQTDemux * qtdemux)
1285 /* Build complete index */
1286 for (i = 0; i < qtdemux->n_streams; i++) {
1287 QtDemuxStream *stream = qtdemux->streams[i];
1289 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1297 GST_LOG_OBJECT (qtdemux,
1298 "Building complete index of stream %u for seeking failed!", i);
1304 gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
1306 gboolean res = TRUE;
1307 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
1309 switch (GST_EVENT_TYPE (event)) {
1310 case GST_EVENT_SEEK:
1312 GstClockTime ts = gst_util_get_timestamp ();
1313 /* Build complete index for seeking */
1314 if (!qtdemux_ensure_index (qtdemux))
1316 ts = gst_util_get_timestamp () - ts;
1317 GST_INFO_OBJECT (qtdemux,
1318 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1320 if (qtdemux->pullbased) {
1321 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1322 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams) {
1323 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1325 GST_DEBUG_OBJECT (qtdemux,
1326 "ignoring seek in push mode in current state");
1329 gst_event_unref (event);
1332 case GST_EVENT_NAVIGATION:
1334 gst_event_unref (event);
1337 res = gst_pad_event_default (pad, event);
1341 gst_object_unref (qtdemux);
1348 GST_ERROR_OBJECT (qtdemux, "Index failed");
1349 gst_event_unref (event);
1354 /* stream/index return sample that is min/max w.r.t. byte position,
1355 * time is min/max w.r.t. time of samples,
1356 * the latter need not be time of the former sample */
1358 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1359 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1362 guint32 ts_timescale = -1; /* the timescale corresponding to min_time */
1363 gint64 time, min_time;
1364 QtDemuxStream *stream;
1370 for (n = 0; n < qtdemux->n_streams; ++n) {
1373 gboolean set_sample;
1376 str = qtdemux->streams[n];
1383 i = str->n_samples - 1;
1386 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1387 if (str->samples[i].size &&
1388 ((fw && (str->samples[i].offset >= byte_pos)) ||
1390 (str->samples[i].offset + str->samples[i].size <=
1392 /* move stream to first available sample */
1394 gst_qtdemux_move_stream (qtdemux, str, i);
1397 /* determine min/max time */
1398 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1399 if (min_time == -1 || (fw && min_time > time) ||
1400 (!fw && min_time < time)) {
1402 ts_timescale = str->timescale;
1404 /* determine stream with leading sample, to get its position */
1406 && (str->samples[i].offset < stream->samples[index].offset))
1408 && (str->samples[i].offset > stream->samples[index].offset))) {
1415 /* no sample for this stream, mark eos */
1417 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1420 if (_time && ts_timescale != -1)
1421 *_time = gst_util_uint64_scale (min_time, GST_SECOND, ts_timescale);
1429 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
1431 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1434 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1436 switch (GST_EVENT_TYPE (event)) {
1437 case GST_EVENT_NEWSEGMENT:
1440 gdouble rate, arate;
1441 gint64 start, stop, time, offset = 0;
1442 QtDemuxStream *stream;
1447 /* some debug output */
1448 gst_segment_init (&segment, GST_FORMAT_UNDEFINED);
1449 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
1450 &start, &stop, &time);
1451 gst_segment_set_newsegment_full (&segment, update, rate, arate, format,
1453 GST_DEBUG_OBJECT (demux,
1454 "received format %d newsegment %" GST_SEGMENT_FORMAT, format,
1457 /* chain will send initial newsegment after pads have been added */
1458 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1459 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1463 /* we only expect a BYTE segment, e.g. following a seek */
1464 if (format == GST_FORMAT_BYTES) {
1467 gst_qtdemux_find_sample (demux, start, TRUE, FALSE, NULL, NULL,
1469 start = MAX (start, 0);
1472 gst_qtdemux_find_sample (demux, stop, FALSE, FALSE, NULL, NULL,
1474 stop = MAX (stop, 0);
1477 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1481 /* accept upstream's notion of segment and distribute along */
1482 gst_segment_set_newsegment_full (&demux->segment, update, rate, arate,
1483 GST_FORMAT_TIME, start, stop, start);
1484 GST_DEBUG_OBJECT (demux, "Pushing newseg update %d, rate %g, "
1485 "applied rate %g, format %d, start %" GST_TIME_FORMAT ", "
1486 "stop %" GST_TIME_FORMAT, update, rate, arate, GST_FORMAT_TIME,
1487 GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1488 gst_qtdemux_push_event (demux,
1489 gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME,
1490 start, stop, start));
1492 /* clear leftover in current segment, if any */
1493 gst_adapter_clear (demux->adapter);
1494 /* set up streaming thread */
1495 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1496 demux->offset = offset;
1498 demux->todrop = stream->samples[idx].offset - offset;
1499 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1501 /* set up for EOS */
1502 demux->neededbytes = -1;
1506 gst_event_unref (event);
1511 case GST_EVENT_FLUSH_STOP:
1515 /* clean up, force EOS if no more info follows */
1516 gst_adapter_clear (demux->adapter);
1518 demux->neededbytes = -1;
1519 /* reset flow return, e.g. following seek */
1520 for (i = 0; i < demux->n_streams; i++) {
1521 demux->streams[i]->last_ret = GST_FLOW_OK;
1522 demux->streams[i]->sent_eos = FALSE;
1527 /* If we are in push mode, and get an EOS before we've seen any streams,
1528 * then error out - we have nowhere to send the EOS */
1529 if (!demux->pullbased && demux->n_streams == 0) {
1530 GST_ELEMENT_ERROR (demux, STREAM, DECODE,
1531 (_("This file contains no playable streams.")),
1532 ("no known streams found"));
1539 res = gst_pad_event_default (demux->sinkpad, event);
1546 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1548 GstQTDemux *demux = GST_QTDEMUX (element);
1550 GST_OBJECT_LOCK (demux);
1551 if (demux->element_index)
1552 gst_object_unref (demux->element_index);
1554 demux->element_index = gst_object_ref (index);
1556 demux->element_index = NULL;
1558 GST_OBJECT_UNLOCK (demux);
1559 /* object lock might be taken again */
1561 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1562 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->element_index);
1566 gst_qtdemux_get_index (GstElement * element)
1568 GstIndex *result = NULL;
1569 GstQTDemux *demux = GST_QTDEMUX (element);
1571 GST_OBJECT_LOCK (demux);
1572 if (demux->element_index)
1573 result = gst_object_ref (demux->element_index);
1574 GST_OBJECT_UNLOCK (demux);
1576 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1582 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1584 g_free ((gpointer) stream->stco.data);
1585 g_free ((gpointer) stream->stsz.data);
1586 g_free ((gpointer) stream->stsc.data);
1587 g_free ((gpointer) stream->stts.data);
1588 g_free ((gpointer) stream->stss.data);
1589 g_free ((gpointer) stream->stps.data);
1590 g_free ((gpointer) stream->ctts.data);
1593 static GstStateChangeReturn
1594 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1596 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1597 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1599 switch (transition) {
1600 case GST_STATE_CHANGE_PAUSED_TO_READY:
1606 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1608 switch (transition) {
1609 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1612 qtdemux->state = QTDEMUX_STATE_INITIAL;
1613 qtdemux->neededbytes = 16;
1614 qtdemux->todrop = 0;
1615 qtdemux->pullbased = FALSE;
1616 qtdemux->offset = 0;
1617 qtdemux->first_mdat = -1;
1618 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1619 if (qtdemux->mdatbuffer)
1620 gst_buffer_unref (qtdemux->mdatbuffer);
1621 qtdemux->mdatbuffer = NULL;
1622 if (qtdemux->comp_brands)
1623 gst_buffer_unref (qtdemux->comp_brands);
1624 qtdemux->comp_brands = NULL;
1625 if (qtdemux->tag_list)
1626 gst_tag_list_free (qtdemux->tag_list);
1627 qtdemux->tag_list = NULL;
1628 if (qtdemux->element_index)
1629 gst_object_unref (qtdemux->element_index);
1630 qtdemux->element_index = NULL;
1631 gst_adapter_clear (qtdemux->adapter);
1632 for (n = 0; n < qtdemux->n_streams; n++) {
1633 QtDemuxStream *stream = qtdemux->streams[n];
1635 while (stream->buffers) {
1636 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1638 g_slist_delete_link (stream->buffers, stream->buffers);
1641 gst_element_remove_pad (element, stream->pad);
1642 if (stream->samples)
1643 g_free (stream->samples);
1645 gst_caps_unref (stream->caps);
1646 if (stream->segments)
1647 g_free (stream->segments);
1648 if (stream->pending_tags)
1649 gst_tag_list_free (stream->pending_tags);
1650 /* free stbl sub-atoms */
1651 gst_qtdemux_stbl_free (stream);
1654 qtdemux->major_brand = 0;
1655 qtdemux->n_streams = 0;
1656 qtdemux->n_video_streams = 0;
1657 qtdemux->n_audio_streams = 0;
1658 qtdemux->n_sub_streams = 0;
1659 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1670 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1672 /* only consider at least a sufficiently complete ftyp atom */
1676 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1677 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1678 GST_FOURCC_ARGS (qtdemux->major_brand));
1679 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1680 memcpy (GST_BUFFER_DATA (buf), buffer + 16, GST_BUFFER_SIZE (buf));
1685 extract_initial_length_and_fourcc (const guint8 * data, guint64 * plength,
1691 length = QT_UINT32 (data);
1692 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1693 fourcc = QT_FOURCC (data + 4);
1694 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1697 length = G_MAXUINT32;
1698 } else if (length == 1) {
1699 /* this means we have an extended size, which is the 64 bit value of
1700 * the next 8 bytes */
1701 length = QT_UINT64 (data + 8);
1702 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1711 static GstFlowReturn
1712 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
1716 GstBuffer *buf = NULL;
1717 GstFlowReturn ret = GST_FLOW_OK;
1718 guint64 cur_offset = qtdemux->offset;
1720 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
1721 if (G_UNLIKELY (ret != GST_FLOW_OK))
1723 if (G_LIKELY (GST_BUFFER_SIZE (buf) == 16))
1724 extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf), &length, &fourcc);
1725 gst_buffer_unref (buf);
1727 if (G_UNLIKELY (length == 0)) {
1728 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
1729 (_("This file is invalid and cannot be played.")),
1730 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
1731 GST_FOURCC_ARGS (fourcc)));
1732 ret = GST_FLOW_ERROR;
1743 GST_LOG_OBJECT (qtdemux,
1744 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
1745 GST_FOURCC_ARGS (fourcc), cur_offset);
1746 qtdemux->offset += length;
1753 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
1754 if (ret != GST_FLOW_OK)
1756 if (length != GST_BUFFER_SIZE (moov)) {
1757 /* Some files have a 'moov' atom at the end of the file which contains
1758 * a terminal 'free' atom where the body of the atom is missing.
1759 * Check for, and permit, this special case.
1761 if (GST_BUFFER_SIZE (moov) >= 8) {
1762 guint8 *final_data = GST_BUFFER_DATA (moov) +
1763 (GST_BUFFER_SIZE (moov) - 8);
1764 guint32 final_length = QT_UINT32 (final_data);
1765 guint32 final_fourcc = QT_FOURCC (final_data + 4);
1766 if (final_fourcc == FOURCC_free &&
1767 GST_BUFFER_SIZE (moov) + final_length - 8 == length) {
1768 /* Ok, we've found that special case. Allocate a new buffer with
1769 * that free atom actually present. */
1770 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
1771 gst_buffer_copy_metadata (newmoov, moov,
1772 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
1773 GST_BUFFER_COPY_CAPS);
1774 memcpy (GST_BUFFER_DATA (newmoov), GST_BUFFER_DATA (moov),
1775 GST_BUFFER_SIZE (moov));
1776 memset (GST_BUFFER_DATA (newmoov) + GST_BUFFER_SIZE (moov), 0,
1778 gst_buffer_unref (moov);
1784 if (length != GST_BUFFER_SIZE (moov)) {
1785 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
1786 (_("This file is incomplete and cannot be played.")),
1787 ("We got less than expected (received %u, wanted %u, offset %"
1788 G_GUINT64_FORMAT ")",
1789 GST_BUFFER_SIZE (moov), (guint) length, cur_offset));
1790 ret = GST_FLOW_ERROR;
1793 qtdemux->offset += length;
1795 qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
1796 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
1798 qtdemux_parse_tree (qtdemux);
1799 g_node_destroy (qtdemux->moov_node);
1800 gst_buffer_unref (moov);
1801 qtdemux->moov_node = NULL;
1802 qtdemux->state = QTDEMUX_STATE_MOVIE;
1803 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
1811 /* extract major brand; might come in handy for ISO vs QT issues */
1812 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
1813 if (ret != GST_FLOW_OK)
1815 qtdemux->offset += length;
1816 qtdemux_parse_ftyp (qtdemux, GST_BUFFER_DATA (ftyp),
1817 GST_BUFFER_SIZE (ftyp));
1818 gst_buffer_unref (ftyp);
1825 GST_LOG_OBJECT (qtdemux,
1826 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
1827 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
1829 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
1830 if (ret != GST_FLOW_OK)
1832 GST_MEMDUMP ("Unknown tag", GST_BUFFER_DATA (unknown),
1833 GST_BUFFER_SIZE (unknown));
1834 gst_buffer_unref (unknown);
1835 qtdemux->offset += length;
1844 /* Seeks to the previous keyframe of the indexed stream and
1845 * aligns other streams with respect to the keyframe timestamp
1846 * of indexed stream. Only called in case of Reverse Playback
1848 static GstFlowReturn
1849 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
1852 guint32 seg_idx = 0, k_index = 0;
1853 guint64 k_pos = 0, last_stop = 0;
1854 QtDemuxSegment *seg = NULL;
1855 QtDemuxStream *ref_str = NULL;
1856 guint64 seg_media_start_mov; /* segment media start time in mov format */
1858 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
1859 * and finally align all the other streams on that timestamp with their
1860 * respective keyframes */
1861 for (n = 0; n < qtdemux->n_streams; n++) {
1862 QtDemuxStream *str = qtdemux->streams[n];
1864 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
1865 qtdemux->segment.last_stop);
1867 /* segment not found, continue with normal flow */
1871 /* No candidate yet, take that one */
1877 /* So that stream has a segment, we prefer video streams */
1878 if (str->subtype == FOURCC_vide) {
1884 if (G_UNLIKELY (!ref_str)) {
1885 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
1889 if (G_UNLIKELY (!ref_str->from_sample)) {
1890 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
1894 /* So that stream has been playing from from_sample to to_sample. We will
1895 * get the timestamp of the previous sample and search for a keyframe before
1896 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
1897 if (ref_str->subtype == FOURCC_vide) {
1898 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
1899 ref_str->from_sample - 1);
1901 k_index = ref_str->from_sample - 10;
1904 /* get current segment for that stream */
1905 seg = &ref_str->segments[ref_str->segment_index];
1906 /* convert seg->media_start to mov format time for timestamp comparison */
1907 seg_media_start_mov =
1908 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
1909 /* Crawl back through segments to find the one containing this I frame */
1910 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
1911 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
1912 ref_str->segment_index);
1913 if (G_UNLIKELY (!ref_str->segment_index)) {
1914 /* Reached first segment, let's consider it's EOS */
1917 ref_str->segment_index--;
1918 seg = &ref_str->segments[ref_str->segment_index];
1920 /* Calculate time position of the keyframe and where we should stop */
1922 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
1923 ref_str->timescale) - seg->media_start) + seg->time;
1925 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
1926 GST_SECOND, ref_str->timescale);
1927 last_stop = (last_stop - seg->media_start) + seg->time;
1929 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
1930 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
1931 k_index, GST_TIME_ARGS (k_pos));
1933 /* Set last_stop with the keyframe timestamp we pushed of that stream */
1934 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, last_stop);
1935 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
1936 GST_TIME_ARGS (last_stop));
1938 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
1939 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
1943 /* Align them all on this */
1944 for (n = 0; n < qtdemux->n_streams; n++) {
1946 guint64 media_start = 0, seg_time = 0;
1947 QtDemuxStream *str = qtdemux->streams[n];
1949 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
1950 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1952 /* segment not found, continue with normal flow */
1956 /* get segment and time in the segment */
1957 seg = &str->segments[seg_idx];
1958 seg_time = k_pos - seg->time;
1960 /* get the media time in the segment */
1961 media_start = seg->media_start + seg_time;
1963 /* get the index of the sample with media time */
1964 index = gst_qtdemux_find_index (qtdemux, str, media_start);
1965 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
1966 GST_TIME_ARGS (media_start), index);
1968 /* find previous keyframe */
1969 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
1971 /* Remember until where we want to go */
1972 str->to_sample = str->from_sample - 1;
1973 /* Define our time position */
1974 str->time_position =
1975 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
1976 str->timescale) - seg->media_start) + seg->time;
1977 /* Now seek back in time */
1978 gst_qtdemux_move_stream (qtdemux, str, k_index);
1979 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
1980 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
1981 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
1987 return GST_FLOW_UNEXPECTED;
1990 /* activate the given segment number @seg_idx of @stream at time @offset.
1991 * @offset is an absolute global position over all the segments.
1993 * This will push out a NEWSEGMENT event with the right values and
1994 * position the stream index to the first decodable sample before
1998 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1999 guint32 seg_idx, guint64 offset)
2002 QtDemuxSegment *segment;
2003 guint32 index, kf_index;
2005 guint64 start, stop, time;
2008 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
2011 /* update the current segment */
2012 stream->segment_index = seg_idx;
2014 /* get the segment */
2015 segment = &stream->segments[seg_idx];
2017 if (G_UNLIKELY (offset < segment->time)) {
2018 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
2023 /* get time in this segment */
2024 seg_time = offset - segment->time;
2026 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
2027 GST_TIME_ARGS (seg_time));
2029 if (G_UNLIKELY (seg_time > segment->duration)) {
2030 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
2031 GST_TIME_ARGS (segment->duration));
2035 /* qtdemux->segment.stop is in outside-time-realm, whereas
2036 * segment->media_stop is in track-time-realm.
2038 * In order to compare the two, we need to bring segment.stop
2039 * into the track-time-realm */
2041 if (qtdemux->segment.stop == -1)
2042 stop = segment->media_stop;
2045 MIN (segment->media_stop,
2046 qtdemux->segment.stop - segment->time + segment->media_start);
2048 if (qtdemux->segment.rate >= 0) {
2049 start = MIN (segment->media_start + seg_time, stop);
2052 start = segment->media_start;
2053 stop = MIN (segment->media_start + seg_time, stop);
2054 time = segment->time;
2057 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
2058 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
2059 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
2061 /* combine global rate with that of the segment */
2062 rate = segment->rate * qtdemux->segment.rate;
2064 /* update the segment values used for clipping */
2065 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
2066 gst_segment_set_newsegment (&stream->segment, FALSE, rate, GST_FORMAT_TIME,
2069 /* now prepare and send the segment */
2071 event = gst_event_new_new_segment (FALSE, rate, GST_FORMAT_TIME,
2073 gst_pad_push_event (stream->pad, event);
2074 /* assume we can send more data now */
2075 stream->last_ret = GST_FLOW_OK;
2076 /* clear to send tags on this pad now */
2077 gst_qtdemux_push_tags (qtdemux, stream);
2080 /* and move to the keyframe before the indicated media time of the
2082 if (qtdemux->segment.rate >= 0) {
2083 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
2084 stream->to_sample = stream->n_samples;
2085 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
2086 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
2087 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
2088 GST_SECOND, stream->timescale)));
2090 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
2091 stream->to_sample = index;
2092 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
2093 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
2094 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
2095 GST_SECOND, stream->timescale)));
2098 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
2099 * encountered an error and printed a message so we return appropriately */
2103 /* we're at the right spot */
2104 if (index == stream->sample_index) {
2105 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
2109 /* find keyframe of the target index */
2110 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
2113 /* indent does stupid stuff with stream->samples[].timestamp */
2115 /* if we move forwards, we don't have to go back to the previous
2116 * keyframe since we already sent that. We can also just jump to
2117 * the keyframe right before the target index if there is one. */
2118 if (index > stream->sample_index) {
2119 /* moving forwards check if we move past a keyframe */
2120 if (kf_index > stream->sample_index) {
2121 GST_DEBUG_OBJECT (qtdemux,
2122 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
2123 GST_TIME_ARGS (gst_util_uint64_scale (
2124 stream->samples[kf_index].timestamp,
2125 GST_SECOND, stream->timescale)));
2126 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
2128 GST_DEBUG_OBJECT (qtdemux,
2129 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
2130 " already sent", kf_index,
2131 GST_TIME_ARGS (gst_util_uint64_scale (
2132 stream->samples[kf_index].timestamp,
2133 GST_SECOND, stream->timescale)));
2136 GST_DEBUG_OBJECT (qtdemux,
2137 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
2138 GST_TIME_ARGS (gst_util_uint64_scale (
2139 stream->samples[kf_index].timestamp,
2140 GST_SECOND, stream->timescale)));
2141 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
2149 /* prepare to get the current sample of @stream, getting essential values.
2151 * This function will also prepare and send the segment when needed.
2153 * Return FALSE if the stream is EOS.
2156 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
2157 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp,
2158 guint64 * duration, gboolean * keyframe)
2160 QtDemuxSample *sample;
2161 guint64 time_position;
2164 g_return_val_if_fail (stream != NULL, FALSE);
2166 time_position = stream->time_position;
2167 if (G_UNLIKELY (time_position == -1))
2170 seg_idx = stream->segment_index;
2171 if (G_UNLIKELY (seg_idx == -1)) {
2172 /* find segment corresponding to time_position if we are looking
2174 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
2176 /* nothing found, we're really eos */
2181 /* different segment, activate it, sample_index will be set. */
2182 if (G_UNLIKELY (stream->segment_index != seg_idx))
2183 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
2185 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
2186 stream->sample_index, stream->n_samples);
2188 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
2191 /* now get the info for the sample we're at */
2192 sample = &stream->samples[stream->sample_index];
2194 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
2195 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
2196 stream->sample_index);
2200 *timestamp = QTSAMPLE_PTS (stream, sample);
2201 *offset = sample->offset;
2202 *size = sample->size;
2203 *duration = QTSAMPLE_DUR_PTS (stream, sample, *timestamp);
2204 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
2206 /* update dummy segment duration */
2207 if (stream->sample_index == stream->n_samples - 1 && stream->n_segments == 1) {
2208 stream->segments[0].duration = stream->segments[0].stop_time =
2209 stream->segments[0].media_stop = *timestamp + *duration;
2217 stream->time_position = -1;
2222 /* move to the next sample in @stream.
2224 * Moves to the next segment when needed.
2227 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
2229 QtDemuxSample *sample;
2230 QtDemuxSegment *segment;
2232 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
2233 /* Mark the stream as EOS */
2234 GST_DEBUG_OBJECT (qtdemux,
2235 "reached max allowed sample %u, mark EOS", stream->to_sample);
2236 stream->time_position = -1;
2240 /* move to next sample */
2241 stream->sample_index++;
2243 /* get current segment */
2244 segment = &stream->segments[stream->segment_index];
2246 /* reached the last sample, we need the next segment */
2247 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
2250 /* get next sample */
2251 sample = &stream->samples[stream->sample_index];
2253 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
2254 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
2255 stream->sample_index);
2259 /* see if we are past the segment */
2260 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
2261 GST_SECOND, stream->timescale) >= segment->media_stop))
2264 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
2265 stream->timescale) >= segment->media_start) {
2266 /* inside the segment, update time_position, looks very familiar to
2267 * GStreamer segments, doesn't it? */
2268 stream->time_position =
2269 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
2270 stream->timescale) - segment->media_start) + segment->time;
2272 /* not yet in segment, time does not yet increment. This means
2273 * that we are still prerolling keyframes to the decoder so it can
2274 * decode the first sample of the segment. */
2275 stream->time_position = segment->time;
2279 /* move to the next segment */
2282 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
2284 if (stream->segment_index == stream->n_segments - 1) {
2285 /* are we at the end of the last segment, we're EOS */
2286 stream->time_position = -1;
2288 /* else we're only at the end of the current segment */
2289 stream->time_position = segment->stop_time;
2291 /* make sure we select a new segment */
2292 stream->segment_index = -1;
2297 gst_qtdemux_sync_streams (GstQTDemux * demux)
2301 if (demux->n_streams <= 1)
2304 for (i = 0; i < demux->n_streams; i++) {
2305 QtDemuxStream *stream;
2306 GstClockTime end_time;
2308 stream = demux->streams[i];
2313 /* TODO advance time on subtitle streams here, if any some day */
2315 /* some clips/trailers may have unbalanced streams at the end,
2316 * so send EOS on shorter stream to prevent stalling others */
2318 /* do not mess with EOS if SEGMENT seeking */
2319 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
2322 if (demux->pullbased) {
2323 /* loop mode is sample time based */
2324 if (stream->time_position != -1)
2327 /* push mode is byte position based */
2328 if (stream->samples[stream->n_samples - 1].offset >= demux->offset)
2332 if (stream->sent_eos)
2335 /* only act if some gap */
2336 end_time = stream->segments[stream->n_segments - 1].stop_time;
2337 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
2338 ", stream end: %" GST_TIME_FORMAT,
2339 GST_TIME_ARGS (demux->segment.last_stop), GST_TIME_ARGS (end_time));
2340 if (end_time + 2 * GST_SECOND < demux->segment.last_stop) {
2341 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
2342 GST_PAD_NAME (stream->pad));
2343 stream->sent_eos = TRUE;
2344 gst_pad_push_event (stream->pad, gst_event_new_eos ());
2349 /* UNEXPECTED and NOT_LINKED need to be combined. This means that we return:
2351 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
2352 * GST_FLOW_UNEXPECTED: when all pads UNEXPECTED or NOT_LINKED.
2354 static GstFlowReturn
2355 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
2359 gboolean unexpected = FALSE, not_linked = TRUE;
2361 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
2363 /* store the value */
2364 stream->last_ret = ret;
2366 for (i = 0; i < demux->n_streams; i++) {
2367 QtDemuxStream *ostream = demux->streams[i];
2369 ret = ostream->last_ret;
2371 /* no unexpected or unlinked, return */
2372 if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
2375 /* we check to see if we have at least 1 unexpected or all unlinked */
2376 unexpected |= (ret == GST_FLOW_UNEXPECTED);
2377 not_linked &= (ret == GST_FLOW_NOT_LINKED);
2380 /* when we get here, we all have unlinked or unexpected */
2382 ret = GST_FLOW_NOT_LINKED;
2383 else if (unexpected)
2384 ret = GST_FLOW_UNEXPECTED;
2386 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
2390 /* the input buffer metadata must be writable. Returns NULL when the buffer is
2391 * completely cliped */
2393 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
2396 gint64 start, stop, cstart, cstop, diff;
2397 GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
2400 gint num_rate, denom_rate;
2404 data = GST_BUFFER_DATA (buf);
2405 size = GST_BUFFER_SIZE (buf);
2407 /* depending on the type, setup the clip parameters */
2408 if (stream->subtype == FOURCC_soun) {
2409 frame_size = stream->bytes_per_frame;
2410 num_rate = GST_SECOND;
2411 denom_rate = (gint) stream->rate;
2413 } else if (stream->subtype == FOURCC_vide) {
2415 num_rate = stream->fps_n;
2416 denom_rate = stream->fps_d;
2421 /* we can only clip if we have a valid timestamp */
2422 timestamp = GST_BUFFER_TIMESTAMP (buf);
2423 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
2426 if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf))) {
2427 duration = GST_BUFFER_DURATION (buf);
2430 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
2434 stop = start + duration;
2436 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
2437 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
2440 /* see if some clipping happened */
2441 diff = cstart - start;
2447 /* bring clipped time to samples and to bytes */
2448 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
2451 GST_DEBUG_OBJECT (qtdemux,
2452 "clipping start to %" GST_TIME_FORMAT " %"
2453 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
2459 diff = stop - cstop;
2464 /* bring clipped time to samples and then to bytes */
2465 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
2467 GST_DEBUG_OBJECT (qtdemux,
2468 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
2469 " bytes", GST_TIME_ARGS (cstop), diff);
2474 GST_BUFFER_TIMESTAMP (buf) = timestamp;
2475 GST_BUFFER_DURATION (buf) = duration;
2476 GST_BUFFER_SIZE (buf) = size;
2477 GST_BUFFER_DATA (buf) = data;
2481 /* dropped buffer */
2484 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
2489 GST_DEBUG_OBJECT (qtdemux, "no timestamp on buffer");
2494 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
2495 gst_buffer_unref (buf);
2500 /* the input buffer metadata must be writable,
2501 * but time/duration etc not yet set and need not be preserved */
2503 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
2507 guint size, nsize = 0;
2510 data = GST_BUFFER_DATA (buf);
2511 size = GST_BUFFER_SIZE (buf);
2513 /* not many cases for now */
2514 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
2515 /* send a one time dvd clut event */
2516 if (stream->pending_event && stream->pad)
2517 gst_pad_push_event (stream->pad, stream->pending_event);
2518 stream->pending_event = NULL;
2519 /* no further processing needed */
2520 stream->need_process = FALSE;
2523 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
2527 if (G_LIKELY (size >= 2)) {
2528 nsize = GST_READ_UINT16_BE (data);
2529 nsize = MIN (nsize, size - 2);
2532 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%d", nsize, size);
2534 /* takes care of UTF-8 validation or UTF-16 recognition,
2535 * no other encoding expected */
2536 str = gst_tag_freeform_string_to_utf8 ((gchar *) data + 2, nsize, NULL);
2538 gst_buffer_unref (buf);
2539 buf = gst_buffer_new ();
2540 GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = (guint8 *) str;
2541 GST_BUFFER_SIZE (buf) = strlen (str);
2543 /* may be 0-size subtitle, which is also sent to keep pipeline going */
2544 GST_BUFFER_DATA (buf) = data + 2;
2545 GST_BUFFER_SIZE (buf) = nsize;
2548 /* FIXME ? convert optional subsequent style info to markup */
2553 /* Sets a buffer's attributes properly and pushes it downstream.
2554 * Also checks for additional actions and custom processing that may
2555 * need to be done first.
2558 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
2559 QtDemuxStream * stream, GstBuffer * buf,
2560 guint64 timestamp, guint64 duration, gboolean keyframe, guint64 position,
2561 guint64 byte_position)
2563 GstFlowReturn ret = GST_FLOW_OK;
2565 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
2569 url = g_strndup ((gchar *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
2571 /* we have RTSP redirect now */
2572 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
2573 gst_structure_new ("redirect",
2574 "new-location", G_TYPE_STRING, url, NULL));
2577 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
2580 /* position reporting */
2581 if (qtdemux->segment.rate >= 0) {
2582 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, position);
2583 gst_qtdemux_sync_streams (qtdemux);
2586 if (G_UNLIKELY (!stream->pad)) {
2587 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
2588 gst_buffer_unref (buf);
2592 /* send out pending buffers */
2593 while (stream->buffers) {
2594 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
2596 if (G_UNLIKELY (stream->discont)) {
2597 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
2598 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
2599 stream->discont = FALSE;
2601 gst_buffer_set_caps (buffer, stream->caps);
2603 gst_pad_push (stream->pad, buffer);
2605 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2608 /* we're going to modify the metadata */
2609 buf = gst_buffer_make_metadata_writable (buf);
2611 if (G_UNLIKELY (stream->need_process))
2612 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
2614 GST_BUFFER_TIMESTAMP (buf) = timestamp;
2615 GST_BUFFER_DURATION (buf) = duration;
2616 GST_BUFFER_OFFSET (buf) = -1;
2617 GST_BUFFER_OFFSET_END (buf) = -1;
2619 if (G_UNLIKELY (stream->padding)) {
2620 GST_BUFFER_DATA (buf) += stream->padding;
2621 GST_BUFFER_SIZE (buf) -= stream->padding;
2624 if (G_UNLIKELY (qtdemux->element_index)) {
2625 GstClockTime stream_time;
2628 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
2630 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
2631 GST_LOG_OBJECT (qtdemux,
2632 "adding association %" GST_TIME_FORMAT "-> %"
2633 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
2634 gst_index_add_association (qtdemux->element_index,
2636 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
2637 GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_TIME, stream_time,
2638 GST_FORMAT_BYTES, byte_position, NULL);
2642 if (stream->need_clip)
2643 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
2645 if (G_UNLIKELY (buf == NULL))
2648 if (G_UNLIKELY (stream->discont)) {
2649 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
2650 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
2651 stream->discont = FALSE;
2655 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
2657 gst_buffer_set_caps (buf, stream->caps);
2659 GST_LOG_OBJECT (qtdemux,
2660 "Pushing buffer with time %" GST_TIME_FORMAT ", duration %"
2661 GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2662 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
2664 ret = gst_pad_push (stream->pad, buf);
2670 static GstFlowReturn
2671 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
2673 GstFlowReturn ret = GST_FLOW_OK;
2674 GstBuffer *buf = NULL;
2675 QtDemuxStream *stream;
2678 guint64 timestamp = GST_CLOCK_TIME_NONE;
2679 guint64 duration = 0;
2680 gboolean keyframe = FALSE;
2685 gst_qtdemux_push_pending_newsegment (qtdemux);
2687 /* Figure out the next stream sample to output, min_time is expressed in
2688 * global time and runs over the edit list segments. */
2689 min_time = G_MAXUINT64;
2691 for (i = 0; i < qtdemux->n_streams; i++) {
2694 stream = qtdemux->streams[i];
2695 position = stream->time_position;
2697 /* position of -1 is EOS */
2698 if (position != -1 && position < min_time) {
2699 min_time = position;
2704 if (G_UNLIKELY (index == -1)) {
2705 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
2709 /* check for segment end */
2710 if (G_UNLIKELY (qtdemux->segment.stop != -1
2711 && qtdemux->segment.stop < min_time)) {
2712 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
2716 stream = qtdemux->streams[index];
2718 /* fetch info for the current sample of this stream */
2719 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
2720 &size, ×tamp, &duration, &keyframe)))
2723 GST_LOG_OBJECT (qtdemux,
2724 "pushing from stream %d, offset %" G_GUINT64_FORMAT
2725 ", size %d, timestamp=%" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
2726 index, offset, size, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
2728 /* hmm, empty sample, skip and move to next sample */
2729 if (G_UNLIKELY (size <= 0))
2732 /* last pushed sample was out of boundary, goto next sample */
2733 if (G_UNLIKELY (stream->last_ret == GST_FLOW_UNEXPECTED))
2736 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
2739 ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
2740 if (G_UNLIKELY (ret != GST_FLOW_OK))
2743 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
2744 timestamp, duration, keyframe, min_time, offset);
2747 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
2748 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
2749 * we have no more data for the pad to push */
2750 if (ret == GST_FLOW_UNEXPECTED)
2754 gst_qtdemux_advance_sample (qtdemux, stream);
2762 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
2763 ret = GST_FLOW_UNEXPECTED;
2768 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
2769 /* EOS will be raised if all are EOS */
2776 gst_qtdemux_loop (GstPad * pad)
2778 GstQTDemux *qtdemux;
2782 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
2784 cur_offset = qtdemux->offset;
2785 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
2786 cur_offset, qtdemux->state);
2788 switch (qtdemux->state) {
2789 case QTDEMUX_STATE_INITIAL:
2790 case QTDEMUX_STATE_HEADER:
2791 ret = gst_qtdemux_loop_state_header (qtdemux);
2793 case QTDEMUX_STATE_MOVIE:
2794 ret = gst_qtdemux_loop_state_movie (qtdemux);
2795 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_UNEXPECTED) {
2796 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
2804 /* if something went wrong, pause */
2805 if (ret != GST_FLOW_OK)
2809 gst_object_unref (qtdemux);
2815 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
2816 (NULL), ("streaming stopped, invalid state"));
2817 qtdemux->segment_running = FALSE;
2818 gst_pad_pause_task (pad);
2819 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
2824 const gchar *reason = gst_flow_get_name (ret);
2826 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
2828 qtdemux->segment_running = FALSE;
2829 gst_pad_pause_task (pad);
2831 /* fatal errors need special actions */
2832 if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
2834 if (ret == GST_FLOW_UNEXPECTED) {
2835 if (qtdemux->n_streams == 0) {
2836 /* we have no streams, post an error */
2837 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2838 (_("This file contains no playable streams.")),
2839 ("no known streams found"));
2841 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2844 /* FIXME: I am not sure this is the right fix. If the sinks are
2845 * supposed to detect the segment is complete and accumulate
2846 * automatically, it does not seem to work here. Need more work */
2847 qtdemux->segment_running = TRUE;
2849 if ((stop = qtdemux->segment.stop) == -1)
2850 stop = qtdemux->segment.duration;
2852 if (qtdemux->segment.rate >= 0) {
2853 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
2854 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
2855 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
2856 GST_FORMAT_TIME, stop));
2858 /* For Reverse Playback */
2859 GST_LOG_OBJECT (qtdemux,
2860 "Sending segment done, at start of segment");
2861 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
2862 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
2863 GST_FORMAT_TIME, qtdemux->segment.start));
2866 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
2867 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
2870 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
2871 (NULL), ("streaming stopped, reason %s", reason));
2872 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
2882 * Returns the size of the first entry at the current offset.
2883 * If -1, there are none (which means EOS or empty file).
2886 next_entry_size (GstQTDemux * demux)
2888 QtDemuxStream *stream;
2891 guint64 smalloffs = (guint64) - 1;
2892 QtDemuxSample *sample;
2894 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
2897 for (i = 0; i < demux->n_streams; i++) {
2898 stream = demux->streams[i];
2900 if (stream->sample_index == -1)
2901 stream->sample_index = 0;
2903 if (stream->sample_index >= stream->n_samples) {
2904 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
2908 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
2909 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
2910 stream->sample_index);
2914 sample = &stream->samples[stream->sample_index];
2916 GST_LOG_OBJECT (demux,
2917 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
2918 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
2919 sample->offset, sample->size);
2921 if (((smalloffs == -1)
2922 || (sample->offset < smalloffs)) && (sample->size)) {
2924 smalloffs = sample->offset;
2928 GST_LOG_OBJECT (demux,
2929 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
2930 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
2935 stream = demux->streams[smallidx];
2936 sample = &stream->samples[stream->sample_index];
2938 if (sample->offset >= demux->offset) {
2939 demux->todrop = sample->offset - demux->offset;
2940 return sample->size + demux->todrop;
2943 GST_DEBUG_OBJECT (demux,
2944 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
2949 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
2951 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
2953 gst_element_post_message (GST_ELEMENT_CAST (demux),
2954 gst_message_new_element (GST_OBJECT_CAST (demux),
2955 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
2959 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
2964 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
2967 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
2968 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
2969 GST_SEEK_TYPE_NONE, -1);
2971 res = gst_pad_push_event (demux->sinkpad, event);
2976 /* FIXME, unverified after edit list updates */
2977 static GstFlowReturn
2978 gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
2981 GstFlowReturn ret = GST_FLOW_OK;
2983 demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad));
2985 gst_adapter_push (demux->adapter, inbuf);
2987 /* we never really mean to buffer that much */
2988 if (demux->neededbytes == -1)
2991 GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
2992 inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
2994 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
2995 (ret == GST_FLOW_OK)) {
2997 GST_DEBUG_OBJECT (demux,
2998 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
2999 demux->state, demux->neededbytes, demux->offset);
3001 switch (demux->state) {
3002 case QTDEMUX_STATE_INITIAL:{
3007 /* prepare newsegment to send when streaming actually starts */
3008 if (!demux->pending_newsegment) {
3009 demux->pending_newsegment =
3010 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
3011 0, GST_CLOCK_TIME_NONE, 0);
3014 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
3016 /* get fourcc/length, set neededbytes */
3017 extract_initial_length_and_fourcc ((guint8 *) data, &size, &fourcc);
3018 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
3019 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
3021 GST_ELEMENT_ERROR (demux, STREAM, DECODE,
3022 (_("This file is invalid and cannot be played.")),
3023 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
3024 GST_FOURCC_ARGS (fourcc)));
3025 ret = GST_FLOW_ERROR;
3028 if (fourcc == FOURCC_mdat) {
3029 if (demux->n_streams > 0) {
3030 /* we have the headers, start playback */
3031 demux->state = QTDEMUX_STATE_MOVIE;
3032 demux->neededbytes = next_entry_size (demux);
3034 /* no headers yet, try to get them */
3037 guint64 old, target;
3040 old = demux->offset;
3041 target = old + size;
3043 /* try to jump over the atom with a seek */
3044 res = qtdemux_seek_offset (demux, target);
3047 GST_DEBUG_OBJECT (demux, "seek success");
3048 /* remember the offset fo the first mdat so we can seek back to it
3049 * after we have the headers */
3050 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
3051 demux->first_mdat = old;
3052 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
3055 /* seek worked, continue reading */
3056 demux->offset = target;
3057 demux->neededbytes = 16;
3058 demux->state = QTDEMUX_STATE_INITIAL;
3060 /* seek failed, need to buffer */
3061 demux->offset = old;
3062 GST_DEBUG_OBJECT (demux, "seek failed");
3063 /* there may be multiple mdat (or alike) buffers */
3065 if (demux->mdatbuffer)
3066 bs = GST_BUFFER_SIZE (demux->mdatbuffer);
3069 if (size + bs > 10 * (1 << 20))
3071 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
3072 demux->neededbytes = size;
3073 if (!demux->mdatbuffer)
3074 demux->mdatoffset = demux->offset;
3077 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
3078 GST_ELEMENT_ERROR (demux, STREAM, DECODE,
3079 (_("This file is invalid and cannot be played.")),
3080 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
3081 GST_FOURCC_ARGS (fourcc), size));
3082 ret = GST_FLOW_ERROR;
3085 /* this means we already started buffering and still no moov header,
3086 * let's continue buffering everything till we get moov */
3087 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
3089 demux->neededbytes = size;
3090 demux->state = QTDEMUX_STATE_HEADER;
3094 case QTDEMUX_STATE_HEADER:{
3098 GST_DEBUG_OBJECT (demux, "In header");
3100 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
3102 /* parse the header */
3103 extract_initial_length_and_fourcc (data, NULL, &fourcc);
3104 if (fourcc == FOURCC_moov) {
3105 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
3107 qtdemux_parse_moov (demux, data, demux->neededbytes);
3108 qtdemux_node_dump (demux, demux->moov_node);
3109 qtdemux_parse_tree (demux);
3111 g_node_destroy (demux->moov_node);
3112 demux->moov_node = NULL;
3113 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
3114 } else if (fourcc == FOURCC_ftyp) {
3115 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
3116 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
3118 GST_WARNING_OBJECT (demux,
3119 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
3120 GST_FOURCC_ARGS (fourcc));
3121 /* Let's jump that one and go back to initial state */
3124 if (demux->mdatbuffer && demux->n_streams) {
3127 /* the mdat was before the header */
3128 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
3129 demux->n_streams, demux->mdatbuffer);
3130 /* restore our adapter/offset view of things with upstream;
3131 * put preceding buffered data ahead of current moov data.
3132 * This should also handle evil mdat, moov, mdat cases and alike */
3133 buf = gst_adapter_take_buffer (demux->adapter,
3134 gst_adapter_available (demux->adapter));
3135 gst_adapter_clear (demux->adapter);
3136 gst_adapter_push (demux->adapter, demux->mdatbuffer);
3137 gst_adapter_push (demux->adapter, buf);
3138 demux->mdatbuffer = NULL;
3139 demux->offset = demux->mdatoffset;
3140 demux->neededbytes = next_entry_size (demux);
3141 demux->state = QTDEMUX_STATE_MOVIE;
3143 GST_DEBUG_OBJECT (demux, "Carrying on normally");
3144 gst_adapter_flush (demux->adapter, demux->neededbytes);
3146 if (demux->first_mdat != -1) {
3149 /* we need to seek back */
3150 res = qtdemux_seek_offset (demux, demux->first_mdat);
3152 demux->offset = demux->first_mdat;
3154 GST_DEBUG_OBJECT (demux, "Seek back failed");
3157 demux->offset += demux->neededbytes;
3159 demux->neededbytes = 16;
3160 demux->state = QTDEMUX_STATE_INITIAL;
3165 case QTDEMUX_STATE_BUFFER_MDAT:{
3168 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
3170 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
3171 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
3172 GST_FOURCC_ARGS (QT_FOURCC (GST_BUFFER_DATA (buf) + 4)));
3173 if (demux->mdatbuffer)
3174 demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
3176 demux->mdatbuffer = buf;
3177 demux->offset += demux->neededbytes;
3178 demux->neededbytes = 16;
3179 demux->state = QTDEMUX_STATE_INITIAL;
3180 gst_qtdemux_post_progress (demux, 1, 1);
3184 case QTDEMUX_STATE_MOVIE:{
3186 QtDemuxStream *stream = NULL;
3187 QtDemuxSample *sample;
3189 guint64 timestamp, duration, position;
3192 GST_DEBUG_OBJECT (demux,
3193 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
3195 if (demux->todrop) {
3196 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
3197 gst_adapter_flush (demux->adapter, demux->todrop);
3198 demux->neededbytes -= demux->todrop;
3199 demux->offset += demux->todrop;
3203 /* initial newsegment sent here after having added pads,
3204 * possible others in sink_event */
3205 if (G_UNLIKELY (demux->pending_newsegment)) {
3206 gst_qtdemux_push_event (demux, demux->pending_newsegment);
3207 demux->pending_newsegment = NULL;
3208 /* clear to send tags on all streams */
3209 for (i = 0; i < demux->n_streams; i++) {
3210 gst_qtdemux_push_tags (demux, demux->streams[i]);
3214 /* Figure out which stream this is packet belongs to */
3215 for (i = 0; i < demux->n_streams; i++) {
3216 stream = demux->streams[i];
3217 if (stream->sample_index >= stream->n_samples)
3219 GST_LOG_OBJECT (demux,
3220 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3221 " / size:%d)", i, stream->sample_index,
3222 stream->samples[stream->sample_index].offset,
3223 stream->samples[stream->sample_index].size);
3225 if (stream->samples[stream->sample_index].offset == demux->offset)
3229 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
3230 goto unknown_stream;
3232 /* Put data in a buffer, set timestamps, caps, ... */
3233 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
3234 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
3235 GST_FOURCC_ARGS (stream->fourcc));
3237 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
3239 sample = &stream->samples[stream->sample_index];
3241 position = QTSAMPLE_DTS (stream, sample);
3242 timestamp = QTSAMPLE_PTS (stream, sample);
3243 duration = QTSAMPLE_DUR_DTS (stream, sample, position);
3244 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3246 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
3247 timestamp, duration, keyframe, position, demux->offset);
3250 ret = gst_qtdemux_combine_flows (demux, stream, ret);
3252 stream->sample_index++;
3254 /* update current offset and figure out size of next buffer */
3255 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
3256 demux->offset, demux->neededbytes);
3257 demux->offset += demux->neededbytes;
3258 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
3261 if ((demux->neededbytes = next_entry_size (demux)) == -1)
3270 /* when buffering movie data, at least show user something is happening */
3271 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
3272 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
3273 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
3274 demux->neededbytes);
3277 gst_object_unref (demux);
3284 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
3285 ret = GST_FLOW_ERROR;
3290 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
3291 ret = GST_FLOW_UNEXPECTED;
3296 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
3297 (NULL), ("qtdemuxer invalid state %d", demux->state));
3298 ret = GST_FLOW_ERROR;
3303 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
3304 (NULL), ("no 'moov' atom within the first 10 MB"));
3305 ret = GST_FLOW_ERROR;
3311 qtdemux_sink_activate (GstPad * sinkpad)
3313 if (gst_pad_check_pull_range (sinkpad))
3314 return gst_pad_activate_pull (sinkpad, TRUE);
3316 return gst_pad_activate_push (sinkpad, TRUE);
3320 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
3322 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
3325 demux->pullbased = TRUE;
3326 demux->segment_running = TRUE;
3327 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
3330 demux->segment_running = FALSE;
3331 return gst_pad_stop_task (sinkpad);
3336 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
3338 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
3340 demux->pullbased = FALSE;
3347 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
3349 return g_malloc (items * size);
3353 qtdemux_zfree (void *opaque, void *addr)
3359 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
3365 z = g_new0 (z_stream, 1);
3366 z->zalloc = qtdemux_zalloc;
3367 z->zfree = qtdemux_zfree;
3370 z->next_in = z_buffer;
3371 z->avail_in = z_length;
3373 buffer = (guint8 *) g_malloc (length);
3374 ret = inflateInit (z);
3375 while (z->avail_in > 0) {
3376 if (z->avail_out == 0) {
3378 buffer = (guint8 *) g_realloc (buffer, length);
3379 z->next_out = buffer + z->total_out;
3380 z->avail_out = 1024;
3382 ret = inflate (z, Z_SYNC_FLUSH);
3386 if (ret != Z_STREAM_END) {
3387 g_warning ("inflate() returned %d", ret);
3393 #endif /* HAVE_ZLIB */
3396 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
3400 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
3402 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
3403 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
3405 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
3411 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
3412 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
3413 if (dcom == NULL || cmvd == NULL)
3414 goto invalid_compression;
3416 method = QT_FOURCC ((guint8 *) dcom->data + 8);
3419 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
3420 guint uncompressed_length;
3421 guint compressed_length;
3424 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
3425 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
3426 GST_LOG ("length = %u", uncompressed_length);
3429 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
3430 compressed_length, uncompressed_length);
3432 qtdemux->moov_node_compressed = qtdemux->moov_node;
3433 qtdemux->moov_node = g_node_new (buf);
3435 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
3436 uncompressed_length);
3439 #endif /* HAVE_ZLIB */
3441 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
3442 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
3449 invalid_compression:
3451 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
3457 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
3460 while (G_UNLIKELY (buf < end)) {
3464 if (G_UNLIKELY (buf + 4 > end)) {
3465 GST_LOG_OBJECT (qtdemux, "buffer overrun");
3468 len = QT_UINT32 (buf);
3469 if (G_UNLIKELY (len == 0)) {
3470 GST_LOG_OBJECT (qtdemux, "empty container");
3473 if (G_UNLIKELY (len < 8)) {
3474 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
3477 if (G_UNLIKELY (len > (end - buf))) {
3478 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
3479 (gint) (end - buf));
3483 child = g_node_new ((guint8 *) buf);
3484 g_node_append (node, child);
3485 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
3486 qtdemux_parse_node (qtdemux, child, buf, len);
3494 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
3497 int len = QT_UINT32 (xdxt->data);
3498 guint8 *buf = xdxt->data;
3499 guint8 *end = buf + len;
3502 /* skip size and type */
3510 size = QT_UINT32 (buf);
3511 type = QT_FOURCC (buf + 4);
3513 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
3515 if (buf + size > end || size <= 0)
3521 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
3522 GST_FOURCC_ARGS (type));
3526 buffer = gst_buffer_new_and_alloc (size);
3527 memcpy (GST_BUFFER_DATA (buffer), buf, size);
3528 stream->buffers = g_slist_append (stream->buffers, buffer);
3529 GST_LOG_OBJECT (qtdemux, "parsing theora header");
3532 buffer = gst_buffer_new_and_alloc (size);
3533 memcpy (GST_BUFFER_DATA (buffer), buf, size);
3534 stream->buffers = g_slist_append (stream->buffers, buffer);
3535 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
3538 buffer = gst_buffer_new_and_alloc (size);
3539 memcpy (GST_BUFFER_DATA (buffer), buf, size);
3540 stream->buffers = g_slist_append (stream->buffers, buffer);
3541 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
3544 GST_WARNING_OBJECT (qtdemux,
3545 "unknown theora cookie %" GST_FOURCC_FORMAT,
3546 GST_FOURCC_ARGS (type));
3555 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
3559 guint32 node_length = 0;
3560 const QtNodeType *type;
3563 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
3565 if (G_UNLIKELY (length < 8))
3566 goto not_enough_data;
3568 node_length = QT_UINT32 (buffer);
3569 fourcc = QT_FOURCC (buffer + 4);
3571 /* ignore empty nodes */
3572 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
3575 type = qtdemux_type_get (fourcc);
3577 end = buffer + length;
3579 GST_LOG_OBJECT (qtdemux,
3580 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
3581 GST_FOURCC_ARGS (fourcc), node_length, type->name);
3583 if (node_length > length)
3584 goto broken_atom_size;
3586 if (type->flags & QT_FLAG_CONTAINER) {
3587 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
3592 if (node_length < 20) {
3593 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
3596 GST_DEBUG_OBJECT (qtdemux,
3597 "parsing stsd (sample table, sample description) atom");
3598 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
3606 /* There are two things we might encounter here: a true mp4a atom, and
3607 an mp4a entry in an stsd atom. The latter is what we're interested
3608 in, and it looks like an atom, but isn't really one. The true mp4a
3609 atom is short, so we detect it based on length here. */
3611 GST_LOG_OBJECT (qtdemux, "skipping small mp4a box");
3615 /* 'version' here is the sound sample description version. Types 0 and
3616 1 are documented in the QTFF reference, but type 2 is not: it's
3617 described in Apple header files instead (struct SoundDescriptionV2
3619 version = QT_UINT16 (buffer + 16);
3621 GST_DEBUG_OBJECT (qtdemux, "mp4a version 0x%08x", version);
3623 /* parse any esds descriptors */
3635 GST_WARNING_OBJECT (qtdemux, "unhandled mp4a version 0x%08x",
3641 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
3650 GST_DEBUG_OBJECT (qtdemux, "parsing in mp4v");
3651 version = QT_UINT32 (buffer + 16);
3652 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
3653 if (1 || version == 0x00000000) {
3654 buf = buffer + 0x32;
3656 /* FIXME Quicktime uses PASCAL string while
3657 * the iso format uses C strings. Check the file
3658 * type before attempting to parse the string here. */
3659 tlen = QT_UINT8 (buf);
3660 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
3662 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
3663 /* the string has a reserved space of 32 bytes so skip
3664 * the remaining 31 */
3666 buf += 4; /* and 4 bytes reserved */
3668 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
3670 qtdemux_parse_container (qtdemux, node, buf, end);
3676 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
3677 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
3682 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
3687 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
3688 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
3696 version = QT_UINT32 (buffer + 12);
3697 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
3704 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
3709 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
3714 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
3718 if (!strcmp (type->name, "unknown"))
3719 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
3723 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT,
3724 GST_FOURCC_ARGS (fourcc));
3730 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3731 (_("This file is corrupt and cannot be played.")),
3732 ("Not enough data for an atom header, got only %u bytes", length));
3737 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3738 (_("This file is corrupt and cannot be played.")),
3739 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
3740 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
3747 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
3751 guint32 child_fourcc;
3753 for (child = g_node_first_child (node); child;
3754 child = g_node_next_sibling (child)) {
3755 buffer = (guint8 *) child->data;
3757 child_fourcc = QT_FOURCC (buffer + 4);
3759 if (G_UNLIKELY (child_fourcc == fourcc)) {
3767 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
3768 GstByteReader * parser)
3772 guint32 child_fourcc, child_len;
3774 for (child = g_node_first_child (node); child;
3775 child = g_node_next_sibling (child)) {
3776 buffer = (guint8 *) child->data;
3778 child_len = QT_UINT32 (buffer);
3779 child_fourcc = QT_FOURCC (buffer + 4);
3781 if (G_UNLIKELY (child_fourcc == fourcc)) {
3782 if (G_UNLIKELY (child_len < (4 + 4)))
3784 /* FIXME: must verify if atom length < parent atom length */
3785 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
3793 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
3797 guint32 child_fourcc;
3799 for (child = g_node_next_sibling (node); child;
3800 child = g_node_next_sibling (child)) {
3801 buffer = (guint8 *) child->data;
3803 child_fourcc = QT_FOURCC (buffer + 4);
3805 if (child_fourcc == fourcc) {
3813 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
3814 QtDemuxStream * stream, GstTagList * list)
3816 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
3817 goto too_many_streams;
3819 /* consistent default for push based mode */
3820 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
3821 gst_segment_set_newsegment (&stream->segment, FALSE, 1.0, GST_FORMAT_TIME,
3822 0, GST_CLOCK_TIME_NONE, 0);
3824 if (stream->subtype == FOURCC_vide) {
3825 gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
3828 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
3831 /* fps is calculated base on the duration of the first frames since
3832 * qt does not have a fixed framerate. */
3833 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
3838 stream->fps_n = stream->timescale;
3839 if (stream->min_duration == 0)
3842 stream->fps_d = stream->min_duration;
3847 gint depth, palette_count;
3848 const guint32 *palette_data = NULL;
3850 gst_caps_set_simple (stream->caps,
3851 "width", G_TYPE_INT, stream->width,
3852 "height", G_TYPE_INT, stream->height,
3853 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
3856 * calculate pixel-aspect-ratio using display width and height */
3857 if (qtdemux->major_brand != FOURCC_qt__) {
3858 GST_DEBUG_OBJECT (qtdemux,
3859 "video size %dx%d, target display size %dx%d", stream->width,
3860 stream->height, stream->display_width, stream->display_height);
3862 if (stream->display_width > 0 && stream->display_height > 0 &&
3863 stream->width > 0 && stream->height > 0) {
3866 /* calculate the pixel aspect ratio using the display and pixel w/h */
3867 n = stream->display_width * stream->height;
3868 d = stream->display_height * stream->width;
3870 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
3871 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
3872 GST_TYPE_FRACTION, n, d, NULL);
3877 /* qt file might have pasp atom */
3878 if (stream->par_w > 0 && stream->par_h > 0) {
3879 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
3880 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
3881 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
3884 depth = stream->bits_per_sample;
3886 /* more than 32 bits means grayscale */
3887 gray = (depth > 32);
3888 /* low 32 bits specify the depth */
3891 /* different number of palette entries is determined by depth. */
3893 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
3894 palette_count = (1 << depth);
3896 switch (palette_count) {
3900 palette_data = ff_qt_default_palette_2;
3903 palette_data = ff_qt_default_palette_4;
3907 palette_data = ff_qt_grayscale_palette_16;
3909 palette_data = ff_qt_default_palette_16;
3913 palette_data = ff_qt_grayscale_palette_256;
3915 palette_data = ff_qt_default_palette_256;
3918 GST_ELEMENT_WARNING (qtdemux, STREAM, DECODE,
3919 (_("The video in this file might not play correctly.")),
3920 ("unsupported palette depth %d", depth));
3926 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
3927 * don't free any of the buffer data. */
3928 palette = gst_buffer_new ();
3929 GST_BUFFER_FLAG_SET (palette, GST_BUFFER_FLAG_READONLY);
3930 GST_BUFFER_DATA (palette) = (guint8 *) palette_data;
3931 GST_BUFFER_SIZE (palette) = sizeof (guint32) * palette_count;
3933 gst_caps_set_simple (stream->caps, "palette_data",
3934 GST_TYPE_BUFFER, palette, NULL);
3935 gst_buffer_unref (palette);
3936 } else if (palette_count != 0) {
3937 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
3938 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
3940 gst_object_unref (stream->pad);
3944 qtdemux->n_video_streams++;
3945 } else if (stream->subtype == FOURCC_soun) {
3946 gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
3949 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
3952 gst_caps_set_simple (stream->caps,
3953 "rate", G_TYPE_INT, (int) stream->rate,
3954 "channels", G_TYPE_INT, stream->n_channels, NULL);
3956 qtdemux->n_audio_streams++;
3957 } else if (stream->subtype == FOURCC_strm) {
3958 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
3959 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
3960 gchar *name = g_strdup_printf ("subtitle_%02d", qtdemux->n_sub_streams);
3963 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
3965 qtdemux->n_sub_streams++;
3967 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3971 qtdemux->streams[qtdemux->n_streams] = stream;
3972 qtdemux->n_streams++;
3973 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
3976 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
3978 gst_pad_use_fixed_caps (stream->pad);
3979 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
3980 gst_pad_set_query_type_function (stream->pad,
3981 gst_qtdemux_get_src_query_types);
3982 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
3984 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
3985 gst_pad_set_caps (stream->pad, stream->caps);
3987 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
3988 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
3989 gst_pad_set_active (stream->pad, TRUE);
3990 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
3991 if (stream->pending_tags)
3992 gst_tag_list_free (stream->pending_tags);
3993 stream->pending_tags = list;
3995 /* post now, send event on pad later */
3996 GST_DEBUG_OBJECT (qtdemux, "Posting tags %" GST_PTR_FORMAT, list);
3997 gst_element_post_message (GST_ELEMENT (qtdemux),
3998 gst_message_new_tag_full (GST_OBJECT (qtdemux), stream->pad,
3999 gst_tag_list_copy (list)));
4001 /* global tags go on each pad anyway */
4002 stream->send_global_tags = TRUE;
4009 GST_ELEMENT_WARNING (qtdemux, STREAM, DECODE,
4010 (_("This file contains too many streams. Only playing first %d"),
4011 GST_QTDEMUX_MAX_STREAMS), (NULL));
4016 /* initialise bytereaders for stbl sub-atoms */
4018 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
4020 /* time-to-sample atom */
4021 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
4024 /* copy atom data into a new buffer for later use */
4025 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
4027 /* skip version + flags */
4028 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
4029 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
4031 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
4033 /* make sure there's enough data */
4034 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 2 * 4))
4037 /* sync sample atom */
4038 stream->stps_present = FALSE;
4039 if ((stream->stss_present =
4040 !!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
4041 &stream->stss) ? TRUE : FALSE) == TRUE) {
4042 /* copy atom data into a new buffer for later use */
4043 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
4045 /* skip version + flags */
4046 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
4047 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
4050 if (stream->n_sample_syncs) {
4051 /* make sure there's enough data */
4052 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
4056 /* partial sync sample atom */
4057 if ((stream->stps_present =
4058 !!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
4059 &stream->stps) ? TRUE : FALSE) == TRUE) {
4060 /* copy atom data into a new buffer for later use */
4061 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
4063 /* skip version + flags */
4064 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
4065 !gst_byte_reader_get_uint32_be (&stream->stps,
4066 &stream->n_sample_partial_syncs))
4069 /* if there are no entries, the stss table contains the real
4071 if (stream->n_sample_partial_syncs) {
4072 /* make sure there's enough data */
4073 if (!qt_atom_parser_has_chunks (&stream->stps,
4074 stream->n_sample_partial_syncs, 4))
4081 /* sample-to-chunk atom */
4082 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
4085 /* copy atom data into a new buffer for later use */
4086 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
4088 /* skip version + flags */
4089 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
4090 !gst_byte_reader_get_uint32_be (&stream->stsc,
4091 &stream->n_samples_per_chunk))
4094 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
4095 stream->n_samples_per_chunk);
4097 /* make sure there's enough data */
4098 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
4104 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
4107 /* copy atom data into a new buffer for later use */
4108 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
4110 /* skip version + flags */
4111 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
4112 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
4117 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
4118 stream->co_size = sizeof (guint32);
4119 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
4121 stream->co_size = sizeof (guint64);
4125 /* copy atom data into a new buffer for later use */
4126 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
4128 /* skip version + flags */
4129 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
4132 /* chunks_are_chunks == 0 means treat chunks as samples */
4133 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
4134 if (stream->chunks_are_chunks) {
4135 /* skip number of entries */
4136 if (!gst_byte_reader_skip (&stream->stco, 4))
4139 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
4142 /* make sure there are enough data in the stsz atom */
4143 if (!stream->sample_size) {
4144 /* different sizes for each sample */
4145 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
4149 /* treat chunks as samples */
4150 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
4154 if (!stream->n_samples) {
4155 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4159 GST_DEBUG_OBJECT (qtdemux,
4160 "allocating n_samples %u * %" G_GSIZE_FORMAT " = (%u MB)",
4161 stream->n_samples, sizeof (QtDemuxSample),
4162 (guint) (stream->n_samples * sizeof (QtDemuxSample)) >> 20);
4164 if (stream->n_samples >=
4165 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
4166 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
4167 "be larger than %uMB (broken file?)", stream->n_samples,
4168 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
4172 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
4173 if (!stream->samples) {
4174 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
4180 /* composition time-to-sample */
4181 if ((stream->ctts_present =
4182 !!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
4183 &stream->ctts) ? TRUE : FALSE) == TRUE) {
4184 /* copy atom data into a new buffer for later use */
4185 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
4187 /* skip version + flags */
4188 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
4189 || !gst_byte_reader_get_uint32_be (&stream->ctts,
4190 &stream->n_composition_times))
4193 /* make sure there's enough data */
4194 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
4199 stream->stbl_index = -1; /* no samples have yet been parsed */
4205 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
4206 (_("This file is corrupt and cannot be played.")), (NULL));
4211 /* collect samples from the next sample to be parsed up to sample @n for @stream
4212 * by reading the info from @stbl
4214 * This code can be executed from both the streaming thread and the seeking
4215 * thread so it takes the object lock to protect itself
4218 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
4222 QtDemuxSample *samples, *first, *cur, *last;
4223 guint32 n_samples_per_chunk;
4226 n_samples = stream->n_samples;
4229 goto out_of_samples;
4231 GST_OBJECT_LOCK (qtdemux);
4232 if (n <= stream->stbl_index)
4233 goto already_parsed;
4235 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
4237 /* pointer to the sample table */
4238 samples = stream->samples;
4240 /* starts from -1, moves to the next sample index to parse */
4241 stream->stbl_index++;
4243 /* keep track of the first and last sample to fill */
4244 first = &samples[stream->stbl_index];
4247 if (stream->chunks_are_chunks) {
4248 /* set the sample sizes */
4249 if (stream->sample_size == 0) {
4250 /* different sizes for each sample */
4251 for (cur = first; cur <= last; cur++) {
4252 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
4253 GST_LOG_OBJECT (qtdemux, "sample %d has size %u", cur - samples,
4257 /* samples have the same size */
4258 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
4259 for (cur = first; cur <= last; cur++)
4260 cur->size = stream->sample_size;
4264 n_samples_per_chunk = stream->n_samples_per_chunk;
4267 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
4270 if (stream->stsc_chunk_index >= stream->last_chunk
4271 || stream->stsc_chunk_index < stream->first_chunk) {
4272 stream->first_chunk =
4273 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
4274 stream->samples_per_chunk =
4275 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
4276 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
4278 /* chunk numbers are counted from 1 it seems */
4279 if (G_UNLIKELY (stream->first_chunk == 0))
4282 --stream->first_chunk;
4284 /* the last chunk of each entry is calculated by taking the first chunk
4285 * of the next entry; except if there is no next, where we fake it with
4287 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
4288 stream->last_chunk = G_MAXUINT32;
4290 stream->last_chunk =
4291 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
4292 if (G_UNLIKELY (stream->last_chunk == 0))
4295 --stream->last_chunk;
4298 GST_LOG_OBJECT (qtdemux,
4299 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
4300 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
4302 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
4305 if (stream->last_chunk != G_MAXUINT32) {
4306 if (!qt_atom_parser_peek_sub (&stream->stco,
4307 stream->first_chunk * stream->co_size,
4308 (stream->last_chunk - stream->first_chunk) * stream->co_size,
4313 stream->co_chunk = stream->stco;
4314 if (!gst_byte_reader_skip (&stream->co_chunk,
4315 stream->first_chunk * stream->co_size))
4319 stream->stsc_chunk_index = stream->first_chunk;
4322 last_chunk = stream->last_chunk;
4324 if (stream->chunks_are_chunks) {
4325 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
4326 guint32 samples_per_chunk;
4327 guint64 chunk_offset;
4329 if (!stream->stsc_sample_index
4330 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
4331 &stream->chunk_offset))
4334 samples_per_chunk = stream->samples_per_chunk;
4335 chunk_offset = stream->chunk_offset;
4337 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
4338 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
4339 G_GUINT64_FORMAT, cur - samples, stream->chunk_offset);
4341 cur->offset = chunk_offset;
4342 chunk_offset += cur->size;
4345 if (G_UNLIKELY (cur > last)) {
4347 stream->stsc_sample_index = k + 1;
4348 stream->chunk_offset = chunk_offset;
4349 stream->stsc_chunk_index = j;
4353 stream->stsc_sample_index = 0;
4355 stream->stsc_chunk_index = j;
4357 cur = &samples[stream->stsc_chunk_index];
4359 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
4362 stream->stsc_chunk_index = j;
4367 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
4370 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
4371 "%" G_GUINT64_FORMAT, j, cur->offset);
4373 if (stream->samples_per_frame * stream->bytes_per_frame) {
4375 (stream->samples_per_chunk * stream->n_channels) /
4376 stream->samples_per_frame * stream->bytes_per_frame;
4378 cur->size = stream->samples_per_chunk;
4381 GST_DEBUG_OBJECT (qtdemux,
4382 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
4383 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
4384 GST_SECOND, stream->timescale)), cur->size);
4386 cur->timestamp = stream->stco_sample_index;
4387 cur->duration = stream->samples_per_chunk;
4388 cur->keyframe = TRUE;
4391 stream->stco_sample_index += stream->samples_per_chunk;
4393 stream->stsc_chunk_index = j;
4395 stream->stsc_index++;
4398 if (!stream->chunks_are_chunks)
4402 guint32 n_sample_times;
4404 n_sample_times = stream->n_sample_times;
4407 for (i = stream->stts_index; i < n_sample_times; i++) {
4408 guint32 stts_samples;
4409 guint32 stts_duration;
4412 if (stream->stts_sample_index >= stream->stts_samples
4413 || !stream->stts_sample_index) {
4415 stream->stts_samples =
4416 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
4417 stream->stts_duration =
4418 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
4420 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %"
4421 G_GUINT64_FORMAT, i, stream->stts_samples, stream->stts_duration);
4423 /* take first duration for fps */
4424 if (G_UNLIKELY (stream->min_duration == 0))
4425 stream->min_duration = stream->stts_duration;
4427 stream->stts_sample_index = 0;
4430 stts_samples = stream->stts_samples;
4431 stts_duration = stream->stts_duration;
4432 stts_time = stream->stts_time;
4434 for (j = stream->stts_sample_index; j < stts_samples; j++) {
4435 GST_DEBUG_OBJECT (qtdemux,
4436 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
4437 cur - samples, j, GST_TIME_ARGS (gst_util_uint64_scale (stts_time,
4438 GST_SECOND, stream->timescale)));
4440 cur->timestamp = stts_time;
4441 cur->duration = stts_duration;
4443 stts_time += stts_duration;
4446 if (G_UNLIKELY (cur > last)) {
4448 stream->stts_time = stts_time;
4449 stream->stts_sample_index = j + 1;
4453 stream->stts_sample_index = 0;
4454 stream->stts_time = stts_time;
4455 stream->stts_index++;
4457 /* fill up empty timestamps with the last timestamp, this can happen when
4458 * the last samples do not decode and so we don't have timestamps for them.
4459 * We however look at the last timestamp to estimate the track length so we
4460 * need something in here. */
4461 for (; cur < last; cur++) {
4462 GST_DEBUG_OBJECT (qtdemux,
4463 "fill sample %d: timestamp %" GST_TIME_FORMAT, cur - samples,
4464 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
4465 stream->timescale)));
4466 cur->timestamp = stream->stts_time;
4472 /* sample sync, can be NULL */
4473 if (stream->stss_present == TRUE) {
4474 guint32 n_sample_syncs;
4476 n_sample_syncs = stream->n_sample_syncs;
4478 if (!n_sample_syncs) {
4479 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
4480 stream->all_keyframe = TRUE;
4482 for (i = stream->stss_index; i < n_sample_syncs; i++) {
4483 /* note that the first sample is index 1, not 0 */
4486 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
4488 if (G_LIKELY (index > 0 && index <= n_samples)) {
4490 samples[index].keyframe = TRUE;
4491 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
4492 /* and exit if we have enough samples */
4493 if (G_UNLIKELY (index >= n)) {
4500 stream->stss_index = i;
4503 /* stps marks partial sync frames like open GOP I-Frames */
4504 if (stream->stps_present == TRUE) {
4505 guint32 n_sample_partial_syncs;
4507 n_sample_partial_syncs = stream->n_sample_partial_syncs;
4509 /* if there are no entries, the stss table contains the real
4511 if (n_sample_partial_syncs) {
4512 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
4513 /* note that the first sample is index 1, not 0 */
4516 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
4518 if (G_LIKELY (index > 0 && index <= n_samples)) {
4520 samples[index].keyframe = TRUE;
4521 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
4522 /* and exit if we have enough samples */
4523 if (G_UNLIKELY (index >= n)) {
4530 stream->stps_index = i;
4534 /* no stss, all samples are keyframes */
4535 stream->all_keyframe = TRUE;
4536 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
4541 /* composition time to sample */
4542 if (stream->ctts_present == TRUE) {
4543 guint32 n_composition_times;
4545 gint32 ctts_soffset;
4547 /* Fill in the pts_offsets */
4549 n_composition_times = stream->n_composition_times;
4551 for (i = stream->ctts_index; i < n_composition_times; i++) {
4552 if (stream->ctts_sample_index >= stream->ctts_count
4553 || !stream->ctts_sample_index) {
4554 stream->ctts_count =
4555 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
4556 stream->ctts_soffset =
4557 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
4558 stream->ctts_sample_index = 0;
4561 ctts_count = stream->ctts_count;
4562 ctts_soffset = stream->ctts_soffset;
4564 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
4565 cur->pts_offset = ctts_soffset;
4568 if (G_UNLIKELY (cur > last))
4570 stream->ctts_sample_index = j + 1;
4573 stream->ctts_sample_index = 0;
4574 stream->ctts_index++;
4578 stream->stbl_index = n;
4579 /* if index has been completely parsed, free data that is no-longer needed */
4580 if (n == stream->n_samples)
4581 gst_qtdemux_stbl_free (stream);
4582 GST_OBJECT_UNLOCK (qtdemux);
4589 GST_LOG_OBJECT (qtdemux,
4590 "Tried to parse up to sample %u but this sample has already been parsed",
4592 GST_OBJECT_UNLOCK (qtdemux);
4598 GST_LOG_OBJECT (qtdemux,
4599 "Tried to parse up to sample %u but there are only %u samples", n + 1,
4601 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
4602 (_("This file is corrupt and cannot be played.")), (NULL));
4607 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
4608 (_("This file is corrupt and cannot be played.")), (NULL));
4609 GST_OBJECT_UNLOCK (qtdemux);
4614 /* collect all segment info for @stream.
4617 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
4622 /* parse and prepare segment info from the edit list */
4623 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
4624 stream->n_segments = 0;
4625 stream->segments = NULL;
4626 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
4630 guint64 time, stime;
4633 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
4634 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
4637 buffer = elst->data;
4639 n_segments = QT_UINT32 (buffer + 12);
4641 /* we might allocate a bit too much, at least allocate 1 segment */
4642 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
4644 /* segments always start from 0 */
4648 for (i = 0; i < n_segments; i++) {
4651 QtDemuxSegment *segment;
4654 media_time = QT_UINT32 (buffer + 20 + i * 12);
4656 /* -1 media time is an empty segment, just ignore it */
4657 if (media_time == G_MAXUINT32)
4660 duration = QT_UINT32 (buffer + 16 + i * 12);
4662 segment = &stream->segments[count++];
4664 /* time and duration expressed in global timescale */
4665 segment->time = stime;
4666 /* add non scaled values so we don't cause roundoff errors */
4668 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
4669 segment->stop_time = stime;
4670 segment->duration = stime - segment->time;
4671 /* media_time expressed in stream timescale */
4672 segment->media_start =
4673 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
4674 segment->media_stop = segment->media_start + segment->duration;
4675 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
4677 if (rate_int <= 1) {
4678 /* 0 is not allowed, some programs write 1 instead of the floating point
4680 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
4684 segment->rate = rate_int / 65536.0;
4687 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
4688 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
4689 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
4690 GST_TIME_ARGS (segment->duration),
4691 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
4693 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
4694 stream->n_segments = count;
4698 /* push based does not handle segments, so act accordingly here,
4699 * and warn if applicable */
4700 if (!qtdemux->pullbased) {
4701 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
4702 /* remove and use default one below, we stream like it anyway */
4703 g_free (stream->segments);
4704 stream->segments = NULL;
4705 stream->n_segments = 0;
4708 /* no segments, create one to play the complete trak */
4709 if (stream->n_segments == 0) {
4710 GstClockTime stream_duration =
4711 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
4713 if (stream->segments == NULL)
4714 stream->segments = g_new (QtDemuxSegment, 1);
4716 stream->segments[0].time = 0;
4717 stream->segments[0].stop_time = stream_duration;
4718 stream->segments[0].duration = stream_duration;
4719 stream->segments[0].media_start = 0;
4720 stream->segments[0].media_stop = stream_duration;
4721 stream->segments[0].rate = 1.0;
4723 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
4724 GST_TIME_ARGS (stream_duration));
4725 stream->n_segments = 1;
4727 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
4733 * Parses the stsd atom of a svq3 trak looking for
4734 * the SMI and gama atoms.
4737 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
4738 guint8 ** gamma, GstBuffer ** seqh)
4740 guint8 *_gamma = NULL;
4741 GstBuffer *_seqh = NULL;
4742 guint8 *stsd_data = stsd->data;
4743 guint32 length = QT_UINT32 (stsd_data);
4747 GST_WARNING_OBJECT (qtdemux, "stsd too short");
4753 version = QT_UINT16 (stsd_data);
4758 while (length > 8) {
4759 guint32 fourcc, size;
4761 size = QT_UINT32 (stsd_data);
4762 fourcc = QT_FOURCC (stsd_data + 4);
4763 data = stsd_data + 8;
4770 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
4771 " for gama atom, expected 12", size);
4776 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
4778 if (_seqh != NULL) {
4779 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
4780 " found, ignoring");
4782 seqh_size = QT_UINT32 (data + 4);
4783 if (seqh_size > 0) {
4784 _seqh = gst_buffer_new_and_alloc (seqh_size);
4785 memcpy (GST_BUFFER_DATA (_seqh), data + 8, seqh_size);
4792 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
4793 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
4797 if (size <= length) {
4803 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
4806 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
4807 G_GUINT16_FORMAT, version);
4818 gst_buffer_unref (_seqh);
4823 * With each track we associate a new QtDemuxStream that contains all the info
4825 * traks that do not decode to something (like strm traks) will not have a pad.
4828 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
4843 QtDemuxStream *stream;
4844 GstTagList *list = NULL;
4845 gchar *codec = NULL;
4846 const guint8 *stsd_data;
4848 guint32 tkhd_flags = 0;
4849 guint8 tkhd_version = 0;
4853 stream = g_new0 (QtDemuxStream, 1);
4854 /* new streams always need a discont */
4855 stream->discont = TRUE;
4856 /* we enable clipping for raw audio/video streams */
4857 stream->need_clip = FALSE;
4858 stream->need_process = FALSE;
4859 stream->segment_index = -1;
4860 stream->time_position = 0;
4861 stream->sample_index = -1;
4862 stream->last_ret = GST_FLOW_OK;
4864 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
4865 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
4866 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
4869 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags: 0x%02x/%06x",
4870 tkhd_version, tkhd_flags);
4872 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
4875 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
4876 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
4877 if (qtdemux->major_brand != FOURCC_mjp2 ||
4878 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
4882 len = QT_UINT32 ((guint8 *) mdhd->data);
4883 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
4884 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
4885 if (version == 0x01000000) {
4888 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
4889 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
4890 stream->lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
4894 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
4895 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
4896 stream->lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
4899 stream->lang_id[0] = 0x60 + ((stream->lang_code >> 10) & 0x1F);
4900 stream->lang_id[1] = 0x60 + ((stream->lang_code >> 5) & 0x1F);
4901 stream->lang_id[2] = 0x60 + (stream->lang_code & 0x1F);
4902 stream->lang_id[3] = 0;
4904 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
4906 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
4908 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%x/%s",
4909 stream->lang_code, stream->lang_id);
4911 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
4914 if (qtdemux->duration != G_MAXINT32 && stream->duration != G_MAXINT32) {
4915 guint64 tdur1, tdur2;
4917 /* don't overflow */
4918 tdur1 = stream->timescale * (guint64) qtdemux->duration;
4919 tdur2 = qtdemux->timescale * (guint64) stream->duration;
4922 * some of those trailers, nowadays, have prologue images that are
4923 * themselves vide tracks as well. I haven't really found a way to
4924 * identify those yet, except for just looking at their duration. */
4925 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
4926 GST_WARNING_OBJECT (qtdemux,
4927 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
4928 " vs. %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
4929 "found, assuming preview image or something; skipping track",
4930 stream->duration, stream->timescale, qtdemux->duration,
4931 qtdemux->timescale);
4937 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
4940 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
4941 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
4943 len = QT_UINT32 ((guint8 *) hdlr->data);
4945 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
4946 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
4947 GST_FOURCC_ARGS (stream->subtype));
4949 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
4952 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
4956 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
4958 stsd_data = (const guint8 *) stsd->data;
4960 /* stsd should at least have one entry */
4961 len = QT_UINT32 (stsd_data);
4965 /* and that entry should fit within stsd */
4966 len = QT_UINT32 (stsd_data + 16);
4967 if (len > QT_UINT32 (stsd_data) + 16)
4969 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
4971 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
4972 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
4973 GST_FOURCC_ARGS (stream->fourcc));
4975 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
4976 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
4977 goto error_encrypted;
4979 if (stream->subtype == FOURCC_vide) {
4980 guint32 w = 0, h = 0;
4982 stream->sampled = TRUE;
4984 /* version 1 uses some 64-bit ints */
4985 if (!gst_byte_reader_skip (&tkhd, (tkhd_version == 1) ? 84 : 72)
4986 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
4987 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
4990 stream->display_width = w >> 16;
4991 stream->display_height = h >> 16;
4997 stream->width = QT_UINT16 (stsd_data + offset + 32);
4998 stream->height = QT_UINT16 (stsd_data + offset + 34);
4999 stream->fps_n = 0; /* this is filled in later */
5000 stream->fps_d = 0; /* this is filled in later */
5001 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
5002 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
5004 GST_LOG_OBJECT (qtdemux, "frame count: %u",
5005 QT_UINT16 (stsd_data + offset + 48));
5008 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
5010 list = gst_tag_list_new ();
5011 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
5012 GST_TAG_VIDEO_CODEC, codec, NULL);
5019 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4v);
5020 /* H264 is MPEG-4 after all,
5021 * and qt seems to put MPEG-4 stuff in there as well */
5023 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_avc1);
5025 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
5026 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
5030 const guint8 *pasp_data = (const guint8 *) pasp->data;
5032 stream->par_w = QT_UINT32 (pasp_data + 8);
5033 stream->par_h = QT_UINT32 (pasp_data + 12);
5040 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
5045 gint len = QT_UINT32 (stsd_data) - 0x66;
5046 const guint8 *avc_data = stsd_data + 0x66;
5049 while (len >= 0x8 &&
5050 QT_FOURCC (avc_data + 0x4) != FOURCC_avcC &&
5051 QT_UINT32 (avc_data) < len) {
5052 len -= QT_UINT32 (avc_data);
5053 avc_data += QT_UINT32 (avc_data);
5056 /* parse, if found */
5057 if (len > 0x8 && QT_FOURCC (avc_data + 0x4) == FOURCC_avcC) {
5061 if (QT_UINT32 (avc_data) < len)
5062 size = QT_UINT32 (avc_data) - 0x8;
5066 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
5068 buf = gst_buffer_new_and_alloc (size);
5069 memcpy (GST_BUFFER_DATA (buf), avc_data + 0x8, size);
5070 gst_caps_set_simple (stream->caps,
5071 "codec_data", GST_TYPE_BUFFER, buf, NULL);
5072 gst_buffer_unref (buf);
5078 /* see annex I of the jpeg2000 spec */
5079 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
5083 guint32 ncomp_map = 0;
5084 gint32 *comp_map = NULL;
5085 guint32 nchan_def = 0;
5086 gint32 *chan_def = NULL;
5088 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
5089 /* some required atoms */
5090 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
5093 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
5097 /* number of components; redundant with info in codestream, but useful
5099 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
5100 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
5102 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
5104 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
5107 GST_DEBUG_OBJECT (qtdemux, "found colr");
5108 /* extract colour space info */
5109 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
5110 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
5112 fourcc = GST_MAKE_FOURCC ('s', 'R', 'G', 'B');
5115 fourcc = GST_MAKE_FOURCC ('G', 'R', 'A', 'Y');
5118 fourcc = GST_MAKE_FOURCC ('s', 'Y', 'U', 'V');
5125 /* colr is required, and only values 16, 17, and 18 are specified,
5126 so error if we have no fourcc */
5129 /* extract component mapping */
5130 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
5132 guint32 cmap_len = 0;
5134 cmap_len = QT_UINT32 (cmap->data);
5135 if (cmap_len >= 8) {
5136 /* normal box, subtract off header */
5138 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
5139 if (cmap_len % 4 == 0) {
5140 ncomp_map = (cmap_len / 4);
5141 comp_map = g_new0 (gint32, ncomp_map);
5142 for (i = 0; i < ncomp_map; i++) {
5145 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
5146 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
5147 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
5148 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
5153 /* extract channel definitions */
5154 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
5156 guint32 cdef_len = 0;
5158 cdef_len = QT_UINT32 (cdef->data);
5159 if (cdef_len >= 10) {
5160 /* normal box, subtract off header and len */
5162 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
5163 if (cdef_len % 6 == 0) {
5164 nchan_def = (cdef_len / 6);
5165 chan_def = g_new0 (gint32, nchan_def);
5166 for (i = 0; i < nchan_def; i++)
5168 for (i = 0; i < nchan_def; i++) {
5169 guint16 cn, typ, asoc;
5170 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
5171 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
5172 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
5173 if (cn < nchan_def) {
5176 chan_def[cn] = asoc;
5179 chan_def[cn] = 0; /* alpha */
5182 chan_def[cn] = -typ;
5190 gst_caps_set_simple (stream->caps,
5191 "num-components", G_TYPE_INT, ncomp, NULL);
5192 gst_caps_set_simple (stream->caps,
5193 "fourcc", GST_TYPE_FOURCC, fourcc, NULL);
5196 GValue arr = { 0, };
5197 GValue elt = { 0, };
5199 g_value_init (&arr, GST_TYPE_ARRAY);
5200 g_value_init (&elt, G_TYPE_INT);
5201 for (i = 0; i < ncomp_map; i++) {
5202 g_value_set_int (&elt, comp_map[i]);
5203 gst_value_array_append_value (&arr, &elt);
5205 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
5206 "component-map", &arr);
5207 g_value_unset (&elt);
5208 g_value_unset (&arr);
5213 GValue arr = { 0, };
5214 GValue elt = { 0, };
5216 g_value_init (&arr, GST_TYPE_ARRAY);
5217 g_value_init (&elt, G_TYPE_INT);
5218 for (i = 0; i < nchan_def; i++) {
5219 g_value_set_int (&elt, chan_def[i]);
5220 gst_value_array_append_value (&arr, &elt);
5222 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
5223 "channel-definitions", &arr);
5224 g_value_unset (&elt);
5225 g_value_unset (&arr);
5229 /* some optional atoms */
5230 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
5231 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
5233 /* indicate possible fields in caps */
5235 data = (guint8 *) field->data + 8;
5237 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
5238 (gint) * data, NULL);
5240 /* add codec_data if provided */
5245 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
5246 data = prefix->data;
5247 len = QT_UINT32 (data);
5250 buf = gst_buffer_new_and_alloc (len);
5251 memcpy (GST_BUFFER_DATA (buf), data + 8, len);
5252 gst_caps_set_simple (stream->caps,
5253 "codec_data", GST_TYPE_BUFFER, buf, NULL);
5254 gst_buffer_unref (buf);
5263 GstBuffer *seqh = NULL;
5264 guint8 *gamma_data = NULL;
5265 gint len = QT_UINT32 (stsd_data);
5267 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
5269 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
5270 QT_FP32 (gamma_data), NULL);
5273 /* sorry for the bad name, but we don't know what this is, other
5274 * than its own fourcc */
5275 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
5279 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
5280 buf = gst_buffer_new_and_alloc (len);
5281 memcpy (GST_BUFFER_DATA (buf), stsd_data, len);
5282 gst_caps_set_simple (stream->caps,
5283 "codec_data", GST_TYPE_BUFFER, buf, NULL);
5284 gst_buffer_unref (buf);
5289 gst_caps_set_simple (stream->caps,
5290 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
5297 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
5298 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
5302 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
5306 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
5307 /* collect the headers and store them in a stream list so that we can
5308 * send them out first */
5309 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
5317 GST_INFO_OBJECT (qtdemux,
5318 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
5319 GST_FOURCC_ARGS (fourcc), stream->caps);
5321 } else if (stream->subtype == FOURCC_soun) {
5322 int version, samplesize;
5323 guint16 compression_id;
5329 version = QT_UINT32 (stsd_data + offset);
5330 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
5331 samplesize = QT_UINT16 (stsd_data + offset + 10);
5332 compression_id = QT_UINT16 (stsd_data + offset + 12);
5333 stream->rate = QT_FP32 (stsd_data + offset + 16);
5335 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
5336 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
5337 QT_UINT32 (stsd_data + offset + 4));
5338 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
5339 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
5340 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
5341 GST_LOG_OBJECT (qtdemux, "packet size: %d",
5342 QT_UINT16 (stsd_data + offset + 14));
5343 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
5345 if (compression_id == 0xfffe)
5346 stream->sampled = TRUE;
5348 /* first assume uncompressed audio */
5349 stream->bytes_per_sample = samplesize / 8;
5350 stream->samples_per_frame = stream->n_channels;
5351 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
5352 stream->samples_per_packet = stream->samples_per_frame;
5353 stream->bytes_per_packet = stream->bytes_per_sample;
5357 /* Yes, these have to be hard-coded */
5360 stream->samples_per_packet = 6;
5361 stream->bytes_per_packet = 1;
5362 stream->bytes_per_frame = 1 * stream->n_channels;
5363 stream->bytes_per_sample = 1;
5364 stream->samples_per_frame = 6 * stream->n_channels;
5369 stream->samples_per_packet = 3;
5370 stream->bytes_per_packet = 1;
5371 stream->bytes_per_frame = 1 * stream->n_channels;
5372 stream->bytes_per_sample = 1;
5373 stream->samples_per_frame = 3 * stream->n_channels;
5378 stream->samples_per_packet = 64;
5379 stream->bytes_per_packet = 34;
5380 stream->bytes_per_frame = 34 * stream->n_channels;
5381 stream->bytes_per_sample = 2;
5382 stream->samples_per_frame = 64 * stream->n_channels;
5388 stream->samples_per_packet = 1;
5389 stream->bytes_per_packet = 1;
5390 stream->bytes_per_frame = 1 * stream->n_channels;
5391 stream->bytes_per_sample = 1;
5392 stream->samples_per_frame = 1 * stream->n_channels;
5397 stream->samples_per_packet = 160;
5398 stream->bytes_per_packet = 33;
5399 stream->bytes_per_frame = 33 * stream->n_channels;
5400 stream->bytes_per_sample = 2;
5401 stream->samples_per_frame = 160 * stream->n_channels;
5408 if (version == 0x00010000) {
5416 /* only parse extra decoding config for non-pcm audio */
5417 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
5418 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
5419 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
5420 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
5422 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
5423 stream->samples_per_packet);
5424 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
5425 stream->bytes_per_packet);
5426 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
5427 stream->bytes_per_frame);
5428 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
5429 stream->bytes_per_sample);
5431 if (!stream->sampled && stream->bytes_per_packet) {
5432 stream->samples_per_frame = (stream->bytes_per_frame /
5433 stream->bytes_per_packet) * stream->samples_per_packet;
5434 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
5435 stream->samples_per_frame);
5440 } else if (version == 0x00020000) {
5447 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
5448 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
5449 stream->rate = qtfp.fp;
5450 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
5452 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
5453 stream->samples_per_packet);
5454 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
5455 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
5458 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
5461 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
5470 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
5472 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
5474 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
5476 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
5479 gst_caps_set_simple (stream->caps,
5480 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
5489 list = gst_tag_list_new ();
5490 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
5491 GST_TAG_AUDIO_CODEC, codec, NULL);
5496 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
5500 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
5502 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
5504 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
5508 /* If the fourcc's bottom 16 bits gives 'sm', then the top
5509 16 bits is a byte-swapped wave-style codec identifier,
5510 and we can find a WAVE header internally to a 'wave' atom here.
5511 This can more clearly be thought of as 'ms' as the top 16 bits, and a
5512 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
5515 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
5516 if (len < offset + 20) {
5517 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
5519 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
5520 const guint8 *data = stsd_data + offset + 16;
5522 GNode *waveheadernode;
5524 wavenode = g_node_new ((guint8 *) data);
5525 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
5526 const guint8 *waveheader;
5529 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
5530 waveheader = (const guint8 *) waveheadernode->data;
5531 headerlen = QT_UINT32 (waveheader);
5533 if (headerlen > 8) {
5534 gst_riff_strf_auds *header = NULL;
5535 GstBuffer *headerbuf;
5541 headerbuf = gst_buffer_new ();
5542 GST_BUFFER_DATA (headerbuf) = (guint8 *) waveheader;
5543 GST_BUFFER_SIZE (headerbuf) = headerlen;
5545 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
5546 headerbuf, &header, &extra)) {
5547 gst_caps_unref (stream->caps);
5548 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
5549 header, extra, NULL, NULL);
5552 gst_buffer_unref (extra);
5556 g_node_destroy (wavenode);
5559 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
5563 /* FIXME: what is in the chunk? */
5566 gint len = QT_UINT32 (stsd_data);
5568 /* seems to be always = 116 = 0x74 */
5574 gint len = QT_UINT32 (stsd_data);
5577 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
5579 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x4C, len - 0x4C);
5580 gst_caps_set_simple (stream->caps,
5581 "codec_data", GST_TYPE_BUFFER, buf, NULL);
5582 gst_buffer_unref (buf);
5584 gst_caps_set_simple (stream->caps,
5585 "samplesize", G_TYPE_INT, samplesize, NULL);
5590 gint len = QT_UINT32 (stsd_data);
5593 GstBuffer *buf = gst_buffer_new_and_alloc (36);
5594 memcpy (GST_BUFFER_DATA (buf), stsd_data + 88, 36);
5595 gst_caps_set_simple (stream->caps,
5596 "codec_data", GST_TYPE_BUFFER, buf, NULL);
5597 gst_buffer_unref (buf);
5599 gst_caps_set_simple (stream->caps,
5600 "samplesize", G_TYPE_INT, samplesize, NULL);
5605 gint len = QT_UINT32 (stsd_data);
5608 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
5610 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34);
5612 gst_caps_set_simple (stream->caps,
5613 "codec_data", GST_TYPE_BUFFER, buf, NULL);
5614 gst_buffer_unref (buf);
5622 GST_INFO_OBJECT (qtdemux,
5623 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
5624 GST_FOURCC_ARGS (fourcc), stream->caps);
5626 } else if (stream->subtype == FOURCC_strm) {
5627 if (fourcc != FOURCC_rtsp) {
5628 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
5629 GST_FOURCC_ARGS (fourcc));
5630 goto unknown_stream;
5632 stream->sampled = TRUE;
5633 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
5635 stream->sampled = TRUE;
5640 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
5642 list = gst_tag_list_new ();
5643 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
5644 GST_TAG_SUBTITLE_CODEC, codec, NULL);
5649 /* hunt for sort-of codec data */
5656 /* look for palette */
5657 /* target mp4s atom */
5658 len = QT_UINT32 (stsd_data + offset);
5659 data = stsd_data + offset;
5660 /* verify sufficient length,
5661 * and esds present with decConfigDescr of expected size and position */
5662 if ((len >= 106 + 8)
5663 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
5664 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
5669 /* move to decConfigDescr data */
5670 data = data + 8 + 42;
5671 for (i = 0; i < 16; i++) {
5672 clut[i] = QT_UINT32 (data);
5676 s = gst_structure_new ("application/x-gst-dvd", "event",
5677 G_TYPE_STRING, "dvd-spu-clut-change",
5678 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
5679 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
5680 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
5681 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
5682 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
5683 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
5684 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
5685 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
5688 /* store event and trigger custom processing */
5689 stream->pending_event =
5690 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
5691 stream->need_process = TRUE;
5699 goto unknown_stream;
5702 /* promote to sampled format */
5703 if (stream->fourcc == FOURCC_samr) {
5704 /* force mono 8000 Hz for AMR */
5705 stream->sampled = TRUE;
5706 stream->n_channels = 1;
5707 stream->rate = 8000;
5708 } else if (stream->fourcc == FOURCC_sawb) {
5709 /* force mono 16000 Hz for AMR-WB */
5710 stream->sampled = TRUE;
5711 stream->n_channels = 1;
5712 stream->rate = 16000;
5713 } else if (stream->fourcc == FOURCC_mp4a) {
5714 stream->sampled = TRUE;
5717 /* collect sample information */
5718 if (!qtdemux_stbl_init (qtdemux, stream, stbl)
5719 || !qtdemux_parse_samples (qtdemux, stream, 0))
5720 goto samples_failed;
5722 /* configure segments */
5723 if (!qtdemux_parse_segments (qtdemux, stream, trak))
5724 goto segments_failed;
5726 /* add some language tag, if useful */
5727 if (stream->lang_code && strcmp (stream->lang_id, "unk") &&
5728 strcmp (stream->lang_id, "und")) {
5729 const gchar *lang_code;
5732 list = gst_tag_list_new ();
5734 /* convert ISO 639-2 code to ISO 639-1 */
5735 lang_code = gst_tag_get_language_code (stream->lang_id);
5736 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
5737 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
5740 /* now we are ready to add the stream */
5741 gst_qtdemux_add_stream (qtdemux, stream, list);
5748 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
5749 (_("This file is corrupt and cannot be played.")), (NULL));
5755 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
5762 /* we posted an error already */
5763 /* free stbl sub-atoms */
5764 gst_qtdemux_stbl_free (stream);
5770 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
5771 GST_FOURCC_ARGS (stream->subtype));
5777 /* check if major or compatible brand is 3GP */
5778 static inline gboolean
5779 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
5782 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
5783 GST_MAKE_FOURCC ('3', 'g', 0, 0));
5784 } else if (qtdemux->comp_brands != NULL) {
5785 guint8 *data = GST_BUFFER_DATA (qtdemux->comp_brands);
5786 guint size = GST_BUFFER_SIZE (qtdemux->comp_brands);
5787 gboolean res = FALSE;
5790 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
5791 GST_MAKE_FOURCC ('3', 'g', 0, 0));
5801 /* check if tag is a spec'ed 3GP tag keyword storing a string */
5802 static inline gboolean
5803 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
5805 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
5806 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
5807 || fourcc == FOURCC_albm;
5811 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
5812 const char *dummy, GNode * node)
5814 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
5818 gdouble longitude, latitude, altitude;
5821 len = QT_UINT32 (node->data);
5828 /* TODO: language code skipped */
5830 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
5833 /* do not alarm in trivial case, but bail out otherwise */
5834 if (*(data + offset) != 0) {
5835 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
5839 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
5840 GST_TAG_GEO_LOCATION_NAME, name, NULL);
5841 offset += strlen (name);
5845 if (len < offset + 2 + 4 + 4 + 4)
5848 /* +1 +1 = skip null-terminator and location role byte */
5850 longitude = QT_FP32 (data + offset);
5853 latitude = QT_FP32 (data + offset);
5856 altitude = QT_FP32 (data + offset);
5858 /* one invalid means all are invalid */
5859 if (longitude >= -180.0 && longitude <= 180.0 &&
5860 latitude >= -90.0 && latitude <= 90.0) {
5861 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
5862 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
5863 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
5864 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
5867 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
5874 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
5881 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
5888 len = QT_UINT32 (node->data);
5892 y = QT_UINT16 ((guint8 *) node->data + 12);
5893 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
5895 date = g_date_new_dmy (1, 1, y);
5896 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
5901 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
5902 const char *dummy, GNode * node)
5905 char *tag_str = NULL;
5910 len = QT_UINT32 (node->data);
5915 entity = (guint8 *) node->data + offset;
5918 table = QT_UINT16 ((guint8 *) node->data + offset);
5920 /* Language code skipped */
5924 /* Tag format: "XXXX://Y[YYYY]/classification info string"
5925 * XXXX: classification entity, fixed length 4 chars.
5926 * Y[YYYY]: classification table, max 5 chars.
5928 tag_str = g_strdup_printf ("----://%u/%s",
5929 table, (char *) node->data + offset);
5931 /* memcpy To be sure we're preserving byte order */
5932 memcpy (tag_str, entity, 4);
5933 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
5935 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
5945 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
5951 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
5952 const char *dummy, GNode * node)
5954 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
5960 gboolean ret = TRUE;
5962 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
5964 len = QT_UINT32 (data->data);
5965 type = QT_UINT32 ((guint8 *) data->data + 8);
5966 if (type == 0x00000001 && len > 16) {
5967 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
5970 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
5971 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
5975 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
5979 len = QT_UINT32 (node->data);
5980 type = QT_UINT32 ((guint8 *) node->data + 4);
5981 if ((type >> 24) == 0xa9) {
5982 /* Type starts with the (C) symbol, so the next 32 bits are
5983 * the language code, which we ignore */
5985 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
5986 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
5987 QT_FOURCC ((guint8 *) node->data + 4))) {
5988 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
5990 /* we go for 3GP style encoding if major brands claims so,
5991 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
5992 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
5993 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
5994 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
5996 /* 16-bit Language code is ignored here as well */
5997 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
6004 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
6005 ret = FALSE; /* may have to fallback */
6007 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
6008 len - offset, env_vars);
6010 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
6011 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
6015 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
6022 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
6023 const char *dummy, GNode * node)
6025 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
6029 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
6030 const char *dummy, GNode * node)
6032 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
6034 char *s, *t, *k = NULL;
6039 /* first try normal string tag if major brand not 3GP */
6040 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
6041 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
6042 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
6043 * let's try it 3gpp way after minor safety check */
6045 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
6051 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
6055 len = QT_UINT32 (data);
6059 count = QT_UINT8 (data + 14);
6061 for (; count; count--) {
6064 if (offset + 1 > len)
6066 slen = QT_UINT8 (data + offset);
6068 if (offset + slen > len)
6070 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
6073 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
6075 t = g_strjoin (",", k, s, NULL);
6083 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
6090 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
6091 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
6100 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
6106 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
6107 const char *tag2, GNode * node)
6114 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6116 len = QT_UINT32 (data->data);
6117 type = QT_UINT32 ((guint8 *) data->data + 8);
6118 if (type == 0x00000000 && len >= 22) {
6119 n1 = QT_UINT16 ((guint8 *) data->data + 18);
6120 n2 = QT_UINT16 ((guint8 *) data->data + 20);
6122 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
6123 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6127 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
6128 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6136 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
6144 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6146 len = QT_UINT32 (data->data);
6147 type = QT_UINT32 ((guint8 *) data->data + 8);
6148 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
6149 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
6150 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
6151 n1 = QT_UINT16 ((guint8 *) data->data + 16);
6153 /* do not add bpm=0 */
6154 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
6155 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6156 tag1, (gdouble) n1, NULL);
6163 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
6164 const char *dummy, GNode * node)
6171 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6173 len = QT_UINT32 (data->data);
6174 type = QT_UINT32 ((guint8 *) data->data + 8);
6175 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
6176 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
6177 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
6178 num = QT_UINT32 ((guint8 *) data->data + 16);
6180 /* do not add num=0 */
6181 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
6182 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6190 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
6198 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6200 len = QT_UINT32 (data->data);
6201 type = QT_UINT32 ((guint8 *) data->data + 8);
6202 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
6203 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
6204 if ((buf = gst_tag_image_data_to_image_buffer ((guint8 *) data->data + 16,
6205 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
6206 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
6207 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6209 gst_buffer_unref (buf);
6216 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
6224 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6226 len = QT_UINT32 (data->data);
6227 type = QT_UINT32 ((guint8 *) data->data + 8);
6228 if (type == 0x00000001 && len > 16) {
6229 guint y, m = 1, d = 1;
6232 s = g_strndup ((char *) data->data + 16, len - 16);
6233 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
6234 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
6235 if (ret >= 1 && y > 1500 && y < 3000) {
6238 date = g_date_new_dmy (d, m, y);
6239 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
6243 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
6251 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
6256 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6258 /* re-route to normal string tag if major brand says so
6259 * or no data atom and compatible brand suggests so */
6260 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
6261 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
6262 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
6269 len = QT_UINT32 (data->data);
6270 type = QT_UINT32 ((guint8 *) data->data + 8);
6271 if (type == 0x00000000 && len >= 18) {
6272 n = QT_UINT16 ((guint8 *) data->data + 16);
6276 genre = gst_tag_id3_genre_get (n - 1);
6277 if (genre != NULL) {
6278 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
6279 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6287 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
6288 const char *tag, const char *tag_bis, GNode * node);
6291 FOURCC_pcst -> if media is a podcast -> bool
6292 FOURCC_cpil -> if media is part of a compilation -> bool
6293 FOURCC_pgap -> if media is part of a gapless context -> bool
6294 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
6300 const gchar *gst_tag;
6301 const gchar *gst_tag_bis;
6302 const GstQTDemuxAddTagFunc func;
6305 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
6306 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
6307 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
6308 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
6309 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
6310 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
6311 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
6312 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
6313 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
6314 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
6315 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
6316 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
6317 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
6318 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
6319 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
6320 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
6321 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
6322 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
6323 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
6324 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
6325 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
6326 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
6327 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
6328 qtdemux_tag_add_num}, {
6329 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
6330 qtdemux_tag_add_num}, {
6331 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
6332 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
6333 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
6334 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
6335 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
6336 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
6337 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
6338 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
6339 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
6340 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
6341 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
6342 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
6343 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
6344 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
6345 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
6346 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
6347 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
6348 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
6349 qtdemux_tag_add_classification}
6353 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
6358 gchar *media_type, *style;
6364 len = QT_UINT32 (data);
6365 buf = gst_buffer_new_and_alloc (len);
6366 memcpy (GST_BUFFER_DATA (buf), data, len);
6368 /* heuristic to determine style of tag */
6369 if (QT_FOURCC (data + 4) == FOURCC_____ ||
6370 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
6372 else if (demux->major_brand == FOURCC_qt__)
6373 style = "quicktime";
6374 /* fall back to assuming iso/3gp tag style */
6378 /* santize the name for the caps. */
6379 for (i = 0; i < 4; i++) {
6380 guint8 d = data[4 + i];
6381 if (g_ascii_isalnum (d))
6382 ndata[i] = g_ascii_tolower (d);
6387 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
6388 ndata[0], ndata[1], ndata[2], ndata[3]);
6389 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
6391 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
6392 gst_buffer_set_caps (buf, caps);
6393 gst_caps_unref (caps);
6394 g_free (media_type);
6396 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
6397 GST_BUFFER_SIZE (buf), caps);
6399 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
6400 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
6401 gst_buffer_unref (buf);
6405 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
6412 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
6414 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
6416 GST_LOG_OBJECT (qtdemux, "no ilst");
6421 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
6424 GST_DEBUG_OBJECT (qtdemux, "new tag list");
6425 qtdemux->tag_list = gst_tag_list_new ();
6427 for (i = 0; i < G_N_ELEMENTS (add_funcs); ++i) {
6428 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
6432 len = QT_UINT32 (node->data);
6434 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
6435 GST_FOURCC_ARGS (add_funcs[i].fourcc));
6437 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
6438 add_funcs[i].gst_tag_bis, node);
6440 g_node_destroy (node);
6444 /* parsed nodes have been removed, pass along remainder as blob */
6445 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
6446 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
6452 GstStructure *structure; /* helper for sort function */
6454 guint min_req_bitrate;
6455 guint min_req_qt_version;
6459 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
6461 GstQtReference *ref_a = (GstQtReference *) a;
6462 GstQtReference *ref_b = (GstQtReference *) b;
6464 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
6465 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
6467 /* known bitrates go before unknown; higher bitrates go first */
6468 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
6471 /* sort the redirects and post a message for the application.
6474 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
6476 GstQtReference *best;
6479 GValue list_val = { 0, };
6482 g_assert (references != NULL);
6484 references = g_list_sort (references, qtdemux_redirects_sort_func);
6486 best = (GstQtReference *) references->data;
6488 g_value_init (&list_val, GST_TYPE_LIST);
6490 for (l = references; l != NULL; l = l->next) {
6491 GstQtReference *ref = (GstQtReference *) l->data;
6492 GValue struct_val = { 0, };
6494 ref->structure = gst_structure_new ("redirect",
6495 "new-location", G_TYPE_STRING, ref->location, NULL);
6497 if (ref->min_req_bitrate > 0) {
6498 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
6499 ref->min_req_bitrate, NULL);
6502 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
6503 g_value_set_boxed (&struct_val, ref->structure);
6504 gst_value_list_append_value (&list_val, &struct_val);
6505 g_value_unset (&struct_val);
6506 /* don't free anything here yet, since we need best->structure below */
6509 g_assert (best != NULL);
6510 s = gst_structure_copy (best->structure);
6512 if (g_list_length (references) > 1) {
6513 gst_structure_set_value (s, "locations", &list_val);
6516 g_value_unset (&list_val);
6518 for (l = references; l != NULL; l = l->next) {
6519 GstQtReference *ref = (GstQtReference *) l->data;
6521 gst_structure_free (ref->structure);
6522 g_free (ref->location);
6525 g_list_free (references);
6527 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
6528 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
6529 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
6532 /* look for redirect nodes, collect all redirect information and
6536 qtdemux_parse_redirects (GstQTDemux * qtdemux)
6538 GNode *rmra, *rmda, *rdrf;
6540 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
6542 GList *redirects = NULL;
6544 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
6546 GstQtReference ref = { NULL, NULL, 0, 0 };
6549 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
6550 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
6551 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
6552 ref.min_req_bitrate);
6555 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
6556 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
6557 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
6559 #ifndef GST_DISABLE_GST_DEBUG
6560 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
6562 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
6564 GST_LOG_OBJECT (qtdemux,
6565 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
6566 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
6567 bitmask, check_type);
6568 if (package == FOURCC_qtim && check_type == 0) {
6569 ref.min_req_qt_version = version;
6573 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
6578 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
6579 ref_data = (guint8 *) rdrf->data + 20;
6580 if (ref_type == FOURCC_alis) {
6581 guint record_len, record_version, fn_len;
6583 /* MacOSX alias record, google for alias-layout.txt */
6584 record_len = QT_UINT16 (ref_data + 4);
6585 record_version = QT_UINT16 (ref_data + 4 + 2);
6586 fn_len = QT_UINT8 (ref_data + 50);
6587 if (record_len > 50 && record_version == 2 && fn_len > 0) {
6588 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
6590 } else if (ref_type == FOURCC_url_) {
6591 ref.location = g_strdup ((gchar *) ref_data);
6593 GST_DEBUG_OBJECT (qtdemux,
6594 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
6595 GST_FOURCC_ARGS (ref_type));
6597 if (ref.location != NULL) {
6598 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
6599 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
6601 GST_WARNING_OBJECT (qtdemux,
6602 "Failed to extract redirect location from rdrf atom");
6606 /* look for others */
6607 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
6610 if (redirects != NULL) {
6611 qtdemux_process_redirects (qtdemux, redirects);
6618 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
6623 tags = gst_tag_list_new ();
6625 if (qtdemux->major_brand == FOURCC_mjp2)
6626 fmt = "Motion JPEG 2000";
6627 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
6629 else if (qtdemux->major_brand == FOURCC_qt__)
6632 fmt = "ISO MP4/M4A";
6634 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
6635 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
6637 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
6643 /* we have read th complete moov node now.
6644 * This function parses all of the relevant info, creates the traks and
6645 * prepares all data structures for playback
6648 qtdemux_parse_tree (GstQTDemux * qtdemux)
6655 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
6657 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
6658 return qtdemux_parse_redirects (qtdemux);
6661 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
6662 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
6664 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
6665 GST_INFO_OBJECT (qtdemux, "duration: %u", qtdemux->duration);
6667 /* set duration in the segment info */
6668 gst_qtdemux_get_duration (qtdemux, &duration);
6669 gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
6671 /* parse all traks */
6672 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
6674 qtdemux_parse_trak (qtdemux, trak);
6675 /* iterate all siblings */
6676 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
6678 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
6680 /* find and push tags, we do this after adding the pads so we can push the
6681 * tags downstream as well. */
6682 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
6684 qtdemux_parse_udta (qtdemux, udta);
6686 GST_LOG_OBJECT (qtdemux, "No udta node found.");
6689 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
6690 GST_INFO_OBJECT (qtdemux, "posting global tags: %" GST_PTR_FORMAT,
6692 /* post now, send event on pads later */
6693 gst_element_post_message (GST_ELEMENT (qtdemux),
6694 gst_message_new_tag (GST_OBJECT (qtdemux),
6695 gst_tag_list_copy (qtdemux->tag_list)));
6700 /* taken from ffmpeg */
6702 get_size (guint8 * ptr, guint8 ** end)
6711 len = (len << 7) | (c & 0x7f);
6720 /* this can change the codec originally present in @list */
6722 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
6723 GNode * esds, GstTagList * list)
6725 int len = QT_UINT32 (esds->data);
6726 guint8 *ptr = esds->data;
6727 guint8 *end = ptr + len;
6729 guint8 *data_ptr = NULL;
6731 guint8 object_type_id = 0;
6732 char *codec_name = NULL;
6733 GstCaps *caps = NULL;
6735 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
6737 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
6740 tag = QT_UINT8 (ptr);
6741 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
6743 len = get_size (ptr, &ptr);
6744 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
6748 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
6749 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
6753 guint max_bitrate, avg_bitrate;
6755 object_type_id = QT_UINT8 (ptr);
6756 max_bitrate = QT_UINT32 (ptr + 5);
6757 avg_bitrate = QT_UINT32 (ptr + 9);
6758 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
6759 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
6760 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
6761 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
6762 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
6763 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6764 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6765 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6767 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6768 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
6775 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
6781 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
6785 GST_ERROR_OBJECT (qtdemux, "parse error");
6790 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
6791 * in use, and should also be used to override some other parameters for some
6793 switch (object_type_id) {
6794 case 0x20: /* MPEG-4 */
6795 break; /* Nothing special needed here */
6796 case 0x21: /* H.264 */
6797 codec_name = "H.264 / AVC";
6798 caps = gst_caps_new_simple ("video/x-h264", NULL);
6800 case 0x40: /* AAC (any) */
6801 case 0x66: /* AAC Main */
6802 case 0x67: /* AAC LC */
6803 case 0x68: /* AAC SSR */
6804 /* Override channels and rate based on the codec_data, as it's often
6806 if (data_ptr && data_len >= 2) {
6807 guint channels, rateindex;
6808 int rates[] = { 96000, 88200, 64000, 48000, 44100, 32000,
6809 24000, 22050, 16000, 12000, 11025, 8000
6812 channels = (data_ptr[1] & 0x7f) >> 3;
6813 if (channels <= 7) {
6814 stream->n_channels = channels;
6817 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
6818 if (rateindex < sizeof (rates) / sizeof (*rates)) {
6819 stream->rate = rates[rateindex];
6823 case 0x60: /* MPEG-2, various profiles */
6829 codec_name = "MPEG-2 video";
6831 gst_caps_unref (stream->caps);
6832 stream->caps = gst_caps_new_simple ("video/mpeg",
6833 "mpegversion", G_TYPE_INT, 2,
6834 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
6836 case 0x69: /* MP3 has two different values, accept either */
6838 /* change to mpeg1 layer 3 audio */
6839 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
6840 "mpegversion", G_TYPE_INT, 1, NULL);
6841 codec_name = "MPEG-1 layer 3";
6843 case 0x6A: /* MPEG-1 */
6844 codec_name = "MPEG-1 video";
6846 gst_caps_unref (stream->caps);
6847 stream->caps = gst_caps_new_simple ("video/mpeg",
6848 "mpegversion", G_TYPE_INT, 1,
6849 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
6851 case 0x6C: /* MJPEG */
6852 caps = gst_caps_new_simple ("image/jpeg", NULL);
6853 codec_name = "Motion-JPEG";
6855 case 0x6D: /* PNG */
6856 caps = gst_caps_new_simple ("image/png", NULL);
6857 codec_name = "PNG still images";
6859 case 0x6E: /* JPEG2000 */
6860 codec_name = "JPEG-2000";
6861 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
6863 case 0xA4: /* Dirac */
6864 codec_name = "Dirac";
6865 caps = gst_caps_new_simple ("video/x-dirac", NULL);
6867 case 0xA5: /* AC3 */
6868 codec_name = "AC-3 audio";
6869 caps = gst_caps_new_simple ("audio/x-ac3", NULL);
6871 case 0xE1: /* QCELP */
6872 /* QCELP, the codec_data is a riff tag (little endian) with
6873 * 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). */
6874 caps = gst_caps_new_simple ("audio/qcelp", NULL);
6875 codec_name = "QCELP";
6881 /* If we have a replacement caps, then change our caps for this stream */
6883 gst_caps_unref (stream->caps);
6884 stream->caps = caps;
6887 if (codec_name && list)
6888 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6889 GST_TAG_AUDIO_CODEC, codec_name, NULL);
6891 /* Add the codec_data attribute to caps, if we have it */
6895 buffer = gst_buffer_new_and_alloc (data_len);
6896 memcpy (GST_BUFFER_DATA (buffer), data_ptr, data_len);
6898 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
6899 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
6901 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
6903 gst_buffer_unref (buffer);
6908 #define _codec(name) \
6911 *codec_name = g_strdup (name); \
6916 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
6917 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
6920 const GstStructure *s;
6924 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
6925 _codec ("PNG still images");
6926 caps = gst_caps_new_simple ("image/png", NULL);
6928 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
6929 _codec ("JPEG still images");
6930 caps = gst_caps_new_simple ("image/jpeg", NULL);
6932 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
6933 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
6934 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
6935 _codec ("Motion-JPEG");
6936 caps = gst_caps_new_simple ("image/jpeg", NULL);
6938 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
6939 _codec ("Motion-JPEG format B");
6940 caps = gst_caps_new_simple ("video/x-mjpeg-b", NULL);
6942 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
6943 _codec ("JPEG-2000");
6944 /* override to what it should be according to spec, avoid palette_data */
6945 stream->bits_per_sample = 24;
6946 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
6948 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
6949 _codec ("Sorensen video v.3");
6950 caps = gst_caps_new_simple ("video/x-svq",
6951 "svqversion", G_TYPE_INT, 3, NULL);
6953 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
6954 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
6955 _codec ("Sorensen video v.1");
6956 caps = gst_caps_new_simple ("video/x-svq",
6957 "svqversion", G_TYPE_INT, 1, NULL);
6959 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
6963 _codec ("Raw RGB video");
6964 bps = QT_UINT16 (stsd_data + 98);
6965 /* set common stuff */
6966 caps = gst_caps_new_simple ("video/x-raw-rgb",
6967 "endianness", G_TYPE_INT, G_BYTE_ORDER, "depth", G_TYPE_INT, bps,
6972 gst_caps_set_simple (caps,
6973 "bpp", G_TYPE_INT, 16,
6974 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
6975 "red_mask", G_TYPE_INT, 0x7c00,
6976 "green_mask", G_TYPE_INT, 0x03e0,
6977 "blue_mask", G_TYPE_INT, 0x001f, NULL);
6980 gst_caps_set_simple (caps,
6981 "bpp", G_TYPE_INT, 16,
6982 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
6983 "red_mask", G_TYPE_INT, 0xf800,
6984 "green_mask", G_TYPE_INT, 0x07e0,
6985 "blue_mask", G_TYPE_INT, 0x001f, NULL);
6988 gst_caps_set_simple (caps,
6989 "bpp", G_TYPE_INT, 24,
6990 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
6991 "red_mask", G_TYPE_INT, 0xff0000,
6992 "green_mask", G_TYPE_INT, 0x00ff00,
6993 "blue_mask", G_TYPE_INT, 0x0000ff, NULL);
6996 gst_caps_set_simple (caps,
6997 "bpp", G_TYPE_INT, 32,
6998 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
6999 "alpha_mask", G_TYPE_INT, 0xff000000,
7000 "red_mask", G_TYPE_INT, 0x00ff0000,
7001 "green_mask", G_TYPE_INT, 0x0000ff00,
7002 "blue_mask", G_TYPE_INT, 0x000000ff, NULL);
7010 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
7011 _codec ("Raw planar YUV 4:2:0");
7012 caps = gst_caps_new_simple ("video/x-raw-yuv",
7013 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
7016 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
7017 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
7018 _codec ("Raw packed YUV 4:2:2");
7019 caps = gst_caps_new_simple ("video/x-raw-yuv",
7020 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'),
7023 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
7024 _codec ("Raw packed YUV 4:2:0");
7025 caps = gst_caps_new_simple ("video/x-raw-yuv",
7026 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'),
7029 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
7030 _codec ("Raw packed YUV 10-bit 4:2:2");
7031 caps = gst_caps_new_simple ("video/x-raw-yuv",
7032 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('v', '2', '1', '0'),
7035 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
7036 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
7037 _codec ("MPEG-1 video");
7038 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
7039 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7041 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
7042 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
7043 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
7044 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
7045 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
7046 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
7047 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
7048 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
7049 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
7050 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
7051 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
7052 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
7053 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
7054 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
7055 _codec ("MPEG-2 video");
7056 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
7057 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7059 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
7060 _codec ("GIF still images");
7061 caps = gst_caps_new_simple ("image/gif", NULL);
7063 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
7064 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
7065 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
7066 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
7068 /* ffmpeg uses the height/width props, don't know why */
7069 caps = gst_caps_new_simple ("video/x-h263", NULL);
7071 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
7072 _codec ("MPEG-4 video");
7073 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
7074 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7076 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
7077 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
7078 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
7079 caps = gst_caps_new_simple ("video/x-msmpeg",
7080 "msmpegversion", G_TYPE_INT, 43, NULL);
7082 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
7083 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
7084 _codec ("3ivX video");
7085 caps = gst_caps_new_simple ("video/x-3ivx", NULL);
7087 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
7089 caps = gst_caps_new_simple ("video/x-divx",
7090 "divxversion", G_TYPE_INT, 3, NULL);
7092 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
7093 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
7095 caps = gst_caps_new_simple ("video/x-divx",
7096 "divxversion", G_TYPE_INT, 4, NULL);
7098 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
7100 caps = gst_caps_new_simple ("video/x-divx",
7101 "divxversion", G_TYPE_INT, 5, NULL);
7103 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
7104 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
7105 _codec ("XVID MPEG-4");
7106 caps = gst_caps_new_simple ("video/x-xvid", NULL);
7109 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
7110 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
7111 caps = gst_caps_new_simple ("video/mpeg",
7112 "mpegversion", G_TYPE_INT, 4, NULL);
7114 *codec_name = g_strdup ("FFmpeg MPEG-4");
7117 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
7119 caps = gst_caps_new_simple ("video/x-cinepak", NULL);
7121 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
7122 _codec ("Apple QuickDraw");
7123 caps = gst_caps_new_simple ("video/x-qdrw", NULL);
7125 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
7126 _codec ("Apple video");
7127 caps = gst_caps_new_simple ("video/x-apple-video", NULL);
7129 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
7130 _codec ("H.264 / AVC");
7131 caps = gst_caps_new_simple ("video/x-h264", NULL);
7133 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
7134 _codec ("Run-length encoding");
7135 caps = gst_caps_new_simple ("video/x-rle",
7136 "layout", G_TYPE_STRING, "quicktime", NULL);
7138 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
7139 _codec ("Indeo Video 3");
7140 caps = gst_caps_new_simple ("video/x-indeo",
7141 "indeoversion", G_TYPE_INT, 3, NULL);
7143 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
7144 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
7145 _codec ("Intel Video 4");
7146 caps = gst_caps_new_simple ("video/x-indeo",
7147 "indeoversion", G_TYPE_INT, 4, NULL);
7149 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
7150 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
7151 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
7152 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
7153 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
7154 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
7155 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
7156 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
7157 _codec ("DV Video");
7158 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
7159 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7161 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
7162 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
7163 _codec ("DVCPro50 Video");
7164 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
7165 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7167 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
7168 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
7169 _codec ("DVCProHD Video");
7170 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
7171 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7173 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
7174 _codec ("Apple Graphics (SMC)");
7175 caps = gst_caps_new_simple ("video/x-smc", NULL);
7177 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
7179 caps = gst_caps_new_simple ("video/x-vp3", NULL);
7181 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
7183 caps = gst_caps_new_simple ("video/x-theora", NULL);
7184 /* theora uses one byte of padding in the data stream because it does not
7185 * allow 0 sized packets while theora does */
7186 stream->padding = 1;
7188 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
7190 caps = gst_caps_new_simple ("video/x-dirac", NULL);
7192 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
7193 _codec ("TIFF still images");
7194 caps = gst_caps_new_simple ("image/tiff", NULL);
7196 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
7197 _codec ("Apple Intermediate Codec");
7198 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
7200 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
7201 _codec ("AVID DNxHD");
7202 caps = gst_caps_from_string ("video/x-dnxhd");
7204 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
7209 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
7210 GST_FOURCC_ARGS (fourcc));
7211 caps = gst_caps_new_simple (s, NULL);
7216 /* enable clipping for raw video streams */
7217 s = gst_caps_get_structure (caps, 0);
7218 name = gst_structure_get_name (s);
7219 if (g_str_has_prefix (name, "video/x-raw-")) {
7220 stream->need_clip = TRUE;
7226 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
7227 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
7230 const GstStructure *s;
7234 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
7237 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
7238 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
7239 _codec ("Raw 8-bit PCM audio");
7240 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 8,
7241 "depth", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
7243 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
7244 endian = G_BIG_ENDIAN;
7246 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
7252 endian = G_LITTLE_ENDIAN;
7254 depth = stream->bytes_per_packet * 8;
7255 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
7258 caps = gst_caps_new_simple ("audio/x-raw-int",
7259 "width", G_TYPE_INT, depth, "depth", G_TYPE_INT, depth,
7260 "endianness", G_TYPE_INT, endian,
7261 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
7264 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
7265 _codec ("Raw 64-bit floating-point audio");
7266 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 64,
7267 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
7269 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
7270 _codec ("Raw 32-bit floating-point audio");
7271 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 32,
7272 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
7275 _codec ("Raw 24-bit PCM audio");
7276 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
7278 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 24,
7279 "depth", G_TYPE_INT, 24,
7280 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
7281 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
7283 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
7284 _codec ("Raw 32-bit PCM audio");
7285 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 32,
7286 "depth", G_TYPE_INT, 32,
7287 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
7288 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
7290 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
7291 _codec ("Mu-law audio");
7292 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
7294 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
7295 _codec ("A-law audio");
7296 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
7300 _codec ("Microsoft ADPCM");
7301 /* Microsoft ADPCM-ACM code 2 */
7302 caps = gst_caps_new_simple ("audio/x-adpcm",
7303 "layout", G_TYPE_STRING, "microsoft", NULL);
7307 _codec ("DVI/IMA ADPCM");
7308 caps = gst_caps_new_simple ("audio/x-adpcm",
7309 "layout", G_TYPE_STRING, "dvi", NULL);
7313 _codec ("DVI/Intel IMA ADPCM");
7314 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
7315 caps = gst_caps_new_simple ("audio/x-adpcm",
7316 "layout", G_TYPE_STRING, "quicktime", NULL);
7320 /* MPEG layer 3, CBR only (pre QT4.1) */
7321 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
7322 _codec ("MPEG-1 layer 3");
7323 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
7324 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
7325 "mpegversion", G_TYPE_INT, 1, NULL);
7328 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
7329 _codec ("AC-3 audio");
7330 caps = gst_caps_new_simple ("audio/x-ac3", NULL);
7331 stream->sampled = TRUE;
7333 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
7335 caps = gst_caps_new_simple ("audio/x-mace",
7336 "maceversion", G_TYPE_INT, 3, NULL);
7338 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
7340 caps = gst_caps_new_simple ("audio/x-mace",
7341 "maceversion", G_TYPE_INT, 6, NULL);
7343 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
7345 caps = gst_caps_new_simple ("application/ogg", NULL);
7347 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
7348 _codec ("DV audio");
7349 caps = gst_caps_new_simple ("audio/x-dv", NULL);
7351 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
7352 _codec ("MPEG-4 AAC audio");
7353 caps = gst_caps_new_simple ("audio/mpeg",
7354 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
7356 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
7357 _codec ("QDesign Music");
7358 caps = gst_caps_new_simple ("audio/x-qdm", NULL);
7360 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
7361 _codec ("QDesign Music v.2");
7362 /* FIXME: QDesign music version 2 (no constant) */
7364 caps = gst_caps_new_simple ("audio/x-qdm2",
7365 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
7366 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
7367 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
7369 caps = gst_caps_new_simple ("audio/x-qdm2", NULL);
7372 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
7373 _codec ("GSM audio");
7374 caps = gst_caps_new_simple ("audio/x-gsm", NULL);
7376 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
7377 _codec ("AMR audio");
7378 caps = gst_caps_new_simple ("audio/AMR", NULL);
7380 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
7381 _codec ("AMR-WB audio");
7382 caps = gst_caps_new_simple ("audio/AMR-WB", NULL);
7384 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
7385 _codec ("Quicktime IMA ADPCM");
7386 caps = gst_caps_new_simple ("audio/x-adpcm",
7387 "layout", G_TYPE_STRING, "quicktime", NULL);
7389 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
7390 _codec ("Apple lossless audio");
7391 caps = gst_caps_new_simple ("audio/x-alac", NULL);
7393 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
7394 _codec ("QualComm PureVoice");
7395 caps = gst_caps_from_string ("audio/qcelp");
7397 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
7403 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
7404 GST_FOURCC_ARGS (fourcc));
7405 caps = gst_caps_new_simple (s, NULL);
7410 /* enable clipping for raw audio streams */
7411 s = gst_caps_get_structure (caps, 0);
7412 name = gst_structure_get_name (s);
7413 if (g_str_has_prefix (name, "audio/x-raw-")) {
7414 stream->need_clip = TRUE;
7420 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
7421 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
7425 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
7428 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
7429 _codec ("DVD subtitle");
7430 caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
7432 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
7433 _codec ("Quicktime timed text");
7435 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
7436 _codec ("3GPP timed text");
7438 caps = gst_caps_new_simple ("text/plain", NULL);
7439 /* actual text piece needs to be extracted */
7440 stream->need_process = TRUE;
7446 s = g_strdup_printf ("text/x-gst-fourcc-%" GST_FOURCC_FORMAT,
7447 GST_FOURCC_ARGS (fourcc));
7448 caps = gst_caps_new_simple (s, NULL);