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 <glib/gprintf.h>
53 #include <gst/tag/tag.h>
55 #include "qtatomparser.h"
56 #include "qtdemux_types.h"
57 #include "qtdemux_dump.h"
58 #include "qtdemux_fourcc.h"
59 #include "qtdemux_lang.h"
61 #include "qtpalette.h"
63 #include "gst/riff/riff-media.h"
64 #include "gst/riff/riff-read.h"
66 #include <gst/pbutils/pbutils.h>
76 /* max. size considered 'sane' for non-mdat atoms */
77 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
79 /* if the sample index is larger than this, something is likely wrong */
80 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
82 GST_DEBUG_CATEGORY (qtdemux_debug);
84 /*typedef struct _QtNode QtNode; */
85 typedef struct _QtDemuxSegment QtDemuxSegment;
86 typedef struct _QtDemuxSample QtDemuxSample;
98 gint32 pts_offset; /* Add this value to timestamp to get the pts */
100 guint64 timestamp; /* DTS In mov time */
101 guint32 duration; /* In mov time */
102 gboolean keyframe; /* TRUE when this packet is a keyframe */
105 /* timestamp is the DTS */
106 #define QTSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
107 GST_SECOND, (stream)->timescale)
108 /* timestamp + offset is the PTS */
109 #define QTSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
110 (sample)->pts_offset, GST_SECOND, (stream)->timescale)
111 /* timestamp + duration - dts is the duration */
112 #define QTSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
113 (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
114 /* timestamp + offset + duration - pts is the duration */
115 #define QTSAMPLE_DUR_PTS(stream,sample,pts) (gst_util_uint64_scale ((sample)->timestamp + \
116 (sample)->pts_offset + (sample)->duration, GST_SECOND, (stream)->timescale) - (pts));
118 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
121 * Quicktime has tracks and segments. A track is a continuous piece of
122 * multimedia content. The track is not always played from start to finish but
123 * instead, pieces of the track are 'cut out' and played in sequence. This is
124 * what the segments do.
126 * Inside the track we have keyframes (K) and delta frames. The track has its
127 * own timing, which starts from 0 and extends to end. The position in the track
128 * is called the media_time.
130 * The segments now describe the pieces that should be played from this track
131 * and are basically tupples of media_time/duration/rate entries. We can have
132 * multiple segments and they are all played after one another. An example:
134 * segment 1: media_time: 1 second, duration: 1 second, rate 1
135 * segment 2: media_time: 3 second, duration: 2 second, rate 2
137 * To correctly play back this track, one must play: 1 second of media starting
138 * from media_time 1 followed by 2 seconds of media starting from media_time 3
141 * Each of the segments will be played at a specific time, the first segment at
142 * time 0, the second one after the duration of the first one, etc.. Note that
143 * the time in resulting playback is not identical to the media_time of the
146 * Visually, assuming the track has 4 second of media_time:
149 * .-----------------------------------------------------------.
150 * track: | K.....K.........K........K.......K.......K...........K... |
151 * '-----------------------------------------------------------'
153 * .------------^ ^ .----------^ ^
154 * / .-------------' / .------------------'
156 * .--------------. .--------------.
157 * | segment 1 | | segment 2 |
158 * '--------------' '--------------'
160 * The challenge here is to cut out the right pieces of the track for each of
161 * the playback segments. This fortunatly can easily be done with the SEGMENT
162 * events of gstreamer.
164 * For playback of segment 1, we need to provide the decoder with the keyframe
165 * (a), in the above figure, but we must instruct it only to output the decoded
166 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
167 * position set to the time of the segment: 0.
169 * We then proceed to push data from keyframe (a) to frame (b). The decoder
170 * decodes but clips all before media_time 1.
172 * After finishing a segment, we push out a new SEGMENT event with the clipping
173 * boundaries of the new data.
175 * This is a good usecase for the GStreamer accumulated SEGMENT events.
178 struct _QtDemuxSegment
180 /* global time and duration, all gst time */
184 /* media time of trak, all gst time */
190 struct _QtDemuxStream
199 /* if the stream has a redirect URI in its headers, we store it here */
203 guint64 duration; /* in timescale */
207 gchar lang_id[4]; /* ISO 639-2T language code */
211 QtDemuxSample *samples;
212 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
213 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
214 the framerate, in timescale units */
216 /* if we use chunks or samples */
228 /* Numerator/denominator framerate */
231 guint16 bits_per_sample;
232 guint16 color_table_id;
237 guint samples_per_packet;
238 guint samples_per_frame;
239 guint bytes_per_packet;
240 guint bytes_per_sample;
241 guint bytes_per_frame;
244 /* when a discontinuity is pending */
247 /* list of buffers to push first */
250 /* if we need to clip this buffer. This is only needed for uncompressed
254 /* buffer needs some custom processing, e.g. subtitles */
255 gboolean need_process;
257 /* current position */
258 guint32 segment_index;
259 guint32 sample_index;
260 guint64 time_position; /* in gst time */
262 /* the Gst segment we are processing out, used for clipping */
265 /* last GstFlowReturn */
266 GstFlowReturn last_ret;
268 /* quicktime segments */
270 QtDemuxSegment *segments;
275 GstTagList *pending_tags;
276 gboolean send_global_tags;
278 GstEvent *pending_event;
288 gboolean chunks_are_chunks;
292 GstByteReader co_chunk;
294 guint32 current_chunk;
296 guint32 samples_per_chunk;
297 guint32 stco_sample_index;
299 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
302 guint32 n_samples_per_chunk;
303 guint32 stsc_chunk_index;
304 guint32 stsc_sample_index;
305 guint64 chunk_offset;
308 guint32 stts_samples;
309 guint32 n_sample_times;
310 guint32 stts_sample_index;
312 guint32 stts_duration;
314 gboolean stss_present;
315 guint32 n_sample_syncs;
318 gboolean stps_present;
319 guint32 n_sample_partial_syncs;
322 gboolean ctts_present;
323 guint32 n_composition_times;
325 guint32 ctts_sample_index;
332 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
333 QTDEMUX_STATE_HEADER, /* Parsing the header */
334 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
335 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
338 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
339 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
340 guint32 fourcc, GstByteReader * parser);
341 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
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 GST_BOILERPLATE (GstQTDemux, gst_qtdemux, GstQTDemux, GST_TYPE_ELEMENT);
371 static void gst_qtdemux_dispose (GObject * object);
373 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
374 static GstIndex *gst_qtdemux_get_index (GstElement * element);
375 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
376 GstStateChange transition);
377 static gboolean qtdemux_sink_activate (GstPad * sinkpad);
378 static gboolean qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active);
379 static gboolean qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active);
381 static void gst_qtdemux_loop (GstPad * pad);
382 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf);
383 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstEvent * event);
385 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer,
387 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
388 const guint8 * buffer, guint length);
389 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
391 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
392 QtDemuxStream * stream, GNode * esds, GstTagList * list);
393 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
394 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
395 gchar ** codec_name);
396 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
397 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
398 gchar ** codec_name);
399 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
400 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
401 gchar ** codec_name);
402 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
403 QtDemuxStream * stream, guint32 n);
407 gst_qtdemux_base_init (gpointer klass)
409 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
411 gst_element_class_add_pad_template (element_class,
412 gst_static_pad_template_get (&gst_qtdemux_sink_template));
413 gst_element_class_add_pad_template (element_class,
414 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
415 gst_element_class_add_pad_template (element_class,
416 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
417 gst_element_class_add_pad_template (element_class,
418 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
419 gst_element_class_set_details_simple (element_class, "QuickTime demuxer",
421 "Demultiplex a QuickTime file into audio and video streams",
422 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
424 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
428 gst_qtdemux_class_init (GstQTDemuxClass * klass)
430 GObjectClass *gobject_class;
431 GstElementClass *gstelement_class;
433 gobject_class = (GObjectClass *) klass;
434 gstelement_class = (GstElementClass *) klass;
436 parent_class = g_type_class_peek_parent (klass);
438 gobject_class->dispose = gst_qtdemux_dispose;
440 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
442 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
443 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
447 gst_qtdemux_init (GstQTDemux * qtdemux, GstQTDemuxClass * klass)
450 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
451 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
452 gst_pad_set_activatepull_function (qtdemux->sinkpad,
453 qtdemux_sink_activate_pull);
454 gst_pad_set_activatepush_function (qtdemux->sinkpad,
455 qtdemux_sink_activate_push);
456 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
457 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
458 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
460 qtdemux->state = QTDEMUX_STATE_INITIAL;
461 qtdemux->pullbased = FALSE;
462 qtdemux->posted_redirect = FALSE;
463 qtdemux->neededbytes = 16;
465 qtdemux->adapter = gst_adapter_new ();
467 qtdemux->first_mdat = -1;
468 qtdemux->got_moov = FALSE;
469 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
470 qtdemux->mdatbuffer = NULL;
471 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
475 gst_qtdemux_dispose (GObject * object)
477 GstQTDemux *qtdemux = GST_QTDEMUX (object);
479 if (qtdemux->adapter) {
480 g_object_unref (G_OBJECT (qtdemux->adapter));
481 qtdemux->adapter = NULL;
484 G_OBJECT_CLASS (parent_class)->dispose (object);
488 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
490 if (qtdemux->posted_redirect) {
491 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
492 (_("This file contains no playable streams.")),
493 ("no known streams found, a redirect message has been posted"));
495 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
496 (_("This file contains no playable streams.")),
497 ("no known streams found"));
502 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
507 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
508 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
509 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
510 (_("This file is invalid and cannot be played.")),
511 ("atom has bogus size %" G_GUINT64_FORMAT, size));
512 return GST_FLOW_ERROR;
515 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
517 if (G_UNLIKELY (flow != GST_FLOW_OK))
520 /* Catch short reads - we don't want any partial atoms */
521 if (G_UNLIKELY (GST_BUFFER_SIZE (*buf) < size)) {
522 GST_WARNING_OBJECT (qtdemux, "short read: %u < %" G_GUINT64_FORMAT,
523 GST_BUFFER_SIZE (*buf), size);
524 gst_buffer_unref (*buf);
526 return GST_FLOW_UNEXPECTED;
534 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
535 GstFormat * dest_format, gint64 * dest_value)
538 QtDemuxStream *stream = gst_pad_get_element_private (pad);
540 if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e') &&
541 (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
544 switch (src_format) {
545 case GST_FORMAT_TIME:
546 switch (*dest_format) {
547 case GST_FORMAT_BYTES:
548 *dest_value = src_value * 1; /* FIXME */
550 case GST_FORMAT_DEFAULT:
551 *dest_value = src_value * 1; /* FIXME */
558 case GST_FORMAT_BYTES:
559 switch (*dest_format) {
560 case GST_FORMAT_TIME:
561 *dest_value = src_value * 1; /* FIXME */
568 case GST_FORMAT_DEFAULT:
569 switch (*dest_format) {
570 case GST_FORMAT_TIME:
571 *dest_value = src_value * 1; /* FIXME */
586 static const GstQueryType *
587 gst_qtdemux_get_src_query_types (GstPad * pad)
589 static const GstQueryType src_types[] = {
600 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
604 *duration = GST_CLOCK_TIME_NONE;
606 if (qtdemux->duration != 0) {
607 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
608 *duration = gst_util_uint64_scale (qtdemux->duration,
609 GST_SECOND, qtdemux->timescale);
616 gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
618 gboolean res = FALSE;
619 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
621 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
623 switch (GST_QUERY_TYPE (query)) {
624 case GST_QUERY_POSITION:
625 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.last_stop)) {
626 gst_query_set_position (query, GST_FORMAT_TIME,
627 qtdemux->segment.last_stop);
631 case GST_QUERY_DURATION:{
634 gst_query_parse_duration (query, &fmt, NULL);
635 if (fmt == GST_FORMAT_TIME) {
636 gint64 duration = -1;
638 gst_qtdemux_get_duration (qtdemux, &duration);
640 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
646 case GST_QUERY_SEEKING:{
650 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
651 if (fmt == GST_FORMAT_TIME) {
652 gint64 duration = -1;
654 gst_qtdemux_get_duration (qtdemux, &duration);
656 if (!qtdemux->pullbased) {
659 /* we might be able with help from upstream */
661 q = gst_query_new_seeking (GST_FORMAT_BYTES);
662 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
663 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
664 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
668 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
674 res = gst_pad_query_default (pad, query);
678 gst_object_unref (qtdemux);
684 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
686 if (G_LIKELY (stream->pad)) {
687 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
688 GST_DEBUG_PAD_NAME (stream->pad));
690 if (G_UNLIKELY (stream->pending_tags)) {
691 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
692 stream->pending_tags);
693 gst_pad_push_event (stream->pad,
694 gst_event_new_tag (stream->pending_tags));
695 stream->pending_tags = NULL;
698 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
699 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
701 gst_pad_push_event (stream->pad,
702 gst_event_new_tag (gst_tag_list_copy (qtdemux->tag_list)));
703 stream->send_global_tags = FALSE;
708 /* push event on all source pads; takes ownership of the event */
710 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
713 gboolean has_valid_stream = FALSE;
714 GstEventType etype = GST_EVENT_TYPE (event);
716 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
717 GST_EVENT_TYPE_NAME (event));
719 for (n = 0; n < qtdemux->n_streams; n++) {
721 QtDemuxStream *stream = qtdemux->streams[n];
723 if ((pad = stream->pad)) {
724 has_valid_stream = TRUE;
726 if (etype == GST_EVENT_EOS)
727 stream->sent_eos = TRUE;
729 gst_pad_push_event (pad, gst_event_ref (event));
733 gst_event_unref (event);
735 /* if it is EOS and there are no pads, post an error */
736 if (!has_valid_stream && etype == GST_EVENT_EOS) {
737 gst_qtdemux_post_no_playable_stream_error (qtdemux);
741 /* push a pending newsegment event, if any from the streaming thread */
743 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
745 if (qtdemux->pending_newsegment) {
746 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
747 qtdemux->pending_newsegment = NULL;
757 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
759 if (s1->timestamp > *media_time)
765 /* find the index of the sample that includes the data for @media_time using a
768 * Returns the index of the sample.
771 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
774 QtDemuxSample *result;
777 /* convert media_time to mov format */
778 media_time = gst_util_uint64_scale (media_time, str->timescale, GST_SECOND);
780 result = gst_util_array_binary_search (str->samples, str->n_samples,
781 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
782 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
784 if (G_LIKELY (result))
785 index = result - str->samples;
792 /* find the index of the sample that includes the data for @media_time using a
795 * Returns the index of the sample.
798 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
801 QtDemuxSample *result = str->samples;
804 /* convert media_time to mov format */
806 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
808 if (media_time == result->timestamp)
812 while (index < str->n_samples - 1) {
813 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
816 if (media_time < result->timestamp)
827 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
832 /* find the index of the keyframe needed to decode the sample at @index
835 * Returns the index of the keyframe.
838 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
841 guint32 new_index = index;
843 if (index >= str->n_samples) {
844 new_index = str->n_samples;
848 /* all keyframes, return index */
849 if (str->all_keyframe) {
854 /* else go back until we have a keyframe */
856 if (str->samples[new_index].keyframe)
866 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
867 "gave %u", index, new_index);
872 /* find the segment for @time_position for @stream
874 * Returns -1 if the segment cannot be found.
877 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
878 guint64 time_position)
883 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
884 GST_TIME_ARGS (time_position));
886 /* find segment corresponding to time_position if we are looking
889 for (i = 0; i < stream->n_segments; i++) {
890 QtDemuxSegment *segment = &stream->segments[i];
892 GST_LOG_OBJECT (qtdemux,
893 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
894 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
896 /* For the last segment we include stop_time in the last segment */
897 if (i < stream->n_segments - 1) {
898 if (segment->time <= time_position && time_position < segment->stop_time) {
899 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
904 if (segment->time <= time_position && time_position <= segment->stop_time) {
905 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
914 /* move the stream @str to the sample position @index.
916 * Updates @str->sample_index and marks discontinuity if needed.
919 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
922 /* no change needed */
923 if (index == str->sample_index)
926 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
929 /* position changed, we have a discont */
930 str->sample_index = index;
931 /* Each time we move in the stream we store the position where we are
933 str->from_sample = index;
938 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
939 gint64 * key_time, gint64 * key_offset)
942 gint64 min_byte_offset = -1;
945 min_offset = desired_time;
947 /* for each stream, find the index of the sample in the segment
948 * and move back to the previous keyframe. */
949 for (n = 0; n < qtdemux->n_streams; n++) {
951 guint32 index, kindex;
958 str = qtdemux->streams[n];
960 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
961 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
963 /* segment not found, continue with normal flow */
967 /* get segment and time in the segment */
968 seg = &str->segments[seg_idx];
969 seg_time = desired_time - seg->time;
971 /* get the media time in the segment */
972 media_start = seg->media_start + seg_time;
974 /* get the index of the sample with media time */
975 index = gst_qtdemux_find_index (qtdemux, str, media_start);
976 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
977 GST_TIME_ARGS (media_start), index);
979 /* find previous keyframe */
980 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
982 /* if the keyframe is at a different position, we need to update the
983 * requested seek time */
984 if (index != kindex) {
987 /* get timestamp of keyframe */
989 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
991 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT,
992 kindex, GST_TIME_ARGS (media_time));
994 /* keyframes in the segment get a chance to change the
995 * desired_offset. keyframes out of the segment are
997 if (media_time >= seg->media_start) {
1000 /* this keyframe is inside the segment, convert back to
1002 seg_time = (media_time - seg->media_start) + seg->time;
1003 if (seg_time < min_offset)
1004 min_offset = seg_time;
1008 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1009 min_byte_offset = str->samples[index].offset;
1013 *key_time = min_offset;
1015 *key_offset = min_byte_offset;
1019 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1020 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1025 g_return_val_if_fail (format != NULL, FALSE);
1026 g_return_val_if_fail (cur != NULL, FALSE);
1027 g_return_val_if_fail (stop != NULL, FALSE);
1029 if (*format == GST_FORMAT_TIME)
1032 fmt = GST_FORMAT_TIME;
1034 if (cur_type != GST_SEEK_TYPE_NONE)
1035 res = gst_pad_query_convert (pad, *format, *cur, &fmt, cur);
1036 if (res && stop_type != GST_SEEK_TYPE_NONE)
1037 res = gst_pad_query_convert (pad, *format, *stop, &fmt, stop);
1040 *format = GST_FORMAT_TIME;
1045 /* perform seek in push based mode:
1046 find BYTE position to move to based on time and delegate to upstream
1049 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1054 GstSeekType cur_type, stop_type;
1059 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1061 gst_event_parse_seek (event, &rate, &format, &flags,
1062 &cur_type, &cur, &stop_type, &stop);
1064 /* FIXME, always play to the end */
1067 /* only forward streaming and seeking is possible */
1069 goto unsupported_seek;
1071 /* convert to TIME if needed and possible */
1072 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1076 /* find reasonable corresponding BYTE position,
1077 * also try to mind about keyframes, since we can not go back a bit for them
1079 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1084 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1085 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1088 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1089 GST_DEBUG_OBJECT (qtdemux,
1090 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1091 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1092 GST_OBJECT_LOCK (qtdemux);
1093 qtdemux->requested_seek_time = cur;
1094 qtdemux->seek_offset = byte_cur;
1095 GST_OBJECT_UNLOCK (qtdemux);
1098 /* BYTE seek event */
1099 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1101 res = gst_pad_push_event (qtdemux->sinkpad, event);
1108 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1114 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1119 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1124 /* perform the seek.
1126 * We set all segment_indexes in the streams to unknown and
1127 * adjust the time_position to the desired position. this is enough
1128 * to trigger a segment switch in the streaming thread to start
1129 * streaming from the desired position.
1131 * Keyframe seeking is a little more complicated when dealing with
1132 * segments. Ideally we want to move to the previous keyframe in
1133 * the segment but there might not be a keyframe in the segment. In
1134 * fact, none of the segments could contain a keyframe. We take a
1135 * practical approach: seek to the previous keyframe in the segment,
1136 * if there is none, seek to the beginning of the segment.
1138 * Called with STREAM_LOCK
1141 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1143 gint64 desired_offset;
1146 desired_offset = segment->last_stop;
1148 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1149 GST_TIME_ARGS (desired_offset));
1151 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
1154 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1155 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1156 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1157 desired_offset = min_offset;
1160 /* and set all streams to the final position */
1161 for (n = 0; n < qtdemux->n_streams; n++) {
1162 QtDemuxStream *stream = qtdemux->streams[n];
1164 stream->time_position = desired_offset;
1165 stream->sample_index = -1;
1166 stream->segment_index = -1;
1167 stream->last_ret = GST_FLOW_OK;
1168 stream->sent_eos = FALSE;
1170 segment->last_stop = desired_offset;
1171 segment->time = desired_offset;
1173 /* we stop at the end */
1174 if (segment->stop == -1)
1175 segment->stop = segment->duration;
1180 /* do a seek in pull based mode */
1182 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1187 GstSeekType cur_type, stop_type;
1191 GstSegment seeksegment;
1195 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1197 gst_event_parse_seek (event, &rate, &format, &flags,
1198 &cur_type, &cur, &stop_type, &stop);
1200 /* we have to have a format as the segment format. Try to convert
1202 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1206 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1208 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1212 flush = flags & GST_SEEK_FLAG_FLUSH;
1214 /* stop streaming, either by flushing or by pausing the task */
1216 /* unlock upstream pull_range */
1217 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1218 /* make sure out loop function exits */
1219 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1221 /* non flushing seek, pause the task */
1222 gst_pad_pause_task (qtdemux->sinkpad);
1225 /* wait for streaming to finish */
1226 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1228 /* copy segment, we need this because we still need the old
1229 * segment when we close the current segment. */
1230 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1233 /* configure the segment with the seek variables */
1234 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1235 gst_segment_set_seek (&seeksegment, rate, format, flags,
1236 cur_type, cur, stop_type, stop, &update);
1239 /* now do the seek, this actually never returns FALSE */
1240 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1242 /* prepare for streaming again */
1244 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop ());
1245 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop ());
1246 } else if (qtdemux->segment_running) {
1247 /* we are running the current segment and doing a non-flushing seek,
1248 * close the segment first based on the last_stop. */
1249 GST_DEBUG_OBJECT (qtdemux, "closing running segment %" G_GINT64_FORMAT
1250 " to %" G_GINT64_FORMAT, qtdemux->segment.start,
1251 qtdemux->segment.last_stop);
1253 if (qtdemux->segment.rate >= 0) {
1254 /* FIXME, rate is the product of the global rate and the (quicktime)
1256 qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
1257 qtdemux->segment.rate, qtdemux->segment.format,
1258 qtdemux->segment.start, qtdemux->segment.last_stop,
1259 qtdemux->segment.time);
1260 } else { /* For Reverse Playback */
1263 if ((stop = qtdemux->segment.stop) == -1)
1264 stop = qtdemux->segment.duration;
1265 /* for reverse playback, we played from stop to last_stop. */
1266 qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
1267 qtdemux->segment.rate, qtdemux->segment.format,
1268 qtdemux->segment.last_stop, stop, qtdemux->segment.last_stop);
1272 /* commit the new segment */
1273 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1275 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1276 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1277 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1278 qtdemux->segment.format, qtdemux->segment.last_stop));
1281 /* restart streaming, NEWSEGMENT will be sent from the streaming
1283 qtdemux->segment_running = TRUE;
1284 for (i = 0; i < qtdemux->n_streams; i++)
1285 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1287 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1290 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1297 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1303 qtdemux_ensure_index (GstQTDemux * qtdemux)
1307 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1309 /* Build complete index */
1310 for (i = 0; i < qtdemux->n_streams; i++) {
1311 QtDemuxStream *stream = qtdemux->streams[i];
1313 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1321 GST_LOG_OBJECT (qtdemux,
1322 "Building complete index of stream %u for seeking failed!", i);
1328 gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
1330 gboolean res = TRUE;
1331 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
1333 switch (GST_EVENT_TYPE (event)) {
1334 case GST_EVENT_SEEK:
1336 #ifndef GST_DISABLE_GST_DEBUG
1337 GstClockTime ts = gst_util_get_timestamp ();
1339 /* Build complete index for seeking */
1340 if (!qtdemux_ensure_index (qtdemux))
1342 #ifndef GST_DISABLE_GST_DEBUG
1343 ts = gst_util_get_timestamp () - ts;
1344 GST_INFO_OBJECT (qtdemux,
1345 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1348 if (qtdemux->pullbased) {
1349 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1350 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams) {
1351 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1353 GST_DEBUG_OBJECT (qtdemux,
1354 "ignoring seek in push mode in current state");
1357 gst_event_unref (event);
1360 case GST_EVENT_NAVIGATION:
1362 gst_event_unref (event);
1365 res = gst_pad_event_default (pad, event);
1369 gst_object_unref (qtdemux);
1376 GST_ERROR_OBJECT (qtdemux, "Index failed");
1377 gst_event_unref (event);
1382 /* stream/index return sample that is min/max w.r.t. byte position,
1383 * time is min/max w.r.t. time of samples,
1384 * the latter need not be time of the former sample */
1386 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1387 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1390 gint64 time, min_time;
1391 QtDemuxStream *stream;
1397 for (n = 0; n < qtdemux->n_streams; ++n) {
1400 gboolean set_sample;
1402 str = qtdemux->streams[n];
1409 i = str->n_samples - 1;
1412 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1413 if (str->samples[i].size &&
1414 ((fw && (str->samples[i].offset >= byte_pos)) ||
1416 (str->samples[i].offset + str->samples[i].size <=
1418 /* move stream to first available sample */
1420 gst_qtdemux_move_stream (qtdemux, str, i);
1423 /* determine min/max time */
1424 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1425 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1426 if (min_time == -1 || (!fw && time > min_time) ||
1427 (fw && time < min_time)) {
1430 /* determine stream with leading sample, to get its position */
1432 && (str->samples[i].offset < stream->samples[index].offset))
1434 && (str->samples[i].offset > stream->samples[index].offset))) {
1441 /* no sample for this stream, mark eos */
1443 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1455 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
1457 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1460 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1462 switch (GST_EVENT_TYPE (event)) {
1463 case GST_EVENT_NEWSEGMENT:
1466 gdouble rate, arate;
1467 gint64 start, stop, time, offset = 0;
1468 QtDemuxStream *stream;
1473 /* some debug output */
1474 gst_segment_init (&segment, GST_FORMAT_UNDEFINED);
1475 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
1476 &start, &stop, &time);
1477 gst_segment_set_newsegment_full (&segment, update, rate, arate, format,
1479 GST_DEBUG_OBJECT (demux,
1480 "received format %d newsegment %" GST_SEGMENT_FORMAT, format,
1483 /* chain will send initial newsegment after pads have been added */
1484 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1485 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1489 /* we only expect a BYTE segment, e.g. following a seek */
1490 if (format == GST_FORMAT_BYTES) {
1492 gint64 requested_seek_time;
1493 guint64 seek_offset;
1497 GST_OBJECT_LOCK (demux);
1498 requested_seek_time = demux->requested_seek_time;
1499 seek_offset = demux->seek_offset;
1500 demux->requested_seek_time = -1;
1501 demux->seek_offset = -1;
1502 GST_OBJECT_UNLOCK (demux);
1504 if (offset == seek_offset) {
1505 start = requested_seek_time;
1507 gst_qtdemux_find_sample (demux, start, TRUE, FALSE, NULL, NULL,
1509 start = MAX (start, 0);
1513 gst_qtdemux_find_sample (demux, stop, FALSE, FALSE, NULL, NULL,
1515 /* keyframe seeking should already arrange for start >= stop,
1516 * but make sure in other rare cases */
1517 stop = MAX (stop, start);
1520 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1524 /* accept upstream's notion of segment and distribute along */
1525 gst_segment_set_newsegment_full (&demux->segment, update, rate, arate,
1526 GST_FORMAT_TIME, start, stop, start);
1527 GST_DEBUG_OBJECT (demux, "Pushing newseg update %d, rate %g, "
1528 "applied rate %g, format %d, start %" GST_TIME_FORMAT ", "
1529 "stop %" GST_TIME_FORMAT, update, rate, arate, GST_FORMAT_TIME,
1530 GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1532 gst_qtdemux_push_event (demux,
1533 gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME,
1534 start, stop, start));
1536 /* clear leftover in current segment, if any */
1537 gst_adapter_clear (demux->adapter);
1538 /* set up streaming thread */
1539 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1540 demux->offset = offset;
1542 demux->todrop = stream->samples[idx].offset - offset;
1543 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1545 /* set up for EOS */
1546 demux->neededbytes = -1;
1550 gst_event_unref (event);
1555 case GST_EVENT_FLUSH_STOP:
1559 /* clean up, force EOS if no more info follows */
1560 gst_adapter_clear (demux->adapter);
1562 demux->neededbytes = -1;
1563 /* reset flow return, e.g. following seek */
1564 for (i = 0; i < demux->n_streams; i++) {
1565 demux->streams[i]->last_ret = GST_FLOW_OK;
1566 demux->streams[i]->sent_eos = FALSE;
1571 /* If we are in push mode, and get an EOS before we've seen any streams,
1572 * then error out - we have nowhere to send the EOS */
1573 if (!demux->pullbased) {
1575 gboolean has_valid_stream = FALSE;
1576 for (i = 0; i < demux->n_streams; i++) {
1577 if (demux->streams[i]->pad != NULL) {
1578 has_valid_stream = TRUE;
1582 if (!has_valid_stream)
1583 gst_qtdemux_post_no_playable_stream_error (demux);
1590 res = gst_pad_event_default (demux->sinkpad, event);
1597 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1599 GstQTDemux *demux = GST_QTDEMUX (element);
1601 GST_OBJECT_LOCK (demux);
1602 if (demux->element_index)
1603 gst_object_unref (demux->element_index);
1605 demux->element_index = gst_object_ref (index);
1607 demux->element_index = NULL;
1609 GST_OBJECT_UNLOCK (demux);
1610 /* object lock might be taken again */
1612 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1613 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->element_index);
1617 gst_qtdemux_get_index (GstElement * element)
1619 GstIndex *result = NULL;
1620 GstQTDemux *demux = GST_QTDEMUX (element);
1622 GST_OBJECT_LOCK (demux);
1623 if (demux->element_index)
1624 result = gst_object_ref (demux->element_index);
1625 GST_OBJECT_UNLOCK (demux);
1627 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1633 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1635 g_free ((gpointer) stream->stco.data);
1636 g_free ((gpointer) stream->stsz.data);
1637 g_free ((gpointer) stream->stsc.data);
1638 g_free ((gpointer) stream->stts.data);
1639 g_free ((gpointer) stream->stss.data);
1640 g_free ((gpointer) stream->stps.data);
1641 g_free ((gpointer) stream->ctts.data);
1644 static GstStateChangeReturn
1645 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1647 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1648 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1650 switch (transition) {
1651 case GST_STATE_CHANGE_PAUSED_TO_READY:
1657 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1659 switch (transition) {
1660 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1663 qtdemux->state = QTDEMUX_STATE_INITIAL;
1664 qtdemux->neededbytes = 16;
1665 qtdemux->todrop = 0;
1666 qtdemux->pullbased = FALSE;
1667 qtdemux->posted_redirect = FALSE;
1668 qtdemux->offset = 0;
1669 qtdemux->first_mdat = -1;
1670 qtdemux->got_moov = FALSE;
1671 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1672 if (qtdemux->mdatbuffer)
1673 gst_buffer_unref (qtdemux->mdatbuffer);
1674 qtdemux->mdatbuffer = NULL;
1675 if (qtdemux->comp_brands)
1676 gst_buffer_unref (qtdemux->comp_brands);
1677 qtdemux->comp_brands = NULL;
1678 if (qtdemux->tag_list)
1679 gst_tag_list_free (qtdemux->tag_list);
1680 qtdemux->tag_list = NULL;
1681 if (qtdemux->element_index)
1682 gst_object_unref (qtdemux->element_index);
1683 qtdemux->element_index = NULL;
1684 gst_adapter_clear (qtdemux->adapter);
1685 for (n = 0; n < qtdemux->n_streams; n++) {
1686 QtDemuxStream *stream = qtdemux->streams[n];
1688 while (stream->buffers) {
1689 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1691 g_slist_delete_link (stream->buffers, stream->buffers);
1694 gst_element_remove_pad (element, stream->pad);
1695 g_free (stream->samples);
1697 gst_caps_unref (stream->caps);
1698 g_free (stream->segments);
1699 if (stream->pending_tags)
1700 gst_tag_list_free (stream->pending_tags);
1701 g_free (stream->redirect_uri);
1702 /* free stbl sub-atoms */
1703 gst_qtdemux_stbl_free (stream);
1706 qtdemux->major_brand = 0;
1707 qtdemux->n_streams = 0;
1708 qtdemux->n_video_streams = 0;
1709 qtdemux->n_audio_streams = 0;
1710 qtdemux->n_sub_streams = 0;
1711 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1712 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1713 qtdemux->seek_offset = 0;
1724 qtdemux_post_global_tags (GstQTDemux * qtdemux)
1726 if (qtdemux->tag_list) {
1727 /* all header tags ready and parsed, push them */
1728 GST_INFO_OBJECT (qtdemux, "posting global tags: %" GST_PTR_FORMAT,
1730 /* post now, send event on pads later */
1731 gst_element_post_message (GST_ELEMENT (qtdemux),
1732 gst_message_new_tag (GST_OBJECT (qtdemux),
1733 gst_tag_list_copy (qtdemux->tag_list)));
1738 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1740 /* only consider at least a sufficiently complete ftyp atom */
1744 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1745 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1746 GST_FOURCC_ARGS (qtdemux->major_brand));
1747 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1748 memcpy (GST_BUFFER_DATA (buf), buffer + 16, GST_BUFFER_SIZE (buf));
1753 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
1755 /* Strip out bogus fields */
1757 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
1759 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
1761 if (qtdemux->tag_list) {
1762 /* prioritize native tags using _KEEP mode */
1763 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
1764 gst_tag_list_free (taglist);
1766 qtdemux->tag_list = taglist;
1771 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1773 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
1774 0x97, 0xA9, 0x42, 0xE8,
1775 0x9C, 0x71, 0x99, 0x94,
1776 0x91, 0xE3, 0xAF, 0xAC
1780 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
1782 if (length <= offset + 16) {
1783 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
1787 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
1789 GstTagList *taglist;
1791 buf = gst_buffer_new ();
1792 GST_BUFFER_DATA (buf) = (guint8 *) buffer + offset + 16;
1793 GST_BUFFER_SIZE (buf) = length - offset - 16;
1795 taglist = gst_tag_list_from_xmp_buffer (buf);
1796 gst_buffer_unref (buf);
1798 qtdemux_handle_xmp_taglist (qtdemux, taglist);
1801 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
1806 extract_initial_length_and_fourcc (const guint8 * data, guint64 * plength,
1812 length = QT_UINT32 (data);
1813 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1814 fourcc = QT_FOURCC (data + 4);
1815 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1818 length = G_MAXUINT32;
1819 } else if (length == 1) {
1820 /* this means we have an extended size, which is the 64 bit value of
1821 * the next 8 bytes */
1822 length = QT_UINT64 (data + 8);
1823 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1832 static GstFlowReturn
1833 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
1837 GstBuffer *buf = NULL;
1838 GstFlowReturn ret = GST_FLOW_OK;
1839 guint64 cur_offset = qtdemux->offset;
1841 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
1842 if (G_UNLIKELY (ret != GST_FLOW_OK))
1844 if (G_LIKELY (GST_BUFFER_SIZE (buf) == 16))
1845 extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf), &length, &fourcc);
1846 gst_buffer_unref (buf);
1848 if (G_UNLIKELY (length == 0)) {
1849 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
1850 (_("This file is invalid and cannot be played.")),
1851 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
1852 GST_FOURCC_ARGS (fourcc)));
1853 ret = GST_FLOW_ERROR;
1864 GST_LOG_OBJECT (qtdemux,
1865 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
1866 GST_FOURCC_ARGS (fourcc), cur_offset);
1867 qtdemux->offset += length;
1874 if (qtdemux->got_moov) {
1875 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
1876 qtdemux->offset += length;
1880 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
1881 if (ret != GST_FLOW_OK)
1883 if (length != GST_BUFFER_SIZE (moov)) {
1884 /* Some files have a 'moov' atom at the end of the file which contains
1885 * a terminal 'free' atom where the body of the atom is missing.
1886 * Check for, and permit, this special case.
1888 if (GST_BUFFER_SIZE (moov) >= 8) {
1889 guint8 *final_data = GST_BUFFER_DATA (moov) +
1890 (GST_BUFFER_SIZE (moov) - 8);
1891 guint32 final_length = QT_UINT32 (final_data);
1892 guint32 final_fourcc = QT_FOURCC (final_data + 4);
1893 if (final_fourcc == FOURCC_free &&
1894 GST_BUFFER_SIZE (moov) + final_length - 8 == length) {
1895 /* Ok, we've found that special case. Allocate a new buffer with
1896 * that free atom actually present. */
1897 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
1898 gst_buffer_copy_metadata (newmoov, moov,
1899 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
1900 GST_BUFFER_COPY_CAPS);
1901 memcpy (GST_BUFFER_DATA (newmoov), GST_BUFFER_DATA (moov),
1902 GST_BUFFER_SIZE (moov));
1903 memset (GST_BUFFER_DATA (newmoov) + GST_BUFFER_SIZE (moov), 0,
1905 gst_buffer_unref (moov);
1911 if (length != GST_BUFFER_SIZE (moov)) {
1912 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
1913 (_("This file is incomplete and cannot be played.")),
1914 ("We got less than expected (received %u, wanted %u, offset %"
1915 G_GUINT64_FORMAT ")",
1916 GST_BUFFER_SIZE (moov), (guint) length, cur_offset));
1917 ret = GST_FLOW_ERROR;
1920 qtdemux->offset += length;
1922 qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
1923 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
1925 qtdemux_parse_tree (qtdemux);
1926 g_node_destroy (qtdemux->moov_node);
1927 gst_buffer_unref (moov);
1928 qtdemux->moov_node = NULL;
1929 qtdemux->got_moov = TRUE;
1936 /* extract major brand; might come in handy for ISO vs QT issues */
1937 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
1938 if (ret != GST_FLOW_OK)
1940 qtdemux->offset += length;
1941 qtdemux_parse_ftyp (qtdemux, GST_BUFFER_DATA (ftyp),
1942 GST_BUFFER_SIZE (ftyp));
1943 gst_buffer_unref (ftyp);
1950 /* uuid are extension atoms */
1951 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
1952 if (ret != GST_FLOW_OK)
1954 qtdemux->offset += length;
1955 qtdemux_parse_uuid (qtdemux, GST_BUFFER_DATA (uuid),
1956 GST_BUFFER_SIZE (uuid));
1957 gst_buffer_unref (uuid);
1964 GST_LOG_OBJECT (qtdemux,
1965 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
1966 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
1968 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
1969 if (ret != GST_FLOW_OK)
1971 GST_MEMDUMP ("Unknown tag", GST_BUFFER_DATA (unknown),
1972 GST_BUFFER_SIZE (unknown));
1973 gst_buffer_unref (unknown);
1974 qtdemux->offset += length;
1980 if (ret == GST_FLOW_UNEXPECTED && qtdemux->got_moov) {
1981 /* Only post, event on pads is done after newsegment */
1982 qtdemux_post_global_tags (qtdemux);
1984 qtdemux->state = QTDEMUX_STATE_MOVIE;
1985 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
1992 /* Seeks to the previous keyframe of the indexed stream and
1993 * aligns other streams with respect to the keyframe timestamp
1994 * of indexed stream. Only called in case of Reverse Playback
1996 static GstFlowReturn
1997 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
2000 guint32 seg_idx = 0, k_index = 0;
2001 guint32 ref_seg_idx, ref_k_index;
2002 guint64 k_pos = 0, last_stop = 0;
2003 QtDemuxSegment *seg = NULL;
2004 QtDemuxStream *ref_str = NULL;
2005 guint64 seg_media_start_mov; /* segment media start time in mov format */
2007 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
2008 * and finally align all the other streams on that timestamp with their
2009 * respective keyframes */
2010 for (n = 0; n < qtdemux->n_streams; n++) {
2011 QtDemuxStream *str = qtdemux->streams[n];
2013 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
2014 qtdemux->segment.last_stop);
2016 /* segment not found, continue with normal flow */
2020 /* No candidate yet, take that one */
2026 /* So that stream has a segment, we prefer video streams */
2027 if (str->subtype == FOURCC_vide) {
2033 if (G_UNLIKELY (!ref_str)) {
2034 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
2038 if (G_UNLIKELY (!ref_str->from_sample)) {
2039 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
2043 /* So that stream has been playing from from_sample to to_sample. We will
2044 * get the timestamp of the previous sample and search for a keyframe before
2045 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
2046 if (ref_str->subtype == FOURCC_vide) {
2047 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
2048 ref_str->from_sample - 1);
2050 if (ref_str->from_sample >= 10)
2051 k_index = ref_str->from_sample - 10;
2056 /* get current segment for that stream */
2057 seg = &ref_str->segments[ref_str->segment_index];
2058 /* convert seg->media_start to mov format time for timestamp comparison */
2059 seg_media_start_mov =
2060 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
2061 /* Crawl back through segments to find the one containing this I frame */
2062 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
2063 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
2064 ref_str->segment_index);
2065 if (G_UNLIKELY (!ref_str->segment_index)) {
2066 /* Reached first segment, let's consider it's EOS */
2069 ref_str->segment_index--;
2070 seg = &ref_str->segments[ref_str->segment_index];
2071 /* convert seg->media_start to mov format time for timestamp comparison */
2072 seg_media_start_mov =
2073 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
2076 /* Calculate time position of the keyframe and where we should stop */
2078 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
2079 ref_str->timescale) - seg->media_start) + seg->time;
2081 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
2082 GST_SECOND, ref_str->timescale);
2083 last_stop = (last_stop - seg->media_start) + seg->time;
2085 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
2086 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
2087 k_index, GST_TIME_ARGS (k_pos));
2089 /* Set last_stop with the keyframe timestamp we pushed of that stream */
2090 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, last_stop);
2091 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
2092 GST_TIME_ARGS (last_stop));
2094 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
2095 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
2099 ref_seg_idx = ref_str->segment_index;
2100 ref_k_index = k_index;
2102 /* Align them all on this */
2103 for (n = 0; n < qtdemux->n_streams; n++) {
2105 guint64 media_start = 0, seg_time = 0;
2106 QtDemuxStream *str = qtdemux->streams[n];
2108 /* aligning reference stream again might lead to backing up to yet another
2109 * keyframe (due to timestamp rounding issues),
2110 * potentially putting more load on downstream; so let's try to avoid */
2111 if (str == ref_str) {
2112 seg_idx = ref_seg_idx;
2113 seg = &str->segments[seg_idx];
2114 k_index = ref_k_index;
2115 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
2116 "sample at index %d", ref_str->segment_index, k_index);
2118 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
2119 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
2121 /* segment not found, continue with normal flow */
2125 /* get segment and time in the segment */
2126 seg = &str->segments[seg_idx];
2127 seg_time = k_pos - seg->time;
2129 /* get the media time in the segment */
2130 media_start = seg->media_start + seg_time;
2132 /* get the index of the sample with media time */
2133 index = gst_qtdemux_find_index (qtdemux, str, media_start);
2134 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
2135 GST_TIME_ARGS (media_start), index);
2137 /* find previous keyframe */
2138 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
2141 /* Remember until where we want to go */
2142 str->to_sample = str->from_sample - 1;
2143 /* Define our time position */
2144 str->time_position =
2145 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
2146 str->timescale) - seg->media_start) + seg->time;
2147 /* Now seek back in time */
2148 gst_qtdemux_move_stream (qtdemux, str, k_index);
2149 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
2150 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
2151 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
2157 return GST_FLOW_UNEXPECTED;
2160 /* activate the given segment number @seg_idx of @stream at time @offset.
2161 * @offset is an absolute global position over all the segments.
2163 * This will push out a NEWSEGMENT event with the right values and
2164 * position the stream index to the first decodable sample before
2168 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
2169 guint32 seg_idx, guint64 offset)
2172 QtDemuxSegment *segment;
2173 guint32 index, kf_index;
2175 guint64 start, stop, time;
2178 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
2181 /* update the current segment */
2182 stream->segment_index = seg_idx;
2184 /* get the segment */
2185 segment = &stream->segments[seg_idx];
2187 if (G_UNLIKELY (offset < segment->time)) {
2188 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
2193 /* segment lies beyond total indicated duration */
2194 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
2195 segment->time > qtdemux->segment.duration)) {
2196 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
2197 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
2202 /* get time in this segment */
2203 seg_time = offset - segment->time;
2205 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
2206 GST_TIME_ARGS (seg_time));
2208 if (G_UNLIKELY (seg_time > segment->duration)) {
2209 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
2210 GST_TIME_ARGS (segment->duration));
2214 /* qtdemux->segment.stop is in outside-time-realm, whereas
2215 * segment->media_stop is in track-time-realm.
2217 * In order to compare the two, we need to bring segment.stop
2218 * into the track-time-realm */
2220 stop = qtdemux->segment.stop;
2222 stop = qtdemux->segment.duration;
2224 stop = segment->media_stop;
2227 MIN (segment->media_stop, stop - segment->time + segment->media_start);
2229 if (qtdemux->segment.rate >= 0) {
2230 start = MIN (segment->media_start + seg_time, stop);
2233 start = segment->media_start;
2234 stop = MIN (segment->media_start + seg_time, stop);
2235 time = segment->time;
2238 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
2239 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
2240 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
2242 /* combine global rate with that of the segment */
2243 rate = segment->rate * qtdemux->segment.rate;
2245 /* update the segment values used for clipping */
2246 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
2247 gst_segment_set_newsegment (&stream->segment, FALSE, rate, GST_FORMAT_TIME,
2250 /* now prepare and send the segment */
2252 event = gst_event_new_new_segment (FALSE, rate, GST_FORMAT_TIME,
2254 gst_pad_push_event (stream->pad, event);
2255 /* assume we can send more data now */
2256 stream->last_ret = GST_FLOW_OK;
2257 /* clear to send tags on this pad now */
2258 gst_qtdemux_push_tags (qtdemux, stream);
2261 /* and move to the keyframe before the indicated media time of the
2263 if (qtdemux->segment.rate >= 0) {
2264 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
2265 stream->to_sample = stream->n_samples;
2266 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
2267 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
2268 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
2269 GST_SECOND, stream->timescale)));
2271 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
2272 stream->to_sample = index;
2273 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
2274 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
2275 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
2276 GST_SECOND, stream->timescale)));
2279 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
2280 * encountered an error and printed a message so we return appropriately */
2284 /* we're at the right spot */
2285 if (index == stream->sample_index) {
2286 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
2290 /* find keyframe of the target index */
2291 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
2294 /* indent does stupid stuff with stream->samples[].timestamp */
2296 /* if we move forwards, we don't have to go back to the previous
2297 * keyframe since we already sent that. We can also just jump to
2298 * the keyframe right before the target index if there is one. */
2299 if (index > stream->sample_index) {
2300 /* moving forwards check if we move past a keyframe */
2301 if (kf_index > stream->sample_index) {
2302 GST_DEBUG_OBJECT (qtdemux,
2303 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
2304 GST_TIME_ARGS (gst_util_uint64_scale (
2305 stream->samples[kf_index].timestamp,
2306 GST_SECOND, stream->timescale)));
2307 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
2309 GST_DEBUG_OBJECT (qtdemux,
2310 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
2311 " already sent", kf_index,
2312 GST_TIME_ARGS (gst_util_uint64_scale (
2313 stream->samples[kf_index].timestamp,
2314 GST_SECOND, stream->timescale)));
2317 GST_DEBUG_OBJECT (qtdemux,
2318 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
2319 GST_TIME_ARGS (gst_util_uint64_scale (
2320 stream->samples[kf_index].timestamp,
2321 GST_SECOND, stream->timescale)));
2322 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
2330 /* prepare to get the current sample of @stream, getting essential values.
2332 * This function will also prepare and send the segment when needed.
2334 * Return FALSE if the stream is EOS.
2337 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
2338 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp,
2339 guint64 * duration, gboolean * keyframe)
2341 QtDemuxSample *sample;
2342 guint64 time_position;
2345 g_return_val_if_fail (stream != NULL, FALSE);
2347 time_position = stream->time_position;
2348 if (G_UNLIKELY (time_position == -1))
2351 seg_idx = stream->segment_index;
2352 if (G_UNLIKELY (seg_idx == -1)) {
2353 /* find segment corresponding to time_position if we are looking
2355 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
2357 /* nothing found, we're really eos */
2362 /* different segment, activate it, sample_index will be set. */
2363 if (G_UNLIKELY (stream->segment_index != seg_idx))
2364 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
2366 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
2367 stream->sample_index, stream->n_samples);
2369 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
2372 /* now get the info for the sample we're at */
2373 sample = &stream->samples[stream->sample_index];
2375 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
2376 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
2377 stream->sample_index);
2381 *timestamp = QTSAMPLE_PTS (stream, sample);
2382 *offset = sample->offset;
2383 *size = sample->size;
2384 *duration = QTSAMPLE_DUR_PTS (stream, sample, *timestamp);
2385 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
2387 /* update dummy segment duration */
2388 if (stream->sample_index == stream->n_samples - 1 && stream->n_segments == 1) {
2389 stream->segments[0].duration = stream->segments[0].stop_time =
2390 stream->segments[0].media_stop = *timestamp + *duration;
2398 stream->time_position = -1;
2403 /* move to the next sample in @stream.
2405 * Moves to the next segment when needed.
2408 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
2410 QtDemuxSample *sample;
2411 QtDemuxSegment *segment;
2413 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
2414 /* Mark the stream as EOS */
2415 GST_DEBUG_OBJECT (qtdemux,
2416 "reached max allowed sample %u, mark EOS", stream->to_sample);
2417 stream->time_position = -1;
2421 /* move to next sample */
2422 stream->sample_index++;
2424 /* get current segment */
2425 segment = &stream->segments[stream->segment_index];
2427 /* reached the last sample, we need the next segment */
2428 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
2431 /* get next sample */
2432 sample = &stream->samples[stream->sample_index];
2434 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
2435 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
2436 stream->sample_index);
2440 /* see if we are past the segment */
2441 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
2442 GST_SECOND, stream->timescale) >= segment->media_stop))
2445 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
2446 stream->timescale) >= segment->media_start) {
2447 /* inside the segment, update time_position, looks very familiar to
2448 * GStreamer segments, doesn't it? */
2449 stream->time_position =
2450 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
2451 stream->timescale) - segment->media_start) + segment->time;
2453 /* not yet in segment, time does not yet increment. This means
2454 * that we are still prerolling keyframes to the decoder so it can
2455 * decode the first sample of the segment. */
2456 stream->time_position = segment->time;
2460 /* move to the next segment */
2463 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
2465 if (stream->segment_index == stream->n_segments - 1) {
2466 /* are we at the end of the last segment, we're EOS */
2467 stream->time_position = -1;
2469 /* else we're only at the end of the current segment */
2470 stream->time_position = segment->stop_time;
2472 /* make sure we select a new segment */
2473 stream->segment_index = -1;
2478 gst_qtdemux_sync_streams (GstQTDemux * demux)
2482 if (demux->n_streams <= 1)
2485 for (i = 0; i < demux->n_streams; i++) {
2486 QtDemuxStream *stream;
2487 GstClockTime end_time;
2489 stream = demux->streams[i];
2494 /* TODO advance time on subtitle streams here, if any some day */
2496 /* some clips/trailers may have unbalanced streams at the end,
2497 * so send EOS on shorter stream to prevent stalling others */
2499 /* do not mess with EOS if SEGMENT seeking */
2500 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
2503 if (demux->pullbased) {
2504 /* loop mode is sample time based */
2505 if (stream->time_position != -1)
2508 /* push mode is byte position based */
2509 if (stream->samples[stream->n_samples - 1].offset >= demux->offset)
2513 if (stream->sent_eos)
2516 /* only act if some gap */
2517 end_time = stream->segments[stream->n_segments - 1].stop_time;
2518 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
2519 ", stream end: %" GST_TIME_FORMAT,
2520 GST_TIME_ARGS (demux->segment.last_stop), GST_TIME_ARGS (end_time));
2521 if (end_time + 2 * GST_SECOND < demux->segment.last_stop) {
2522 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
2523 GST_PAD_NAME (stream->pad));
2524 stream->sent_eos = TRUE;
2525 gst_pad_push_event (stream->pad, gst_event_new_eos ());
2530 /* UNEXPECTED and NOT_LINKED need to be combined. This means that we return:
2532 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
2533 * GST_FLOW_UNEXPECTED: when all pads UNEXPECTED or NOT_LINKED.
2535 static GstFlowReturn
2536 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
2540 gboolean unexpected = FALSE, not_linked = TRUE;
2542 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
2544 /* store the value */
2545 stream->last_ret = ret;
2547 for (i = 0; i < demux->n_streams; i++) {
2548 QtDemuxStream *ostream = demux->streams[i];
2550 ret = ostream->last_ret;
2552 /* no unexpected or unlinked, return */
2553 if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
2556 /* we check to see if we have at least 1 unexpected or all unlinked */
2557 unexpected |= (ret == GST_FLOW_UNEXPECTED);
2558 not_linked &= (ret == GST_FLOW_NOT_LINKED);
2561 /* when we get here, we all have unlinked or unexpected */
2563 ret = GST_FLOW_NOT_LINKED;
2564 else if (unexpected)
2565 ret = GST_FLOW_UNEXPECTED;
2567 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
2571 /* the input buffer metadata must be writable. Returns NULL when the buffer is
2572 * completely cliped */
2574 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
2577 gint64 start, stop, cstart, cstop, diff;
2578 GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
2581 gint num_rate, denom_rate;
2585 data = GST_BUFFER_DATA (buf);
2586 size = GST_BUFFER_SIZE (buf);
2588 /* depending on the type, setup the clip parameters */
2589 if (stream->subtype == FOURCC_soun) {
2590 frame_size = stream->bytes_per_frame;
2591 num_rate = GST_SECOND;
2592 denom_rate = (gint) stream->rate;
2594 } else if (stream->subtype == FOURCC_vide) {
2596 num_rate = stream->fps_n;
2597 denom_rate = stream->fps_d;
2602 /* we can only clip if we have a valid timestamp */
2603 timestamp = GST_BUFFER_TIMESTAMP (buf);
2604 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
2607 if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf))) {
2608 duration = GST_BUFFER_DURATION (buf);
2611 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
2615 stop = start + duration;
2617 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
2618 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
2621 /* see if some clipping happened */
2622 diff = cstart - start;
2628 /* bring clipped time to samples and to bytes */
2629 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
2632 GST_DEBUG_OBJECT (qtdemux,
2633 "clipping start to %" GST_TIME_FORMAT " %"
2634 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
2640 diff = stop - cstop;
2645 /* bring clipped time to samples and then to bytes */
2646 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
2648 GST_DEBUG_OBJECT (qtdemux,
2649 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
2650 " bytes", GST_TIME_ARGS (cstop), diff);
2655 GST_BUFFER_TIMESTAMP (buf) = timestamp;
2656 GST_BUFFER_DURATION (buf) = duration;
2657 GST_BUFFER_SIZE (buf) = size;
2658 GST_BUFFER_DATA (buf) = data;
2662 /* dropped buffer */
2665 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
2670 GST_DEBUG_OBJECT (qtdemux, "no timestamp on buffer");
2675 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
2676 gst_buffer_unref (buf);
2681 /* the input buffer metadata must be writable,
2682 * but time/duration etc not yet set and need not be preserved */
2684 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
2688 guint size, nsize = 0;
2691 data = GST_BUFFER_DATA (buf);
2692 size = GST_BUFFER_SIZE (buf);
2694 /* not many cases for now */
2695 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
2696 /* send a one time dvd clut event */
2697 if (stream->pending_event && stream->pad)
2698 gst_pad_push_event (stream->pad, stream->pending_event);
2699 stream->pending_event = NULL;
2700 /* no further processing needed */
2701 stream->need_process = FALSE;
2704 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
2708 if (G_LIKELY (size >= 2)) {
2709 nsize = GST_READ_UINT16_BE (data);
2710 nsize = MIN (nsize, size - 2);
2713 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%d", nsize, size);
2715 /* takes care of UTF-8 validation or UTF-16 recognition,
2716 * no other encoding expected */
2717 str = gst_tag_freeform_string_to_utf8 ((gchar *) data + 2, nsize, NULL);
2719 gst_buffer_unref (buf);
2720 buf = gst_buffer_new ();
2721 GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = (guint8 *) str;
2722 GST_BUFFER_SIZE (buf) = strlen (str);
2724 /* may be 0-size subtitle, which is also sent to keep pipeline going */
2725 GST_BUFFER_DATA (buf) = data + 2;
2726 GST_BUFFER_SIZE (buf) = nsize;
2729 /* FIXME ? convert optional subsequent style info to markup */
2734 /* Sets a buffer's attributes properly and pushes it downstream.
2735 * Also checks for additional actions and custom processing that may
2736 * need to be done first.
2739 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
2740 QtDemuxStream * stream, GstBuffer * buf,
2741 guint64 timestamp, guint64 duration, gboolean keyframe, guint64 position,
2742 guint64 byte_position)
2744 GstFlowReturn ret = GST_FLOW_OK;
2746 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
2749 url = g_strndup ((gchar *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
2750 if (url != NULL && strlen (url) != 0) {
2751 /* we have RTSP redirect now */
2752 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
2753 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
2754 gst_structure_new ("redirect",
2755 "new-location", G_TYPE_STRING, url, NULL)));
2756 qtdemux->posted_redirect = TRUE;
2758 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
2764 /* position reporting */
2765 if (qtdemux->segment.rate >= 0) {
2766 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, position);
2767 gst_qtdemux_sync_streams (qtdemux);
2770 if (G_UNLIKELY (!stream->pad)) {
2771 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
2772 gst_buffer_unref (buf);
2776 /* send out pending buffers */
2777 while (stream->buffers) {
2778 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
2780 if (G_UNLIKELY (stream->discont)) {
2781 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
2782 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
2783 stream->discont = FALSE;
2785 gst_buffer_set_caps (buffer, stream->caps);
2787 gst_pad_push (stream->pad, buffer);
2789 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2792 /* we're going to modify the metadata */
2793 buf = gst_buffer_make_metadata_writable (buf);
2795 if (G_UNLIKELY (stream->need_process))
2796 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
2798 GST_BUFFER_TIMESTAMP (buf) = timestamp;
2799 GST_BUFFER_DURATION (buf) = duration;
2800 GST_BUFFER_OFFSET (buf) = -1;
2801 GST_BUFFER_OFFSET_END (buf) = -1;
2803 if (G_UNLIKELY (stream->padding)) {
2804 GST_BUFFER_DATA (buf) += stream->padding;
2805 GST_BUFFER_SIZE (buf) -= stream->padding;
2808 if (G_UNLIKELY (qtdemux->element_index)) {
2809 GstClockTime stream_time;
2812 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
2814 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
2815 GST_LOG_OBJECT (qtdemux,
2816 "adding association %" GST_TIME_FORMAT "-> %"
2817 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
2818 gst_index_add_association (qtdemux->element_index,
2820 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
2821 GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_TIME, stream_time,
2822 GST_FORMAT_BYTES, byte_position, NULL);
2826 if (stream->need_clip)
2827 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
2829 if (G_UNLIKELY (buf == NULL))
2832 if (G_UNLIKELY (stream->discont)) {
2833 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
2834 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
2835 stream->discont = FALSE;
2839 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
2841 gst_buffer_set_caps (buf, stream->caps);
2843 GST_LOG_OBJECT (qtdemux,
2844 "Pushing buffer with time %" GST_TIME_FORMAT ", duration %"
2845 GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2846 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
2848 ret = gst_pad_push (stream->pad, buf);
2854 static GstFlowReturn
2855 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
2857 GstFlowReturn ret = GST_FLOW_OK;
2858 GstBuffer *buf = NULL;
2859 QtDemuxStream *stream;
2862 guint64 timestamp = GST_CLOCK_TIME_NONE;
2863 guint64 duration = 0;
2864 gboolean keyframe = FALSE;
2869 gst_qtdemux_push_pending_newsegment (qtdemux);
2871 /* Figure out the next stream sample to output, min_time is expressed in
2872 * global time and runs over the edit list segments. */
2873 min_time = G_MAXUINT64;
2875 for (i = 0; i < qtdemux->n_streams; i++) {
2878 stream = qtdemux->streams[i];
2879 position = stream->time_position;
2881 /* position of -1 is EOS */
2882 if (position != -1 && position < min_time) {
2883 min_time = position;
2888 if (G_UNLIKELY (index == -1)) {
2889 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
2893 /* check for segment end */
2894 if (G_UNLIKELY (qtdemux->segment.stop != -1
2895 && qtdemux->segment.stop < min_time)) {
2896 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
2900 stream = qtdemux->streams[index];
2902 /* fetch info for the current sample of this stream */
2903 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
2904 &size, ×tamp, &duration, &keyframe)))
2907 GST_LOG_OBJECT (qtdemux,
2908 "pushing from stream %d, offset %" G_GUINT64_FORMAT
2909 ", size %d, timestamp=%" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
2910 index, offset, size, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
2912 /* hmm, empty sample, skip and move to next sample */
2913 if (G_UNLIKELY (size <= 0))
2916 /* last pushed sample was out of boundary, goto next sample */
2917 if (G_UNLIKELY (stream->last_ret == GST_FLOW_UNEXPECTED))
2920 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
2923 ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
2924 if (G_UNLIKELY (ret != GST_FLOW_OK))
2927 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
2928 timestamp, duration, keyframe, min_time, offset);
2931 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
2932 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
2933 * we have no more data for the pad to push */
2934 if (ret == GST_FLOW_UNEXPECTED)
2938 gst_qtdemux_advance_sample (qtdemux, stream);
2946 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
2947 ret = GST_FLOW_UNEXPECTED;
2952 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
2953 /* EOS will be raised if all are EOS */
2960 gst_qtdemux_loop (GstPad * pad)
2962 GstQTDemux *qtdemux;
2966 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
2968 cur_offset = qtdemux->offset;
2969 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
2970 cur_offset, qtdemux->state);
2972 switch (qtdemux->state) {
2973 case QTDEMUX_STATE_INITIAL:
2974 case QTDEMUX_STATE_HEADER:
2975 ret = gst_qtdemux_loop_state_header (qtdemux);
2977 case QTDEMUX_STATE_MOVIE:
2978 ret = gst_qtdemux_loop_state_movie (qtdemux);
2979 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_UNEXPECTED) {
2980 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
2988 /* if something went wrong, pause */
2989 if (ret != GST_FLOW_OK)
2993 gst_object_unref (qtdemux);
2999 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3000 (NULL), ("streaming stopped, invalid state"));
3001 qtdemux->segment_running = FALSE;
3002 gst_pad_pause_task (pad);
3003 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3008 const gchar *reason = gst_flow_get_name (ret);
3010 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
3012 qtdemux->segment_running = FALSE;
3013 gst_pad_pause_task (pad);
3015 /* fatal errors need special actions */
3017 if (ret == GST_FLOW_UNEXPECTED) {
3018 if (qtdemux->n_streams == 0) {
3019 /* we have no streams, post an error */
3020 gst_qtdemux_post_no_playable_stream_error (qtdemux);
3022 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3025 /* FIXME: I am not sure this is the right fix. If the sinks are
3026 * supposed to detect the segment is complete and accumulate
3027 * automatically, it does not seem to work here. Need more work */
3028 qtdemux->segment_running = TRUE;
3030 if ((stop = qtdemux->segment.stop) == -1)
3031 stop = qtdemux->segment.duration;
3033 if (qtdemux->segment.rate >= 0) {
3034 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
3035 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3036 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3037 GST_FORMAT_TIME, stop));
3039 /* For Reverse Playback */
3040 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
3041 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3042 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3043 GST_FORMAT_TIME, qtdemux->segment.start));
3046 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
3047 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3049 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
3050 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3051 (NULL), ("streaming stopped, reason %s", reason));
3052 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3061 * Returns the size of the first entry at the current offset.
3062 * If -1, there are none (which means EOS or empty file).
3065 next_entry_size (GstQTDemux * demux)
3067 QtDemuxStream *stream;
3070 guint64 smalloffs = (guint64) - 1;
3071 QtDemuxSample *sample;
3073 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
3076 for (i = 0; i < demux->n_streams; i++) {
3077 stream = demux->streams[i];
3079 if (stream->sample_index == -1)
3080 stream->sample_index = 0;
3082 if (stream->sample_index >= stream->n_samples) {
3083 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
3087 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
3088 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
3089 stream->sample_index);
3093 sample = &stream->samples[stream->sample_index];
3095 GST_LOG_OBJECT (demux,
3096 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3097 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
3098 sample->offset, sample->size);
3100 if (((smalloffs == -1)
3101 || (sample->offset < smalloffs)) && (sample->size)) {
3103 smalloffs = sample->offset;
3107 GST_LOG_OBJECT (demux,
3108 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
3109 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
3114 stream = demux->streams[smallidx];
3115 sample = &stream->samples[stream->sample_index];
3117 if (sample->offset >= demux->offset) {
3118 demux->todrop = sample->offset - demux->offset;
3119 return sample->size + demux->todrop;
3122 GST_DEBUG_OBJECT (demux,
3123 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
3128 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
3130 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
3132 gst_element_post_message (GST_ELEMENT_CAST (demux),
3133 gst_message_new_element (GST_OBJECT_CAST (demux),
3134 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
3138 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
3143 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
3146 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
3147 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
3148 GST_SEEK_TYPE_NONE, -1);
3150 res = gst_pad_push_event (demux->sinkpad, event);
3155 /* FIXME, unverified after edit list updates */
3156 static GstFlowReturn
3157 gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
3160 GstFlowReturn ret = GST_FLOW_OK;
3162 demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad));
3164 gst_adapter_push (demux->adapter, inbuf);
3166 /* we never really mean to buffer that much */
3167 if (demux->neededbytes == -1)
3170 GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
3171 inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
3173 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
3174 (ret == GST_FLOW_OK)) {
3176 GST_DEBUG_OBJECT (demux,
3177 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
3178 demux->state, demux->neededbytes, demux->offset);
3180 switch (demux->state) {
3181 case QTDEMUX_STATE_INITIAL:{
3186 /* prepare newsegment to send when streaming actually starts */
3187 if (!demux->pending_newsegment) {
3188 demux->pending_newsegment =
3189 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
3190 0, GST_CLOCK_TIME_NONE, 0);
3193 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
3195 /* get fourcc/length, set neededbytes */
3196 extract_initial_length_and_fourcc ((guint8 *) data, &size, &fourcc);
3197 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
3198 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
3200 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
3201 (_("This file is invalid and cannot be played.")),
3202 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
3203 GST_FOURCC_ARGS (fourcc)));
3204 ret = GST_FLOW_ERROR;
3207 if (fourcc == FOURCC_mdat) {
3208 if (demux->n_streams > 0) {
3209 /* we have the headers, start playback */
3210 demux->state = QTDEMUX_STATE_MOVIE;
3211 demux->neededbytes = next_entry_size (demux);
3213 /* Only post, event on pads is done after newsegment */
3214 qtdemux_post_global_tags (demux);
3217 /* no headers yet, try to get them */
3220 guint64 old, target;
3223 old = demux->offset;
3224 target = old + size;
3226 /* try to jump over the atom with a seek */
3227 res = qtdemux_seek_offset (demux, target);
3230 GST_DEBUG_OBJECT (demux, "seek success");
3231 /* remember the offset fo the first mdat so we can seek back to it
3232 * after we have the headers */
3233 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
3234 demux->first_mdat = old;
3235 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
3238 /* seek worked, continue reading */
3239 demux->offset = target;
3240 demux->neededbytes = 16;
3241 demux->state = QTDEMUX_STATE_INITIAL;
3243 /* seek failed, need to buffer */
3244 demux->offset = old;
3245 GST_DEBUG_OBJECT (demux, "seek failed");
3246 /* there may be multiple mdat (or alike) buffers */
3248 if (demux->mdatbuffer)
3249 bs = GST_BUFFER_SIZE (demux->mdatbuffer);
3252 if (size + bs > 10 * (1 << 20))
3254 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
3255 demux->neededbytes = size;
3256 if (!demux->mdatbuffer)
3257 demux->mdatoffset = demux->offset;
3260 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
3261 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
3262 (_("This file is invalid and cannot be played.")),
3263 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
3264 GST_FOURCC_ARGS (fourcc), size));
3265 ret = GST_FLOW_ERROR;
3268 /* this means we already started buffering and still no moov header,
3269 * let's continue buffering everything till we get moov */
3270 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
3272 demux->neededbytes = size;
3273 demux->state = QTDEMUX_STATE_HEADER;
3277 case QTDEMUX_STATE_HEADER:{
3281 GST_DEBUG_OBJECT (demux, "In header");
3283 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
3285 /* parse the header */
3286 extract_initial_length_and_fourcc (data, NULL, &fourcc);
3287 if (fourcc == FOURCC_moov) {
3288 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
3290 demux->got_moov = TRUE;
3292 qtdemux_parse_moov (demux, data, demux->neededbytes);
3293 qtdemux_node_dump (demux, demux->moov_node);
3294 qtdemux_parse_tree (demux);
3296 g_node_destroy (demux->moov_node);
3297 demux->moov_node = NULL;
3298 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
3299 } else if (fourcc == FOURCC_ftyp) {
3300 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
3301 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
3302 } else if (fourcc == FOURCC_uuid) {
3303 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
3304 qtdemux_parse_uuid (demux, data, demux->neededbytes);
3306 GST_WARNING_OBJECT (demux,
3307 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
3308 GST_FOURCC_ARGS (fourcc));
3309 /* Let's jump that one and go back to initial state */
3312 if (demux->mdatbuffer && demux->n_streams) {
3315 /* the mdat was before the header */
3316 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
3317 demux->n_streams, demux->mdatbuffer);
3318 /* restore our adapter/offset view of things with upstream;
3319 * put preceding buffered data ahead of current moov data.
3320 * This should also handle evil mdat, moov, mdat cases and alike */
3321 buf = gst_adapter_take_buffer (demux->adapter,
3322 gst_adapter_available (demux->adapter));
3323 gst_adapter_clear (demux->adapter);
3324 gst_adapter_push (demux->adapter, demux->mdatbuffer);
3325 gst_adapter_push (demux->adapter, buf);
3326 demux->mdatbuffer = NULL;
3327 demux->offset = demux->mdatoffset;
3328 demux->neededbytes = next_entry_size (demux);
3329 demux->state = QTDEMUX_STATE_MOVIE;
3331 /* Only post, event on pads is done after newsegment */
3332 qtdemux_post_global_tags (demux);
3335 GST_DEBUG_OBJECT (demux, "Carrying on normally");
3336 gst_adapter_flush (demux->adapter, demux->neededbytes);
3338 if (demux->got_moov && demux->first_mdat != -1) {
3341 /* we need to seek back */
3342 res = qtdemux_seek_offset (demux, demux->first_mdat);
3344 demux->offset = demux->first_mdat;
3346 GST_DEBUG_OBJECT (demux, "Seek back failed");
3349 demux->offset += demux->neededbytes;
3351 demux->neededbytes = 16;
3352 demux->state = QTDEMUX_STATE_INITIAL;
3357 case QTDEMUX_STATE_BUFFER_MDAT:{
3360 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
3362 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
3363 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
3364 GST_FOURCC_ARGS (QT_FOURCC (GST_BUFFER_DATA (buf) + 4)));
3365 if (demux->mdatbuffer)
3366 demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
3368 demux->mdatbuffer = buf;
3369 demux->offset += demux->neededbytes;
3370 demux->neededbytes = 16;
3371 demux->state = QTDEMUX_STATE_INITIAL;
3372 gst_qtdemux_post_progress (demux, 1, 1);
3376 case QTDEMUX_STATE_MOVIE:{
3378 QtDemuxStream *stream = NULL;
3379 QtDemuxSample *sample;
3381 guint64 timestamp, duration, position;
3384 GST_DEBUG_OBJECT (demux,
3385 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
3387 if (demux->todrop) {
3388 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
3389 gst_adapter_flush (demux->adapter, demux->todrop);
3390 demux->neededbytes -= demux->todrop;
3391 demux->offset += demux->todrop;
3395 /* initial newsegment sent here after having added pads,
3396 * possible others in sink_event */
3397 if (G_UNLIKELY (demux->pending_newsegment)) {
3398 gst_qtdemux_push_event (demux, demux->pending_newsegment);
3399 demux->pending_newsegment = NULL;
3400 /* clear to send tags on all streams */
3401 for (i = 0; i < demux->n_streams; i++) {
3402 gst_qtdemux_push_tags (demux, demux->streams[i]);
3406 /* Figure out which stream this is packet belongs to */
3407 for (i = 0; i < demux->n_streams; i++) {
3408 stream = demux->streams[i];
3409 if (stream->sample_index >= stream->n_samples)
3411 GST_LOG_OBJECT (demux,
3412 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3413 " / size:%d)", i, stream->sample_index,
3414 stream->samples[stream->sample_index].offset,
3415 stream->samples[stream->sample_index].size);
3417 if (stream->samples[stream->sample_index].offset == demux->offset)
3421 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
3422 goto unknown_stream;
3424 /* Put data in a buffer, set timestamps, caps, ... */
3425 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
3426 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
3427 GST_FOURCC_ARGS (stream->fourcc));
3429 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
3431 sample = &stream->samples[stream->sample_index];
3433 position = QTSAMPLE_DTS (stream, sample);
3434 timestamp = QTSAMPLE_PTS (stream, sample);
3435 duration = QTSAMPLE_DUR_DTS (stream, sample, position);
3436 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3438 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
3439 timestamp, duration, keyframe, position, demux->offset);
3442 ret = gst_qtdemux_combine_flows (demux, stream, ret);
3444 stream->sample_index++;
3446 /* update current offset and figure out size of next buffer */
3447 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
3448 demux->offset, demux->neededbytes);
3449 demux->offset += demux->neededbytes;
3450 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
3453 if ((demux->neededbytes = next_entry_size (demux)) == -1)
3462 /* when buffering movie data, at least show user something is happening */
3463 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
3464 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
3465 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
3466 demux->neededbytes);
3469 gst_object_unref (demux);
3476 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
3477 ret = GST_FLOW_ERROR;
3482 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
3483 ret = GST_FLOW_UNEXPECTED;
3488 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
3489 (NULL), ("qtdemuxer invalid state %d", demux->state));
3490 ret = GST_FLOW_ERROR;
3495 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
3496 (NULL), ("no 'moov' atom within the first 10 MB"));
3497 ret = GST_FLOW_ERROR;
3503 qtdemux_sink_activate (GstPad * sinkpad)
3505 if (gst_pad_check_pull_range (sinkpad))
3506 return gst_pad_activate_pull (sinkpad, TRUE);
3508 return gst_pad_activate_push (sinkpad, TRUE);
3512 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
3514 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
3517 demux->pullbased = TRUE;
3518 demux->segment_running = TRUE;
3519 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
3522 demux->segment_running = FALSE;
3523 return gst_pad_stop_task (sinkpad);
3528 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
3530 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
3532 demux->pullbased = FALSE;
3539 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
3541 return g_malloc (items * size);
3545 qtdemux_zfree (void *opaque, void *addr)
3551 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
3557 z = g_new0 (z_stream, 1);
3558 z->zalloc = qtdemux_zalloc;
3559 z->zfree = qtdemux_zfree;
3562 z->next_in = z_buffer;
3563 z->avail_in = z_length;
3565 buffer = (guint8 *) g_malloc (length);
3566 ret = inflateInit (z);
3567 while (z->avail_in > 0) {
3568 if (z->avail_out == 0) {
3570 buffer = (guint8 *) g_realloc (buffer, length);
3571 z->next_out = buffer + z->total_out;
3572 z->avail_out = 1024;
3574 ret = inflate (z, Z_SYNC_FLUSH);
3578 if (ret != Z_STREAM_END) {
3579 g_warning ("inflate() returned %d", ret);
3585 #endif /* HAVE_ZLIB */
3588 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
3592 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
3594 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
3595 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
3597 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
3603 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
3604 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
3605 if (dcom == NULL || cmvd == NULL)
3606 goto invalid_compression;
3608 method = QT_FOURCC ((guint8 *) dcom->data + 8);
3611 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
3612 guint uncompressed_length;
3613 guint compressed_length;
3616 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
3617 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
3618 GST_LOG ("length = %u", uncompressed_length);
3621 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
3622 compressed_length, uncompressed_length);
3624 qtdemux->moov_node_compressed = qtdemux->moov_node;
3625 qtdemux->moov_node = g_node_new (buf);
3627 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
3628 uncompressed_length);
3631 #endif /* HAVE_ZLIB */
3633 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
3634 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
3641 invalid_compression:
3643 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
3649 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
3652 while (G_UNLIKELY (buf < end)) {
3656 if (G_UNLIKELY (buf + 4 > end)) {
3657 GST_LOG_OBJECT (qtdemux, "buffer overrun");
3660 len = QT_UINT32 (buf);
3661 if (G_UNLIKELY (len == 0)) {
3662 GST_LOG_OBJECT (qtdemux, "empty container");
3665 if (G_UNLIKELY (len < 8)) {
3666 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
3669 if (G_UNLIKELY (len > (end - buf))) {
3670 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
3671 (gint) (end - buf));
3675 child = g_node_new ((guint8 *) buf);
3676 g_node_append (node, child);
3677 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
3678 qtdemux_parse_node (qtdemux, child, buf, len);
3686 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
3689 int len = QT_UINT32 (xdxt->data);
3690 guint8 *buf = xdxt->data;
3691 guint8 *end = buf + len;
3694 /* skip size and type */
3702 size = QT_UINT32 (buf);
3703 type = QT_FOURCC (buf + 4);
3705 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
3707 if (buf + size > end || size <= 0)
3713 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
3714 GST_FOURCC_ARGS (type));
3718 buffer = gst_buffer_new_and_alloc (size);
3719 memcpy (GST_BUFFER_DATA (buffer), buf, size);
3720 stream->buffers = g_slist_append (stream->buffers, buffer);
3721 GST_LOG_OBJECT (qtdemux, "parsing theora header");
3724 buffer = gst_buffer_new_and_alloc (size);
3725 memcpy (GST_BUFFER_DATA (buffer), buf, size);
3726 stream->buffers = g_slist_append (stream->buffers, buffer);
3727 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
3730 buffer = gst_buffer_new_and_alloc (size);
3731 memcpy (GST_BUFFER_DATA (buffer), buf, size);
3732 stream->buffers = g_slist_append (stream->buffers, buffer);
3733 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
3736 GST_WARNING_OBJECT (qtdemux,
3737 "unknown theora cookie %" GST_FOURCC_FORMAT,
3738 GST_FOURCC_ARGS (type));
3747 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
3751 guint32 node_length = 0;
3752 const QtNodeType *type;
3755 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
3757 if (G_UNLIKELY (length < 8))
3758 goto not_enough_data;
3760 node_length = QT_UINT32 (buffer);
3761 fourcc = QT_FOURCC (buffer + 4);
3763 /* ignore empty nodes */
3764 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
3767 type = qtdemux_type_get (fourcc);
3769 end = buffer + length;
3771 GST_LOG_OBJECT (qtdemux,
3772 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
3773 GST_FOURCC_ARGS (fourcc), node_length, type->name);
3775 if (node_length > length)
3776 goto broken_atom_size;
3778 if (type->flags & QT_FLAG_CONTAINER) {
3779 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
3784 if (node_length < 20) {
3785 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
3788 GST_DEBUG_OBJECT (qtdemux,
3789 "parsing stsd (sample table, sample description) atom");
3790 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
3800 /* also read alac (or whatever) in stead of mp4a in the following,
3801 * since a similar layout is used in other cases as well */
3802 if (fourcc == FOURCC_mp4a)
3807 /* There are two things we might encounter here: a true mp4a atom, and
3808 an mp4a entry in an stsd atom. The latter is what we're interested
3809 in, and it looks like an atom, but isn't really one. The true mp4a
3810 atom is short, so we detect it based on length here. */
3811 if (length < min_size) {
3812 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
3813 GST_FOURCC_ARGS (fourcc));
3817 /* 'version' here is the sound sample description version. Types 0 and
3818 1 are documented in the QTFF reference, but type 2 is not: it's
3819 described in Apple header files instead (struct SoundDescriptionV2
3821 version = QT_UINT16 (buffer + 16);
3823 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
3824 GST_FOURCC_ARGS (fourcc), version);
3826 /* parse any esds descriptors */
3838 GST_WARNING_OBJECT (qtdemux,
3839 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
3840 GST_FOURCC_ARGS (fourcc), version);
3845 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
3855 GST_DEBUG_OBJECT (qtdemux, "parsing in mp4v");
3856 version = QT_UINT32 (buffer + 16);
3857 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
3858 if (1 || version == 0x00000000) {
3859 buf = buffer + 0x32;
3861 /* FIXME Quicktime uses PASCAL string while
3862 * the iso format uses C strings. Check the file
3863 * type before attempting to parse the string here. */
3864 tlen = QT_UINT8 (buf);
3865 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
3867 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
3868 /* the string has a reserved space of 32 bytes so skip
3869 * the remaining 31 */
3871 buf += 4; /* and 4 bytes reserved */
3873 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
3875 qtdemux_parse_container (qtdemux, node, buf, end);
3881 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
3882 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
3887 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
3892 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
3893 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
3901 version = QT_UINT32 (buffer + 12);
3902 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
3909 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
3914 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
3919 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
3923 if (!strcmp (type->name, "unknown"))
3924 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
3928 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
3929 GST_FOURCC_ARGS (fourcc));
3935 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3936 (_("This file is corrupt and cannot be played.")),
3937 ("Not enough data for an atom header, got only %u bytes", length));
3942 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3943 (_("This file is corrupt and cannot be played.")),
3944 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
3945 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
3952 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
3956 guint32 child_fourcc;
3958 for (child = g_node_first_child (node); child;
3959 child = g_node_next_sibling (child)) {
3960 buffer = (guint8 *) child->data;
3962 child_fourcc = QT_FOURCC (buffer + 4);
3964 if (G_UNLIKELY (child_fourcc == fourcc)) {
3972 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
3973 GstByteReader * parser)
3977 guint32 child_fourcc, child_len;
3979 for (child = g_node_first_child (node); child;
3980 child = g_node_next_sibling (child)) {
3981 buffer = (guint8 *) child->data;
3983 child_len = QT_UINT32 (buffer);
3984 child_fourcc = QT_FOURCC (buffer + 4);
3986 if (G_UNLIKELY (child_fourcc == fourcc)) {
3987 if (G_UNLIKELY (child_len < (4 + 4)))
3989 /* FIXME: must verify if atom length < parent atom length */
3990 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
3998 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
4002 guint32 child_fourcc;
4004 for (child = g_node_next_sibling (node); child;
4005 child = g_node_next_sibling (child)) {
4006 buffer = (guint8 *) child->data;
4008 child_fourcc = QT_FOURCC (buffer + 4);
4010 if (child_fourcc == fourcc) {
4018 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
4019 QtDemuxStream * stream, GstTagList * list)
4021 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
4022 goto too_many_streams;
4024 /* consistent default for push based mode */
4025 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
4026 gst_segment_set_newsegment (&stream->segment, FALSE, 1.0, GST_FORMAT_TIME,
4027 0, GST_CLOCK_TIME_NONE, 0);
4029 if (stream->subtype == FOURCC_vide) {
4030 gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
4033 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
4036 /* fps is calculated base on the duration of the first frames since
4037 * qt does not have a fixed framerate. */
4038 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
4043 stream->fps_n = stream->timescale;
4044 if (stream->min_duration == 0)
4047 stream->fps_d = stream->min_duration;
4052 gint depth, palette_count;
4053 const guint32 *palette_data = NULL;
4055 gst_caps_set_simple (stream->caps,
4056 "width", G_TYPE_INT, stream->width,
4057 "height", G_TYPE_INT, stream->height,
4058 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
4060 /* calculate pixel-aspect-ratio using display width and height */
4061 GST_DEBUG_OBJECT (qtdemux,
4062 "video size %dx%d, target display size %dx%d", stream->width,
4063 stream->height, stream->display_width, stream->display_height);
4065 if (stream->display_width > 0 && stream->display_height > 0 &&
4066 stream->width > 0 && stream->height > 0) {
4069 /* calculate the pixel aspect ratio using the display and pixel w/h */
4070 n = stream->display_width * stream->height;
4071 d = stream->display_height * stream->width;
4074 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
4075 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
4076 GST_TYPE_FRACTION, n, d, NULL);
4079 /* qt file might have pasp atom */
4080 if (stream->par_w > 0 && stream->par_h > 0) {
4081 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
4082 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
4083 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
4086 depth = stream->bits_per_sample;
4088 /* more than 32 bits means grayscale */
4089 gray = (depth > 32);
4090 /* low 32 bits specify the depth */
4093 /* different number of palette entries is determined by depth. */
4095 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
4096 palette_count = (1 << depth);
4098 switch (palette_count) {
4102 palette_data = ff_qt_default_palette_2;
4105 palette_data = ff_qt_default_palette_4;
4109 palette_data = ff_qt_grayscale_palette_16;
4111 palette_data = ff_qt_default_palette_16;
4115 palette_data = ff_qt_grayscale_palette_256;
4117 palette_data = ff_qt_default_palette_256;
4120 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4121 (_("The video in this file might not play correctly.")),
4122 ("unsupported palette depth %d", depth));
4128 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
4129 * don't free any of the buffer data. */
4130 palette = gst_buffer_new ();
4131 GST_BUFFER_FLAG_SET (palette, GST_BUFFER_FLAG_READONLY);
4132 GST_BUFFER_DATA (palette) = (guint8 *) palette_data;
4133 GST_BUFFER_SIZE (palette) = sizeof (guint32) * palette_count;
4135 gst_caps_set_simple (stream->caps, "palette_data",
4136 GST_TYPE_BUFFER, palette, NULL);
4137 gst_buffer_unref (palette);
4138 } else if (palette_count != 0) {
4139 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
4140 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
4142 gst_object_unref (stream->pad);
4146 qtdemux->n_video_streams++;
4147 } else if (stream->subtype == FOURCC_soun) {
4148 gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
4151 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
4154 gst_caps_set_simple (stream->caps,
4155 "rate", G_TYPE_INT, (int) stream->rate,
4156 "channels", G_TYPE_INT, stream->n_channels, NULL);
4158 qtdemux->n_audio_streams++;
4159 } else if (stream->subtype == FOURCC_strm) {
4160 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
4161 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
4162 gchar *name = g_strdup_printf ("subtitle_%02d", qtdemux->n_sub_streams);
4165 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
4167 qtdemux->n_sub_streams++;
4169 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
4173 qtdemux->streams[qtdemux->n_streams] = stream;
4174 qtdemux->n_streams++;
4175 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
4178 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
4180 gst_pad_use_fixed_caps (stream->pad);
4181 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
4182 gst_pad_set_query_type_function (stream->pad,
4183 gst_qtdemux_get_src_query_types);
4184 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
4186 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
4187 gst_pad_set_caps (stream->pad, stream->caps);
4189 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
4190 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
4191 gst_pad_set_active (stream->pad, TRUE);
4192 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
4193 if (stream->pending_tags)
4194 gst_tag_list_free (stream->pending_tags);
4195 stream->pending_tags = list;
4197 /* post now, send event on pad later */
4198 GST_DEBUG_OBJECT (qtdemux, "Posting tags %" GST_PTR_FORMAT, list);
4199 gst_element_post_message (GST_ELEMENT (qtdemux),
4200 gst_message_new_tag_full (GST_OBJECT (qtdemux), stream->pad,
4201 gst_tag_list_copy (list)));
4203 /* global tags go on each pad anyway */
4204 stream->send_global_tags = TRUE;
4211 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4212 (_("This file contains too many streams. Only playing first %d"),
4213 GST_QTDEMUX_MAX_STREAMS), (NULL));
4218 /* initialise bytereaders for stbl sub-atoms */
4220 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
4222 /* time-to-sample atom */
4223 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
4226 /* copy atom data into a new buffer for later use */
4227 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
4229 /* skip version + flags */
4230 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
4231 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
4233 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
4235 /* make sure there's enough data */
4236 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 2 * 4))
4239 /* sync sample atom */
4240 stream->stps_present = FALSE;
4241 if ((stream->stss_present =
4242 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
4243 &stream->stss) ? TRUE : FALSE) == TRUE) {
4244 /* copy atom data into a new buffer for later use */
4245 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
4247 /* skip version + flags */
4248 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
4249 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
4252 if (stream->n_sample_syncs) {
4253 /* make sure there's enough data */
4254 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
4258 /* partial sync sample atom */
4259 if ((stream->stps_present =
4260 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
4261 &stream->stps) ? TRUE : FALSE) == TRUE) {
4262 /* copy atom data into a new buffer for later use */
4263 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
4265 /* skip version + flags */
4266 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
4267 !gst_byte_reader_get_uint32_be (&stream->stps,
4268 &stream->n_sample_partial_syncs))
4271 /* if there are no entries, the stss table contains the real
4273 if (stream->n_sample_partial_syncs) {
4274 /* make sure there's enough data */
4275 if (!qt_atom_parser_has_chunks (&stream->stps,
4276 stream->n_sample_partial_syncs, 4))
4283 /* sample-to-chunk atom */
4284 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
4287 /* copy atom data into a new buffer for later use */
4288 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
4290 /* skip version + flags */
4291 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
4292 !gst_byte_reader_get_uint32_be (&stream->stsc,
4293 &stream->n_samples_per_chunk))
4296 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
4297 stream->n_samples_per_chunk);
4299 /* make sure there's enough data */
4300 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
4306 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
4309 /* copy atom data into a new buffer for later use */
4310 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
4312 /* skip version + flags */
4313 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
4314 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
4319 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
4320 stream->co_size = sizeof (guint32);
4321 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
4323 stream->co_size = sizeof (guint64);
4327 /* copy atom data into a new buffer for later use */
4328 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
4330 /* skip version + flags */
4331 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
4334 /* chunks_are_chunks == 0 means treat chunks as samples */
4335 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
4336 if (stream->chunks_are_chunks) {
4337 /* skip number of entries */
4338 if (!gst_byte_reader_skip (&stream->stco, 4))
4341 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
4344 /* make sure there are enough data in the stsz atom */
4345 if (!stream->sample_size) {
4346 /* different sizes for each sample */
4347 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
4351 /* treat chunks as samples */
4352 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
4356 if (!stream->n_samples) {
4357 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4361 GST_DEBUG_OBJECT (qtdemux,
4362 "allocating n_samples %u * %" G_GSIZE_FORMAT " = (%u MB)",
4363 stream->n_samples, sizeof (QtDemuxSample),
4364 (guint) (stream->n_samples * sizeof (QtDemuxSample)) >> 20);
4366 if (stream->n_samples >=
4367 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
4368 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
4369 "be larger than %uMB (broken file?)", stream->n_samples,
4370 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
4374 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
4375 if (!stream->samples) {
4376 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
4382 /* composition time-to-sample */
4383 if ((stream->ctts_present =
4384 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
4385 &stream->ctts) ? TRUE : FALSE) == TRUE) {
4386 /* copy atom data into a new buffer for later use */
4387 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
4389 /* skip version + flags */
4390 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
4391 || !gst_byte_reader_get_uint32_be (&stream->ctts,
4392 &stream->n_composition_times))
4395 /* make sure there's enough data */
4396 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
4401 stream->stbl_index = -1; /* no samples have yet been parsed */
4407 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4408 (_("This file is corrupt and cannot be played.")), (NULL));
4413 /* collect samples from the next sample to be parsed up to sample @n for @stream
4414 * by reading the info from @stbl
4416 * This code can be executed from both the streaming thread and the seeking
4417 * thread so it takes the object lock to protect itself
4420 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
4423 QtDemuxSample *samples, *first, *cur, *last;
4424 guint32 n_samples_per_chunk;
4427 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
4428 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
4429 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
4431 n_samples = stream->n_samples;
4434 goto out_of_samples;
4436 GST_OBJECT_LOCK (qtdemux);
4437 if (n <= stream->stbl_index)
4438 goto already_parsed;
4440 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
4442 /* pointer to the sample table */
4443 samples = stream->samples;
4445 /* starts from -1, moves to the next sample index to parse */
4446 stream->stbl_index++;
4448 /* keep track of the first and last sample to fill */
4449 first = &samples[stream->stbl_index];
4452 if (stream->chunks_are_chunks) {
4453 /* set the sample sizes */
4454 if (stream->sample_size == 0) {
4455 /* different sizes for each sample */
4456 for (cur = first; cur <= last; cur++) {
4457 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
4458 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
4459 (guint) (cur - samples), cur->size);
4462 /* samples have the same size */
4463 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
4464 for (cur = first; cur <= last; cur++)
4465 cur->size = stream->sample_size;
4469 n_samples_per_chunk = stream->n_samples_per_chunk;
4472 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
4475 if (stream->stsc_chunk_index >= stream->last_chunk
4476 || stream->stsc_chunk_index < stream->first_chunk) {
4477 stream->first_chunk =
4478 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
4479 stream->samples_per_chunk =
4480 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
4481 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
4483 /* chunk numbers are counted from 1 it seems */
4484 if (G_UNLIKELY (stream->first_chunk == 0))
4487 --stream->first_chunk;
4489 /* the last chunk of each entry is calculated by taking the first chunk
4490 * of the next entry; except if there is no next, where we fake it with
4492 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
4493 stream->last_chunk = G_MAXUINT32;
4495 stream->last_chunk =
4496 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
4497 if (G_UNLIKELY (stream->last_chunk == 0))
4500 --stream->last_chunk;
4503 GST_LOG_OBJECT (qtdemux,
4504 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
4505 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
4507 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
4510 if (stream->last_chunk != G_MAXUINT32) {
4511 if (!qt_atom_parser_peek_sub (&stream->stco,
4512 stream->first_chunk * stream->co_size,
4513 (stream->last_chunk - stream->first_chunk) * stream->co_size,
4518 stream->co_chunk = stream->stco;
4519 if (!gst_byte_reader_skip (&stream->co_chunk,
4520 stream->first_chunk * stream->co_size))
4524 stream->stsc_chunk_index = stream->first_chunk;
4527 last_chunk = stream->last_chunk;
4529 if (stream->chunks_are_chunks) {
4530 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
4531 guint32 samples_per_chunk;
4532 guint64 chunk_offset;
4534 if (!stream->stsc_sample_index
4535 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
4536 &stream->chunk_offset))
4539 samples_per_chunk = stream->samples_per_chunk;
4540 chunk_offset = stream->chunk_offset;
4542 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
4543 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
4544 G_GUINT64_FORMAT, (guint) (cur - samples), stream->chunk_offset);
4546 cur->offset = chunk_offset;
4547 chunk_offset += cur->size;
4550 if (G_UNLIKELY (cur > last)) {
4552 stream->stsc_sample_index = k + 1;
4553 stream->chunk_offset = chunk_offset;
4554 stream->stsc_chunk_index = j;
4558 stream->stsc_sample_index = 0;
4560 stream->stsc_chunk_index = j;
4562 cur = &samples[stream->stsc_chunk_index];
4564 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
4567 stream->stsc_chunk_index = j;
4572 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
4575 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
4576 "%" G_GUINT64_FORMAT, j, cur->offset);
4578 if (stream->samples_per_frame * stream->bytes_per_frame) {
4580 (stream->samples_per_chunk * stream->n_channels) /
4581 stream->samples_per_frame * stream->bytes_per_frame;
4583 cur->size = stream->samples_per_chunk;
4586 GST_DEBUG_OBJECT (qtdemux,
4587 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
4588 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
4589 GST_SECOND, stream->timescale)), cur->size);
4591 cur->timestamp = stream->stco_sample_index;
4592 cur->duration = stream->samples_per_chunk;
4593 cur->keyframe = TRUE;
4596 stream->stco_sample_index += stream->samples_per_chunk;
4598 stream->stsc_chunk_index = j;
4600 stream->stsc_index++;
4603 if (!stream->chunks_are_chunks)
4607 guint32 n_sample_times;
4609 n_sample_times = stream->n_sample_times;
4612 for (i = stream->stts_index; i < n_sample_times; i++) {
4613 guint32 stts_samples;
4614 guint32 stts_duration;
4617 if (stream->stts_sample_index >= stream->stts_samples
4618 || !stream->stts_sample_index) {
4620 stream->stts_samples =
4621 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
4622 stream->stts_duration =
4623 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
4625 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
4626 i, stream->stts_samples, stream->stts_duration);
4628 stream->stts_sample_index = 0;
4631 stts_samples = stream->stts_samples;
4632 stts_duration = stream->stts_duration;
4633 stts_time = stream->stts_time;
4635 for (j = stream->stts_sample_index; j < stts_samples; j++) {
4636 GST_DEBUG_OBJECT (qtdemux,
4637 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
4638 (guint) (cur - samples), j,
4639 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
4640 stream->timescale)));
4642 cur->timestamp = stts_time;
4643 cur->duration = stts_duration;
4645 stts_time += stts_duration;
4648 if (G_UNLIKELY (cur > last)) {
4650 stream->stts_time = stts_time;
4651 stream->stts_sample_index = j + 1;
4655 stream->stts_sample_index = 0;
4656 stream->stts_time = stts_time;
4657 stream->stts_index++;
4659 /* fill up empty timestamps with the last timestamp, this can happen when
4660 * the last samples do not decode and so we don't have timestamps for them.
4661 * We however look at the last timestamp to estimate the track length so we
4662 * need something in here. */
4663 for (; cur < last; cur++) {
4664 GST_DEBUG_OBJECT (qtdemux,
4665 "fill sample %d: timestamp %" GST_TIME_FORMAT,
4666 (guint) (cur - samples),
4667 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
4668 stream->timescale)));
4669 cur->timestamp = stream->stts_time;
4675 /* sample sync, can be NULL */
4676 if (stream->stss_present == TRUE) {
4677 guint32 n_sample_syncs;
4679 n_sample_syncs = stream->n_sample_syncs;
4681 if (!n_sample_syncs) {
4682 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
4683 stream->all_keyframe = TRUE;
4685 for (i = stream->stss_index; i < n_sample_syncs; i++) {
4686 /* note that the first sample is index 1, not 0 */
4689 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
4691 if (G_LIKELY (index > 0 && index <= n_samples)) {
4693 samples[index].keyframe = TRUE;
4694 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
4695 /* and exit if we have enough samples */
4696 if (G_UNLIKELY (index >= n)) {
4703 stream->stss_index = i;
4706 /* stps marks partial sync frames like open GOP I-Frames */
4707 if (stream->stps_present == TRUE) {
4708 guint32 n_sample_partial_syncs;
4710 n_sample_partial_syncs = stream->n_sample_partial_syncs;
4712 /* if there are no entries, the stss table contains the real
4714 if (n_sample_partial_syncs) {
4715 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
4716 /* note that the first sample is index 1, not 0 */
4719 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
4721 if (G_LIKELY (index > 0 && index <= n_samples)) {
4723 samples[index].keyframe = TRUE;
4724 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
4725 /* and exit if we have enough samples */
4726 if (G_UNLIKELY (index >= n)) {
4733 stream->stps_index = i;
4737 /* no stss, all samples are keyframes */
4738 stream->all_keyframe = TRUE;
4739 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
4744 /* composition time to sample */
4745 if (stream->ctts_present == TRUE) {
4746 guint32 n_composition_times;
4748 gint32 ctts_soffset;
4750 /* Fill in the pts_offsets */
4752 n_composition_times = stream->n_composition_times;
4754 for (i = stream->ctts_index; i < n_composition_times; i++) {
4755 if (stream->ctts_sample_index >= stream->ctts_count
4756 || !stream->ctts_sample_index) {
4757 stream->ctts_count =
4758 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
4759 stream->ctts_soffset =
4760 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
4761 stream->ctts_sample_index = 0;
4764 ctts_count = stream->ctts_count;
4765 ctts_soffset = stream->ctts_soffset;
4767 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
4768 cur->pts_offset = ctts_soffset;
4771 if (G_UNLIKELY (cur > last)) {
4773 stream->ctts_sample_index = j + 1;
4777 stream->ctts_sample_index = 0;
4778 stream->ctts_index++;
4782 stream->stbl_index = n;
4783 /* if index has been completely parsed, free data that is no-longer needed */
4784 if (n == stream->n_samples)
4785 gst_qtdemux_stbl_free (stream);
4786 GST_OBJECT_UNLOCK (qtdemux);
4793 GST_LOG_OBJECT (qtdemux,
4794 "Tried to parse up to sample %u but this sample has already been parsed",
4796 GST_OBJECT_UNLOCK (qtdemux);
4802 GST_LOG_OBJECT (qtdemux,
4803 "Tried to parse up to sample %u but there are only %u samples", n + 1,
4805 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4806 (_("This file is corrupt and cannot be played.")), (NULL));
4811 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4812 (_("This file is corrupt and cannot be played.")), (NULL));
4813 GST_OBJECT_UNLOCK (qtdemux);
4818 /* collect all segment info for @stream.
4821 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
4826 /* parse and prepare segment info from the edit list */
4827 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
4828 stream->n_segments = 0;
4829 stream->segments = NULL;
4830 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
4834 guint64 time, stime;
4837 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
4838 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
4841 buffer = elst->data;
4843 n_segments = QT_UINT32 (buffer + 12);
4845 /* we might allocate a bit too much, at least allocate 1 segment */
4846 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
4848 /* segments always start from 0 */
4852 for (i = 0; i < n_segments; i++) {
4855 QtDemuxSegment *segment;
4858 media_time = QT_UINT32 (buffer + 20 + i * 12);
4860 /* -1 media time is an empty segment, just ignore it */
4861 if (media_time == G_MAXUINT32)
4864 duration = QT_UINT32 (buffer + 16 + i * 12);
4866 segment = &stream->segments[count++];
4868 /* time and duration expressed in global timescale */
4869 segment->time = stime;
4870 /* add non scaled values so we don't cause roundoff errors */
4872 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
4873 segment->stop_time = stime;
4874 segment->duration = stime - segment->time;
4875 /* media_time expressed in stream timescale */
4876 segment->media_start =
4877 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
4878 segment->media_stop = segment->media_start + segment->duration;
4879 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
4881 if (rate_int <= 1) {
4882 /* 0 is not allowed, some programs write 1 instead of the floating point
4884 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
4888 segment->rate = rate_int / 65536.0;
4891 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
4892 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
4893 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
4894 GST_TIME_ARGS (segment->duration),
4895 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
4897 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
4898 stream->n_segments = count;
4902 /* push based does not handle segments, so act accordingly here,
4903 * and warn if applicable */
4904 if (!qtdemux->pullbased) {
4905 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
4906 /* remove and use default one below, we stream like it anyway */
4907 g_free (stream->segments);
4908 stream->segments = NULL;
4909 stream->n_segments = 0;
4912 /* no segments, create one to play the complete trak */
4913 if (stream->n_segments == 0) {
4914 GstClockTime stream_duration =
4915 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
4917 if (stream->segments == NULL)
4918 stream->segments = g_new (QtDemuxSegment, 1);
4920 stream->segments[0].time = 0;
4921 stream->segments[0].stop_time = stream_duration;
4922 stream->segments[0].duration = stream_duration;
4923 stream->segments[0].media_start = 0;
4924 stream->segments[0].media_stop = stream_duration;
4925 stream->segments[0].rate = 1.0;
4927 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
4928 GST_TIME_ARGS (stream_duration));
4929 stream->n_segments = 1;
4931 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
4937 * Parses the stsd atom of a svq3 trak looking for
4938 * the SMI and gama atoms.
4941 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
4942 guint8 ** gamma, GstBuffer ** seqh)
4944 guint8 *_gamma = NULL;
4945 GstBuffer *_seqh = NULL;
4946 guint8 *stsd_data = stsd->data;
4947 guint32 length = QT_UINT32 (stsd_data);
4951 GST_WARNING_OBJECT (qtdemux, "stsd too short");
4957 version = QT_UINT16 (stsd_data);
4962 while (length > 8) {
4963 guint32 fourcc, size;
4965 size = QT_UINT32 (stsd_data);
4966 fourcc = QT_FOURCC (stsd_data + 4);
4967 data = stsd_data + 8;
4974 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
4975 " for gama atom, expected 12", size);
4980 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
4982 if (_seqh != NULL) {
4983 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
4984 " found, ignoring");
4986 seqh_size = QT_UINT32 (data + 4);
4987 if (seqh_size > 0) {
4988 _seqh = gst_buffer_new_and_alloc (seqh_size);
4989 memcpy (GST_BUFFER_DATA (_seqh), data + 8, seqh_size);
4996 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
4997 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
5001 if (size <= length) {
5007 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
5010 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
5011 G_GUINT16_FORMAT, version);
5022 gst_buffer_unref (_seqh);
5027 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
5035 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
5036 * atom that might contain a 'data' atom with the rtsp uri.
5037 * This case was reported in bug #597497, some info about
5038 * the hndl atom can be found in TN1195
5040 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
5041 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
5044 guint32 dref_num_entries = 0;
5045 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
5046 gst_byte_reader_skip (&dref, 4) &&
5047 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
5051 /* search dref entries for hndl atom */
5052 for (i = 0; i < dref_num_entries; i++) {
5053 guint32 size = 0, type;
5054 guint8 string_len = 0;
5055 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
5056 qt_atom_parser_get_fourcc (&dref, &type)) {
5057 if (type == FOURCC_hndl) {
5058 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
5060 /* skip data reference handle bytes and the
5061 * following pascal string and some extra 4
5062 * bytes I have no idea what are */
5063 if (!gst_byte_reader_skip (&dref, 4) ||
5064 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
5065 !gst_byte_reader_skip (&dref, string_len + 4)) {
5066 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
5070 /* iterate over the atoms to find the data atom */
5071 while (gst_byte_reader_get_remaining (&dref) >= 8) {
5075 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
5076 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
5077 if (atom_type == FOURCC_data) {
5078 const guint8 *uri_aux = NULL;
5080 /* found the data atom that might contain the rtsp uri */
5081 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
5082 "hndl atom, interpreting it as an URI");
5083 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
5085 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
5086 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
5088 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
5089 "didn't contain a rtsp address");
5091 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
5096 /* skipping to the next entry */
5097 gst_byte_reader_skip (&dref, atom_size - 8);
5099 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
5106 /* skip to the next entry */
5107 gst_byte_reader_skip (&dref, size - 8);
5109 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
5112 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
5119 less_than (gconstpointer a, gconstpointer b)
5121 const guint32 *av = a, *bv = b;
5127 * With each track we associate a new QtDemuxStream that contains all the info
5129 * traks that do not decode to something (like strm traks) will not have a pad.
5132 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
5147 QtDemuxStream *stream;
5148 GstTagList *list = NULL;
5149 gchar *codec = NULL;
5150 const guint8 *stsd_data;
5151 guint16 lang_code; /* quicktime lang code or packed iso code */
5153 guint32 tkhd_flags = 0;
5154 guint8 tkhd_version = 0;
5158 stream = g_new0 (QtDemuxStream, 1);
5159 /* new streams always need a discont */
5160 stream->discont = TRUE;
5161 /* we enable clipping for raw audio/video streams */
5162 stream->need_clip = FALSE;
5163 stream->need_process = FALSE;
5164 stream->segment_index = -1;
5165 stream->time_position = 0;
5166 stream->sample_index = -1;
5167 stream->last_ret = GST_FLOW_OK;
5169 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
5170 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
5171 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
5174 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags: 0x%02x/%06x",
5175 tkhd_version, tkhd_flags);
5177 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
5180 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
5181 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
5182 if (qtdemux->major_brand != FOURCC_mjp2 ||
5183 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
5187 len = QT_UINT32 ((guint8 *) mdhd->data);
5188 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
5189 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
5190 if (version == 0x01000000) {
5193 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
5194 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
5195 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
5199 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
5200 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
5201 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
5204 if (lang_code < 0x800) {
5205 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
5207 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
5208 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
5209 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
5210 stream->lang_id[3] = 0;
5213 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
5215 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
5217 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
5218 lang_code, stream->lang_id);
5220 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
5223 if (qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
5224 guint64 tdur1, tdur2;
5226 /* don't overflow */
5227 tdur1 = stream->timescale * (guint64) qtdemux->duration;
5228 tdur2 = qtdemux->timescale * (guint64) stream->duration;
5231 * some of those trailers, nowadays, have prologue images that are
5232 * themselves vide tracks as well. I haven't really found a way to
5233 * identify those yet, except for just looking at their duration. */
5234 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
5235 GST_WARNING_OBJECT (qtdemux,
5236 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
5237 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
5238 "found, assuming preview image or something; skipping track",
5239 stream->duration, stream->timescale, qtdemux->duration,
5240 qtdemux->timescale);
5246 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
5249 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
5250 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
5252 len = QT_UINT32 ((guint8 *) hdlr->data);
5254 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
5255 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
5256 GST_FOURCC_ARGS (stream->subtype));
5258 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
5261 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
5265 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
5267 stsd_data = (const guint8 *) stsd->data;
5269 /* stsd should at least have one entry */
5270 len = QT_UINT32 (stsd_data);
5274 /* and that entry should fit within stsd */
5275 len = QT_UINT32 (stsd_data + 16);
5276 if (len > QT_UINT32 (stsd_data) + 16)
5278 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
5280 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
5281 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
5282 GST_FOURCC_ARGS (stream->fourcc));
5284 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
5285 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
5286 goto error_encrypted;
5288 if (stream->subtype == FOURCC_vide) {
5289 guint32 w = 0, h = 0;
5291 stream->sampled = TRUE;
5293 /* version 1 uses some 64-bit ints */
5294 if (!gst_byte_reader_skip (&tkhd, (tkhd_version == 1) ? 84 : 72)
5295 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
5296 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
5299 stream->display_width = w >> 16;
5300 stream->display_height = h >> 16;
5306 stream->width = QT_UINT16 (stsd_data + offset + 32);
5307 stream->height = QT_UINT16 (stsd_data + offset + 34);
5308 stream->fps_n = 0; /* this is filled in later */
5309 stream->fps_d = 0; /* this is filled in later */
5310 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
5311 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
5313 GST_LOG_OBJECT (qtdemux, "frame count: %u",
5314 QT_UINT16 (stsd_data + offset + 48));
5317 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
5319 list = gst_tag_list_new ();
5320 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
5321 GST_TAG_VIDEO_CODEC, codec, NULL);
5328 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4v);
5330 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_MP4V);
5331 /* H264 is MPEG-4 after all,
5332 * and qt seems to put MPEG-4 stuff in there as well */
5334 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_avc1);
5336 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
5337 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
5341 const guint8 *pasp_data = (const guint8 *) pasp->data;
5343 stream->par_w = QT_UINT32 (pasp_data + 8);
5344 stream->par_h = QT_UINT32 (pasp_data + 12);
5351 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
5356 gint len = QT_UINT32 (stsd_data) - 0x66;
5357 const guint8 *avc_data = stsd_data + 0x66;
5360 while (len >= 0x8) {
5363 if (QT_UINT32 (avc_data) <= len)
5364 size = QT_UINT32 (avc_data) - 0x8;
5369 /* No real data, so break out */
5372 switch (QT_FOURCC (avc_data + 0x4)) {
5375 /* parse, if found */
5378 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
5380 /* First 4 bytes are the length of the atom, the next 4 bytes
5381 * are the fourcc, the next 1 byte is the version, and the
5382 * subsequent bytes are sequence parameter set like data. */
5383 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
5384 avc_data + 8 + 1, size - 1);
5386 buf = gst_buffer_new_and_alloc (size);
5387 memcpy (GST_BUFFER_DATA (buf), avc_data + 0x8, size);
5388 gst_caps_set_simple (stream->caps,
5389 "codec_data", GST_TYPE_BUFFER, buf, NULL);
5390 gst_buffer_unref (buf);
5396 guint avg_bitrate, max_bitrate;
5398 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
5402 max_bitrate = QT_UINT32 (avc_data + 0xc);
5403 avg_bitrate = QT_UINT32 (avc_data + 0x10);
5405 if (!max_bitrate && !avg_bitrate)
5408 /* Some muxers seem to swap the average and maximum bitrates
5409 * (I'm looking at you, YouTube), so we swap for sanity. */
5410 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
5411 guint temp = avg_bitrate;
5413 avg_bitrate = max_bitrate;
5418 list = gst_tag_list_new ();
5420 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
5421 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
5422 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
5424 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
5425 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
5426 GST_TAG_BITRATE, avg_bitrate, NULL);
5437 avc_data += size + 8;
5447 GST_DEBUG_OBJECT (qtdemux, "found mp4v");
5449 /* codec data might be in glbl extension atom */
5450 glbl = qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl);
5456 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
5458 len = QT_UINT32 (data);
5461 buf = gst_buffer_new_and_alloc (len);
5462 memcpy (GST_BUFFER_DATA (buf), data + 8, len);
5463 gst_caps_set_simple (stream->caps,
5464 "codec_data", GST_TYPE_BUFFER, buf, NULL);
5465 gst_buffer_unref (buf);
5471 /* see annex I of the jpeg2000 spec */
5472 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
5476 guint32 ncomp_map = 0;
5477 gint32 *comp_map = NULL;
5478 guint32 nchan_def = 0;
5479 gint32 *chan_def = NULL;
5481 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
5482 /* some required atoms */
5483 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
5486 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
5490 /* number of components; redundant with info in codestream, but useful
5492 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
5493 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
5495 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
5497 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
5500 GST_DEBUG_OBJECT (qtdemux, "found colr");
5501 /* extract colour space info */
5502 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
5503 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
5505 fourcc = GST_MAKE_FOURCC ('s', 'R', 'G', 'B');
5508 fourcc = GST_MAKE_FOURCC ('G', 'R', 'A', 'Y');
5511 fourcc = GST_MAKE_FOURCC ('s', 'Y', 'U', 'V');
5518 /* colr is required, and only values 16, 17, and 18 are specified,
5519 so error if we have no fourcc */
5522 /* extract component mapping */
5523 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
5525 guint32 cmap_len = 0;
5527 cmap_len = QT_UINT32 (cmap->data);
5528 if (cmap_len >= 8) {
5529 /* normal box, subtract off header */
5531 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
5532 if (cmap_len % 4 == 0) {
5533 ncomp_map = (cmap_len / 4);
5534 comp_map = g_new0 (gint32, ncomp_map);
5535 for (i = 0; i < ncomp_map; i++) {
5538 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
5539 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
5540 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
5541 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
5546 /* extract channel definitions */
5547 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
5549 guint32 cdef_len = 0;
5551 cdef_len = QT_UINT32 (cdef->data);
5552 if (cdef_len >= 10) {
5553 /* normal box, subtract off header and len */
5555 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
5556 if (cdef_len % 6 == 0) {
5557 nchan_def = (cdef_len / 6);
5558 chan_def = g_new0 (gint32, nchan_def);
5559 for (i = 0; i < nchan_def; i++)
5561 for (i = 0; i < nchan_def; i++) {
5562 guint16 cn, typ, asoc;
5563 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
5564 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
5565 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
5566 if (cn < nchan_def) {
5569 chan_def[cn] = asoc;
5572 chan_def[cn] = 0; /* alpha */
5575 chan_def[cn] = -typ;
5583 gst_caps_set_simple (stream->caps,
5584 "num-components", G_TYPE_INT, ncomp, NULL);
5585 gst_caps_set_simple (stream->caps,
5586 "fourcc", GST_TYPE_FOURCC, fourcc, NULL);
5589 GValue arr = { 0, };
5590 GValue elt = { 0, };
5592 g_value_init (&arr, GST_TYPE_ARRAY);
5593 g_value_init (&elt, G_TYPE_INT);
5594 for (i = 0; i < ncomp_map; i++) {
5595 g_value_set_int (&elt, comp_map[i]);
5596 gst_value_array_append_value (&arr, &elt);
5598 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
5599 "component-map", &arr);
5600 g_value_unset (&elt);
5601 g_value_unset (&arr);
5606 GValue arr = { 0, };
5607 GValue elt = { 0, };
5609 g_value_init (&arr, GST_TYPE_ARRAY);
5610 g_value_init (&elt, G_TYPE_INT);
5611 for (i = 0; i < nchan_def; i++) {
5612 g_value_set_int (&elt, chan_def[i]);
5613 gst_value_array_append_value (&arr, &elt);
5615 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
5616 "channel-definitions", &arr);
5617 g_value_unset (&elt);
5618 g_value_unset (&arr);
5622 /* some optional atoms */
5623 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
5624 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
5626 /* indicate possible fields in caps */
5628 data = (guint8 *) field->data + 8;
5630 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
5631 (gint) * data, NULL);
5633 /* add codec_data if provided */
5638 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
5639 data = prefix->data;
5640 len = QT_UINT32 (data);
5643 buf = gst_buffer_new_and_alloc (len);
5644 memcpy (GST_BUFFER_DATA (buf), data + 8, len);
5645 gst_caps_set_simple (stream->caps,
5646 "codec_data", GST_TYPE_BUFFER, buf, NULL);
5647 gst_buffer_unref (buf);
5656 GstBuffer *seqh = NULL;
5657 guint8 *gamma_data = NULL;
5658 gint len = QT_UINT32 (stsd_data);
5660 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
5662 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
5663 QT_FP32 (gamma_data), NULL);
5666 /* sorry for the bad name, but we don't know what this is, other
5667 * than its own fourcc */
5668 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
5672 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
5673 buf = gst_buffer_new_and_alloc (len);
5674 memcpy (GST_BUFFER_DATA (buf), stsd_data, len);
5675 gst_caps_set_simple (stream->caps,
5676 "codec_data", GST_TYPE_BUFFER, buf, NULL);
5677 gst_buffer_unref (buf);
5682 gst_caps_set_simple (stream->caps,
5683 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
5690 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
5691 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
5695 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
5699 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
5700 /* collect the headers and store them in a stream list so that we can
5701 * send them out first */
5702 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
5710 GST_INFO_OBJECT (qtdemux,
5711 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
5712 GST_FOURCC_ARGS (fourcc), stream->caps);
5714 } else if (stream->subtype == FOURCC_soun) {
5715 int version, samplesize;
5716 guint16 compression_id;
5722 version = QT_UINT32 (stsd_data + offset);
5723 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
5724 samplesize = QT_UINT16 (stsd_data + offset + 10);
5725 compression_id = QT_UINT16 (stsd_data + offset + 12);
5726 stream->rate = QT_FP32 (stsd_data + offset + 16);
5728 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
5729 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
5730 QT_UINT32 (stsd_data + offset + 4));
5731 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
5732 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
5733 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
5734 GST_LOG_OBJECT (qtdemux, "packet size: %d",
5735 QT_UINT16 (stsd_data + offset + 14));
5736 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
5738 if (compression_id == 0xfffe)
5739 stream->sampled = TRUE;
5741 /* first assume uncompressed audio */
5742 stream->bytes_per_sample = samplesize / 8;
5743 stream->samples_per_frame = stream->n_channels;
5744 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
5745 stream->samples_per_packet = stream->samples_per_frame;
5746 stream->bytes_per_packet = stream->bytes_per_sample;
5750 /* Yes, these have to be hard-coded */
5753 stream->samples_per_packet = 6;
5754 stream->bytes_per_packet = 1;
5755 stream->bytes_per_frame = 1 * stream->n_channels;
5756 stream->bytes_per_sample = 1;
5757 stream->samples_per_frame = 6 * stream->n_channels;
5762 stream->samples_per_packet = 3;
5763 stream->bytes_per_packet = 1;
5764 stream->bytes_per_frame = 1 * stream->n_channels;
5765 stream->bytes_per_sample = 1;
5766 stream->samples_per_frame = 3 * stream->n_channels;
5771 stream->samples_per_packet = 64;
5772 stream->bytes_per_packet = 34;
5773 stream->bytes_per_frame = 34 * stream->n_channels;
5774 stream->bytes_per_sample = 2;
5775 stream->samples_per_frame = 64 * stream->n_channels;
5781 stream->samples_per_packet = 1;
5782 stream->bytes_per_packet = 1;
5783 stream->bytes_per_frame = 1 * stream->n_channels;
5784 stream->bytes_per_sample = 1;
5785 stream->samples_per_frame = 1 * stream->n_channels;
5790 stream->samples_per_packet = 160;
5791 stream->bytes_per_packet = 33;
5792 stream->bytes_per_frame = 33 * stream->n_channels;
5793 stream->bytes_per_sample = 2;
5794 stream->samples_per_frame = 160 * stream->n_channels;
5801 if (version == 0x00010000) {
5809 /* only parse extra decoding config for non-pcm audio */
5810 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
5811 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
5812 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
5813 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
5815 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
5816 stream->samples_per_packet);
5817 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
5818 stream->bytes_per_packet);
5819 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
5820 stream->bytes_per_frame);
5821 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
5822 stream->bytes_per_sample);
5824 if (!stream->sampled && stream->bytes_per_packet) {
5825 stream->samples_per_frame = (stream->bytes_per_frame /
5826 stream->bytes_per_packet) * stream->samples_per_packet;
5827 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
5828 stream->samples_per_frame);
5833 } else if (version == 0x00020000) {
5840 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
5841 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
5842 stream->rate = qtfp.fp;
5843 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
5845 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
5846 stream->samples_per_packet);
5847 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
5848 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
5851 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
5854 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
5863 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
5865 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
5867 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
5869 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
5872 gst_caps_set_simple (stream->caps,
5873 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
5882 list = gst_tag_list_new ();
5883 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
5884 GST_TAG_AUDIO_CODEC, codec, NULL);
5889 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
5893 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
5895 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
5897 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
5901 /* If the fourcc's bottom 16 bits gives 'sm', then the top
5902 16 bits is a byte-swapped wave-style codec identifier,
5903 and we can find a WAVE header internally to a 'wave' atom here.
5904 This can more clearly be thought of as 'ms' as the top 16 bits, and a
5905 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
5908 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
5909 if (len < offset + 20) {
5910 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
5912 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
5913 const guint8 *data = stsd_data + offset + 16;
5915 GNode *waveheadernode;
5917 wavenode = g_node_new ((guint8 *) data);
5918 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
5919 const guint8 *waveheader;
5922 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
5923 waveheader = (const guint8 *) waveheadernode->data;
5924 headerlen = QT_UINT32 (waveheader);
5926 if (headerlen > 8) {
5927 gst_riff_strf_auds *header = NULL;
5928 GstBuffer *headerbuf;
5934 headerbuf = gst_buffer_new ();
5935 GST_BUFFER_DATA (headerbuf) = (guint8 *) waveheader;
5936 GST_BUFFER_SIZE (headerbuf) = headerlen;
5938 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
5939 headerbuf, &header, &extra)) {
5940 gst_caps_unref (stream->caps);
5941 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
5942 header, extra, NULL, NULL);
5945 gst_buffer_unref (extra);
5949 g_node_destroy (wavenode);
5952 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
5956 /* FIXME: what is in the chunk? */
5959 gint len = QT_UINT32 (stsd_data);
5961 /* seems to be always = 116 = 0x74 */
5967 gint len = QT_UINT32 (stsd_data);
5970 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
5972 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x4C, len - 0x4C);
5973 gst_caps_set_simple (stream->caps,
5974 "codec_data", GST_TYPE_BUFFER, buf, NULL);
5975 gst_buffer_unref (buf);
5977 gst_caps_set_simple (stream->caps,
5978 "samplesize", G_TYPE_INT, samplesize, NULL);
5983 GNode *alac, *wave = NULL;
5985 /* apparently, m4a has this atom appended directly in the stsd entry,
5986 * while mov has it in a wave atom */
5987 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
5989 /* alac now refers to stsd entry atom */
5990 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
5992 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
5994 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
5997 gint len = QT_UINT32 (alac->data);
6001 GST_DEBUG_OBJECT (qtdemux,
6002 "discarding alac atom with unexpected len %d", len);
6004 /* codec-data contains alac atom size and prefix,
6005 * ffmpeg likes it that way, not quite gst-ish though ...*/
6006 buf = gst_buffer_new_and_alloc (len);
6007 memcpy (GST_BUFFER_DATA (buf), alac->data, len);
6008 gst_caps_set_simple (stream->caps,
6009 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6010 gst_buffer_unref (buf);
6013 gst_caps_set_simple (stream->caps,
6014 "samplesize", G_TYPE_INT, samplesize, NULL);
6019 gint len = QT_UINT32 (stsd_data);
6022 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
6024 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34);
6026 gst_caps_set_simple (stream->caps,
6027 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6028 gst_buffer_unref (buf);
6036 GST_INFO_OBJECT (qtdemux,
6037 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
6038 GST_FOURCC_ARGS (fourcc), stream->caps);
6040 } else if (stream->subtype == FOURCC_strm) {
6041 if (fourcc == FOURCC_rtsp) {
6042 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
6044 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
6045 GST_FOURCC_ARGS (fourcc));
6046 goto unknown_stream;
6048 stream->sampled = TRUE;
6049 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
6051 stream->sampled = TRUE;
6056 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6058 list = gst_tag_list_new ();
6059 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6060 GST_TAG_SUBTITLE_CODEC, codec, NULL);
6065 /* hunt for sort-of codec data */
6072 /* look for palette */
6073 /* target mp4s atom */
6074 len = QT_UINT32 (stsd_data + offset);
6075 data = stsd_data + offset;
6076 /* verify sufficient length,
6077 * and esds present with decConfigDescr of expected size and position */
6078 if ((len >= 106 + 8)
6079 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
6080 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
6085 /* move to decConfigDescr data */
6086 data = data + 8 + 42;
6087 for (i = 0; i < 16; i++) {
6088 clut[i] = QT_UINT32 (data);
6092 s = gst_structure_new ("application/x-gst-dvd", "event",
6093 G_TYPE_STRING, "dvd-spu-clut-change",
6094 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
6095 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
6096 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
6097 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
6098 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
6099 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
6100 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
6101 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
6104 /* store event and trigger custom processing */
6105 stream->pending_event =
6106 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
6107 stream->need_process = TRUE;
6115 goto unknown_stream;
6118 /* promote to sampled format */
6119 if (stream->fourcc == FOURCC_samr) {
6120 /* force mono 8000 Hz for AMR */
6121 stream->sampled = TRUE;
6122 stream->n_channels = 1;
6123 stream->rate = 8000;
6124 } else if (stream->fourcc == FOURCC_sawb) {
6125 /* force mono 16000 Hz for AMR-WB */
6126 stream->sampled = TRUE;
6127 stream->n_channels = 1;
6128 stream->rate = 16000;
6129 } else if (stream->fourcc == FOURCC_mp4a) {
6130 stream->sampled = TRUE;
6133 /* collect sample information */
6134 if (!qtdemux_stbl_init (qtdemux, stream, stbl)
6135 || !qtdemux_parse_samples (qtdemux, stream, 0))
6136 goto samples_failed;
6138 /* parse number of initial sample to set frame rate cap */
6139 if (G_UNLIKELY (stream->min_duration == 0)) {
6140 guint32 sample_num = 1;
6141 const guint samples = 20;
6144 while (sample_num < stream->n_samples && sample_num < samples) {
6145 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
6146 goto samples_failed;
6149 /* collect and sort durations */
6150 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
6152 while (sample_num <= stream->stbl_index) {
6153 g_array_append_val (durations, stream->samples[sample_num].duration);
6156 g_array_sort (durations, less_than);
6157 stream->min_duration = g_array_index (durations, guint32, samples / 2);
6158 g_array_free (durations, TRUE);
6160 /* configure segments */
6161 if (!qtdemux_parse_segments (qtdemux, stream, trak))
6162 goto segments_failed;
6164 /* add some language tag, if useful */
6165 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
6166 strcmp (stream->lang_id, "und")) {
6167 const gchar *lang_code;
6170 list = gst_tag_list_new ();
6172 /* convert ISO 639-2 code to ISO 639-1 */
6173 lang_code = gst_tag_get_language_code (stream->lang_id);
6174 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6175 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
6178 /* now we are ready to add the stream */
6179 gst_qtdemux_add_stream (qtdemux, stream, list);
6186 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6187 (_("This file is corrupt and cannot be played.")), (NULL));
6193 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
6200 /* we posted an error already */
6201 /* free stbl sub-atoms */
6202 gst_qtdemux_stbl_free (stream);
6208 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
6209 GST_FOURCC_ARGS (stream->subtype));
6215 /* check if major or compatible brand is 3GP */
6216 static inline gboolean
6217 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
6220 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
6221 GST_MAKE_FOURCC ('3', 'g', 0, 0));
6222 } else if (qtdemux->comp_brands != NULL) {
6223 guint8 *data = GST_BUFFER_DATA (qtdemux->comp_brands);
6224 guint size = GST_BUFFER_SIZE (qtdemux->comp_brands);
6225 gboolean res = FALSE;
6228 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
6229 GST_MAKE_FOURCC ('3', 'g', 0, 0));
6239 /* check if tag is a spec'ed 3GP tag keyword storing a string */
6240 static inline gboolean
6241 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
6243 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
6244 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
6245 || fourcc == FOURCC_albm;
6249 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
6250 const char *dummy, GNode * node)
6252 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
6256 gdouble longitude, latitude, altitude;
6259 len = QT_UINT32 (node->data);
6266 /* TODO: language code skipped */
6268 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
6271 /* do not alarm in trivial case, but bail out otherwise */
6272 if (*(data + offset) != 0) {
6273 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
6277 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6278 GST_TAG_GEO_LOCATION_NAME, name, NULL);
6279 offset += strlen (name);
6283 if (len < offset + 2 + 4 + 4 + 4)
6286 /* +1 +1 = skip null-terminator and location role byte */
6288 /* table in spec says unsigned, semantics say negative has meaning ... */
6289 longitude = QT_SFP32 (data + offset);
6292 latitude = QT_SFP32 (data + offset);
6295 altitude = QT_SFP32 (data + offset);
6297 /* one invalid means all are invalid */
6298 if (longitude >= -180.0 && longitude <= 180.0 &&
6299 latitude >= -90.0 && latitude <= 90.0) {
6300 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6301 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
6302 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
6303 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
6306 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
6313 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
6320 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
6327 len = QT_UINT32 (node->data);
6331 y = QT_UINT16 ((guint8 *) node->data + 12);
6332 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
6334 date = g_date_new_dmy (1, 1, y);
6335 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
6340 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
6341 const char *dummy, GNode * node)
6344 char *tag_str = NULL;
6349 len = QT_UINT32 (node->data);
6354 entity = (guint8 *) node->data + offset;
6357 table = QT_UINT16 ((guint8 *) node->data + offset);
6359 /* Language code skipped */
6363 /* Tag format: "XXXX://Y[YYYY]/classification info string"
6364 * XXXX: classification entity, fixed length 4 chars.
6365 * Y[YYYY]: classification table, max 5 chars.
6367 tag_str = g_strdup_printf ("----://%u/%s",
6368 table, (char *) node->data + offset);
6370 /* memcpy To be sure we're preserving byte order */
6371 memcpy (tag_str, entity, 4);
6372 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
6374 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
6384 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
6390 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
6391 const char *dummy, GNode * node)
6393 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
6399 gboolean ret = TRUE;
6401 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6403 len = QT_UINT32 (data->data);
6404 type = QT_UINT32 ((guint8 *) data->data + 8);
6405 if (type == 0x00000001 && len > 16) {
6406 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
6409 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
6410 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
6414 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
6418 len = QT_UINT32 (node->data);
6419 type = QT_UINT32 ((guint8 *) node->data + 4);
6420 if ((type >> 24) == 0xa9) {
6421 /* Type starts with the (C) symbol, so the next 32 bits are
6422 * the language code, which we ignore */
6424 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
6425 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
6426 QT_FOURCC ((guint8 *) node->data + 4))) {
6427 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
6429 /* we go for 3GP style encoding if major brands claims so,
6430 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
6431 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
6432 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
6433 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
6435 /* 16-bit Language code is ignored here as well */
6436 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
6443 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
6444 ret = FALSE; /* may have to fallback */
6446 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
6447 len - offset, env_vars);
6449 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
6450 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
6454 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
6461 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
6462 const char *dummy, GNode * node)
6464 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
6468 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
6469 const char *dummy, GNode * node)
6471 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
6473 char *s, *t, *k = NULL;
6478 /* first try normal string tag if major brand not 3GP */
6479 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
6480 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
6481 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
6482 * let's try it 3gpp way after minor safety check */
6484 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
6490 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
6494 len = QT_UINT32 (data);
6498 count = QT_UINT8 (data + 14);
6500 for (; count; count--) {
6503 if (offset + 1 > len)
6505 slen = QT_UINT8 (data + offset);
6507 if (offset + slen > len)
6509 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
6512 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
6514 t = g_strjoin (",", k, s, NULL);
6522 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
6529 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
6530 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
6539 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
6545 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
6546 const char *tag2, GNode * node)
6553 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6555 len = QT_UINT32 (data->data);
6556 type = QT_UINT32 ((guint8 *) data->data + 8);
6557 if (type == 0x00000000 && len >= 22) {
6558 n1 = QT_UINT16 ((guint8 *) data->data + 18);
6559 n2 = QT_UINT16 ((guint8 *) data->data + 20);
6561 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
6562 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6566 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
6567 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6575 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
6583 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6585 len = QT_UINT32 (data->data);
6586 type = QT_UINT32 ((guint8 *) data->data + 8);
6587 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
6588 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
6589 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
6590 n1 = QT_UINT16 ((guint8 *) data->data + 16);
6592 /* do not add bpm=0 */
6593 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
6594 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6595 tag1, (gdouble) n1, NULL);
6602 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
6603 const char *dummy, GNode * node)
6610 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6612 len = QT_UINT32 (data->data);
6613 type = QT_UINT32 ((guint8 *) data->data + 8);
6614 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
6615 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
6616 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
6617 num = QT_UINT32 ((guint8 *) data->data + 16);
6619 /* do not add num=0 */
6620 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
6621 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6629 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
6637 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6639 len = QT_UINT32 (data->data);
6640 type = QT_UINT32 ((guint8 *) data->data + 8);
6641 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
6642 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
6643 if ((buf = gst_tag_image_data_to_image_buffer ((guint8 *) data->data + 16,
6644 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
6645 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
6646 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6648 gst_buffer_unref (buf);
6655 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
6663 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6665 len = QT_UINT32 (data->data);
6666 type = QT_UINT32 ((guint8 *) data->data + 8);
6667 if (type == 0x00000001 && len > 16) {
6668 guint y, m = 1, d = 1;
6671 s = g_strndup ((char *) data->data + 16, len - 16);
6672 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
6673 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
6674 if (ret >= 1 && y > 1500 && y < 3000) {
6677 date = g_date_new_dmy (d, m, y);
6678 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
6682 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
6690 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
6695 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6697 /* re-route to normal string tag if major brand says so
6698 * or no data atom and compatible brand suggests so */
6699 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
6700 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
6701 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
6708 len = QT_UINT32 (data->data);
6709 type = QT_UINT32 ((guint8 *) data->data + 8);
6710 if (type == 0x00000000 && len >= 18) {
6711 n = QT_UINT16 ((guint8 *) data->data + 16);
6715 genre = gst_tag_id3_genre_get (n - 1);
6716 if (genre != NULL) {
6717 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
6718 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
6727 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
6728 guint8 * data, guint32 datasize)
6733 /* make a copy to have \0 at the end */
6734 datacopy = g_strndup ((gchar *) data, datasize);
6736 /* convert the str to double */
6737 if (sscanf (datacopy, "%lf", &value) == 1) {
6738 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
6739 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
6741 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
6749 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
6750 const char *tag_bis, GNode * node)
6759 const gchar *meanstr;
6760 const gchar *namestr;
6762 /* checking the whole ---- atom size for consistency */
6763 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
6764 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
6768 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
6770 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
6774 meansize = QT_UINT32 (mean->data);
6775 if (meansize <= 12) {
6776 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
6779 meanstr = ((gchar *) mean->data) + 12;
6781 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
6783 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
6787 namesize = QT_UINT32 (name->data);
6788 if (namesize <= 12) {
6789 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
6792 namestr = ((gchar *) name->data) + 12;
6799 * uint24 - data type
6803 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
6805 GST_WARNING_OBJECT (demux, "No data atom in this tag");
6808 datasize = QT_UINT32 (data->data);
6809 if (datasize <= 16) {
6810 GST_WARNING_OBJECT (demux, "Data atom too small");
6813 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
6815 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
6816 if (strncmp (namestr, "replaygain_track_gain", namesize - 12) == 0) {
6817 qtdemux_add_double_tag_from_str (demux,
6818 GST_TAG_TRACK_GAIN, ((guint8 *) data->data) + 16, datasize - 16);
6820 } else if (strncmp (namestr, "replaygain_track_peak", namesize - 12) == 0) {
6821 qtdemux_add_double_tag_from_str (demux,
6822 GST_TAG_TRACK_PEAK, ((guint8 *) data->data) + 16, datasize - 16);
6824 } else if (strncmp (namestr, "replaygain_album_gain", namesize - 12) == 0) {
6825 qtdemux_add_double_tag_from_str (demux,
6826 GST_TAG_ALBUM_GAIN, ((guint8 *) data->data) + 16, datasize - 16);
6828 } else if (strncmp (namestr, "replaygain_album_peak", namesize - 12) == 0) {
6829 qtdemux_add_double_tag_from_str (demux,
6830 GST_TAG_ALBUM_PEAK, ((guint8 *) data->data) + 16, datasize - 16);
6848 meanstr_dbg = g_strndup (meanstr, meansize - 12);
6849 namestr_dbg = g_strndup (namestr, namesize - 12);
6851 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
6852 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
6854 g_free (namestr_dbg);
6855 g_free (meanstr_dbg);
6860 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
6861 const char *tag, const char *tag_bis, GNode * node);
6864 FOURCC_pcst -> if media is a podcast -> bool
6865 FOURCC_cpil -> if media is part of a compilation -> bool
6866 FOURCC_pgap -> if media is part of a gapless context -> bool
6867 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
6873 const gchar *gst_tag;
6874 const gchar *gst_tag_bis;
6875 const GstQTDemuxAddTagFunc func;
6878 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
6879 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
6880 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
6881 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
6882 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
6883 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
6884 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
6885 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
6886 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
6887 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
6888 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
6889 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
6890 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
6891 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
6892 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
6893 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
6894 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
6895 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
6896 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
6897 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
6898 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
6899 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
6900 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
6901 qtdemux_tag_add_num}, {
6902 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
6903 qtdemux_tag_add_num}, {
6904 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
6905 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
6906 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
6907 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
6908 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
6909 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
6910 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
6911 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
6912 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
6913 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
6914 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
6915 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
6916 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
6917 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
6918 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
6919 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
6920 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
6921 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
6922 qtdemux_tag_add_classification}, {
6924 /* This is a special case, some tags are stored in this
6925 * 'reverse dns naming', according to:
6926 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
6929 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}
6933 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
6945 len = QT_UINT32 (data);
6946 buf = gst_buffer_new_and_alloc (len);
6947 memcpy (GST_BUFFER_DATA (buf), data, len);
6949 /* heuristic to determine style of tag */
6950 if (QT_FOURCC (data + 4) == FOURCC_____ ||
6951 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
6953 else if (demux->major_brand == FOURCC_qt__)
6954 style = "quicktime";
6955 /* fall back to assuming iso/3gp tag style */
6959 /* santize the name for the caps. */
6960 for (i = 0; i < 4; i++) {
6961 guint8 d = data[4 + i];
6962 if (g_ascii_isalnum (d))
6963 ndata[i] = g_ascii_tolower (d);
6968 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
6969 ndata[0], ndata[1], ndata[2], ndata[3]);
6970 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
6972 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
6973 gst_buffer_set_caps (buf, caps);
6974 gst_caps_unref (caps);
6975 g_free (media_type);
6977 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
6978 GST_BUFFER_SIZE (buf), caps);
6980 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
6981 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
6982 gst_buffer_unref (buf);
6986 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
6994 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
6996 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
6998 GST_LOG_OBJECT (qtdemux, "no ilst");
7003 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
7006 GST_DEBUG_OBJECT (qtdemux, "new tag list");
7007 qtdemux->tag_list = gst_tag_list_new ();
7010 while (i < G_N_ELEMENTS (add_funcs)) {
7011 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
7015 len = QT_UINT32 (node->data);
7017 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
7018 GST_FOURCC_ARGS (add_funcs[i].fourcc));
7020 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
7021 add_funcs[i].gst_tag_bis, node);
7023 g_node_destroy (node);
7029 /* parsed nodes have been removed, pass along remainder as blob */
7030 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
7031 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
7033 /* parse up XMP_ node if existing */
7034 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
7037 GstTagList *taglist;
7039 buf = gst_buffer_new ();
7040 GST_BUFFER_DATA (buf) = ((guint8 *) xmp_->data) + 8;
7041 GST_BUFFER_SIZE (buf) = QT_UINT32 ((guint8 *) xmp_->data) - 8;
7043 taglist = gst_tag_list_from_xmp_buffer (buf);
7044 gst_buffer_unref (buf);
7046 qtdemux_handle_xmp_taglist (qtdemux, taglist);
7048 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
7055 GstStructure *structure; /* helper for sort function */
7057 guint min_req_bitrate;
7058 guint min_req_qt_version;
7062 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
7064 GstQtReference *ref_a = (GstQtReference *) a;
7065 GstQtReference *ref_b = (GstQtReference *) b;
7067 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
7068 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
7070 /* known bitrates go before unknown; higher bitrates go first */
7071 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
7074 /* sort the redirects and post a message for the application.
7077 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
7079 GstQtReference *best;
7082 GValue list_val = { 0, };
7085 g_assert (references != NULL);
7087 references = g_list_sort (references, qtdemux_redirects_sort_func);
7089 best = (GstQtReference *) references->data;
7091 g_value_init (&list_val, GST_TYPE_LIST);
7093 for (l = references; l != NULL; l = l->next) {
7094 GstQtReference *ref = (GstQtReference *) l->data;
7095 GValue struct_val = { 0, };
7097 ref->structure = gst_structure_new ("redirect",
7098 "new-location", G_TYPE_STRING, ref->location, NULL);
7100 if (ref->min_req_bitrate > 0) {
7101 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
7102 ref->min_req_bitrate, NULL);
7105 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
7106 g_value_set_boxed (&struct_val, ref->structure);
7107 gst_value_list_append_value (&list_val, &struct_val);
7108 g_value_unset (&struct_val);
7109 /* don't free anything here yet, since we need best->structure below */
7112 g_assert (best != NULL);
7113 s = gst_structure_copy (best->structure);
7115 if (g_list_length (references) > 1) {
7116 gst_structure_set_value (s, "locations", &list_val);
7119 g_value_unset (&list_val);
7121 for (l = references; l != NULL; l = l->next) {
7122 GstQtReference *ref = (GstQtReference *) l->data;
7124 gst_structure_free (ref->structure);
7125 g_free (ref->location);
7128 g_list_free (references);
7130 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
7131 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
7132 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
7133 qtdemux->posted_redirect = TRUE;
7136 /* look for redirect nodes, collect all redirect information and
7140 qtdemux_parse_redirects (GstQTDemux * qtdemux)
7142 GNode *rmra, *rmda, *rdrf;
7144 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
7146 GList *redirects = NULL;
7148 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
7150 GstQtReference ref = { NULL, NULL, 0, 0 };
7153 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
7154 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
7155 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
7156 ref.min_req_bitrate);
7159 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
7160 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
7161 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
7163 #ifndef GST_DISABLE_GST_DEBUG
7164 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
7166 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
7168 GST_LOG_OBJECT (qtdemux,
7169 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
7170 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
7171 bitmask, check_type);
7172 if (package == FOURCC_qtim && check_type == 0) {
7173 ref.min_req_qt_version = version;
7177 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
7182 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
7183 ref_data = (guint8 *) rdrf->data + 20;
7184 if (ref_type == FOURCC_alis) {
7185 guint record_len, record_version, fn_len;
7187 /* MacOSX alias record, google for alias-layout.txt */
7188 record_len = QT_UINT16 (ref_data + 4);
7189 record_version = QT_UINT16 (ref_data + 4 + 2);
7190 fn_len = QT_UINT8 (ref_data + 50);
7191 if (record_len > 50 && record_version == 2 && fn_len > 0) {
7192 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
7194 } else if (ref_type == FOURCC_url_) {
7195 ref.location = g_strdup ((gchar *) ref_data);
7197 GST_DEBUG_OBJECT (qtdemux,
7198 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
7199 GST_FOURCC_ARGS (ref_type));
7201 if (ref.location != NULL) {
7202 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
7203 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
7205 GST_WARNING_OBJECT (qtdemux,
7206 "Failed to extract redirect location from rdrf atom");
7210 /* look for others */
7211 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
7214 if (redirects != NULL) {
7215 qtdemux_process_redirects (qtdemux, redirects);
7222 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
7227 tags = gst_tag_list_new ();
7229 if (qtdemux->major_brand == FOURCC_mjp2)
7230 fmt = "Motion JPEG 2000";
7231 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
7233 else if (qtdemux->major_brand == FOURCC_qt__)
7236 fmt = "ISO MP4/M4A";
7238 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
7239 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
7241 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
7247 /* we have read th complete moov node now.
7248 * This function parses all of the relevant info, creates the traks and
7249 * prepares all data structures for playback
7252 qtdemux_parse_tree (GstQTDemux * qtdemux)
7260 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
7262 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
7263 return qtdemux_parse_redirects (qtdemux);
7266 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
7268 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
7269 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
7270 } else if (version == 0) {
7271 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
7272 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
7274 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
7278 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
7279 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
7281 /* set duration in the segment info */
7282 gst_qtdemux_get_duration (qtdemux, &duration);
7283 gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
7285 /* parse all traks */
7286 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
7288 qtdemux_parse_trak (qtdemux, trak);
7289 /* iterate all siblings */
7290 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
7292 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7294 /* find and push tags, we do this after adding the pads so we can push the
7295 * tags downstream as well. */
7296 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
7298 qtdemux_parse_udta (qtdemux, udta);
7300 GST_LOG_OBJECT (qtdemux, "No udta node found.");
7303 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
7305 /* check if we should post a redirect in case there is a single trak
7306 * and it is a redirecting trak */
7307 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7310 qtdemux_post_global_tags (qtdemux);
7312 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7313 "an external content");
7314 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7315 gst_structure_new ("redirect",
7316 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7318 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7319 qtdemux->posted_redirect = TRUE;
7325 /* taken from ffmpeg */
7327 get_size (guint8 * ptr, guint8 ** end)
7336 len = (len << 7) | (c & 0x7f);
7345 /* this can change the codec originally present in @list */
7347 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
7348 GNode * esds, GstTagList * list)
7350 int len = QT_UINT32 (esds->data);
7351 guint8 *ptr = esds->data;
7352 guint8 *end = ptr + len;
7354 guint8 *data_ptr = NULL;
7356 guint8 object_type_id = 0;
7357 const char *codec_name = NULL;
7358 GstCaps *caps = NULL;
7360 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
7362 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
7365 tag = QT_UINT8 (ptr);
7366 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
7368 len = get_size (ptr, &ptr);
7369 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
7373 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
7374 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
7378 guint max_bitrate, avg_bitrate;
7380 object_type_id = QT_UINT8 (ptr);
7381 max_bitrate = QT_UINT32 (ptr + 5);
7382 avg_bitrate = QT_UINT32 (ptr + 9);
7383 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
7384 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
7385 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
7386 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
7387 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
7388 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
7389 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7390 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
7392 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
7393 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7400 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
7406 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
7410 GST_ERROR_OBJECT (qtdemux, "parse error");
7415 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
7416 * in use, and should also be used to override some other parameters for some
7418 switch (object_type_id) {
7419 case 0x20: /* MPEG-4 */
7420 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
7421 * profile_and_level_indication */
7422 if (data_ptr != NULL && data_len >= 5 &&
7423 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
7424 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
7425 data_ptr + 4, data_len - 4);
7427 break; /* Nothing special needed here */
7428 case 0x21: /* H.264 */
7429 codec_name = "H.264 / AVC";
7430 caps = gst_caps_new_simple ("video/x-h264", NULL);
7432 case 0x40: /* AAC (any) */
7433 case 0x66: /* AAC Main */
7434 case 0x67: /* AAC LC */
7435 case 0x68: /* AAC SSR */
7436 /* Override channels and rate based on the codec_data, as it's often
7438 /* Only do so for basic setup without HE-AAC extension */
7439 if (data_ptr && data_len == 2) {
7440 guint channels, rateindex, rate;
7442 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
7443 channels = (data_ptr[1] & 0x7f) >> 3;
7444 if (channels > 0 && channels < 7) {
7445 stream->n_channels = channels;
7446 } else if (channels == 7) {
7447 stream->n_channels = 8;
7450 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
7451 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
7453 stream->rate = rate;
7456 /* Set level and profile if possible */
7457 if (data_ptr != NULL && data_len >= 2) {
7458 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
7459 data_ptr, data_len);
7462 case 0x60: /* MPEG-2, various profiles */
7468 codec_name = "MPEG-2 video";
7470 gst_caps_unref (stream->caps);
7471 stream->caps = gst_caps_new_simple ("video/mpeg",
7472 "mpegversion", G_TYPE_INT, 2,
7473 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7475 case 0x69: /* MP3 has two different values, accept either */
7477 /* change to mpeg1 layer 3 audio */
7478 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
7479 "mpegversion", G_TYPE_INT, 1, NULL);
7480 codec_name = "MPEG-1 layer 3";
7482 case 0x6A: /* MPEG-1 */
7483 codec_name = "MPEG-1 video";
7485 gst_caps_unref (stream->caps);
7486 stream->caps = gst_caps_new_simple ("video/mpeg",
7487 "mpegversion", G_TYPE_INT, 1,
7488 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7490 case 0x6C: /* MJPEG */
7491 caps = gst_caps_new_simple ("image/jpeg", NULL);
7492 codec_name = "Motion-JPEG";
7494 case 0x6D: /* PNG */
7495 caps = gst_caps_new_simple ("image/png", NULL);
7496 codec_name = "PNG still images";
7498 case 0x6E: /* JPEG2000 */
7499 codec_name = "JPEG-2000";
7500 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
7502 case 0xA4: /* Dirac */
7503 codec_name = "Dirac";
7504 caps = gst_caps_new_simple ("video/x-dirac", NULL);
7506 case 0xA5: /* AC3 */
7507 codec_name = "AC-3 audio";
7508 caps = gst_caps_new_simple ("audio/x-ac3",
7509 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
7511 case 0xE1: /* QCELP */
7512 /* QCELP, the codec_data is a riff tag (little endian) with
7513 * 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). */
7514 caps = gst_caps_new_simple ("audio/qcelp", NULL);
7515 codec_name = "QCELP";
7521 /* If we have a replacement caps, then change our caps for this stream */
7523 gst_caps_unref (stream->caps);
7524 stream->caps = caps;
7527 if (codec_name && list)
7528 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7529 GST_TAG_AUDIO_CODEC, codec_name, NULL);
7531 /* Add the codec_data attribute to caps, if we have it */
7535 buffer = gst_buffer_new_and_alloc (data_len);
7536 memcpy (GST_BUFFER_DATA (buffer), data_ptr, data_len);
7538 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
7539 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
7541 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
7543 gst_buffer_unref (buffer);
7548 #define _codec(name) \
7551 *codec_name = g_strdup (name); \
7556 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
7557 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
7560 const GstStructure *s;
7564 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
7565 _codec ("PNG still images");
7566 caps = gst_caps_new_simple ("image/png", NULL);
7568 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
7569 _codec ("JPEG still images");
7570 caps = gst_caps_new_simple ("image/jpeg", NULL);
7572 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
7573 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
7574 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
7575 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
7576 _codec ("Motion-JPEG");
7577 caps = gst_caps_new_simple ("image/jpeg", NULL);
7579 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
7580 _codec ("Motion-JPEG format B");
7581 caps = gst_caps_new_simple ("video/x-mjpeg-b", NULL);
7583 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
7584 _codec ("JPEG-2000");
7585 /* override to what it should be according to spec, avoid palette_data */
7586 stream->bits_per_sample = 24;
7587 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
7589 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
7590 _codec ("Sorensen video v.3");
7591 caps = gst_caps_new_simple ("video/x-svq",
7592 "svqversion", G_TYPE_INT, 3, NULL);
7594 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
7595 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
7596 _codec ("Sorensen video v.1");
7597 caps = gst_caps_new_simple ("video/x-svq",
7598 "svqversion", G_TYPE_INT, 1, NULL);
7600 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
7604 _codec ("Raw RGB video");
7605 bps = QT_UINT16 (stsd_data + 98);
7606 /* set common stuff */
7607 caps = gst_caps_new_simple ("video/x-raw-rgb",
7608 "endianness", G_TYPE_INT, G_BYTE_ORDER, "depth", G_TYPE_INT, bps,
7613 gst_caps_set_simple (caps,
7614 "bpp", G_TYPE_INT, 16,
7615 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
7616 "red_mask", G_TYPE_INT, 0x7c00,
7617 "green_mask", G_TYPE_INT, 0x03e0,
7618 "blue_mask", G_TYPE_INT, 0x001f, NULL);
7621 gst_caps_set_simple (caps,
7622 "bpp", G_TYPE_INT, 16,
7623 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
7624 "red_mask", G_TYPE_INT, 0xf800,
7625 "green_mask", G_TYPE_INT, 0x07e0,
7626 "blue_mask", G_TYPE_INT, 0x001f, NULL);
7629 gst_caps_set_simple (caps,
7630 "bpp", G_TYPE_INT, 24,
7631 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
7632 "red_mask", G_TYPE_INT, 0xff0000,
7633 "green_mask", G_TYPE_INT, 0x00ff00,
7634 "blue_mask", G_TYPE_INT, 0x0000ff, NULL);
7637 gst_caps_set_simple (caps,
7638 "bpp", G_TYPE_INT, 32,
7639 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
7640 "alpha_mask", G_TYPE_INT, 0xff000000,
7641 "red_mask", G_TYPE_INT, 0x00ff0000,
7642 "green_mask", G_TYPE_INT, 0x0000ff00,
7643 "blue_mask", G_TYPE_INT, 0x000000ff, NULL);
7651 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
7652 _codec ("Raw planar YUV 4:2:0");
7653 caps = gst_caps_new_simple ("video/x-raw-yuv",
7654 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
7657 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
7658 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
7659 _codec ("Raw packed YUV 4:2:2");
7660 caps = gst_caps_new_simple ("video/x-raw-yuv",
7661 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'),
7664 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
7665 _codec ("Raw packed YUV 4:2:2");
7666 caps = gst_caps_new_simple ("video/x-raw-yuv",
7667 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'),
7670 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
7671 _codec ("Raw packed YUV 10-bit 4:2:2");
7672 caps = gst_caps_new_simple ("video/x-raw-yuv",
7673 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('v', '2', '1', '0'),
7676 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
7677 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
7678 _codec ("MPEG-1 video");
7679 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
7680 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7682 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
7683 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
7684 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
7685 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
7686 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
7687 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
7688 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
7689 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
7690 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
7691 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
7692 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
7693 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
7694 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
7695 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
7696 _codec ("MPEG-2 video");
7697 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
7698 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7700 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
7701 _codec ("GIF still images");
7702 caps = gst_caps_new_simple ("image/gif", NULL);
7704 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
7705 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
7706 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
7707 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
7709 /* ffmpeg uses the height/width props, don't know why */
7710 caps = gst_caps_new_simple ("video/x-h263", NULL);
7712 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
7713 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
7714 _codec ("MPEG-4 video");
7715 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
7716 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7718 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
7719 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
7720 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
7721 caps = gst_caps_new_simple ("video/x-msmpeg",
7722 "msmpegversion", G_TYPE_INT, 43, NULL);
7724 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
7725 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
7726 _codec ("3ivX video");
7727 caps = gst_caps_new_simple ("video/x-3ivx", NULL);
7729 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
7731 caps = gst_caps_new_simple ("video/x-divx",
7732 "divxversion", G_TYPE_INT, 3, NULL);
7734 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
7735 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
7737 caps = gst_caps_new_simple ("video/x-divx",
7738 "divxversion", G_TYPE_INT, 4, NULL);
7740 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
7742 caps = gst_caps_new_simple ("video/x-divx",
7743 "divxversion", G_TYPE_INT, 5, NULL);
7745 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
7746 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
7747 _codec ("XVID MPEG-4");
7748 caps = gst_caps_new_simple ("video/x-xvid", NULL);
7751 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
7752 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
7753 caps = gst_caps_new_simple ("video/mpeg",
7754 "mpegversion", G_TYPE_INT, 4, NULL);
7756 *codec_name = g_strdup ("FFmpeg MPEG-4");
7759 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
7761 caps = gst_caps_new_simple ("video/x-cinepak", NULL);
7763 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
7764 _codec ("Apple QuickDraw");
7765 caps = gst_caps_new_simple ("video/x-qdrw", NULL);
7767 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
7768 _codec ("Apple video");
7769 caps = gst_caps_new_simple ("video/x-apple-video", NULL);
7771 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
7772 _codec ("H.264 / AVC");
7773 caps = gst_caps_new_simple ("video/x-h264", NULL);
7775 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
7776 _codec ("Run-length encoding");
7777 caps = gst_caps_new_simple ("video/x-rle",
7778 "layout", G_TYPE_STRING, "quicktime", NULL);
7780 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
7781 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
7782 _codec ("Indeo Video 3");
7783 caps = gst_caps_new_simple ("video/x-indeo",
7784 "indeoversion", G_TYPE_INT, 3, NULL);
7786 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
7787 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
7788 _codec ("Intel Video 4");
7789 caps = gst_caps_new_simple ("video/x-indeo",
7790 "indeoversion", G_TYPE_INT, 4, NULL);
7792 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
7793 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
7794 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
7795 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
7796 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
7797 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
7798 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
7799 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
7800 _codec ("DV Video");
7801 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
7802 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7804 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
7805 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
7806 _codec ("DVCPro50 Video");
7807 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
7808 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7810 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
7811 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
7812 _codec ("DVCProHD Video");
7813 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
7814 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
7816 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
7817 _codec ("Apple Graphics (SMC)");
7818 caps = gst_caps_new_simple ("video/x-smc", NULL);
7820 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
7822 caps = gst_caps_new_simple ("video/x-vp3", NULL);
7824 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
7826 caps = gst_caps_new_simple ("video/x-theora", NULL);
7827 /* theora uses one byte of padding in the data stream because it does not
7828 * allow 0 sized packets while theora does */
7829 stream->padding = 1;
7831 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
7833 caps = gst_caps_new_simple ("video/x-dirac", NULL);
7835 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
7836 _codec ("TIFF still images");
7837 caps = gst_caps_new_simple ("image/tiff", NULL);
7839 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
7840 _codec ("Apple Intermediate Codec");
7841 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
7843 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
7844 _codec ("AVID DNxHD");
7845 caps = gst_caps_from_string ("video/x-dnxhd");
7847 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
7849 caps = gst_caps_from_string ("video/x-vp8");
7851 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
7856 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
7857 GST_FOURCC_ARGS (fourcc));
7858 caps = gst_caps_new_simple (s, NULL);
7863 /* enable clipping for raw video streams */
7864 s = gst_caps_get_structure (caps, 0);
7865 name = gst_structure_get_name (s);
7866 if (g_str_has_prefix (name, "video/x-raw-")) {
7867 stream->need_clip = TRUE;
7873 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
7874 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
7877 const GstStructure *s;
7881 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
7884 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
7885 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
7886 _codec ("Raw 8-bit PCM audio");
7887 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 8,
7888 "depth", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
7890 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
7891 endian = G_BIG_ENDIAN;
7893 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
7899 endian = G_LITTLE_ENDIAN;
7901 depth = stream->bytes_per_packet * 8;
7902 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
7905 caps = gst_caps_new_simple ("audio/x-raw-int",
7906 "width", G_TYPE_INT, depth, "depth", G_TYPE_INT, depth,
7907 "endianness", G_TYPE_INT, endian,
7908 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
7911 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
7912 _codec ("Raw 64-bit floating-point audio");
7913 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 64,
7914 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
7916 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
7917 _codec ("Raw 32-bit floating-point audio");
7918 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 32,
7919 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
7922 _codec ("Raw 24-bit PCM audio");
7923 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
7925 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 24,
7926 "depth", G_TYPE_INT, 24,
7927 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
7928 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
7930 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
7931 _codec ("Raw 32-bit PCM audio");
7932 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 32,
7933 "depth", G_TYPE_INT, 32,
7934 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
7935 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
7937 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
7938 _codec ("Mu-law audio");
7939 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
7941 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
7942 _codec ("A-law audio");
7943 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
7947 _codec ("Microsoft ADPCM");
7948 /* Microsoft ADPCM-ACM code 2 */
7949 caps = gst_caps_new_simple ("audio/x-adpcm",
7950 "layout", G_TYPE_STRING, "microsoft", NULL);
7954 _codec ("DVI/IMA ADPCM");
7955 caps = gst_caps_new_simple ("audio/x-adpcm",
7956 "layout", G_TYPE_STRING, "dvi", NULL);
7960 _codec ("DVI/Intel IMA ADPCM");
7961 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
7962 caps = gst_caps_new_simple ("audio/x-adpcm",
7963 "layout", G_TYPE_STRING, "quicktime", NULL);
7967 /* MPEG layer 3, CBR only (pre QT4.1) */
7968 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
7969 _codec ("MPEG-1 layer 3");
7970 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
7971 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
7972 "mpegversion", G_TYPE_INT, 1, NULL);
7975 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
7976 _codec ("AC-3 audio");
7977 caps = gst_caps_new_simple ("audio/x-ac3",
7978 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
7979 stream->sampled = TRUE;
7981 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
7983 caps = gst_caps_new_simple ("audio/x-mace",
7984 "maceversion", G_TYPE_INT, 3, NULL);
7986 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
7988 caps = gst_caps_new_simple ("audio/x-mace",
7989 "maceversion", G_TYPE_INT, 6, NULL);
7991 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
7993 caps = gst_caps_new_simple ("application/ogg", NULL);
7995 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
7996 _codec ("DV audio");
7997 caps = gst_caps_new_simple ("audio/x-dv", NULL);
7999 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
8000 _codec ("MPEG-4 AAC audio");
8001 caps = gst_caps_new_simple ("audio/mpeg",
8002 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
8003 "stream-format", G_TYPE_STRING, "raw", NULL);
8005 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
8006 _codec ("QDesign Music");
8007 caps = gst_caps_new_simple ("audio/x-qdm", NULL);
8009 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
8010 _codec ("QDesign Music v.2");
8011 /* FIXME: QDesign music version 2 (no constant) */
8013 caps = gst_caps_new_simple ("audio/x-qdm2",
8014 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
8015 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
8016 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
8018 caps = gst_caps_new_simple ("audio/x-qdm2", NULL);
8021 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
8022 _codec ("GSM audio");
8023 caps = gst_caps_new_simple ("audio/x-gsm", NULL);
8025 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
8026 _codec ("AMR audio");
8027 caps = gst_caps_new_simple ("audio/AMR", NULL);
8029 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
8030 _codec ("AMR-WB audio");
8031 caps = gst_caps_new_simple ("audio/AMR-WB", NULL);
8033 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
8034 _codec ("Quicktime IMA ADPCM");
8035 caps = gst_caps_new_simple ("audio/x-adpcm",
8036 "layout", G_TYPE_STRING, "quicktime", NULL);
8038 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
8039 _codec ("Apple lossless audio");
8040 caps = gst_caps_new_simple ("audio/x-alac", NULL);
8042 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
8043 _codec ("QualComm PureVoice");
8044 caps = gst_caps_from_string ("audio/qcelp");
8046 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
8052 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
8053 GST_FOURCC_ARGS (fourcc));
8054 caps = gst_caps_new_simple (s, NULL);
8059 /* enable clipping for raw audio streams */
8060 s = gst_caps_get_structure (caps, 0);
8061 name = gst_structure_get_name (s);
8062 if (g_str_has_prefix (name, "audio/x-raw-")) {
8063 stream->need_clip = TRUE;
8069 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
8070 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
8074 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
8077 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
8078 _codec ("DVD subtitle");
8079 caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
8081 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
8082 _codec ("Quicktime timed text");
8084 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
8085 _codec ("3GPP timed text");
8087 caps = gst_caps_new_simple ("text/plain", NULL);
8088 /* actual text piece needs to be extracted */
8089 stream->need_process = TRUE;
8095 s = g_strdup_printf ("text/x-gst-fourcc-%" GST_FOURCC_FORMAT,
8096 GST_FOURCC_ARGS (fourcc));
8097 caps = gst_caps_new_simple (s, NULL);