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 /* For converting qt creation times to unix epoch times */
83 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
84 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
85 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
86 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
88 GST_DEBUG_CATEGORY (qtdemux_debug);
90 /*typedef struct _QtNode QtNode; */
91 typedef struct _QtDemuxSegment QtDemuxSegment;
92 typedef struct _QtDemuxSample QtDemuxSample;
101 struct _QtDemuxSample
104 gint32 pts_offset; /* Add this value to timestamp to get the pts */
106 guint64 timestamp; /* DTS In mov time */
107 guint32 duration; /* In mov time */
108 gboolean keyframe; /* TRUE when this packet is a keyframe */
111 /* timestamp is the DTS */
112 #define QTSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
113 GST_SECOND, (stream)->timescale)
114 /* timestamp + offset is the PTS */
115 #define QTSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
116 (sample)->pts_offset, GST_SECOND, (stream)->timescale)
117 /* timestamp + duration - dts is the duration */
118 #define QTSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
119 (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
120 /* timestamp + offset + duration - pts is the duration */
121 #define QTSAMPLE_DUR_PTS(stream,sample,pts) (gst_util_uint64_scale ((sample)->timestamp + \
122 (sample)->pts_offset + (sample)->duration, GST_SECOND, (stream)->timescale) - (pts));
124 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
127 * Quicktime has tracks and segments. A track is a continuous piece of
128 * multimedia content. The track is not always played from start to finish but
129 * instead, pieces of the track are 'cut out' and played in sequence. This is
130 * what the segments do.
132 * Inside the track we have keyframes (K) and delta frames. The track has its
133 * own timing, which starts from 0 and extends to end. The position in the track
134 * is called the media_time.
136 * The segments now describe the pieces that should be played from this track
137 * and are basically tupples of media_time/duration/rate entries. We can have
138 * multiple segments and they are all played after one another. An example:
140 * segment 1: media_time: 1 second, duration: 1 second, rate 1
141 * segment 2: media_time: 3 second, duration: 2 second, rate 2
143 * To correctly play back this track, one must play: 1 second of media starting
144 * from media_time 1 followed by 2 seconds of media starting from media_time 3
147 * Each of the segments will be played at a specific time, the first segment at
148 * time 0, the second one after the duration of the first one, etc.. Note that
149 * the time in resulting playback is not identical to the media_time of the
152 * Visually, assuming the track has 4 second of media_time:
155 * .-----------------------------------------------------------.
156 * track: | K.....K.........K........K.......K.......K...........K... |
157 * '-----------------------------------------------------------'
159 * .------------^ ^ .----------^ ^
160 * / .-------------' / .------------------'
162 * .--------------. .--------------.
163 * | segment 1 | | segment 2 |
164 * '--------------' '--------------'
166 * The challenge here is to cut out the right pieces of the track for each of
167 * the playback segments. This fortunatly can easily be done with the SEGMENT
168 * events of gstreamer.
170 * For playback of segment 1, we need to provide the decoder with the keyframe
171 * (a), in the above figure, but we must instruct it only to output the decoded
172 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
173 * position set to the time of the segment: 0.
175 * We then proceed to push data from keyframe (a) to frame (b). The decoder
176 * decodes but clips all before media_time 1.
178 * After finishing a segment, we push out a new SEGMENT event with the clipping
179 * boundaries of the new data.
181 * This is a good usecase for the GStreamer accumulated SEGMENT events.
184 struct _QtDemuxSegment
186 /* global time and duration, all gst time */
190 /* media time of trak, all gst time */
196 struct _QtDemuxStream
205 /* if the stream has a redirect URI in its headers, we store it here */
212 guint64 duration; /* in timescale */
216 gchar lang_id[4]; /* ISO 639-2T language code */
220 QtDemuxSample *samples;
221 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
222 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
223 the framerate, in timescale units */
225 /* if we use chunks or samples */
237 /* Numerator/denominator framerate */
240 guint16 bits_per_sample;
241 guint16 color_table_id;
246 guint samples_per_packet;
247 guint samples_per_frame;
248 guint bytes_per_packet;
249 guint bytes_per_sample;
250 guint bytes_per_frame;
253 /* when a discontinuity is pending */
256 /* list of buffers to push first */
259 /* if we need to clip this buffer. This is only needed for uncompressed
263 /* buffer needs some custom processing, e.g. subtitles */
264 gboolean need_process;
266 /* current position */
267 guint32 segment_index;
268 guint32 sample_index;
269 guint64 time_position; /* in gst time */
271 /* the Gst segment we are processing out, used for clipping */
274 /* last GstFlowReturn */
275 GstFlowReturn last_ret;
277 /* quicktime segments */
279 QtDemuxSegment *segments;
284 GstTagList *pending_tags;
285 gboolean send_global_tags;
287 GstEvent *pending_event;
297 gboolean chunks_are_chunks;
301 GstByteReader co_chunk;
303 guint32 current_chunk;
305 guint32 samples_per_chunk;
306 guint32 stco_sample_index;
308 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
311 guint32 n_samples_per_chunk;
312 guint32 stsc_chunk_index;
313 guint32 stsc_sample_index;
314 guint64 chunk_offset;
317 guint32 stts_samples;
318 guint32 n_sample_times;
319 guint32 stts_sample_index;
321 guint32 stts_duration;
323 gboolean stss_present;
324 guint32 n_sample_syncs;
327 gboolean stps_present;
328 guint32 n_sample_partial_syncs;
331 gboolean ctts_present;
332 guint32 n_composition_times;
334 guint32 ctts_sample_index;
339 gboolean parsed_trex;
340 guint32 def_sample_duration;
341 guint32 def_sample_size;
342 guint32 def_sample_flags;
347 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
348 QTDEMUX_STATE_HEADER, /* Parsing the header */
349 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
350 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
353 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
354 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
355 guint32 fourcc, GstByteReader * parser);
356 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
357 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
358 guint32 fourcc, GstByteReader * parser);
360 static GstStaticPadTemplate gst_qtdemux_sink_template =
361 GST_STATIC_PAD_TEMPLATE ("sink",
364 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
368 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
369 GST_STATIC_PAD_TEMPLATE ("video_%02d",
372 GST_STATIC_CAPS_ANY);
374 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
375 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
378 GST_STATIC_CAPS_ANY);
380 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
381 GST_STATIC_PAD_TEMPLATE ("subtitle_%02d",
384 GST_STATIC_CAPS_ANY);
386 GST_BOILERPLATE (GstQTDemux, gst_qtdemux, GstQTDemux, GST_TYPE_ELEMENT);
388 static void gst_qtdemux_dispose (GObject * object);
391 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
394 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
395 QtDemuxStream * str, gint64 media_offset);
397 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
398 static GstIndex *gst_qtdemux_get_index (GstElement * element);
399 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
400 GstStateChange transition);
401 static gboolean qtdemux_sink_activate (GstPad * sinkpad);
402 static gboolean qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active);
403 static gboolean qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active);
405 static void gst_qtdemux_loop (GstPad * pad);
406 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf);
407 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstEvent * event);
409 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
410 const guint8 * buffer, guint length);
411 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
412 const guint8 * buffer, guint length);
413 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
415 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
416 QtDemuxStream * stream, GNode * esds, GstTagList * list);
417 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
418 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
419 gchar ** codec_name);
420 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
421 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
422 gchar ** codec_name);
423 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
424 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
425 gchar ** codec_name);
426 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
427 QtDemuxStream * stream, guint32 n);
428 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
431 gst_qtdemux_base_init (gpointer klass)
433 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
435 gst_element_class_add_pad_template (element_class,
436 gst_static_pad_template_get (&gst_qtdemux_sink_template));
437 gst_element_class_add_pad_template (element_class,
438 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
439 gst_element_class_add_pad_template (element_class,
440 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
441 gst_element_class_add_pad_template (element_class,
442 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
443 gst_element_class_set_details_simple (element_class, "QuickTime demuxer",
445 "Demultiplex a QuickTime file into audio and video streams",
446 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
448 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
452 gst_qtdemux_class_init (GstQTDemuxClass * klass)
454 GObjectClass *gobject_class;
455 GstElementClass *gstelement_class;
457 gobject_class = (GObjectClass *) klass;
458 gstelement_class = (GstElementClass *) klass;
460 parent_class = g_type_class_peek_parent (klass);
462 gobject_class->dispose = gst_qtdemux_dispose;
464 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
466 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
467 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
469 gst_tag_register_musicbrainz_tags ();
473 gst_qtdemux_init (GstQTDemux * qtdemux, GstQTDemuxClass * klass)
476 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
477 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
478 gst_pad_set_activatepull_function (qtdemux->sinkpad,
479 qtdemux_sink_activate_pull);
480 gst_pad_set_activatepush_function (qtdemux->sinkpad,
481 qtdemux_sink_activate_push);
482 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
483 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
484 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
486 qtdemux->state = QTDEMUX_STATE_INITIAL;
487 qtdemux->pullbased = FALSE;
488 qtdemux->posted_redirect = FALSE;
489 qtdemux->neededbytes = 16;
491 qtdemux->adapter = gst_adapter_new ();
493 qtdemux->first_mdat = -1;
494 qtdemux->got_moov = FALSE;
495 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
496 qtdemux->mdatbuffer = NULL;
497 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
501 gst_qtdemux_dispose (GObject * object)
503 GstQTDemux *qtdemux = GST_QTDEMUX (object);
505 if (qtdemux->adapter) {
506 g_object_unref (G_OBJECT (qtdemux->adapter));
507 qtdemux->adapter = NULL;
510 G_OBJECT_CLASS (parent_class)->dispose (object);
514 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
516 if (qtdemux->posted_redirect) {
517 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
518 (_("This file contains no playable streams.")),
519 ("no known streams found, a redirect message has been posted"));
521 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
522 (_("This file contains no playable streams.")),
523 ("no known streams found"));
528 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
533 if (G_UNLIKELY (size == 0)) {
535 GstBuffer *tmp = NULL;
537 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
538 if (ret != GST_FLOW_OK)
541 size = QT_UINT32 (GST_BUFFER_DATA (tmp));
542 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
544 gst_buffer_unref (tmp);
547 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
548 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
549 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
550 /* we're pulling header but already got most interesting bits,
551 * so never mind the rest (e.g. tags) (that much) */
552 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
554 return GST_FLOW_UNEXPECTED;
556 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
557 (_("This file is invalid and cannot be played.")),
558 ("atom has bogus size %" G_GUINT64_FORMAT, size));
559 return GST_FLOW_ERROR;
563 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
565 if (G_UNLIKELY (flow != GST_FLOW_OK))
568 /* Catch short reads - we don't want any partial atoms */
569 if (G_UNLIKELY (GST_BUFFER_SIZE (*buf) < size)) {
570 GST_WARNING_OBJECT (qtdemux, "short read: %u < %" G_GUINT64_FORMAT,
571 GST_BUFFER_SIZE (*buf), size);
572 gst_buffer_unref (*buf);
574 return GST_FLOW_UNEXPECTED;
582 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
583 GstFormat dest_format, gint64 * dest_value)
586 QtDemuxStream *stream = gst_pad_get_element_private (pad);
587 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
590 if (stream->subtype != FOURCC_vide) {
595 switch (src_format) {
596 case GST_FORMAT_TIME:
597 switch (dest_format) {
598 case GST_FORMAT_BYTES:{
599 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
603 *dest_value = stream->samples[index].offset;
605 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
606 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
607 GST_TIME_ARGS (src_value), *dest_value);
615 case GST_FORMAT_BYTES:
616 switch (dest_format) {
617 case GST_FORMAT_TIME:{
619 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
626 gst_util_uint64_scale (stream->samples[index].timestamp,
627 GST_SECOND, stream->timescale);
628 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
629 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
630 src_value, GST_TIME_ARGS (*dest_value));
643 gst_object_unref (qtdemux);
649 static const GstQueryType *
650 gst_qtdemux_get_src_query_types (GstPad * pad)
652 static const GstQueryType src_types[] = {
665 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
669 *duration = GST_CLOCK_TIME_NONE;
671 if (qtdemux->duration != 0) {
672 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
673 *duration = gst_util_uint64_scale (qtdemux->duration,
674 GST_SECOND, qtdemux->timescale);
681 gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
683 gboolean res = FALSE;
684 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
686 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
688 switch (GST_QUERY_TYPE (query)) {
689 case GST_QUERY_POSITION:
690 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.last_stop)) {
691 gst_query_set_position (query, GST_FORMAT_TIME,
692 qtdemux->segment.last_stop);
696 case GST_QUERY_DURATION:{
699 gst_query_parse_duration (query, &fmt, NULL);
700 if (fmt == GST_FORMAT_TIME) {
701 gint64 duration = -1;
703 gst_qtdemux_get_duration (qtdemux, &duration);
705 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
711 case GST_QUERY_CONVERT:{
712 GstFormat src_fmt, dest_fmt;
713 gint64 src_value, dest_value = 0;
715 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
717 res = gst_qtdemux_src_convert (pad,
718 src_fmt, src_value, dest_fmt, &dest_value);
720 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
725 case GST_QUERY_FORMATS:
726 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
729 case GST_QUERY_SEEKING:{
733 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
734 if (fmt == GST_FORMAT_TIME) {
735 gint64 duration = -1;
737 gst_qtdemux_get_duration (qtdemux, &duration);
739 if (!qtdemux->pullbased) {
742 /* we might be able with help from upstream */
744 q = gst_query_new_seeking (GST_FORMAT_BYTES);
745 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
746 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
747 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
751 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
757 res = gst_pad_query_default (pad, query);
761 gst_object_unref (qtdemux);
767 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
769 if (G_LIKELY (stream->pad)) {
770 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
771 GST_DEBUG_PAD_NAME (stream->pad));
773 if (G_UNLIKELY (stream->pending_tags)) {
774 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
775 stream->pending_tags);
776 gst_pad_push_event (stream->pad,
777 gst_event_new_tag (stream->pending_tags));
778 stream->pending_tags = NULL;
781 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
782 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
784 gst_pad_push_event (stream->pad,
785 gst_event_new_tag (gst_tag_list_copy (qtdemux->tag_list)));
786 stream->send_global_tags = FALSE;
791 /* push event on all source pads; takes ownership of the event */
793 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
796 gboolean has_valid_stream = FALSE;
797 GstEventType etype = GST_EVENT_TYPE (event);
799 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
800 GST_EVENT_TYPE_NAME (event));
802 for (n = 0; n < qtdemux->n_streams; n++) {
804 QtDemuxStream *stream = qtdemux->streams[n];
806 if ((pad = stream->pad)) {
807 has_valid_stream = TRUE;
809 if (etype == GST_EVENT_EOS) {
810 /* let's not send twice */
811 if (stream->sent_eos)
813 stream->sent_eos = TRUE;
816 gst_pad_push_event (pad, gst_event_ref (event));
820 gst_event_unref (event);
822 /* if it is EOS and there are no pads, post an error */
823 if (!has_valid_stream && etype == GST_EVENT_EOS) {
824 gst_qtdemux_post_no_playable_stream_error (qtdemux);
828 /* push a pending newsegment event, if any from the streaming thread */
830 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
832 if (qtdemux->pending_newsegment) {
833 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
834 qtdemux->pending_newsegment = NULL;
844 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
846 if (s1->timestamp > *media_time)
852 /* find the index of the sample that includes the data for @media_time using a
853 * binary search. Only to be called in optimized cases of linear search below.
855 * Returns the index of the sample.
858 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
861 QtDemuxSample *result;
864 /* convert media_time to mov format */
866 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
868 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
869 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
870 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
872 if (G_LIKELY (result))
873 index = result - str->samples;
882 /* find the index of the sample that includes the data for @media_offset using a
885 * Returns the index of the sample.
888 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
889 QtDemuxStream * str, gint64 media_offset)
891 QtDemuxSample *result = str->samples;
894 if (result == NULL || str->n_samples == 0)
897 if (media_offset == result->offset)
901 while (index < str->n_samples - 1) {
902 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
905 if (media_offset < result->offset)
916 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
921 /* find the index of the sample that includes the data for @media_time using a
922 * linear search, and keeping in mind that not all samples may have been parsed
923 * yet. If possible, it will delegate to binary search.
925 * Returns the index of the sample.
928 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
934 /* convert media_time to mov format */
936 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
938 if (mov_time == str->samples[0].timestamp)
941 /* use faster search if requested time in already parsed range */
942 if (str->stbl_index >= 0 &&
943 mov_time <= str->samples[str->stbl_index].timestamp)
944 return gst_qtdemux_find_index (qtdemux, str, media_time);
946 while (index < str->n_samples - 1) {
947 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
950 if (mov_time < str->samples[index + 1].timestamp)
960 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
965 /* find the index of the keyframe needed to decode the sample at @index
968 * Returns the index of the keyframe.
971 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
974 guint32 new_index = index;
976 if (index >= str->n_samples) {
977 new_index = str->n_samples;
981 /* all keyframes, return index */
982 if (str->all_keyframe) {
987 /* else go back until we have a keyframe */
989 if (str->samples[new_index].keyframe)
999 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1000 "gave %u", index, new_index);
1005 /* find the segment for @time_position for @stream
1007 * Returns -1 if the segment cannot be found.
1010 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1011 guint64 time_position)
1016 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1017 GST_TIME_ARGS (time_position));
1019 /* find segment corresponding to time_position if we are looking
1022 for (i = 0; i < stream->n_segments; i++) {
1023 QtDemuxSegment *segment = &stream->segments[i];
1025 GST_LOG_OBJECT (qtdemux,
1026 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1027 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1029 /* For the last segment we include stop_time in the last segment */
1030 if (i < stream->n_segments - 1) {
1031 if (segment->time <= time_position && time_position < segment->stop_time) {
1032 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1037 if (segment->time <= time_position && time_position <= segment->stop_time) {
1038 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1047 /* move the stream @str to the sample position @index.
1049 * Updates @str->sample_index and marks discontinuity if needed.
1052 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1055 /* no change needed */
1056 if (index == str->sample_index)
1059 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1062 /* position changed, we have a discont */
1063 str->sample_index = index;
1064 /* Each time we move in the stream we store the position where we are
1066 str->from_sample = index;
1067 str->discont = TRUE;
1071 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1072 gint64 * key_time, gint64 * key_offset)
1075 gint64 min_byte_offset = -1;
1078 min_offset = desired_time;
1080 /* for each stream, find the index of the sample in the segment
1081 * and move back to the previous keyframe. */
1082 for (n = 0; n < qtdemux->n_streams; n++) {
1084 guint32 index, kindex;
1086 guint64 media_start;
1089 QtDemuxSegment *seg;
1091 str = qtdemux->streams[n];
1093 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1094 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1096 /* segment not found, continue with normal flow */
1100 /* get segment and time in the segment */
1101 seg = &str->segments[seg_idx];
1102 seg_time = desired_time - seg->time;
1104 /* get the media time in the segment */
1105 media_start = seg->media_start + seg_time;
1107 /* get the index of the sample with media time */
1108 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1109 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
1110 GST_TIME_ARGS (media_start), index);
1112 /* find previous keyframe */
1113 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1115 /* if the keyframe is at a different position, we need to update the
1116 * requested seek time */
1117 if (index != kindex) {
1120 /* get timestamp of keyframe */
1122 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1124 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT,
1125 kindex, GST_TIME_ARGS (media_time));
1127 /* keyframes in the segment get a chance to change the
1128 * desired_offset. keyframes out of the segment are
1130 if (media_time >= seg->media_start) {
1133 /* this keyframe is inside the segment, convert back to
1135 seg_time = (media_time - seg->media_start) + seg->time;
1136 if (seg_time < min_offset)
1137 min_offset = seg_time;
1141 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1142 min_byte_offset = str->samples[index].offset;
1146 *key_time = min_offset;
1148 *key_offset = min_byte_offset;
1152 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1153 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1158 g_return_val_if_fail (format != NULL, FALSE);
1159 g_return_val_if_fail (cur != NULL, FALSE);
1160 g_return_val_if_fail (stop != NULL, FALSE);
1162 if (*format == GST_FORMAT_TIME)
1165 fmt = GST_FORMAT_TIME;
1167 if (cur_type != GST_SEEK_TYPE_NONE)
1168 res = gst_pad_query_convert (pad, *format, *cur, &fmt, cur);
1169 if (res && stop_type != GST_SEEK_TYPE_NONE)
1170 res = gst_pad_query_convert (pad, *format, *stop, &fmt, stop);
1173 *format = GST_FORMAT_TIME;
1178 /* perform seek in push based mode:
1179 find BYTE position to move to based on time and delegate to upstream
1182 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1187 GstSeekType cur_type, stop_type;
1192 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1194 gst_event_parse_seek (event, &rate, &format, &flags,
1195 &cur_type, &cur, &stop_type, &stop);
1197 /* FIXME, always play to the end */
1200 /* only forward streaming and seeking is possible */
1202 goto unsupported_seek;
1204 /* convert to TIME if needed and possible */
1205 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1209 /* find reasonable corresponding BYTE position,
1210 * also try to mind about keyframes, since we can not go back a bit for them
1212 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1217 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1218 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1221 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1222 GST_DEBUG_OBJECT (qtdemux,
1223 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1224 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1225 GST_OBJECT_LOCK (qtdemux);
1226 qtdemux->requested_seek_time = cur;
1227 qtdemux->seek_offset = byte_cur;
1228 GST_OBJECT_UNLOCK (qtdemux);
1231 /* BYTE seek event */
1232 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1234 res = gst_pad_push_event (qtdemux->sinkpad, event);
1241 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1247 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1252 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1257 /* perform the seek.
1259 * We set all segment_indexes in the streams to unknown and
1260 * adjust the time_position to the desired position. this is enough
1261 * to trigger a segment switch in the streaming thread to start
1262 * streaming from the desired position.
1264 * Keyframe seeking is a little more complicated when dealing with
1265 * segments. Ideally we want to move to the previous keyframe in
1266 * the segment but there might not be a keyframe in the segment. In
1267 * fact, none of the segments could contain a keyframe. We take a
1268 * practical approach: seek to the previous keyframe in the segment,
1269 * if there is none, seek to the beginning of the segment.
1271 * Called with STREAM_LOCK
1274 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1276 gint64 desired_offset;
1279 desired_offset = segment->last_stop;
1281 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1282 GST_TIME_ARGS (desired_offset));
1284 /* may not have enough fragmented info to do this adjustment,
1285 * and we can't scan (and probably should not) at this time with
1286 * possibly flushing upstream */
1287 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1290 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1291 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1292 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1293 desired_offset = min_offset;
1296 /* and set all streams to the final position */
1297 for (n = 0; n < qtdemux->n_streams; n++) {
1298 QtDemuxStream *stream = qtdemux->streams[n];
1300 stream->time_position = desired_offset;
1301 stream->sample_index = -1;
1302 stream->segment_index = -1;
1303 stream->last_ret = GST_FLOW_OK;
1304 stream->sent_eos = FALSE;
1306 segment->last_stop = desired_offset;
1307 segment->time = desired_offset;
1309 /* we stop at the end */
1310 if (segment->stop == -1)
1311 segment->stop = segment->duration;
1316 /* do a seek in pull based mode */
1318 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1323 GstSeekType cur_type, stop_type;
1327 GstSegment seeksegment;
1331 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1333 gst_event_parse_seek (event, &rate, &format, &flags,
1334 &cur_type, &cur, &stop_type, &stop);
1336 /* we have to have a format as the segment format. Try to convert
1338 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1342 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1344 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1348 flush = flags & GST_SEEK_FLAG_FLUSH;
1350 /* stop streaming, either by flushing or by pausing the task */
1352 /* unlock upstream pull_range */
1353 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1354 /* make sure out loop function exits */
1355 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1357 /* non flushing seek, pause the task */
1358 gst_pad_pause_task (qtdemux->sinkpad);
1361 /* wait for streaming to finish */
1362 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1364 /* copy segment, we need this because we still need the old
1365 * segment when we close the current segment. */
1366 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1369 /* configure the segment with the seek variables */
1370 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1371 gst_segment_set_seek (&seeksegment, rate, format, flags,
1372 cur_type, cur, stop_type, stop, &update);
1375 /* now do the seek, this actually never returns FALSE */
1376 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1378 /* prepare for streaming again */
1380 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop ());
1381 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop ());
1382 } else if (qtdemux->segment_running) {
1383 /* we are running the current segment and doing a non-flushing seek,
1384 * close the segment first based on the last_stop. */
1385 GST_DEBUG_OBJECT (qtdemux, "closing running segment %" G_GINT64_FORMAT
1386 " to %" G_GINT64_FORMAT, qtdemux->segment.start,
1387 qtdemux->segment.last_stop);
1389 if (qtdemux->segment.rate >= 0) {
1390 /* FIXME, rate is the product of the global rate and the (quicktime)
1392 qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
1393 qtdemux->segment.rate, qtdemux->segment.format,
1394 qtdemux->segment.start, qtdemux->segment.last_stop,
1395 qtdemux->segment.time);
1396 } else { /* For Reverse Playback */
1399 if ((stop = qtdemux->segment.stop) == -1)
1400 stop = qtdemux->segment.duration;
1401 /* for reverse playback, we played from stop to last_stop. */
1402 qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
1403 qtdemux->segment.rate, qtdemux->segment.format,
1404 qtdemux->segment.last_stop, stop, qtdemux->segment.last_stop);
1408 /* commit the new segment */
1409 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1411 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1412 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1413 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1414 qtdemux->segment.format, qtdemux->segment.last_stop));
1417 /* restart streaming, NEWSEGMENT will be sent from the streaming
1419 qtdemux->segment_running = TRUE;
1420 for (i = 0; i < qtdemux->n_streams; i++)
1421 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1423 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1426 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1433 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1439 qtdemux_ensure_index (GstQTDemux * qtdemux)
1443 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1445 /* Build complete index */
1446 for (i = 0; i < qtdemux->n_streams; i++) {
1447 QtDemuxStream *stream = qtdemux->streams[i];
1449 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1457 GST_LOG_OBJECT (qtdemux,
1458 "Building complete index of stream %u for seeking failed!", i);
1464 gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
1466 gboolean res = TRUE;
1467 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
1469 switch (GST_EVENT_TYPE (event)) {
1470 case GST_EVENT_SEEK:
1472 #ifndef GST_DISABLE_GST_DEBUG
1473 GstClockTime ts = gst_util_get_timestamp ();
1475 /* Build complete index for seeking;
1476 * if not a fragmented file at least */
1477 if (!qtdemux->fragmented)
1478 if (!qtdemux_ensure_index (qtdemux))
1480 #ifndef GST_DISABLE_GST_DEBUG
1481 ts = gst_util_get_timestamp () - ts;
1482 GST_INFO_OBJECT (qtdemux,
1483 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1486 if (qtdemux->pullbased) {
1487 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1488 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams &&
1489 !qtdemux->fragmented) {
1490 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1492 GST_DEBUG_OBJECT (qtdemux,
1493 "ignoring seek in push mode in current state");
1496 gst_event_unref (event);
1499 case GST_EVENT_NAVIGATION:
1501 gst_event_unref (event);
1504 res = gst_pad_event_default (pad, event);
1508 gst_object_unref (qtdemux);
1516 GST_ERROR_OBJECT (qtdemux, "Index failed");
1517 gst_event_unref (event);
1523 /* stream/index return sample that is min/max w.r.t. byte position,
1524 * time is min/max w.r.t. time of samples,
1525 * the latter need not be time of the former sample */
1527 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1528 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1531 gint64 time, min_time;
1532 QtDemuxStream *stream;
1538 for (n = 0; n < qtdemux->n_streams; ++n) {
1541 gboolean set_sample;
1543 str = qtdemux->streams[n];
1550 i = str->n_samples - 1;
1553 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1554 if (str->samples[i].size &&
1555 ((fw && (str->samples[i].offset >= byte_pos)) ||
1557 (str->samples[i].offset + str->samples[i].size <=
1559 /* move stream to first available sample */
1561 gst_qtdemux_move_stream (qtdemux, str, i);
1564 /* determine min/max time */
1565 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1566 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1567 if (min_time == -1 || (!fw && time > min_time) ||
1568 (fw && time < min_time)) {
1571 /* determine stream with leading sample, to get its position */
1573 && (str->samples[i].offset < stream->samples[index].offset))
1575 && (str->samples[i].offset > stream->samples[index].offset))) {
1582 /* no sample for this stream, mark eos */
1584 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1596 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
1598 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1601 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1603 switch (GST_EVENT_TYPE (event)) {
1604 case GST_EVENT_NEWSEGMENT:
1607 gdouble rate, arate;
1608 gint64 start, stop, time, offset = 0;
1609 QtDemuxStream *stream;
1614 /* some debug output */
1615 gst_segment_init (&segment, GST_FORMAT_UNDEFINED);
1616 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
1617 &start, &stop, &time);
1618 gst_segment_set_newsegment_full (&segment, update, rate, arate, format,
1620 GST_DEBUG_OBJECT (demux,
1621 "received format %d newsegment %" GST_SEGMENT_FORMAT, format,
1624 /* chain will send initial newsegment after pads have been added */
1625 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1626 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1630 /* we only expect a BYTE segment, e.g. following a seek */
1631 if (format == GST_FORMAT_BYTES) {
1633 gint64 requested_seek_time;
1634 guint64 seek_offset;
1638 GST_OBJECT_LOCK (demux);
1639 requested_seek_time = demux->requested_seek_time;
1640 seek_offset = demux->seek_offset;
1641 demux->requested_seek_time = -1;
1642 demux->seek_offset = -1;
1643 GST_OBJECT_UNLOCK (demux);
1645 if (offset == seek_offset) {
1646 start = requested_seek_time;
1648 gst_qtdemux_find_sample (demux, start, TRUE, FALSE, NULL, NULL,
1650 start = MAX (start, 0);
1654 gst_qtdemux_find_sample (demux, stop, FALSE, FALSE, NULL, NULL,
1656 /* keyframe seeking should already arrange for start >= stop,
1657 * but make sure in other rare cases */
1658 stop = MAX (stop, start);
1661 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1665 /* accept upstream's notion of segment and distribute along */
1666 gst_segment_set_newsegment_full (&demux->segment, update, rate, arate,
1667 GST_FORMAT_TIME, start, stop, start);
1668 GST_DEBUG_OBJECT (demux, "Pushing newseg update %d, rate %g, "
1669 "applied rate %g, format %d, start %" GST_TIME_FORMAT ", "
1670 "stop %" GST_TIME_FORMAT, update, rate, arate, GST_FORMAT_TIME,
1671 GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
1673 gst_qtdemux_push_event (demux,
1674 gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME,
1675 start, stop, start));
1677 /* clear leftover in current segment, if any */
1678 gst_adapter_clear (demux->adapter);
1679 /* set up streaming thread */
1680 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1681 demux->offset = offset;
1683 demux->todrop = stream->samples[idx].offset - offset;
1684 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1686 /* set up for EOS */
1687 demux->neededbytes = -1;
1691 gst_event_unref (event);
1696 case GST_EVENT_FLUSH_STOP:
1700 /* clean up, force EOS if no more info follows */
1701 gst_adapter_clear (demux->adapter);
1703 demux->neededbytes = -1;
1704 /* reset flow return, e.g. following seek */
1705 for (i = 0; i < demux->n_streams; i++) {
1706 demux->streams[i]->last_ret = GST_FLOW_OK;
1707 demux->streams[i]->sent_eos = FALSE;
1712 /* If we are in push mode, and get an EOS before we've seen any streams,
1713 * then error out - we have nowhere to send the EOS */
1714 if (!demux->pullbased) {
1716 gboolean has_valid_stream = FALSE;
1717 for (i = 0; i < demux->n_streams; i++) {
1718 if (demux->streams[i]->pad != NULL) {
1719 has_valid_stream = TRUE;
1723 if (!has_valid_stream)
1724 gst_qtdemux_post_no_playable_stream_error (demux);
1731 res = gst_pad_event_default (demux->sinkpad, event);
1738 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1740 GstQTDemux *demux = GST_QTDEMUX (element);
1742 GST_OBJECT_LOCK (demux);
1743 if (demux->element_index)
1744 gst_object_unref (demux->element_index);
1746 demux->element_index = gst_object_ref (index);
1748 demux->element_index = NULL;
1750 GST_OBJECT_UNLOCK (demux);
1751 /* object lock might be taken again */
1753 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1754 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
1755 demux->element_index, demux->index_id);
1759 gst_qtdemux_get_index (GstElement * element)
1761 GstIndex *result = NULL;
1762 GstQTDemux *demux = GST_QTDEMUX (element);
1764 GST_OBJECT_LOCK (demux);
1765 if (demux->element_index)
1766 result = gst_object_ref (demux->element_index);
1767 GST_OBJECT_UNLOCK (demux);
1769 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1775 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1777 g_free ((gpointer) stream->stco.data);
1778 stream->stco.data = NULL;
1779 g_free ((gpointer) stream->stsz.data);
1780 stream->stsz.data = NULL;
1781 g_free ((gpointer) stream->stsc.data);
1782 stream->stsc.data = NULL;
1783 g_free ((gpointer) stream->stts.data);
1784 stream->stts.data = NULL;
1785 g_free ((gpointer) stream->stss.data);
1786 stream->stss.data = NULL;
1787 g_free ((gpointer) stream->stps.data);
1788 stream->stps.data = NULL;
1789 g_free ((gpointer) stream->ctts.data);
1790 stream->ctts.data = NULL;
1794 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
1796 while (stream->buffers) {
1797 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1798 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1801 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
1802 g_free (stream->samples);
1804 gst_caps_unref (stream->caps);
1805 g_free (stream->segments);
1806 if (stream->pending_tags)
1807 gst_tag_list_free (stream->pending_tags);
1808 g_free (stream->redirect_uri);
1809 /* free stbl sub-atoms */
1810 gst_qtdemux_stbl_free (stream);
1814 static GstStateChangeReturn
1815 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1817 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1818 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1820 switch (transition) {
1821 case GST_STATE_CHANGE_PAUSED_TO_READY:
1827 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1829 switch (transition) {
1830 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1833 qtdemux->state = QTDEMUX_STATE_INITIAL;
1834 qtdemux->neededbytes = 16;
1835 qtdemux->todrop = 0;
1836 qtdemux->pullbased = FALSE;
1837 qtdemux->posted_redirect = FALSE;
1838 qtdemux->offset = 0;
1839 qtdemux->first_mdat = -1;
1840 qtdemux->header_size = 0;
1841 qtdemux->got_moov = FALSE;
1842 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1843 if (qtdemux->mdatbuffer)
1844 gst_buffer_unref (qtdemux->mdatbuffer);
1845 qtdemux->mdatbuffer = NULL;
1846 if (qtdemux->comp_brands)
1847 gst_buffer_unref (qtdemux->comp_brands);
1848 qtdemux->comp_brands = NULL;
1849 if (qtdemux->tag_list)
1850 gst_tag_list_free (qtdemux->tag_list);
1851 qtdemux->tag_list = NULL;
1852 if (qtdemux->element_index)
1853 gst_object_unref (qtdemux->element_index);
1854 qtdemux->element_index = NULL;
1855 gst_adapter_clear (qtdemux->adapter);
1856 for (n = 0; n < qtdemux->n_streams; n++) {
1857 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1858 qtdemux->streams[n] = NULL;
1860 qtdemux->major_brand = 0;
1861 qtdemux->n_streams = 0;
1862 qtdemux->n_video_streams = 0;
1863 qtdemux->n_audio_streams = 0;
1864 qtdemux->n_sub_streams = 0;
1865 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1866 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1867 qtdemux->seek_offset = 0;
1868 qtdemux->upstream_seekable = FALSE;
1869 qtdemux->upstream_size = 0;
1880 qtdemux_post_global_tags (GstQTDemux * qtdemux)
1882 if (qtdemux->tag_list) {
1883 /* all header tags ready and parsed, push them */
1884 GST_INFO_OBJECT (qtdemux, "posting global tags: %" GST_PTR_FORMAT,
1886 /* post now, send event on pads later */
1887 gst_element_post_message (GST_ELEMENT (qtdemux),
1888 gst_message_new_tag (GST_OBJECT (qtdemux),
1889 gst_tag_list_copy (qtdemux->tag_list)));
1894 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1896 /* counts as header data */
1897 qtdemux->header_size += length;
1899 /* only consider at least a sufficiently complete ftyp atom */
1903 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1904 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1905 GST_FOURCC_ARGS (qtdemux->major_brand));
1906 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1907 memcpy (GST_BUFFER_DATA (buf), buffer + 16, GST_BUFFER_SIZE (buf));
1912 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
1914 /* Strip out bogus fields */
1916 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
1918 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
1920 if (qtdemux->tag_list) {
1921 /* prioritize native tags using _KEEP mode */
1922 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
1923 gst_tag_list_free (taglist);
1925 qtdemux->tag_list = taglist;
1930 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1932 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
1933 0x97, 0xA9, 0x42, 0xE8,
1934 0x9C, 0x71, 0x99, 0x94,
1935 0x91, 0xE3, 0xAF, 0xAC
1939 /* counts as header data */
1940 qtdemux->header_size += length;
1942 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
1944 if (length <= offset + 16) {
1945 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
1949 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
1951 GstTagList *taglist;
1953 buf = gst_buffer_new ();
1954 GST_BUFFER_DATA (buf) = (guint8 *) buffer + offset + 16;
1955 GST_BUFFER_SIZE (buf) = length - offset - 16;
1957 taglist = gst_tag_list_from_xmp_buffer (buf);
1958 gst_buffer_unref (buf);
1960 qtdemux_handle_xmp_taglist (qtdemux, taglist);
1963 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
1967 /* caller verifies at least 8 bytes in buf */
1969 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1970 guint64 * plength, guint32 * pfourcc)
1975 length = QT_UINT32 (data);
1976 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1977 fourcc = QT_FOURCC (data + 4);
1978 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1981 length = G_MAXUINT32;
1982 } else if (length == 1 && size >= 16) {
1983 /* this means we have an extended size, which is the 64 bit value of
1984 * the next 8 bytes */
1985 length = QT_UINT64 (data + 8);
1986 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1996 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
1998 guint32 version = 0;
1999 guint64 duration = 0;
2001 if (!gst_byte_reader_get_uint32_be (br, &version))
2006 if (!gst_byte_reader_get_uint64_be (br, &duration))
2011 if (!gst_byte_reader_get_uint32_be (br, &dur))
2016 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2017 qtdemux->duration = duration;
2023 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2029 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2030 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2032 if (!stream->parsed_trex && qtdemux->moov_node) {
2034 GstByteReader trex_data;
2036 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2038 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2041 guint32 id = 0, dur = 0, size = 0, flags = 0;
2043 /* skip version/flags */
2044 if (!gst_byte_reader_skip (&trex_data, 4))
2046 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2048 if (id != stream->track_id)
2050 /* sample description index; ignore */
2051 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2053 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2055 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2057 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2060 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2061 "duration %d, size %d, flags 0x%x", stream->track_id,
2064 stream->parsed_trex = TRUE;
2065 stream->def_sample_duration = dur;
2066 stream->def_sample_size = size;
2067 stream->def_sample_flags = flags;
2070 /* iterate all siblings */
2071 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2077 *ds_duration = stream->def_sample_duration;
2078 *ds_size = stream->def_sample_size;
2079 *ds_size = stream->def_sample_size;
2081 /* even then, above values are better than random ... */
2082 if (G_UNLIKELY (!stream->parsed_trex)) {
2083 GST_WARNING_OBJECT (qtdemux,
2084 "failed to find fragment defaults for stream %d", stream->track_id);
2092 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2093 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2094 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2095 gint64 * base_offset, gint64 * running_offset)
2098 gint32 data_offset = 0;
2099 guint32 flags = 0, first_flags = 0, samples_count = 0;
2102 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2103 QtDemuxSample *sample;
2104 gboolean ismv = FALSE;
2106 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2107 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2108 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2111 /* presence of stss or not can't really tell us much,
2112 * and flags and so on tend to be marginally reliable in these files */
2113 if (stream->subtype == FOURCC_soun) {
2114 GST_DEBUG_OBJECT (qtdemux,
2115 "sound track in fragmented file; marking all keyframes");
2116 stream->all_keyframe = TRUE;
2119 if (!gst_byte_reader_skip (trun, 1) ||
2120 !gst_byte_reader_get_uint24_be (trun, &flags))
2123 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2126 if (flags & TR_DATA_OFFSET) {
2127 /* note this is really signed */
2128 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2130 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2131 /* default base offset = first byte of moof */
2132 if (*base_offset == -1) {
2133 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2134 *base_offset = moof_offset;
2136 *running_offset = *base_offset + data_offset;
2138 /* if no offset at all, that would mean data starts at moof start,
2139 * which is a bit wrong and is ismv crappy way, so compensate
2140 * assuming data is in mdat following moof */
2141 if (*base_offset == -1) {
2142 *base_offset = moof_offset + moof_length + 8;
2143 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2146 if (*running_offset == -1)
2147 *running_offset = *base_offset;
2150 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2152 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2153 data_offset, flags, samples_count);
2155 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2156 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2157 GST_DEBUG_OBJECT (qtdemux,
2158 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2159 flags ^= TR_FIRST_SAMPLE_FLAGS;
2161 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2163 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2167 /* FIXME ? spec says other bits should also be checked to determine
2168 * entry size (and prefix size for that matter) */
2170 dur_offset = size_offset = 0;
2171 if (flags & TR_SAMPLE_DURATION) {
2172 GST_LOG_OBJECT (qtdemux, "entry duration present");
2173 dur_offset = entry_size;
2176 if (flags & TR_SAMPLE_SIZE) {
2177 GST_LOG_OBJECT (qtdemux, "entry size present");
2178 size_offset = entry_size;
2181 if (flags & TR_SAMPLE_FLAGS) {
2182 GST_LOG_OBJECT (qtdemux, "entry flags present");
2183 flags_offset = entry_size;
2186 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2187 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2188 ct_offset = entry_size;
2192 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2194 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2196 if (stream->n_samples >=
2197 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2200 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2201 stream->n_samples, (guint) sizeof (QtDemuxSample),
2202 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2204 /* create a new array of samples if it's the first sample parsed */
2205 if (stream->n_samples == 0)
2206 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2207 /* or try to reallocate it with space enough to insert the new samples */
2209 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2210 stream->n_samples + samples_count);
2211 if (stream->samples == NULL)
2214 if (G_UNLIKELY (stream->n_samples == 0)) {
2215 /* the timestamp of the first sample is also provided by the tfra entry
2216 * but we shouldn't rely on it as it is at the end of files */
2219 /* subsequent fragments extend stream */
2221 stream->samples[stream->n_samples - 1].timestamp +
2222 stream->samples[stream->n_samples - 1].duration;
2224 sample = stream->samples + stream->n_samples;
2225 for (i = 0; i < samples_count; i++) {
2226 guint32 dur, size, sflags, ct;
2228 /* first read sample data */
2229 if (flags & TR_SAMPLE_DURATION) {
2230 dur = QT_UINT32 (data + dur_offset);
2232 dur = d_sample_duration;
2234 if (flags & TR_SAMPLE_SIZE) {
2235 size = QT_UINT32 (data + size_offset);
2237 size = d_sample_size;
2239 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2241 sflags = first_flags;
2243 sflags = d_sample_flags;
2245 } else if (flags & TR_SAMPLE_FLAGS) {
2246 sflags = QT_UINT32 (data + flags_offset);
2248 sflags = d_sample_flags;
2250 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2251 ct = QT_UINT32 (data + ct_offset);
2257 /* fill the sample information */
2258 sample->offset = *running_offset;
2259 sample->pts_offset = ct;
2260 sample->size = size;
2261 sample->timestamp = timestamp;
2262 sample->duration = dur;
2263 /* sample-is-difference-sample */
2264 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2265 * now idea how it relates to bitfield other than massive LE/BE confusion */
2266 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2267 *running_offset += size;
2272 stream->n_samples += samples_count;
2278 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2283 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2289 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2290 "be larger than %uMB (broken file?)", stream->n_samples,
2291 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2296 /* find stream with @id */
2297 static inline QtDemuxStream *
2298 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2300 QtDemuxStream *stream;
2304 if (G_UNLIKELY (!id)) {
2305 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2309 /* try to get it fast and simple */
2310 if (G_LIKELY (id <= qtdemux->n_streams)) {
2311 stream = qtdemux->streams[id - 1];
2312 if (G_LIKELY (stream->track_id == id))
2316 /* linear search otherwise */
2317 for (i = 0; i < qtdemux->n_streams; i++) {
2318 stream = qtdemux->streams[i];
2319 if (stream->track_id == id)
2327 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2328 QtDemuxStream ** stream, guint32 * default_sample_duration,
2329 guint32 * default_sample_size, guint32 * default_sample_flags,
2330 gint64 * base_offset)
2333 guint32 track_id = 0;
2335 if (!gst_byte_reader_skip (tfhd, 1) ||
2336 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2339 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2342 *stream = qtdemux_find_stream (qtdemux, track_id);
2343 if (G_UNLIKELY (!*stream))
2344 goto unknown_stream;
2346 if (flags & TF_BASE_DATA_OFFSET)
2347 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2350 /* obtain stream defaults */
2351 qtdemux_parse_trex (qtdemux, *stream,
2352 default_sample_duration, default_sample_size, default_sample_flags);
2354 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2355 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2356 if (!gst_byte_reader_skip (tfhd, 4))
2359 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2360 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2363 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2364 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2367 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2368 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2375 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2380 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2386 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2387 guint64 moof_offset, QtDemuxStream * stream)
2389 GNode *moof_node, *traf_node, *tfhd_node, *trun_node;
2390 GstByteReader trun_data, tfhd_data;
2391 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2392 gint64 base_offset, running_offset;
2394 /* NOTE @stream ignored */
2396 moof_node = g_node_new ((guint8 *) buffer);
2397 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2398 qtdemux_node_dump (qtdemux, moof_node);
2400 /* unknown base_offset to start with */
2401 base_offset = running_offset = -1;
2402 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2404 /* Fragment Header node */
2406 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2410 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2411 &ds_size, &ds_flags, &base_offset))
2413 if (G_UNLIKELY (!stream)) {
2414 /* we lost track of offset, we'll need to regain it,
2415 * but can delay complaining until later or avoid doing so altogether */
2419 if (G_UNLIKELY (base_offset < -1))
2421 /* Track Run node */
2423 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2426 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2427 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2429 /* iterate all siblings */
2430 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2433 /* if no new base_offset provided for next traf,
2434 * base is end of current traf */
2435 base_offset = running_offset;
2436 running_offset = -1;
2438 /* iterate all siblings */
2439 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2441 g_node_destroy (moof_node);
2446 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2451 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2456 g_node_destroy (moof_node);
2457 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2458 (_("This file is corrupt and cannot be played.")), (NULL));
2463 /* might be used if some day we actually use mfra & co
2464 * for random access to fragments,
2465 * but that will require quite some modifications and much less relying
2466 * on a sample array */
2469 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2470 QtDemuxStream * stream)
2472 guint64 time = 0, moof_offset = 0;
2473 guint32 ver_flags, track_id, len, num_entries, i;
2474 guint value_size, traf_size, trun_size, sample_size;
2475 GstBuffer *buf = NULL;
2479 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2480 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2482 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2485 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2486 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2487 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2490 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2491 track_id, stream->track_id);
2492 if (track_id != stream->track_id) {
2496 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2497 sample_size = (len & 3) + 1;
2498 trun_size = ((len & 12) >> 2) + 1;
2499 traf_size = ((len & 48) >> 4) + 1;
2501 if (num_entries == 0)
2504 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2505 value_size + value_size + traf_size + trun_size + sample_size))
2508 for (i = 0; i < num_entries; i++) {
2509 qt_atom_parser_get_offset (&tfra, value_size, &time);
2510 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2511 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2512 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2513 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2515 GST_LOG_OBJECT (qtdemux,
2516 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2517 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2518 stream->timescale)), moof_offset);
2520 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2521 if (ret != GST_FLOW_OK)
2523 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2524 moof_offset, stream);
2525 gst_buffer_unref (buf);
2533 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2534 (_("This file is corrupt and cannot be played.")), (NULL));
2539 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2545 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2548 GNode *mfra_node, *tfra_node;
2551 if (!qtdemux->mfra_offset)
2554 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2555 if (ret != GST_FLOW_OK)
2558 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2559 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2560 GST_BUFFER_SIZE (buffer));
2562 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2565 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2566 /* iterate all siblings */
2567 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2569 g_node_destroy (mfra_node);
2570 gst_buffer_unref (buffer);
2576 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2577 (_("This file is corrupt and cannot be played.")), (NULL));
2582 static GstFlowReturn
2583 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2584 guint32 * mfro_size)
2586 GstFlowReturn ret = GST_FLOW_ERROR;
2587 GstBuffer *mfro = NULL;
2590 GstFormat fmt = GST_FORMAT_BYTES;
2592 if (!gst_pad_query_peer_duration (qtdemux->sinkpad, &fmt, &len)) {
2593 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2594 "can not locate mfro");
2598 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2599 if (ret != GST_FLOW_OK)
2602 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2603 if (fourcc != FOURCC_mfro)
2606 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2607 if (GST_BUFFER_SIZE (mfro) >= 16) {
2608 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
2609 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
2610 if (*mfro_size >= len) {
2611 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
2612 ret = GST_FLOW_ERROR;
2615 *mfra_offset = len - *mfro_size;
2620 gst_buffer_unref (mfro);
2626 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
2629 guint32 mfra_size = 0;
2630 guint64 mfra_offset = 0;
2633 qtdemux->fragmented = FALSE;
2635 /* We check here if it is a fragmented mp4 container */
2636 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
2637 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
2638 qtdemux->fragmented = TRUE;
2639 GST_DEBUG_OBJECT (qtdemux,
2640 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
2641 qtdemux->mfra_offset = mfra_offset;
2646 static GstFlowReturn
2647 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
2651 GstBuffer *buf = NULL;
2652 GstFlowReturn ret = GST_FLOW_OK;
2653 guint64 cur_offset = qtdemux->offset;
2655 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
2656 if (G_UNLIKELY (ret != GST_FLOW_OK))
2658 if (G_LIKELY (GST_BUFFER_SIZE (buf) >= 8))
2659 extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf),
2660 GST_BUFFER_SIZE (buf), &length, &fourcc);
2661 gst_buffer_unref (buf);
2663 /* maybe we already got most we needed, so only consider this eof */
2664 if (G_UNLIKELY (length == 0)) {
2665 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
2666 (_("Invalid atom size.")),
2667 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
2668 GST_FOURCC_ARGS (fourcc)));
2669 ret = GST_FLOW_UNEXPECTED;
2675 /* record for later parsing when needed */
2676 if (!qtdemux->moof_offset) {
2677 qtdemux->moof_offset = qtdemux->offset;
2686 GST_LOG_OBJECT (qtdemux,
2687 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
2688 GST_FOURCC_ARGS (fourcc), cur_offset);
2689 qtdemux->offset += length;
2696 if (qtdemux->got_moov) {
2697 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
2698 qtdemux->offset += length;
2702 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
2703 if (ret != GST_FLOW_OK)
2705 if (length != GST_BUFFER_SIZE (moov)) {
2706 /* Some files have a 'moov' atom at the end of the file which contains
2707 * a terminal 'free' atom where the body of the atom is missing.
2708 * Check for, and permit, this special case.
2710 if (GST_BUFFER_SIZE (moov) >= 8) {
2711 guint8 *final_data = GST_BUFFER_DATA (moov) +
2712 (GST_BUFFER_SIZE (moov) - 8);
2713 guint32 final_length = QT_UINT32 (final_data);
2714 guint32 final_fourcc = QT_FOURCC (final_data + 4);
2715 if (final_fourcc == FOURCC_free &&
2716 GST_BUFFER_SIZE (moov) + final_length - 8 == length) {
2717 /* Ok, we've found that special case. Allocate a new buffer with
2718 * that free atom actually present. */
2719 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
2720 gst_buffer_copy_metadata (newmoov, moov,
2721 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
2722 GST_BUFFER_COPY_CAPS);
2723 memcpy (GST_BUFFER_DATA (newmoov), GST_BUFFER_DATA (moov),
2724 GST_BUFFER_SIZE (moov));
2725 memset (GST_BUFFER_DATA (newmoov) + GST_BUFFER_SIZE (moov), 0,
2727 gst_buffer_unref (moov);
2733 if (length != GST_BUFFER_SIZE (moov)) {
2734 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2735 (_("This file is incomplete and cannot be played.")),
2736 ("We got less than expected (received %u, wanted %u, offset %"
2737 G_GUINT64_FORMAT ")",
2738 GST_BUFFER_SIZE (moov), (guint) length, cur_offset));
2739 gst_buffer_unref (moov);
2740 ret = GST_FLOW_ERROR;
2743 qtdemux->offset += length;
2745 qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
2746 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
2748 qtdemux_parse_tree (qtdemux);
2749 g_node_destroy (qtdemux->moov_node);
2750 gst_buffer_unref (moov);
2751 qtdemux->moov_node = NULL;
2752 qtdemux->got_moov = TRUE;
2760 /* extract major brand; might come in handy for ISO vs QT issues */
2761 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
2762 if (ret != GST_FLOW_OK)
2764 qtdemux->offset += length;
2765 qtdemux_parse_ftyp (qtdemux, GST_BUFFER_DATA (ftyp),
2766 GST_BUFFER_SIZE (ftyp));
2767 gst_buffer_unref (ftyp);
2774 /* uuid are extension atoms */
2775 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
2776 if (ret != GST_FLOW_OK)
2778 qtdemux->offset += length;
2779 qtdemux_parse_uuid (qtdemux, GST_BUFFER_DATA (uuid),
2780 GST_BUFFER_SIZE (uuid));
2781 gst_buffer_unref (uuid);
2788 GST_LOG_OBJECT (qtdemux,
2789 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
2790 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
2792 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
2793 if (ret != GST_FLOW_OK)
2795 GST_MEMDUMP ("Unknown tag", GST_BUFFER_DATA (unknown),
2796 GST_BUFFER_SIZE (unknown));
2797 gst_buffer_unref (unknown);
2798 qtdemux->offset += length;
2804 if (ret == GST_FLOW_UNEXPECTED && qtdemux->got_moov) {
2805 /* digested all data, show what we have */
2806 ret = qtdemux_expose_streams (qtdemux);
2808 /* Only post, event on pads is done after newsegment */
2809 qtdemux_post_global_tags (qtdemux);
2811 qtdemux->state = QTDEMUX_STATE_MOVIE;
2812 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
2819 /* Seeks to the previous keyframe of the indexed stream and
2820 * aligns other streams with respect to the keyframe timestamp
2821 * of indexed stream. Only called in case of Reverse Playback
2823 static GstFlowReturn
2824 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
2827 guint32 seg_idx = 0, k_index = 0;
2828 guint32 ref_seg_idx, ref_k_index;
2829 guint64 k_pos = 0, last_stop = 0;
2830 QtDemuxSegment *seg = NULL;
2831 QtDemuxStream *ref_str = NULL;
2832 guint64 seg_media_start_mov; /* segment media start time in mov format */
2834 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
2835 * and finally align all the other streams on that timestamp with their
2836 * respective keyframes */
2837 for (n = 0; n < qtdemux->n_streams; n++) {
2838 QtDemuxStream *str = qtdemux->streams[n];
2840 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
2841 qtdemux->segment.last_stop);
2843 /* segment not found, continue with normal flow */
2847 /* No candidate yet, take that one */
2853 /* So that stream has a segment, we prefer video streams */
2854 if (str->subtype == FOURCC_vide) {
2860 if (G_UNLIKELY (!ref_str)) {
2861 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
2865 if (G_UNLIKELY (!ref_str->from_sample)) {
2866 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
2870 /* So that stream has been playing from from_sample to to_sample. We will
2871 * get the timestamp of the previous sample and search for a keyframe before
2872 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
2873 if (ref_str->subtype == FOURCC_vide) {
2874 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
2875 ref_str->from_sample - 1);
2877 if (ref_str->from_sample >= 10)
2878 k_index = ref_str->from_sample - 10;
2883 /* get current segment for that stream */
2884 seg = &ref_str->segments[ref_str->segment_index];
2885 /* convert seg->media_start to mov format time for timestamp comparison */
2886 seg_media_start_mov =
2887 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
2888 /* Crawl back through segments to find the one containing this I frame */
2889 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
2890 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
2891 ref_str->segment_index);
2892 if (G_UNLIKELY (!ref_str->segment_index)) {
2893 /* Reached first segment, let's consider it's EOS */
2896 ref_str->segment_index--;
2897 seg = &ref_str->segments[ref_str->segment_index];
2898 /* convert seg->media_start to mov format time for timestamp comparison */
2899 seg_media_start_mov =
2900 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
2903 /* Calculate time position of the keyframe and where we should stop */
2905 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
2906 ref_str->timescale) - seg->media_start) + seg->time;
2908 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
2909 GST_SECOND, ref_str->timescale);
2910 last_stop = (last_stop - seg->media_start) + seg->time;
2912 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
2913 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
2914 k_index, GST_TIME_ARGS (k_pos));
2916 /* Set last_stop with the keyframe timestamp we pushed of that stream */
2917 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, last_stop);
2918 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
2919 GST_TIME_ARGS (last_stop));
2921 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
2922 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
2926 ref_seg_idx = ref_str->segment_index;
2927 ref_k_index = k_index;
2929 /* Align them all on this */
2930 for (n = 0; n < qtdemux->n_streams; n++) {
2932 guint64 media_start = 0, seg_time = 0;
2933 QtDemuxStream *str = qtdemux->streams[n];
2935 /* aligning reference stream again might lead to backing up to yet another
2936 * keyframe (due to timestamp rounding issues),
2937 * potentially putting more load on downstream; so let's try to avoid */
2938 if (str == ref_str) {
2939 seg_idx = ref_seg_idx;
2940 seg = &str->segments[seg_idx];
2941 k_index = ref_k_index;
2942 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
2943 "sample at index %d", ref_str->segment_index, k_index);
2945 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
2946 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
2948 /* segment not found, continue with normal flow */
2952 /* get segment and time in the segment */
2953 seg = &str->segments[seg_idx];
2954 seg_time = k_pos - seg->time;
2956 /* get the media time in the segment */
2957 media_start = seg->media_start + seg_time;
2959 /* get the index of the sample with media time */
2960 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
2961 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
2962 GST_TIME_ARGS (media_start), index);
2964 /* find previous keyframe */
2965 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
2968 /* Remember until where we want to go */
2969 str->to_sample = str->from_sample - 1;
2970 /* Define our time position */
2971 str->time_position =
2972 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
2973 str->timescale) - seg->media_start) + seg->time;
2974 /* Now seek back in time */
2975 gst_qtdemux_move_stream (qtdemux, str, k_index);
2976 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
2977 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
2978 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
2984 return GST_FLOW_UNEXPECTED;
2987 /* activate the given segment number @seg_idx of @stream at time @offset.
2988 * @offset is an absolute global position over all the segments.
2990 * This will push out a NEWSEGMENT event with the right values and
2991 * position the stream index to the first decodable sample before
2995 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
2996 guint32 seg_idx, guint64 offset)
2999 QtDemuxSegment *segment;
3000 guint32 index, kf_index;
3002 guint64 start, stop, time;
3005 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3008 /* update the current segment */
3009 stream->segment_index = seg_idx;
3011 /* get the segment */
3012 segment = &stream->segments[seg_idx];
3014 if (G_UNLIKELY (offset < segment->time)) {
3015 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3020 /* segment lies beyond total indicated duration */
3021 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3022 segment->time > qtdemux->segment.duration)) {
3023 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3024 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3029 /* get time in this segment */
3030 seg_time = offset - segment->time;
3032 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3033 GST_TIME_ARGS (seg_time));
3035 if (G_UNLIKELY (seg_time > segment->duration)) {
3036 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3037 GST_TIME_ARGS (segment->duration));
3041 /* qtdemux->segment.stop is in outside-time-realm, whereas
3042 * segment->media_stop is in track-time-realm.
3044 * In order to compare the two, we need to bring segment.stop
3045 * into the track-time-realm */
3047 stop = qtdemux->segment.stop;
3049 stop = qtdemux->segment.duration;
3051 stop = segment->media_stop;
3054 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3056 if (qtdemux->segment.rate >= 0) {
3057 start = MIN (segment->media_start + seg_time, stop);
3060 if (segment->media_start >= qtdemux->segment.start) {
3061 start = segment->media_start;
3062 time = segment->time;
3064 start = qtdemux->segment.start;
3065 time = segment->time + (qtdemux->segment.start - segment->media_start);
3068 start = MAX (segment->media_start, qtdemux->segment.start);
3069 stop = MIN (segment->media_start + seg_time, stop);
3072 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3073 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3074 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3076 /* combine global rate with that of the segment */
3077 rate = segment->rate * qtdemux->segment.rate;
3079 /* update the segment values used for clipping */
3080 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
3081 gst_segment_set_newsegment (&stream->segment, FALSE, rate, GST_FORMAT_TIME,
3084 /* now prepare and send the segment */
3086 event = gst_event_new_new_segment (FALSE, rate, GST_FORMAT_TIME,
3088 gst_pad_push_event (stream->pad, event);
3089 /* assume we can send more data now */
3090 stream->last_ret = GST_FLOW_OK;
3091 /* clear to send tags on this pad now */
3092 gst_qtdemux_push_tags (qtdemux, stream);
3095 /* and move to the keyframe before the indicated media time of the
3097 if (qtdemux->segment.rate >= 0) {
3098 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3099 stream->to_sample = G_MAXUINT32;
3100 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3101 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3102 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3103 GST_SECOND, stream->timescale)));
3105 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3106 stream->to_sample = index;
3107 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3108 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3109 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3110 GST_SECOND, stream->timescale)));
3113 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3114 * encountered an error and printed a message so we return appropriately */
3118 /* we're at the right spot */
3119 if (index == stream->sample_index) {
3120 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3124 /* find keyframe of the target index */
3125 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3128 /* indent does stupid stuff with stream->samples[].timestamp */
3130 /* if we move forwards, we don't have to go back to the previous
3131 * keyframe since we already sent that. We can also just jump to
3132 * the keyframe right before the target index if there is one. */
3133 if (index > stream->sample_index) {
3134 /* moving forwards check if we move past a keyframe */
3135 if (kf_index > stream->sample_index) {
3136 GST_DEBUG_OBJECT (qtdemux,
3137 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3138 GST_TIME_ARGS (gst_util_uint64_scale (
3139 stream->samples[kf_index].timestamp,
3140 GST_SECOND, stream->timescale)));
3141 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3143 GST_DEBUG_OBJECT (qtdemux,
3144 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3145 " already sent", kf_index,
3146 GST_TIME_ARGS (gst_util_uint64_scale (
3147 stream->samples[kf_index].timestamp,
3148 GST_SECOND, stream->timescale)));
3151 GST_DEBUG_OBJECT (qtdemux,
3152 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3153 GST_TIME_ARGS (gst_util_uint64_scale (
3154 stream->samples[kf_index].timestamp,
3155 GST_SECOND, stream->timescale)));
3156 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3164 /* prepare to get the current sample of @stream, getting essential values.
3166 * This function will also prepare and send the segment when needed.
3168 * Return FALSE if the stream is EOS.
3171 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3172 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp,
3173 guint64 * duration, gboolean * keyframe)
3175 QtDemuxSample *sample;
3176 guint64 time_position;
3179 g_return_val_if_fail (stream != NULL, FALSE);
3181 time_position = stream->time_position;
3182 if (G_UNLIKELY (time_position == -1))
3185 seg_idx = stream->segment_index;
3186 if (G_UNLIKELY (seg_idx == -1)) {
3187 /* find segment corresponding to time_position if we are looking
3189 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3191 /* nothing found, we're really eos */
3196 /* different segment, activate it, sample_index will be set. */
3197 if (G_UNLIKELY (stream->segment_index != seg_idx))
3198 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3200 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3201 stream->sample_index, stream->n_samples);
3203 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3206 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3207 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3208 stream->sample_index);
3212 /* now get the info for the sample we're at */
3213 sample = &stream->samples[stream->sample_index];
3215 *timestamp = QTSAMPLE_PTS (stream, sample);
3216 *offset = sample->offset;
3217 *size = sample->size;
3218 *duration = QTSAMPLE_DUR_PTS (stream, sample, *timestamp);
3219 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3226 stream->time_position = -1;
3231 /* move to the next sample in @stream.
3233 * Moves to the next segment when needed.
3236 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3238 QtDemuxSample *sample;
3239 QtDemuxSegment *segment;
3241 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3242 /* Mark the stream as EOS */
3243 GST_DEBUG_OBJECT (qtdemux,
3244 "reached max allowed sample %u, mark EOS", stream->to_sample);
3245 stream->time_position = -1;
3249 /* move to next sample */
3250 stream->sample_index++;
3252 /* get current segment */
3253 segment = &stream->segments[stream->segment_index];
3255 /* reached the last sample, we need the next segment */
3256 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3259 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3260 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3261 stream->sample_index);
3265 /* get next sample */
3266 sample = &stream->samples[stream->sample_index];
3268 /* see if we are past the segment */
3269 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3270 GST_SECOND, stream->timescale) >= segment->media_stop))
3273 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3274 stream->timescale) >= segment->media_start) {
3275 /* inside the segment, update time_position, looks very familiar to
3276 * GStreamer segments, doesn't it? */
3277 stream->time_position =
3278 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3279 stream->timescale) - segment->media_start) + segment->time;
3281 /* not yet in segment, time does not yet increment. This means
3282 * that we are still prerolling keyframes to the decoder so it can
3283 * decode the first sample of the segment. */
3284 stream->time_position = segment->time;
3288 /* move to the next segment */
3291 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3293 if (stream->segment_index == stream->n_segments - 1) {
3294 /* are we at the end of the last segment, we're EOS */
3295 stream->time_position = -1;
3297 /* else we're only at the end of the current segment */
3298 stream->time_position = segment->stop_time;
3300 /* make sure we select a new segment */
3301 stream->segment_index = -1;
3306 gst_qtdemux_sync_streams (GstQTDemux * demux)
3310 if (demux->n_streams <= 1)
3313 for (i = 0; i < demux->n_streams; i++) {
3314 QtDemuxStream *stream;
3315 GstClockTime end_time;
3317 stream = demux->streams[i];
3322 /* TODO advance time on subtitle streams here, if any some day */
3324 /* some clips/trailers may have unbalanced streams at the end,
3325 * so send EOS on shorter stream to prevent stalling others */
3327 /* do not mess with EOS if SEGMENT seeking */
3328 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3331 if (demux->pullbased) {
3332 /* loop mode is sample time based */
3333 if (stream->time_position != -1)
3336 /* push mode is byte position based */
3337 if (stream->n_samples &&
3338 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3342 if (stream->sent_eos)
3345 /* only act if some gap */
3346 end_time = stream->segments[stream->n_segments - 1].stop_time;
3347 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3348 ", stream end: %" GST_TIME_FORMAT,
3349 GST_TIME_ARGS (demux->segment.last_stop), GST_TIME_ARGS (end_time));
3350 if (end_time + 2 * GST_SECOND < demux->segment.last_stop) {
3351 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3352 GST_PAD_NAME (stream->pad));
3353 stream->sent_eos = TRUE;
3354 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3359 /* UNEXPECTED and NOT_LINKED need to be combined. This means that we return:
3361 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3362 * GST_FLOW_UNEXPECTED: when all pads UNEXPECTED or NOT_LINKED.
3364 static GstFlowReturn
3365 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3369 gboolean unexpected = FALSE, not_linked = TRUE;
3371 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3373 /* store the value */
3374 stream->last_ret = ret;
3376 /* any other error that is not-linked or eos can be returned right away */
3377 if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
3380 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3381 for (i = 0; i < demux->n_streams; i++) {
3382 QtDemuxStream *ostream = demux->streams[i];
3384 ret = ostream->last_ret;
3386 /* no unexpected or unlinked, return */
3387 if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
3390 /* we check to see if we have at least 1 unexpected or all unlinked */
3391 unexpected |= (ret == GST_FLOW_UNEXPECTED);
3392 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3395 /* when we get here, we all have unlinked or unexpected */
3397 ret = GST_FLOW_NOT_LINKED;
3398 else if (unexpected)
3399 ret = GST_FLOW_UNEXPECTED;
3401 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3405 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3406 * completely cliped */
3408 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3411 gint64 start, stop, cstart, cstop, diff;
3412 GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
3415 gint num_rate, denom_rate;
3419 data = GST_BUFFER_DATA (buf);
3420 size = GST_BUFFER_SIZE (buf);
3422 /* depending on the type, setup the clip parameters */
3423 if (stream->subtype == FOURCC_soun) {
3424 frame_size = stream->bytes_per_frame;
3425 num_rate = GST_SECOND;
3426 denom_rate = (gint) stream->rate;
3428 } else if (stream->subtype == FOURCC_vide) {
3430 num_rate = stream->fps_n;
3431 denom_rate = stream->fps_d;
3436 /* we can only clip if we have a valid timestamp */
3437 timestamp = GST_BUFFER_TIMESTAMP (buf);
3438 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
3441 if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf))) {
3442 duration = GST_BUFFER_DURATION (buf);
3445 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3449 stop = start + duration;
3451 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3452 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3455 /* see if some clipping happened */
3456 diff = cstart - start;
3462 /* bring clipped time to samples and to bytes */
3463 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3466 GST_DEBUG_OBJECT (qtdemux,
3467 "clipping start to %" GST_TIME_FORMAT " %"
3468 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3474 diff = stop - cstop;
3479 /* bring clipped time to samples and then to bytes */
3480 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3482 GST_DEBUG_OBJECT (qtdemux,
3483 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3484 " bytes", GST_TIME_ARGS (cstop), diff);
3489 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3490 GST_BUFFER_DURATION (buf) = duration;
3491 GST_BUFFER_SIZE (buf) = size;
3492 GST_BUFFER_DATA (buf) = data;
3496 /* dropped buffer */
3499 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3504 GST_DEBUG_OBJECT (qtdemux, "no timestamp on buffer");
3509 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3510 gst_buffer_unref (buf);
3515 /* the input buffer metadata must be writable,
3516 * but time/duration etc not yet set and need not be preserved */
3518 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3522 guint size, nsize = 0;
3525 data = GST_BUFFER_DATA (buf);
3526 size = GST_BUFFER_SIZE (buf);
3528 /* not many cases for now */
3529 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3530 /* send a one time dvd clut event */
3531 if (stream->pending_event && stream->pad)
3532 gst_pad_push_event (stream->pad, stream->pending_event);
3533 stream->pending_event = NULL;
3534 /* no further processing needed */
3535 stream->need_process = FALSE;
3538 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
3542 if (G_LIKELY (size >= 2)) {
3543 nsize = GST_READ_UINT16_BE (data);
3544 nsize = MIN (nsize, size - 2);
3547 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%d", nsize, size);
3549 /* takes care of UTF-8 validation or UTF-16 recognition,
3550 * no other encoding expected */
3551 str = gst_tag_freeform_string_to_utf8 ((gchar *) data + 2, nsize, NULL);
3553 gst_buffer_unref (buf);
3554 buf = gst_buffer_new ();
3555 GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = (guint8 *) str;
3556 GST_BUFFER_SIZE (buf) = strlen (str);
3558 /* may be 0-size subtitle, which is also sent to keep pipeline going */
3559 GST_BUFFER_DATA (buf) = data + 2;
3560 GST_BUFFER_SIZE (buf) = nsize;
3563 /* FIXME ? convert optional subsequent style info to markup */
3568 /* Sets a buffer's attributes properly and pushes it downstream.
3569 * Also checks for additional actions and custom processing that may
3570 * need to be done first.
3573 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3574 QtDemuxStream * stream, GstBuffer * buf,
3575 guint64 timestamp, guint64 duration, gboolean keyframe, guint64 position,
3576 guint64 byte_position)
3578 GstFlowReturn ret = GST_FLOW_OK;
3580 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
3583 url = g_strndup ((gchar *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
3584 if (url != NULL && strlen (url) != 0) {
3585 /* we have RTSP redirect now */
3586 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3587 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
3588 gst_structure_new ("redirect",
3589 "new-location", G_TYPE_STRING, url, NULL)));
3590 qtdemux->posted_redirect = TRUE;
3592 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
3598 /* position reporting */
3599 if (qtdemux->segment.rate >= 0) {
3600 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, position);
3601 gst_qtdemux_sync_streams (qtdemux);
3604 if (G_UNLIKELY (!stream->pad)) {
3605 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
3606 gst_buffer_unref (buf);
3610 /* send out pending buffers */
3611 while (stream->buffers) {
3612 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
3614 if (G_UNLIKELY (stream->discont)) {
3615 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3616 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
3617 stream->discont = FALSE;
3619 gst_buffer_set_caps (buffer, stream->caps);
3621 gst_pad_push (stream->pad, buffer);
3623 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
3626 /* we're going to modify the metadata */
3627 buf = gst_buffer_make_metadata_writable (buf);
3629 if (G_UNLIKELY (stream->need_process))
3630 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
3632 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3633 GST_BUFFER_DURATION (buf) = duration;
3634 GST_BUFFER_OFFSET (buf) = -1;
3635 GST_BUFFER_OFFSET_END (buf) = -1;
3637 if (G_UNLIKELY (stream->padding)) {
3638 GST_BUFFER_DATA (buf) += stream->padding;
3639 GST_BUFFER_SIZE (buf) -= stream->padding;
3642 if (G_UNLIKELY (qtdemux->element_index)) {
3643 GstClockTime stream_time;
3646 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
3648 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
3649 GST_LOG_OBJECT (qtdemux,
3650 "adding association %" GST_TIME_FORMAT "-> %"
3651 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
3652 gst_index_add_association (qtdemux->element_index,
3654 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
3655 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
3656 GST_FORMAT_BYTES, byte_position, NULL);
3660 if (stream->need_clip)
3661 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
3663 if (G_UNLIKELY (buf == NULL))
3666 if (G_UNLIKELY (stream->discont)) {
3667 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3668 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3669 stream->discont = FALSE;
3673 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3675 gst_buffer_set_caps (buf, stream->caps);
3677 GST_LOG_OBJECT (qtdemux,
3678 "Pushing buffer with time %" GST_TIME_FORMAT ", duration %"
3679 GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
3680 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
3682 ret = gst_pad_push (stream->pad, buf);
3688 static GstFlowReturn
3689 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
3691 GstFlowReturn ret = GST_FLOW_OK;
3692 GstBuffer *buf = NULL;
3693 QtDemuxStream *stream;
3696 guint64 timestamp = GST_CLOCK_TIME_NONE;
3697 guint64 duration = 0;
3698 gboolean keyframe = FALSE;
3703 gst_qtdemux_push_pending_newsegment (qtdemux);
3705 /* Figure out the next stream sample to output, min_time is expressed in
3706 * global time and runs over the edit list segments. */
3707 min_time = G_MAXUINT64;
3709 for (i = 0; i < qtdemux->n_streams; i++) {
3712 stream = qtdemux->streams[i];
3713 position = stream->time_position;
3715 /* position of -1 is EOS */
3716 if (position != -1 && position < min_time) {
3717 min_time = position;
3722 if (G_UNLIKELY (index == -1)) {
3723 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
3727 /* check for segment end */
3728 if (G_UNLIKELY (qtdemux->segment.stop != -1
3729 && qtdemux->segment.stop < min_time)) {
3730 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
3734 stream = qtdemux->streams[index];
3736 /* fetch info for the current sample of this stream */
3737 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
3738 &size, ×tamp, &duration, &keyframe)))
3741 GST_LOG_OBJECT (qtdemux,
3742 "pushing from stream %d, offset %" G_GUINT64_FORMAT
3743 ", size %d, timestamp=%" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
3744 index, offset, size, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
3746 /* hmm, empty sample, skip and move to next sample */
3747 if (G_UNLIKELY (size <= 0))
3750 /* last pushed sample was out of boundary, goto next sample */
3751 if (G_UNLIKELY (stream->last_ret == GST_FLOW_UNEXPECTED))
3754 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
3757 ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
3758 if (G_UNLIKELY (ret != GST_FLOW_OK))
3761 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
3762 timestamp, duration, keyframe, min_time, offset);
3765 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
3766 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
3767 * we have no more data for the pad to push */
3768 if (ret == GST_FLOW_UNEXPECTED)
3772 gst_qtdemux_advance_sample (qtdemux, stream);
3780 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
3781 ret = GST_FLOW_UNEXPECTED;
3786 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
3787 /* EOS will be raised if all are EOS */
3794 gst_qtdemux_loop (GstPad * pad)
3796 GstQTDemux *qtdemux;
3800 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
3802 cur_offset = qtdemux->offset;
3803 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
3804 cur_offset, qtdemux->state);
3806 switch (qtdemux->state) {
3807 case QTDEMUX_STATE_INITIAL:
3808 case QTDEMUX_STATE_HEADER:
3809 ret = gst_qtdemux_loop_state_header (qtdemux);
3811 case QTDEMUX_STATE_MOVIE:
3812 ret = gst_qtdemux_loop_state_movie (qtdemux);
3813 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_UNEXPECTED) {
3814 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
3822 /* if something went wrong, pause */
3823 if (ret != GST_FLOW_OK)
3827 gst_object_unref (qtdemux);
3833 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3834 (NULL), ("streaming stopped, invalid state"));
3835 qtdemux->segment_running = FALSE;
3836 gst_pad_pause_task (pad);
3837 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3842 const gchar *reason = gst_flow_get_name (ret);
3844 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
3846 qtdemux->segment_running = FALSE;
3847 gst_pad_pause_task (pad);
3849 /* fatal errors need special actions */
3851 if (ret == GST_FLOW_UNEXPECTED) {
3852 if (qtdemux->n_streams == 0) {
3853 /* we have no streams, post an error */
3854 gst_qtdemux_post_no_playable_stream_error (qtdemux);
3856 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3859 /* FIXME: I am not sure this is the right fix. If the sinks are
3860 * supposed to detect the segment is complete and accumulate
3861 * automatically, it does not seem to work here. Need more work */
3862 qtdemux->segment_running = TRUE;
3864 if ((stop = qtdemux->segment.stop) == -1)
3865 stop = qtdemux->segment.duration;
3867 if (qtdemux->segment.rate >= 0) {
3868 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
3869 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3870 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3871 GST_FORMAT_TIME, stop));
3873 /* For Reverse Playback */
3874 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
3875 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3876 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3877 GST_FORMAT_TIME, qtdemux->segment.start));
3880 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
3881 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3883 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
3884 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3885 (NULL), ("streaming stopped, reason %s", reason));
3886 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3895 * Returns the size of the first entry at the current offset.
3896 * If -1, there are none (which means EOS or empty file).
3899 next_entry_size (GstQTDemux * demux)
3901 QtDemuxStream *stream;
3904 guint64 smalloffs = (guint64) - 1;
3905 QtDemuxSample *sample;
3907 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
3910 for (i = 0; i < demux->n_streams; i++) {
3911 stream = demux->streams[i];
3913 if (stream->sample_index == -1)
3914 stream->sample_index = 0;
3916 if (stream->sample_index >= stream->n_samples) {
3917 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
3921 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
3922 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
3923 stream->sample_index);
3927 sample = &stream->samples[stream->sample_index];
3929 GST_LOG_OBJECT (demux,
3930 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3931 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
3932 sample->offset, sample->size);
3934 if (((smalloffs == -1)
3935 || (sample->offset < smalloffs)) && (sample->size)) {
3937 smalloffs = sample->offset;
3941 GST_LOG_OBJECT (demux,
3942 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
3943 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
3948 stream = demux->streams[smallidx];
3949 sample = &stream->samples[stream->sample_index];
3951 if (sample->offset >= demux->offset) {
3952 demux->todrop = sample->offset - demux->offset;
3953 return sample->size + demux->todrop;
3956 GST_DEBUG_OBJECT (demux,
3957 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
3962 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
3964 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
3966 gst_element_post_message (GST_ELEMENT_CAST (demux),
3967 gst_message_new_element (GST_OBJECT_CAST (demux),
3968 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
3972 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
3977 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
3980 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
3981 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
3982 GST_SEEK_TYPE_NONE, -1);
3984 res = gst_pad_push_event (demux->sinkpad, event);
3989 /* check for seekable upstream, above and beyond a mere query */
3991 gst_qtdemux_check_seekability (GstQTDemux * demux)
3994 gboolean seekable = FALSE;
3995 gint64 start = -1, stop = -1;
3997 if (demux->upstream_size)
4000 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4001 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4002 GST_DEBUG_OBJECT (demux, "seeking query failed");
4006 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4008 /* try harder to query upstream size if we didn't get it the first time */
4009 if (seekable && stop == -1) {
4010 GstFormat fmt = GST_FORMAT_BYTES;
4012 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4013 gst_pad_query_peer_duration (demux->sinkpad, &fmt, &stop);
4016 /* if upstream doesn't know the size, it's likely that it's not seekable in
4017 * practice even if it technically may be seekable */
4018 if (seekable && (start != 0 || stop <= start)) {
4019 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4024 gst_query_unref (query);
4026 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4027 G_GUINT64_FORMAT ")", seekable, start, stop);
4028 demux->upstream_seekable = seekable;
4029 demux->upstream_size = seekable ? stop : -1;
4032 /* FIXME, unverified after edit list updates */
4033 static GstFlowReturn
4034 gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
4037 GstFlowReturn ret = GST_FLOW_OK;
4039 demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad));
4041 gst_adapter_push (demux->adapter, inbuf);
4043 /* we never really mean to buffer that much */
4044 if (demux->neededbytes == -1)
4047 GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
4048 inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
4050 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4051 (ret == GST_FLOW_OK)) {
4053 GST_DEBUG_OBJECT (demux,
4054 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4055 demux->state, demux->neededbytes, demux->offset);
4057 switch (demux->state) {
4058 case QTDEMUX_STATE_INITIAL:{
4063 gst_qtdemux_check_seekability (demux);
4065 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
4067 /* get fourcc/length, set neededbytes */
4068 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4070 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4071 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4073 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4074 (_("This file is invalid and cannot be played.")),
4075 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4076 GST_FOURCC_ARGS (fourcc)));
4077 ret = GST_FLOW_ERROR;
4080 if (fourcc == FOURCC_mdat) {
4081 if (demux->n_streams > 0) {
4082 /* we have the headers, start playback */
4083 demux->state = QTDEMUX_STATE_MOVIE;
4084 demux->neededbytes = next_entry_size (demux);
4085 demux->mdatleft = size;
4087 /* Only post, event on pads is done after newsegment */
4088 qtdemux_post_global_tags (demux);
4091 /* no headers yet, try to get them */
4094 guint64 old, target;
4097 old = demux->offset;
4098 target = old + size;
4100 /* try to jump over the atom with a seek */
4101 /* only bother if it seems worth doing so,
4102 * and avoids possible upstream/server problems */
4103 if (demux->upstream_seekable &&
4104 demux->upstream_size > 4 * (1 << 20)) {
4105 res = qtdemux_seek_offset (demux, target);
4107 GST_DEBUG_OBJECT (demux, "skipping seek");
4112 GST_DEBUG_OBJECT (demux, "seek success");
4113 /* remember the offset fo the first mdat so we can seek back to it
4114 * after we have the headers */
4115 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4116 demux->first_mdat = old;
4117 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4120 /* seek worked, continue reading */
4121 demux->offset = target;
4122 demux->neededbytes = 16;
4123 demux->state = QTDEMUX_STATE_INITIAL;
4125 /* seek failed, need to buffer */
4126 demux->offset = old;
4127 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4128 /* there may be multiple mdat (or alike) buffers */
4130 if (demux->mdatbuffer)
4131 bs = GST_BUFFER_SIZE (demux->mdatbuffer);
4134 if (size + bs > 10 * (1 << 20))
4136 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4137 demux->neededbytes = size;
4138 if (!demux->mdatbuffer)
4139 demux->mdatoffset = demux->offset;
4142 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4143 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4144 (_("This file is invalid and cannot be played.")),
4145 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4146 GST_FOURCC_ARGS (fourcc), size));
4147 ret = GST_FLOW_ERROR;
4150 /* this means we already started buffering and still no moov header,
4151 * let's continue buffering everything till we get moov */
4152 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
4154 demux->neededbytes = size;
4155 demux->state = QTDEMUX_STATE_HEADER;
4159 case QTDEMUX_STATE_HEADER:{
4163 GST_DEBUG_OBJECT (demux, "In header");
4165 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
4167 /* parse the header */
4168 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4170 if (fourcc == FOURCC_moov) {
4171 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4173 demux->got_moov = TRUE;
4175 /* prepare newsegment to send when streaming actually starts */
4176 if (!demux->pending_newsegment) {
4177 demux->pending_newsegment =
4178 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
4179 0, GST_CLOCK_TIME_NONE, 0);
4182 qtdemux_parse_moov (demux, data, demux->neededbytes);
4183 qtdemux_node_dump (demux, demux->moov_node);
4184 qtdemux_parse_tree (demux);
4185 qtdemux_expose_streams (demux);
4187 g_node_destroy (demux->moov_node);
4188 demux->moov_node = NULL;
4189 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4190 } else if (fourcc == FOURCC_moof) {
4191 if (demux->got_moov && demux->fragmented) {
4192 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4193 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4194 demux->offset, NULL)) {
4195 ret = GST_FLOW_ERROR;
4199 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4201 } else if (fourcc == FOURCC_ftyp) {
4202 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4203 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4204 } else if (fourcc == FOURCC_uuid) {
4205 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4206 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4208 GST_WARNING_OBJECT (demux,
4209 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4210 GST_FOURCC_ARGS (fourcc));
4211 /* Let's jump that one and go back to initial state */
4214 if (demux->mdatbuffer && demux->n_streams) {
4215 /* the mdat was before the header */
4216 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4217 demux->n_streams, demux->mdatbuffer);
4218 /* restore our adapter/offset view of things with upstream;
4219 * put preceding buffered data ahead of current moov data.
4220 * This should also handle evil mdat, moov, mdat cases and alike */
4221 gst_adapter_clear (demux->adapter);
4222 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4223 demux->mdatbuffer = NULL;
4224 demux->offset = demux->mdatoffset;
4225 demux->neededbytes = next_entry_size (demux);
4226 demux->state = QTDEMUX_STATE_MOVIE;
4227 demux->mdatleft = gst_adapter_available (demux->adapter);
4229 /* Only post, event on pads is done after newsegment */
4230 qtdemux_post_global_tags (demux);
4233 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4234 gst_adapter_flush (demux->adapter, demux->neededbytes);
4236 if (demux->got_moov && demux->first_mdat != -1) {
4239 /* we need to seek back */
4240 res = qtdemux_seek_offset (demux, demux->first_mdat);
4242 demux->offset = demux->first_mdat;
4244 GST_DEBUG_OBJECT (demux, "Seek back failed");
4247 demux->offset += demux->neededbytes;
4249 demux->neededbytes = 16;
4250 demux->state = QTDEMUX_STATE_INITIAL;
4255 case QTDEMUX_STATE_BUFFER_MDAT:{
4258 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4260 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4261 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4262 GST_FOURCC_ARGS (QT_FOURCC (GST_BUFFER_DATA (buf) + 4)));
4263 if (demux->mdatbuffer)
4264 demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
4266 demux->mdatbuffer = buf;
4267 demux->offset += demux->neededbytes;
4268 demux->neededbytes = 16;
4269 demux->state = QTDEMUX_STATE_INITIAL;
4270 gst_qtdemux_post_progress (demux, 1, 1);
4274 case QTDEMUX_STATE_MOVIE:{
4276 QtDemuxStream *stream = NULL;
4277 QtDemuxSample *sample;
4279 guint64 timestamp, duration, position;
4282 GST_DEBUG_OBJECT (demux,
4283 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4285 if (demux->fragmented) {
4286 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4288 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4289 /* if needed data starts within this atom,
4290 * then it should not exceed this atom */
4291 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4292 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4293 (_("This file is invalid and cannot be played.")),
4294 ("sample data crosses atom boundary"));
4295 ret = GST_FLOW_ERROR;
4298 demux->mdatleft -= demux->neededbytes;
4300 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4301 /* so we are dropping more than left in this atom */
4302 demux->todrop -= demux->mdatleft;
4303 demux->neededbytes -= demux->mdatleft;
4304 demux->mdatleft = 0;
4305 /* need to resume atom parsing so we do not miss any other pieces */
4306 demux->state = QTDEMUX_STATE_INITIAL;
4307 demux->neededbytes = 16;
4312 if (demux->todrop) {
4313 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4314 gst_adapter_flush (demux->adapter, demux->todrop);
4315 demux->neededbytes -= demux->todrop;
4316 demux->offset += demux->todrop;
4320 /* initial newsegment sent here after having added pads,
4321 * possible others in sink_event */
4322 if (G_UNLIKELY (demux->pending_newsegment)) {
4323 gst_qtdemux_push_event (demux, demux->pending_newsegment);
4324 demux->pending_newsegment = NULL;
4325 /* clear to send tags on all streams */
4326 for (i = 0; i < demux->n_streams; i++) {
4327 gst_qtdemux_push_tags (demux, demux->streams[i]);
4331 /* Figure out which stream this is packet belongs to */
4332 for (i = 0; i < demux->n_streams; i++) {
4333 stream = demux->streams[i];
4334 if (stream->sample_index >= stream->n_samples)
4336 GST_LOG_OBJECT (demux,
4337 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4338 " / size:%d)", i, stream->sample_index,
4339 stream->samples[stream->sample_index].offset,
4340 stream->samples[stream->sample_index].size);
4342 if (stream->samples[stream->sample_index].offset == demux->offset)
4346 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4347 goto unknown_stream;
4349 /* Put data in a buffer, set timestamps, caps, ... */
4350 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4351 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4352 GST_FOURCC_ARGS (stream->fourcc));
4354 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4356 sample = &stream->samples[stream->sample_index];
4358 position = QTSAMPLE_DTS (stream, sample);
4359 timestamp = QTSAMPLE_PTS (stream, sample);
4360 duration = QTSAMPLE_DUR_DTS (stream, sample, position);
4361 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4363 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4364 timestamp, duration, keyframe, position, demux->offset);
4367 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4369 stream->sample_index++;
4371 /* update current offset and figure out size of next buffer */
4372 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4373 demux->offset, demux->neededbytes);
4374 demux->offset += demux->neededbytes;
4375 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4378 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4379 if (demux->fragmented) {
4380 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4381 /* there may be more to follow, only finish this atom */
4382 demux->todrop = demux->mdatleft;
4383 demux->neededbytes = demux->todrop;
4395 /* when buffering movie data, at least show user something is happening */
4396 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4397 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4398 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4399 demux->neededbytes);
4402 gst_object_unref (demux);
4409 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4410 ret = GST_FLOW_ERROR;
4415 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4416 ret = GST_FLOW_UNEXPECTED;
4421 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4422 (NULL), ("qtdemuxer invalid state %d", demux->state));
4423 ret = GST_FLOW_ERROR;
4428 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4429 (NULL), ("no 'moov' atom within the first 10 MB"));
4430 ret = GST_FLOW_ERROR;
4436 qtdemux_sink_activate (GstPad * sinkpad)
4438 if (gst_pad_check_pull_range (sinkpad))
4439 return gst_pad_activate_pull (sinkpad, TRUE);
4441 return gst_pad_activate_push (sinkpad, TRUE);
4445 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
4447 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
4450 demux->pullbased = TRUE;
4451 demux->segment_running = TRUE;
4452 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4455 demux->segment_running = FALSE;
4456 return gst_pad_stop_task (sinkpad);
4461 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
4463 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
4465 demux->pullbased = FALSE;
4472 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4474 return g_malloc (items * size);
4478 qtdemux_zfree (void *opaque, void *addr)
4484 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4490 z = g_new0 (z_stream, 1);
4491 z->zalloc = qtdemux_zalloc;
4492 z->zfree = qtdemux_zfree;
4495 z->next_in = z_buffer;
4496 z->avail_in = z_length;
4498 buffer = (guint8 *) g_malloc (length);
4499 ret = inflateInit (z);
4500 while (z->avail_in > 0) {
4501 if (z->avail_out == 0) {
4503 buffer = (guint8 *) g_realloc (buffer, length);
4504 z->next_out = buffer + z->total_out;
4505 z->avail_out = 1024;
4507 ret = inflate (z, Z_SYNC_FLUSH);
4511 if (ret != Z_STREAM_END) {
4512 g_warning ("inflate() returned %d", ret);
4518 #endif /* HAVE_ZLIB */
4521 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4525 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4527 /* counts as header data */
4528 qtdemux->header_size += length;
4530 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4531 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4533 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4539 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4540 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4541 if (dcom == NULL || cmvd == NULL)
4542 goto invalid_compression;
4544 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4547 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4548 guint uncompressed_length;
4549 guint compressed_length;
4552 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4553 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4554 GST_LOG ("length = %u", uncompressed_length);
4557 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4558 compressed_length, uncompressed_length);
4560 qtdemux->moov_node_compressed = qtdemux->moov_node;
4561 qtdemux->moov_node = g_node_new (buf);
4563 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4564 uncompressed_length);
4567 #endif /* HAVE_ZLIB */
4569 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4570 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
4577 invalid_compression:
4579 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
4585 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
4588 while (G_UNLIKELY (buf < end)) {
4592 if (G_UNLIKELY (buf + 4 > end)) {
4593 GST_LOG_OBJECT (qtdemux, "buffer overrun");
4596 len = QT_UINT32 (buf);
4597 if (G_UNLIKELY (len == 0)) {
4598 GST_LOG_OBJECT (qtdemux, "empty container");
4601 if (G_UNLIKELY (len < 8)) {
4602 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
4605 if (G_UNLIKELY (len > (end - buf))) {
4606 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
4607 (gint) (end - buf));
4611 child = g_node_new ((guint8 *) buf);
4612 g_node_append (node, child);
4613 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
4614 qtdemux_parse_node (qtdemux, child, buf, len);
4622 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
4625 int len = QT_UINT32 (xdxt->data);
4626 guint8 *buf = xdxt->data;
4627 guint8 *end = buf + len;
4630 /* skip size and type */
4638 size = QT_UINT32 (buf);
4639 type = QT_FOURCC (buf + 4);
4641 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
4643 if (buf + size > end || size <= 0)
4649 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
4650 GST_FOURCC_ARGS (type));
4654 buffer = gst_buffer_new_and_alloc (size);
4655 memcpy (GST_BUFFER_DATA (buffer), buf, size);
4656 stream->buffers = g_slist_append (stream->buffers, buffer);
4657 GST_LOG_OBJECT (qtdemux, "parsing theora header");
4660 buffer = gst_buffer_new_and_alloc (size);
4661 memcpy (GST_BUFFER_DATA (buffer), buf, size);
4662 stream->buffers = g_slist_append (stream->buffers, buffer);
4663 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
4666 buffer = gst_buffer_new_and_alloc (size);
4667 memcpy (GST_BUFFER_DATA (buffer), buf, size);
4668 stream->buffers = g_slist_append (stream->buffers, buffer);
4669 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
4672 GST_WARNING_OBJECT (qtdemux,
4673 "unknown theora cookie %" GST_FOURCC_FORMAT,
4674 GST_FOURCC_ARGS (type));
4683 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
4687 guint32 node_length = 0;
4688 const QtNodeType *type;
4691 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
4693 if (G_UNLIKELY (length < 8))
4694 goto not_enough_data;
4696 node_length = QT_UINT32 (buffer);
4697 fourcc = QT_FOURCC (buffer + 4);
4699 /* ignore empty nodes */
4700 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
4703 type = qtdemux_type_get (fourcc);
4705 end = buffer + length;
4707 GST_LOG_OBJECT (qtdemux,
4708 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
4709 GST_FOURCC_ARGS (fourcc), node_length, type->name);
4711 if (node_length > length)
4712 goto broken_atom_size;
4714 if (type->flags & QT_FLAG_CONTAINER) {
4715 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
4720 if (node_length < 20) {
4721 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
4724 GST_DEBUG_OBJECT (qtdemux,
4725 "parsing stsd (sample table, sample description) atom");
4726 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
4736 /* also read alac (or whatever) in stead of mp4a in the following,
4737 * since a similar layout is used in other cases as well */
4738 if (fourcc == FOURCC_mp4a)
4743 /* There are two things we might encounter here: a true mp4a atom, and
4744 an mp4a entry in an stsd atom. The latter is what we're interested
4745 in, and it looks like an atom, but isn't really one. The true mp4a
4746 atom is short, so we detect it based on length here. */
4747 if (length < min_size) {
4748 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
4749 GST_FOURCC_ARGS (fourcc));
4753 /* 'version' here is the sound sample description version. Types 0 and
4754 1 are documented in the QTFF reference, but type 2 is not: it's
4755 described in Apple header files instead (struct SoundDescriptionV2
4757 version = QT_UINT16 (buffer + 16);
4759 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
4760 GST_FOURCC_ARGS (fourcc), version);
4762 /* parse any esds descriptors */
4774 GST_WARNING_OBJECT (qtdemux,
4775 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
4776 GST_FOURCC_ARGS (fourcc), version);
4781 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4793 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
4794 GST_FOURCC_ARGS (fourcc));
4795 version = QT_UINT32 (buffer + 16);
4796 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
4797 if (1 || version == 0x00000000) {
4798 buf = buffer + 0x32;
4800 /* FIXME Quicktime uses PASCAL string while
4801 * the iso format uses C strings. Check the file
4802 * type before attempting to parse the string here. */
4803 tlen = QT_UINT8 (buf);
4804 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
4806 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
4807 /* the string has a reserved space of 32 bytes so skip
4808 * the remaining 31 */
4810 buf += 4; /* and 4 bytes reserved */
4812 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
4814 qtdemux_parse_container (qtdemux, node, buf, end);
4820 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
4821 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
4826 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
4831 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
4832 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
4840 version = QT_UINT32 (buffer + 12);
4841 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
4848 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
4853 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4858 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
4862 if (!strcmp (type->name, "unknown"))
4863 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
4867 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
4868 GST_FOURCC_ARGS (fourcc));
4874 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4875 (_("This file is corrupt and cannot be played.")),
4876 ("Not enough data for an atom header, got only %u bytes", length));
4881 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4882 (_("This file is corrupt and cannot be played.")),
4883 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
4884 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
4891 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
4895 guint32 child_fourcc;
4897 for (child = g_node_first_child (node); child;
4898 child = g_node_next_sibling (child)) {
4899 buffer = (guint8 *) child->data;
4901 child_fourcc = QT_FOURCC (buffer + 4);
4903 if (G_UNLIKELY (child_fourcc == fourcc)) {
4911 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
4912 GstByteReader * parser)
4916 guint32 child_fourcc, child_len;
4918 for (child = g_node_first_child (node); child;
4919 child = g_node_next_sibling (child)) {
4920 buffer = (guint8 *) child->data;
4922 child_len = QT_UINT32 (buffer);
4923 child_fourcc = QT_FOURCC (buffer + 4);
4925 if (G_UNLIKELY (child_fourcc == fourcc)) {
4926 if (G_UNLIKELY (child_len < (4 + 4)))
4928 /* FIXME: must verify if atom length < parent atom length */
4929 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4937 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
4938 GstByteReader * parser)
4942 guint32 child_fourcc, child_len;
4944 for (child = g_node_next_sibling (node); child;
4945 child = g_node_next_sibling (child)) {
4946 buffer = (guint8 *) child->data;
4948 child_fourcc = QT_FOURCC (buffer + 4);
4950 if (child_fourcc == fourcc) {
4952 child_len = QT_UINT32 (buffer);
4953 if (G_UNLIKELY (child_len < (4 + 4)))
4955 /* FIXME: must verify if atom length < parent atom length */
4956 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4965 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
4967 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
4971 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
4972 QtDemuxStream * stream, GstTagList * list)
4974 /* consistent default for push based mode */
4975 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
4976 gst_segment_set_newsegment (&stream->segment, FALSE, 1.0, GST_FORMAT_TIME,
4977 0, GST_CLOCK_TIME_NONE, 0);
4979 if (stream->subtype == FOURCC_vide) {
4980 gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
4983 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
4986 /* fps is calculated base on the duration of the first frames since
4987 * qt does not have a fixed framerate. */
4988 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
4993 stream->fps_n = stream->timescale;
4994 if (stream->min_duration == 0)
4997 stream->fps_d = stream->min_duration;
5002 gint depth, palette_count;
5003 const guint32 *palette_data = NULL;
5005 gst_caps_set_simple (stream->caps,
5006 "width", G_TYPE_INT, stream->width,
5007 "height", G_TYPE_INT, stream->height,
5008 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5010 /* calculate pixel-aspect-ratio using display width and height */
5011 GST_DEBUG_OBJECT (qtdemux,
5012 "video size %dx%d, target display size %dx%d", stream->width,
5013 stream->height, stream->display_width, stream->display_height);
5015 if (stream->display_width > 0 && stream->display_height > 0 &&
5016 stream->width > 0 && stream->height > 0) {
5019 /* calculate the pixel aspect ratio using the display and pixel w/h */
5020 n = stream->display_width * stream->height;
5021 d = stream->display_height * stream->width;
5024 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5025 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5026 GST_TYPE_FRACTION, n, d, NULL);
5029 /* qt file might have pasp atom */
5030 if (stream->par_w > 0 && stream->par_h > 0) {
5031 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5032 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5033 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5036 depth = stream->bits_per_sample;
5038 /* more than 32 bits means grayscale */
5039 gray = (depth > 32);
5040 /* low 32 bits specify the depth */
5043 /* different number of palette entries is determined by depth. */
5045 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
5046 palette_count = (1 << depth);
5048 switch (palette_count) {
5052 palette_data = ff_qt_default_palette_2;
5055 palette_data = ff_qt_default_palette_4;
5059 palette_data = ff_qt_grayscale_palette_16;
5061 palette_data = ff_qt_default_palette_16;
5065 palette_data = ff_qt_grayscale_palette_256;
5067 palette_data = ff_qt_default_palette_256;
5070 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5071 (_("The video in this file might not play correctly.")),
5072 ("unsupported palette depth %d", depth));
5078 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5079 * don't free any of the buffer data. */
5080 palette = gst_buffer_new ();
5081 GST_BUFFER_FLAG_SET (palette, GST_BUFFER_FLAG_READONLY);
5082 GST_BUFFER_DATA (palette) = (guint8 *) palette_data;
5083 GST_BUFFER_SIZE (palette) = sizeof (guint32) * palette_count;
5085 gst_caps_set_simple (stream->caps, "palette_data",
5086 GST_TYPE_BUFFER, palette, NULL);
5087 gst_buffer_unref (palette);
5088 } else if (palette_count != 0) {
5089 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5090 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5092 gst_object_unref (stream->pad);
5096 qtdemux->n_video_streams++;
5097 } else if (stream->subtype == FOURCC_soun) {
5098 gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
5101 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5104 gst_caps_set_simple (stream->caps,
5105 "rate", G_TYPE_INT, (int) stream->rate,
5106 "channels", G_TYPE_INT, stream->n_channels, NULL);
5108 qtdemux->n_audio_streams++;
5109 } else if (stream->subtype == FOURCC_strm) {
5110 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5111 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
5112 gchar *name = g_strdup_printf ("subtitle_%02d", qtdemux->n_sub_streams);
5115 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5117 qtdemux->n_sub_streams++;
5119 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5124 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5126 gst_pad_use_fixed_caps (stream->pad);
5127 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5128 gst_pad_set_query_type_function (stream->pad,
5129 gst_qtdemux_get_src_query_types);
5130 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5132 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5133 gst_pad_set_caps (stream->pad, stream->caps);
5135 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5136 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5137 gst_pad_set_active (stream->pad, TRUE);
5138 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5139 if (stream->pending_tags)
5140 gst_tag_list_free (stream->pending_tags);
5141 stream->pending_tags = list;
5143 /* post now, send event on pad later */
5144 GST_DEBUG_OBJECT (qtdemux, "Posting tags %" GST_PTR_FORMAT, list);
5145 gst_element_post_message (GST_ELEMENT (qtdemux),
5146 gst_message_new_tag_full (GST_OBJECT (qtdemux), stream->pad,
5147 gst_tag_list_copy (list)));
5149 /* global tags go on each pad anyway */
5150 stream->send_global_tags = TRUE;
5156 /* find next atom with @fourcc starting at @offset */
5157 static GstFlowReturn
5158 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5159 guint64 * length, guint32 fourcc)
5165 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5166 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5169 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5170 if (G_UNLIKELY (ret != GST_FLOW_OK))
5172 if (G_LIKELY (GST_BUFFER_SIZE (buf) != 16)) {
5174 ret = GST_FLOW_UNEXPECTED;
5175 gst_buffer_unref (buf);
5178 extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf), 16, length,
5180 gst_buffer_unref (buf);
5182 if (G_UNLIKELY (*length == 0)) {
5183 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5184 ret = GST_FLOW_ERROR;
5188 if (lfourcc == fourcc) {
5189 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5193 GST_LOG_OBJECT (qtdemux,
5194 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5195 GST_FOURCC_ARGS (fourcc), *offset);
5204 /* might simply have had last one */
5205 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5210 /* should only do something in pull mode */
5211 /* call with OBJECT lock */
5212 static GstFlowReturn
5213 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5215 guint64 length, offset;
5216 GstBuffer *buf = NULL;
5217 GstFlowReturn ret = GST_FLOW_OK;
5218 GstFlowReturn res = GST_FLOW_OK;
5220 offset = qtdemux->moof_offset;
5221 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5224 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5225 return GST_FLOW_UNEXPECTED;
5228 /* best not do pull etc with lock held */
5229 GST_OBJECT_UNLOCK (qtdemux);
5231 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5232 if (ret != GST_FLOW_OK)
5235 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5236 if (G_UNLIKELY (ret != GST_FLOW_OK))
5238 if (!qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf),
5239 GST_BUFFER_SIZE (buf), offset, NULL)) {
5240 gst_buffer_unref (buf);
5245 gst_buffer_unref (buf);
5249 /* look for next moof */
5250 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5251 if (G_UNLIKELY (ret != GST_FLOW_OK))
5255 GST_OBJECT_LOCK (qtdemux);
5257 qtdemux->moof_offset = offset;
5263 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5265 res = GST_FLOW_ERROR;
5270 /* maybe upstream temporarily flushing */
5271 if (ret != GST_FLOW_WRONG_STATE) {
5272 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5275 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5276 /* resume at current position next time */
5283 /* initialise bytereaders for stbl sub-atoms */
5285 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5287 stream->stbl_index = -1; /* no samples have yet been parsed */
5289 /* time-to-sample atom */
5290 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5293 /* copy atom data into a new buffer for later use */
5294 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5296 /* skip version + flags */
5297 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5298 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5300 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5302 /* make sure there's enough data */
5303 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 2 * 4))
5306 /* sync sample atom */
5307 stream->stps_present = FALSE;
5308 if ((stream->stss_present =
5309 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5310 &stream->stss) ? TRUE : FALSE) == TRUE) {
5311 /* copy atom data into a new buffer for later use */
5312 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5314 /* skip version + flags */
5315 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5316 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5319 if (stream->n_sample_syncs) {
5320 /* make sure there's enough data */
5321 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5325 /* partial sync sample atom */
5326 if ((stream->stps_present =
5327 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5328 &stream->stps) ? TRUE : FALSE) == TRUE) {
5329 /* copy atom data into a new buffer for later use */
5330 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5332 /* skip version + flags */
5333 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5334 !gst_byte_reader_get_uint32_be (&stream->stps,
5335 &stream->n_sample_partial_syncs))
5338 /* if there are no entries, the stss table contains the real
5340 if (stream->n_sample_partial_syncs) {
5341 /* make sure there's enough data */
5342 if (!qt_atom_parser_has_chunks (&stream->stps,
5343 stream->n_sample_partial_syncs, 4))
5350 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5353 /* copy atom data into a new buffer for later use */
5354 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5356 /* skip version + flags */
5357 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5358 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5361 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5364 if (!stream->n_samples)
5367 /* sample-to-chunk atom */
5368 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5371 /* copy atom data into a new buffer for later use */
5372 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5374 /* skip version + flags */
5375 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5376 !gst_byte_reader_get_uint32_be (&stream->stsc,
5377 &stream->n_samples_per_chunk))
5380 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5381 stream->n_samples_per_chunk);
5383 /* make sure there's enough data */
5384 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5390 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5391 stream->co_size = sizeof (guint32);
5392 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5394 stream->co_size = sizeof (guint64);
5398 /* copy atom data into a new buffer for later use */
5399 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5401 /* skip version + flags */
5402 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5405 /* chunks_are_chunks == 0 means treat chunks as samples */
5406 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5407 if (stream->chunks_are_chunks) {
5408 /* skip number of entries */
5409 if (!gst_byte_reader_skip (&stream->stco, 4))
5412 /* make sure there are enough data in the stsz atom */
5413 if (!stream->sample_size) {
5414 /* different sizes for each sample */
5415 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5419 /* treat chunks as samples */
5420 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5424 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5425 stream->n_samples, (guint) sizeof (QtDemuxSample),
5426 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5428 if (stream->n_samples >=
5429 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5430 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5431 "be larger than %uMB (broken file?)", stream->n_samples,
5432 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5436 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5437 if (!stream->samples) {
5438 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5444 /* composition time-to-sample */
5445 if ((stream->ctts_present =
5446 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5447 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5448 /* copy atom data into a new buffer for later use */
5449 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5451 /* skip version + flags */
5452 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5453 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5454 &stream->n_composition_times))
5457 /* make sure there's enough data */
5458 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5467 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5468 (_("This file is corrupt and cannot be played.")), (NULL));
5473 gst_qtdemux_stbl_free (stream);
5474 if (!qtdemux->fragmented) {
5475 /* not quite good */
5476 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5479 /* may pick up samples elsewhere */
5485 /* collect samples from the next sample to be parsed up to sample @n for @stream
5486 * by reading the info from @stbl
5488 * This code can be executed from both the streaming thread and the seeking
5489 * thread so it takes the object lock to protect itself
5492 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
5495 QtDemuxSample *samples, *first, *cur, *last;
5496 guint32 n_samples_per_chunk;
5499 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
5500 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
5501 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
5503 n_samples = stream->n_samples;
5506 goto out_of_samples;
5508 GST_OBJECT_LOCK (qtdemux);
5509 if (n <= stream->stbl_index)
5510 goto already_parsed;
5512 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
5514 if (!stream->stsz.data) {
5515 /* so we already parsed and passed all the moov samples;
5516 * onto fragmented ones */
5517 g_assert (qtdemux->fragmented);
5521 /* pointer to the sample table */
5522 samples = stream->samples;
5524 /* starts from -1, moves to the next sample index to parse */
5525 stream->stbl_index++;
5527 /* keep track of the first and last sample to fill */
5528 first = &samples[stream->stbl_index];
5531 if (stream->chunks_are_chunks) {
5532 /* set the sample sizes */
5533 if (stream->sample_size == 0) {
5534 /* different sizes for each sample */
5535 for (cur = first; cur <= last; cur++) {
5536 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
5537 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
5538 (guint) (cur - samples), cur->size);
5541 /* samples have the same size */
5542 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
5543 for (cur = first; cur <= last; cur++)
5544 cur->size = stream->sample_size;
5548 n_samples_per_chunk = stream->n_samples_per_chunk;
5551 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
5554 if (stream->stsc_chunk_index >= stream->last_chunk
5555 || stream->stsc_chunk_index < stream->first_chunk) {
5556 stream->first_chunk =
5557 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5558 stream->samples_per_chunk =
5559 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5560 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
5562 /* chunk numbers are counted from 1 it seems */
5563 if (G_UNLIKELY (stream->first_chunk == 0))
5566 --stream->first_chunk;
5568 /* the last chunk of each entry is calculated by taking the first chunk
5569 * of the next entry; except if there is no next, where we fake it with
5571 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
5572 stream->last_chunk = G_MAXUINT32;
5574 stream->last_chunk =
5575 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
5576 if (G_UNLIKELY (stream->last_chunk == 0))
5579 --stream->last_chunk;
5582 GST_LOG_OBJECT (qtdemux,
5583 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
5584 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
5586 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
5589 if (stream->last_chunk != G_MAXUINT32) {
5590 if (!qt_atom_parser_peek_sub (&stream->stco,
5591 stream->first_chunk * stream->co_size,
5592 (stream->last_chunk - stream->first_chunk) * stream->co_size,
5597 stream->co_chunk = stream->stco;
5598 if (!gst_byte_reader_skip (&stream->co_chunk,
5599 stream->first_chunk * stream->co_size))
5603 stream->stsc_chunk_index = stream->first_chunk;
5606 last_chunk = stream->last_chunk;
5608 if (stream->chunks_are_chunks) {
5609 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5610 guint32 samples_per_chunk;
5611 guint64 chunk_offset;
5613 if (!stream->stsc_sample_index
5614 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
5615 &stream->chunk_offset))
5618 samples_per_chunk = stream->samples_per_chunk;
5619 chunk_offset = stream->chunk_offset;
5621 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
5622 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
5623 G_GUINT64_FORMAT, (guint) (cur - samples), stream->chunk_offset);
5625 cur->offset = chunk_offset;
5626 chunk_offset += cur->size;
5629 if (G_UNLIKELY (cur > last)) {
5631 stream->stsc_sample_index = k + 1;
5632 stream->chunk_offset = chunk_offset;
5633 stream->stsc_chunk_index = j;
5637 stream->stsc_sample_index = 0;
5639 stream->stsc_chunk_index = j;
5641 cur = &samples[stream->stsc_chunk_index];
5643 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5646 stream->stsc_chunk_index = j;
5651 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
5654 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
5655 "%" G_GUINT64_FORMAT, j, cur->offset);
5657 if (stream->samples_per_frame * stream->bytes_per_frame) {
5659 (stream->samples_per_chunk * stream->n_channels) /
5660 stream->samples_per_frame * stream->bytes_per_frame;
5662 cur->size = stream->samples_per_chunk;
5665 GST_DEBUG_OBJECT (qtdemux,
5666 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
5667 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
5668 GST_SECOND, stream->timescale)), cur->size);
5670 cur->timestamp = stream->stco_sample_index;
5671 cur->duration = stream->samples_per_chunk;
5672 cur->keyframe = TRUE;
5675 stream->stco_sample_index += stream->samples_per_chunk;
5677 stream->stsc_chunk_index = j;
5679 stream->stsc_index++;
5682 if (!stream->chunks_are_chunks)
5686 guint32 n_sample_times;
5688 n_sample_times = stream->n_sample_times;
5691 for (i = stream->stts_index; i < n_sample_times; i++) {
5692 guint32 stts_samples;
5693 gint32 stts_duration;
5696 if (stream->stts_sample_index >= stream->stts_samples
5697 || !stream->stts_sample_index) {
5699 stream->stts_samples =
5700 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5701 stream->stts_duration =
5702 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5704 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
5705 i, stream->stts_samples, stream->stts_duration);
5707 stream->stts_sample_index = 0;
5710 stts_samples = stream->stts_samples;
5711 stts_duration = stream->stts_duration;
5712 stts_time = stream->stts_time;
5714 for (j = stream->stts_sample_index; j < stts_samples; j++) {
5715 GST_DEBUG_OBJECT (qtdemux,
5716 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
5717 (guint) (cur - samples), j,
5718 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
5719 stream->timescale)));
5721 cur->timestamp = stts_time;
5722 cur->duration = stts_duration;
5724 /* avoid 32-bit wrap-around,
5725 * but still mind possible 'negative' duration */
5726 stts_time += (gint64) stts_duration;
5729 if (G_UNLIKELY (cur > last)) {
5731 stream->stts_time = stts_time;
5732 stream->stts_sample_index = j + 1;
5736 stream->stts_sample_index = 0;
5737 stream->stts_time = stts_time;
5738 stream->stts_index++;
5740 /* fill up empty timestamps with the last timestamp, this can happen when
5741 * the last samples do not decode and so we don't have timestamps for them.
5742 * We however look at the last timestamp to estimate the track length so we
5743 * need something in here. */
5744 for (; cur < last; cur++) {
5745 GST_DEBUG_OBJECT (qtdemux,
5746 "fill sample %d: timestamp %" GST_TIME_FORMAT,
5747 (guint) (cur - samples),
5748 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
5749 stream->timescale)));
5750 cur->timestamp = stream->stts_time;
5756 /* sample sync, can be NULL */
5757 if (stream->stss_present == TRUE) {
5758 guint32 n_sample_syncs;
5760 n_sample_syncs = stream->n_sample_syncs;
5762 if (!n_sample_syncs) {
5763 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
5764 stream->all_keyframe = TRUE;
5766 for (i = stream->stss_index; i < n_sample_syncs; i++) {
5767 /* note that the first sample is index 1, not 0 */
5770 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
5772 if (G_LIKELY (index > 0 && index <= n_samples)) {
5774 samples[index].keyframe = TRUE;
5775 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5776 /* and exit if we have enough samples */
5777 if (G_UNLIKELY (index >= n)) {
5784 stream->stss_index = i;
5787 /* stps marks partial sync frames like open GOP I-Frames */
5788 if (stream->stps_present == TRUE) {
5789 guint32 n_sample_partial_syncs;
5791 n_sample_partial_syncs = stream->n_sample_partial_syncs;
5793 /* if there are no entries, the stss table contains the real
5795 if (n_sample_partial_syncs) {
5796 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
5797 /* note that the first sample is index 1, not 0 */
5800 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
5802 if (G_LIKELY (index > 0 && index <= n_samples)) {
5804 samples[index].keyframe = TRUE;
5805 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5806 /* and exit if we have enough samples */
5807 if (G_UNLIKELY (index >= n)) {
5814 stream->stps_index = i;
5818 /* no stss, all samples are keyframes */
5819 stream->all_keyframe = TRUE;
5820 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
5825 /* composition time to sample */
5826 if (stream->ctts_present == TRUE) {
5827 guint32 n_composition_times;
5829 gint32 ctts_soffset;
5831 /* Fill in the pts_offsets */
5833 n_composition_times = stream->n_composition_times;
5835 for (i = stream->ctts_index; i < n_composition_times; i++) {
5836 if (stream->ctts_sample_index >= stream->ctts_count
5837 || !stream->ctts_sample_index) {
5838 stream->ctts_count =
5839 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
5840 stream->ctts_soffset =
5841 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
5842 stream->ctts_sample_index = 0;
5845 ctts_count = stream->ctts_count;
5846 ctts_soffset = stream->ctts_soffset;
5848 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
5849 cur->pts_offset = ctts_soffset;
5852 if (G_UNLIKELY (cur > last)) {
5854 stream->ctts_sample_index = j + 1;
5858 stream->ctts_sample_index = 0;
5859 stream->ctts_index++;
5863 stream->stbl_index = n;
5864 /* if index has been completely parsed, free data that is no-longer needed */
5865 if (n + 1 == stream->n_samples) {
5866 gst_qtdemux_stbl_free (stream);
5867 GST_DEBUG_OBJECT (qtdemux,
5868 "parsed all available samples; checking for more");
5869 while (n + 1 == stream->n_samples)
5870 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
5873 GST_OBJECT_UNLOCK (qtdemux);
5880 GST_LOG_OBJECT (qtdemux,
5881 "Tried to parse up to sample %u but this sample has already been parsed",
5883 /* if fragmented, there may be more */
5884 if (qtdemux->fragmented && n == stream->stbl_index)
5886 GST_OBJECT_UNLOCK (qtdemux);
5892 GST_LOG_OBJECT (qtdemux,
5893 "Tried to parse up to sample %u but there are only %u samples", n + 1,
5895 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5896 (_("This file is corrupt and cannot be played.")), (NULL));
5901 GST_OBJECT_UNLOCK (qtdemux);
5902 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5903 (_("This file is corrupt and cannot be played.")), (NULL));
5908 /* collect all segment info for @stream.
5911 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
5916 /* parse and prepare segment info from the edit list */
5917 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
5918 stream->n_segments = 0;
5919 stream->segments = NULL;
5920 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
5924 guint64 time, stime;
5927 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
5928 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
5931 buffer = elst->data;
5933 n_segments = QT_UINT32 (buffer + 12);
5935 /* we might allocate a bit too much, at least allocate 1 segment */
5936 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
5938 /* segments always start from 0 */
5942 for (i = 0; i < n_segments; i++) {
5945 QtDemuxSegment *segment;
5948 media_time = QT_UINT32 (buffer + 20 + i * 12);
5950 /* -1 media time is an empty segment, just ignore it */
5951 if (media_time == G_MAXUINT32)
5954 duration = QT_UINT32 (buffer + 16 + i * 12);
5956 segment = &stream->segments[count++];
5958 /* time and duration expressed in global timescale */
5959 segment->time = stime;
5960 /* add non scaled values so we don't cause roundoff errors */
5962 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
5963 segment->stop_time = stime;
5964 segment->duration = stime - segment->time;
5965 /* media_time expressed in stream timescale */
5966 segment->media_start =
5967 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
5968 segment->media_stop = segment->media_start + segment->duration;
5969 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
5971 if (rate_int <= 1) {
5972 /* 0 is not allowed, some programs write 1 instead of the floating point
5974 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
5978 segment->rate = rate_int / 65536.0;
5981 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
5982 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
5983 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
5984 GST_TIME_ARGS (segment->duration),
5985 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
5987 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
5988 stream->n_segments = count;
5992 /* push based does not handle segments, so act accordingly here,
5993 * and warn if applicable */
5994 if (!qtdemux->pullbased) {
5995 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
5996 /* remove and use default one below, we stream like it anyway */
5997 g_free (stream->segments);
5998 stream->segments = NULL;
5999 stream->n_segments = 0;
6002 /* no segments, create one to play the complete trak */
6003 if (stream->n_segments == 0) {
6004 GstClockTime stream_duration =
6005 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6007 if (stream->segments == NULL)
6008 stream->segments = g_new (QtDemuxSegment, 1);
6010 /* represent unknown our way */
6011 if (stream_duration == 0)
6012 stream_duration = -1;
6014 stream->segments[0].time = 0;
6015 stream->segments[0].stop_time = stream_duration;
6016 stream->segments[0].duration = stream_duration;
6017 stream->segments[0].media_start = 0;
6018 stream->segments[0].media_stop = stream_duration;
6019 stream->segments[0].rate = 1.0;
6021 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6022 GST_TIME_ARGS (stream_duration));
6023 stream->n_segments = 1;
6025 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6031 * Parses the stsd atom of a svq3 trak looking for
6032 * the SMI and gama atoms.
6035 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6036 guint8 ** gamma, GstBuffer ** seqh)
6038 guint8 *_gamma = NULL;
6039 GstBuffer *_seqh = NULL;
6040 guint8 *stsd_data = stsd->data;
6041 guint32 length = QT_UINT32 (stsd_data);
6045 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6051 version = QT_UINT16 (stsd_data);
6056 while (length > 8) {
6057 guint32 fourcc, size;
6059 size = QT_UINT32 (stsd_data);
6060 fourcc = QT_FOURCC (stsd_data + 4);
6061 data = stsd_data + 8;
6068 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6069 " for gama atom, expected 12", size);
6074 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6076 if (_seqh != NULL) {
6077 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6078 " found, ignoring");
6080 seqh_size = QT_UINT32 (data + 4);
6081 if (seqh_size > 0) {
6082 _seqh = gst_buffer_new_and_alloc (seqh_size);
6083 memcpy (GST_BUFFER_DATA (_seqh), data + 8, seqh_size);
6090 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6091 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6095 if (size <= length) {
6101 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6104 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6105 G_GUINT16_FORMAT, version);
6116 gst_buffer_unref (_seqh);
6121 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6128 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6129 * atom that might contain a 'data' atom with the rtsp uri.
6130 * This case was reported in bug #597497, some info about
6131 * the hndl atom can be found in TN1195
6133 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6134 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6137 guint32 dref_num_entries = 0;
6138 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6139 gst_byte_reader_skip (&dref, 4) &&
6140 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6143 /* search dref entries for hndl atom */
6144 for (i = 0; i < dref_num_entries; i++) {
6145 guint32 size = 0, type;
6146 guint8 string_len = 0;
6147 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6148 qt_atom_parser_get_fourcc (&dref, &type)) {
6149 if (type == FOURCC_hndl) {
6150 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6152 /* skip data reference handle bytes and the
6153 * following pascal string and some extra 4
6154 * bytes I have no idea what are */
6155 if (!gst_byte_reader_skip (&dref, 4) ||
6156 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6157 !gst_byte_reader_skip (&dref, string_len + 4)) {
6158 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6162 /* iterate over the atoms to find the data atom */
6163 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6167 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6168 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6169 if (atom_type == FOURCC_data) {
6170 const guint8 *uri_aux = NULL;
6172 /* found the data atom that might contain the rtsp uri */
6173 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6174 "hndl atom, interpreting it as an URI");
6175 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6177 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6178 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6180 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6181 "didn't contain a rtsp address");
6183 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6188 /* skipping to the next entry */
6189 gst_byte_reader_skip (&dref, atom_size - 8);
6191 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6198 /* skip to the next entry */
6199 gst_byte_reader_skip (&dref, size - 8);
6201 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6204 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6211 less_than (gconstpointer a, gconstpointer b)
6213 const guint32 *av = a, *bv = b;
6218 #define AMR_NB_ALL_MODES 0x81ff
6219 #define AMR_WB_ALL_MODES 0x83ff
6221 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
6223 /* The 'damr' atom is of the form:
6225 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
6226 * 32 b 8 b 16 b 8 b 8 b
6228 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
6229 * represents the highest mode used in the stream (and thus the maximum
6230 * bitrate), with a couple of special cases as seen below.
6233 /* Map of frame type ID -> bitrate */
6234 static const guint nb_bitrates[] = {
6235 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
6237 static const guint wb_bitrates[] = {
6238 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
6240 const guint8 *data = GST_BUFFER_DATA (buf);
6241 guint size = QT_UINT32 (data), max_mode;
6244 if (GST_BUFFER_SIZE (buf) != 0x11) {
6245 GST_DEBUG ("Atom should have size 0x11, not %u", size);
6249 if (QT_FOURCC (data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
6250 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
6251 GST_FOURCC_ARGS (QT_UINT32 (data + 4)));
6255 mode_set = QT_UINT16 (data + 13);
6257 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
6258 max_mode = 7 + (wb ? 1 : 0);
6260 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
6261 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
6263 if (max_mode == -1) {
6264 GST_DEBUG ("No mode indication was found (mode set) = %x",
6269 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
6276 * With each track we associate a new QtDemuxStream that contains all the info
6278 * traks that do not decode to something (like strm traks) will not have a pad.
6281 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6296 QtDemuxStream *stream;
6297 GstTagList *list = NULL;
6298 gchar *codec = NULL;
6299 const guint8 *stsd_data;
6300 guint16 lang_code; /* quicktime lang code or packed iso code */
6302 guint32 tkhd_flags = 0;
6303 guint8 tkhd_version = 0;
6305 guint value_size, len;
6307 stream = g_new0 (QtDemuxStream, 1);
6308 /* new streams always need a discont */
6309 stream->discont = TRUE;
6310 /* we enable clipping for raw audio/video streams */
6311 stream->need_clip = FALSE;
6312 stream->need_process = FALSE;
6313 stream->segment_index = -1;
6314 stream->time_position = 0;
6315 stream->sample_index = -1;
6316 stream->last_ret = GST_FLOW_OK;
6318 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6319 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6320 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6323 /* pick between 64 or 32 bits */
6324 value_size = tkhd_version == 1 ? 8 : 4;
6325 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6326 !gst_byte_reader_get_uint32_be (&tkhd, &stream->track_id))
6329 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6330 tkhd_version, tkhd_flags, stream->track_id);
6332 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6335 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6336 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6337 if (qtdemux->major_brand != FOURCC_mjp2 ||
6338 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6342 len = QT_UINT32 ((guint8 *) mdhd->data);
6343 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6344 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6345 if (version == 0x01000000) {
6348 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6349 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6350 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6354 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6355 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6356 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6359 if (lang_code < 0x800) {
6360 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6362 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6363 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6364 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6365 stream->lang_id[3] = 0;
6368 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6370 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6372 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6373 lang_code, stream->lang_id);
6375 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6378 /* fragmented files may have bogus duration in moov */
6379 if (!qtdemux->fragmented &&
6380 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6381 guint64 tdur1, tdur2;
6383 /* don't overflow */
6384 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6385 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6388 * some of those trailers, nowadays, have prologue images that are
6389 * themselves vide tracks as well. I haven't really found a way to
6390 * identify those yet, except for just looking at their duration. */
6391 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6392 GST_WARNING_OBJECT (qtdemux,
6393 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6394 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6395 "found, assuming preview image or something; skipping track",
6396 stream->duration, stream->timescale, qtdemux->duration,
6397 qtdemux->timescale);
6403 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6406 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6407 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6409 len = QT_UINT32 ((guint8 *) hdlr->data);
6411 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6412 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6413 GST_FOURCC_ARGS (stream->subtype));
6415 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6418 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6422 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6424 stsd_data = (const guint8 *) stsd->data;
6426 /* stsd should at least have one entry */
6427 len = QT_UINT32 (stsd_data);
6431 /* and that entry should fit within stsd */
6432 len = QT_UINT32 (stsd_data + 16);
6433 if (len > QT_UINT32 (stsd_data) + 16)
6435 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6437 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6438 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6439 GST_FOURCC_ARGS (stream->fourcc));
6441 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6442 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6443 goto error_encrypted;
6445 if (stream->subtype == FOURCC_vide) {
6446 guint32 w = 0, h = 0;
6448 stream->sampled = TRUE;
6450 /* version 1 uses some 64-bit ints */
6451 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6452 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6453 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6456 stream->display_width = w >> 16;
6457 stream->display_height = h >> 16;
6463 stream->width = QT_UINT16 (stsd_data + offset + 32);
6464 stream->height = QT_UINT16 (stsd_data + offset + 34);
6465 stream->fps_n = 0; /* this is filled in later */
6466 stream->fps_d = 0; /* this is filled in later */
6467 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6468 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6470 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6471 QT_UINT16 (stsd_data + offset + 48));
6474 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6476 list = gst_tag_list_new ();
6477 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6478 GST_TAG_VIDEO_CODEC, codec, NULL);
6485 /* pick 'the' stsd child */
6486 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
6488 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
6489 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
6493 const guint8 *pasp_data = (const guint8 *) pasp->data;
6495 stream->par_w = QT_UINT32 (pasp_data + 8);
6496 stream->par_h = QT_UINT32 (pasp_data + 12);
6503 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
6508 gint len = QT_UINT32 (stsd_data) - 0x66;
6509 const guint8 *avc_data = stsd_data + 0x66;
6512 while (len >= 0x8) {
6515 if (QT_UINT32 (avc_data) <= len)
6516 size = QT_UINT32 (avc_data) - 0x8;
6521 /* No real data, so break out */
6524 switch (QT_FOURCC (avc_data + 0x4)) {
6527 /* parse, if found */
6530 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
6532 /* First 4 bytes are the length of the atom, the next 4 bytes
6533 * are the fourcc, the next 1 byte is the version, and the
6534 * subsequent bytes are sequence parameter set like data. */
6535 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
6536 avc_data + 8 + 1, size - 1);
6538 buf = gst_buffer_new_and_alloc (size);
6539 memcpy (GST_BUFFER_DATA (buf), avc_data + 0x8, size);
6540 gst_caps_set_simple (stream->caps,
6541 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6542 gst_buffer_unref (buf);
6548 guint avg_bitrate, max_bitrate;
6550 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
6554 max_bitrate = QT_UINT32 (avc_data + 0xc);
6555 avg_bitrate = QT_UINT32 (avc_data + 0x10);
6557 if (!max_bitrate && !avg_bitrate)
6560 /* Some muxers seem to swap the average and maximum bitrates
6561 * (I'm looking at you, YouTube), so we swap for sanity. */
6562 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
6563 guint temp = avg_bitrate;
6565 avg_bitrate = max_bitrate;
6570 list = gst_tag_list_new ();
6572 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6573 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6574 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6576 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6577 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6578 GST_TAG_BITRATE, avg_bitrate, NULL);
6589 avc_data += size + 8;
6601 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
6602 GST_FOURCC_ARGS (fourcc));
6604 /* codec data might be in glbl extension atom */
6606 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
6612 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
6614 len = QT_UINT32 (data);
6617 buf = gst_buffer_new_and_alloc (len);
6618 memcpy (GST_BUFFER_DATA (buf), data + 8, len);
6619 gst_caps_set_simple (stream->caps,
6620 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6621 gst_buffer_unref (buf);
6628 /* see annex I of the jpeg2000 spec */
6629 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
6633 guint32 ncomp_map = 0;
6634 gint32 *comp_map = NULL;
6635 guint32 nchan_def = 0;
6636 gint32 *chan_def = NULL;
6638 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
6639 /* some required atoms */
6640 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
6643 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
6647 /* number of components; redundant with info in codestream, but useful
6649 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
6650 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
6652 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
6654 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
6657 GST_DEBUG_OBJECT (qtdemux, "found colr");
6658 /* extract colour space info */
6659 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
6660 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
6662 fourcc = GST_MAKE_FOURCC ('s', 'R', 'G', 'B');
6665 fourcc = GST_MAKE_FOURCC ('G', 'R', 'A', 'Y');
6668 fourcc = GST_MAKE_FOURCC ('s', 'Y', 'U', 'V');
6675 /* colr is required, and only values 16, 17, and 18 are specified,
6676 so error if we have no fourcc */
6679 /* extract component mapping */
6680 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
6682 guint32 cmap_len = 0;
6684 cmap_len = QT_UINT32 (cmap->data);
6685 if (cmap_len >= 8) {
6686 /* normal box, subtract off header */
6688 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
6689 if (cmap_len % 4 == 0) {
6690 ncomp_map = (cmap_len / 4);
6691 comp_map = g_new0 (gint32, ncomp_map);
6692 for (i = 0; i < ncomp_map; i++) {
6695 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
6696 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
6697 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
6698 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
6703 /* extract channel definitions */
6704 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
6706 guint32 cdef_len = 0;
6708 cdef_len = QT_UINT32 (cdef->data);
6709 if (cdef_len >= 10) {
6710 /* normal box, subtract off header and len */
6712 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
6713 if (cdef_len % 6 == 0) {
6714 nchan_def = (cdef_len / 6);
6715 chan_def = g_new0 (gint32, nchan_def);
6716 for (i = 0; i < nchan_def; i++)
6718 for (i = 0; i < nchan_def; i++) {
6719 guint16 cn, typ, asoc;
6720 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
6721 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
6722 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
6723 if (cn < nchan_def) {
6726 chan_def[cn] = asoc;
6729 chan_def[cn] = 0; /* alpha */
6732 chan_def[cn] = -typ;
6740 gst_caps_set_simple (stream->caps,
6741 "num-components", G_TYPE_INT, ncomp, NULL);
6742 gst_caps_set_simple (stream->caps,
6743 "fourcc", GST_TYPE_FOURCC, fourcc, NULL);
6746 GValue arr = { 0, };
6747 GValue elt = { 0, };
6749 g_value_init (&arr, GST_TYPE_ARRAY);
6750 g_value_init (&elt, G_TYPE_INT);
6751 for (i = 0; i < ncomp_map; i++) {
6752 g_value_set_int (&elt, comp_map[i]);
6753 gst_value_array_append_value (&arr, &elt);
6755 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6756 "component-map", &arr);
6757 g_value_unset (&elt);
6758 g_value_unset (&arr);
6763 GValue arr = { 0, };
6764 GValue elt = { 0, };
6766 g_value_init (&arr, GST_TYPE_ARRAY);
6767 g_value_init (&elt, G_TYPE_INT);
6768 for (i = 0; i < nchan_def; i++) {
6769 g_value_set_int (&elt, chan_def[i]);
6770 gst_value_array_append_value (&arr, &elt);
6772 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6773 "channel-definitions", &arr);
6774 g_value_unset (&elt);
6775 g_value_unset (&arr);
6779 /* some optional atoms */
6780 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
6781 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
6783 /* indicate possible fields in caps */
6785 data = (guint8 *) field->data + 8;
6787 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
6788 (gint) * data, NULL);
6790 /* add codec_data if provided */
6795 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
6796 data = prefix->data;
6797 len = QT_UINT32 (data);
6800 buf = gst_buffer_new_and_alloc (len);
6801 memcpy (GST_BUFFER_DATA (buf), data + 8, len);
6802 gst_caps_set_simple (stream->caps,
6803 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6804 gst_buffer_unref (buf);
6813 GstBuffer *seqh = NULL;
6814 guint8 *gamma_data = NULL;
6815 gint len = QT_UINT32 (stsd_data);
6817 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
6819 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
6820 QT_FP32 (gamma_data), NULL);
6823 /* sorry for the bad name, but we don't know what this is, other
6824 * than its own fourcc */
6825 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
6829 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
6830 buf = gst_buffer_new_and_alloc (len);
6831 memcpy (GST_BUFFER_DATA (buf), stsd_data, len);
6832 gst_caps_set_simple (stream->caps,
6833 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6834 gst_buffer_unref (buf);
6839 gst_caps_set_simple (stream->caps,
6840 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
6847 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
6848 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
6852 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
6856 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
6857 /* collect the headers and store them in a stream list so that we can
6858 * send them out first */
6859 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
6869 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
6870 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
6873 ovc1_data = ovc1->data;
6874 ovc1_len = QT_UINT32 (ovc1_data);
6875 if (ovc1_len <= 198) {
6876 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
6879 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
6880 memcpy (GST_BUFFER_DATA (buf), ovc1_data + 198, ovc1_len - 198);
6881 gst_caps_set_simple (stream->caps,
6882 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6883 gst_buffer_unref (buf);
6891 GST_INFO_OBJECT (qtdemux,
6892 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
6893 GST_FOURCC_ARGS (fourcc), stream->caps);
6895 } else if (stream->subtype == FOURCC_soun) {
6896 int version, samplesize;
6897 guint16 compression_id;
6898 gboolean amrwb = FALSE;
6904 version = QT_UINT32 (stsd_data + offset);
6905 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
6906 samplesize = QT_UINT16 (stsd_data + offset + 10);
6907 compression_id = QT_UINT16 (stsd_data + offset + 12);
6908 stream->rate = QT_FP32 (stsd_data + offset + 16);
6910 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
6911 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
6912 QT_UINT32 (stsd_data + offset + 4));
6913 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
6914 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
6915 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
6916 GST_LOG_OBJECT (qtdemux, "packet size: %d",
6917 QT_UINT16 (stsd_data + offset + 14));
6918 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
6920 if (compression_id == 0xfffe)
6921 stream->sampled = TRUE;
6923 /* first assume uncompressed audio */
6924 stream->bytes_per_sample = samplesize / 8;
6925 stream->samples_per_frame = stream->n_channels;
6926 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
6927 stream->samples_per_packet = stream->samples_per_frame;
6928 stream->bytes_per_packet = stream->bytes_per_sample;
6932 /* Yes, these have to be hard-coded */
6935 stream->samples_per_packet = 6;
6936 stream->bytes_per_packet = 1;
6937 stream->bytes_per_frame = 1 * stream->n_channels;
6938 stream->bytes_per_sample = 1;
6939 stream->samples_per_frame = 6 * stream->n_channels;
6944 stream->samples_per_packet = 3;
6945 stream->bytes_per_packet = 1;
6946 stream->bytes_per_frame = 1 * stream->n_channels;
6947 stream->bytes_per_sample = 1;
6948 stream->samples_per_frame = 3 * stream->n_channels;
6953 stream->samples_per_packet = 64;
6954 stream->bytes_per_packet = 34;
6955 stream->bytes_per_frame = 34 * stream->n_channels;
6956 stream->bytes_per_sample = 2;
6957 stream->samples_per_frame = 64 * stream->n_channels;
6963 stream->samples_per_packet = 1;
6964 stream->bytes_per_packet = 1;
6965 stream->bytes_per_frame = 1 * stream->n_channels;
6966 stream->bytes_per_sample = 1;
6967 stream->samples_per_frame = 1 * stream->n_channels;
6972 stream->samples_per_packet = 160;
6973 stream->bytes_per_packet = 33;
6974 stream->bytes_per_frame = 33 * stream->n_channels;
6975 stream->bytes_per_sample = 2;
6976 stream->samples_per_frame = 160 * stream->n_channels;
6983 if (version == 0x00010000) {
6991 /* only parse extra decoding config for non-pcm audio */
6992 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
6993 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
6994 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
6995 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
6997 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
6998 stream->samples_per_packet);
6999 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7000 stream->bytes_per_packet);
7001 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
7002 stream->bytes_per_frame);
7003 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
7004 stream->bytes_per_sample);
7006 if (!stream->sampled && stream->bytes_per_packet) {
7007 stream->samples_per_frame = (stream->bytes_per_frame /
7008 stream->bytes_per_packet) * stream->samples_per_packet;
7009 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
7010 stream->samples_per_frame);
7015 } else if (version == 0x00020000) {
7022 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7023 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
7024 stream->rate = qtfp.fp;
7025 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
7027 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7028 stream->samples_per_packet);
7029 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7030 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7033 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
7036 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
7045 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
7047 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
7049 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
7051 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
7054 gst_caps_set_simple (stream->caps,
7055 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
7062 const gchar *owma_data, *codec_name = NULL;
7066 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
7067 /* FIXME this should also be gst_riff_strf_auds,
7068 * but the latter one is actually missing bits-per-sample :( */
7073 gint32 nSamplesPerSec;
7074 gint32 nAvgBytesPerSec;
7076 gint16 wBitsPerSample;
7081 GST_DEBUG_OBJECT (qtdemux, "parse owma");
7082 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
7085 owma_data = owma->data;
7086 owma_len = QT_UINT32 (owma_data);
7087 if (owma_len <= 54) {
7088 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
7091 wfex = (WAVEFORMATEX *) (owma_data + 36);
7092 buf = gst_buffer_new_and_alloc (owma_len - 54);
7093 memcpy (GST_BUFFER_DATA (buf), owma_data + 54, owma_len - 54);
7094 if (wfex->wFormatTag == 0x0161) {
7095 codec_name = "Windows Media Audio";
7097 } else if (wfex->wFormatTag == 0x0162) {
7098 codec_name = "Windows Media Audio 9 Pro";
7100 } else if (wfex->wFormatTag == 0x0163) {
7101 codec_name = "Windows Media Audio 9 Lossless";
7102 /* is that correct? gstffmpegcodecmap.c is missing it, but
7103 * fluendo codec seems to support it */
7107 gst_caps_set_simple (stream->caps,
7108 "codec_data", GST_TYPE_BUFFER, buf,
7109 "wmaversion", G_TYPE_INT, version,
7110 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
7111 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
7112 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7113 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7115 gst_buffer_unref (buf);
7119 codec = g_strdup (codec_name);
7131 list = gst_tag_list_new ();
7132 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7133 GST_TAG_AUDIO_CODEC, codec, NULL);
7137 /* some bitrate info may have ended up in caps */
7138 s = gst_caps_get_structure (stream->caps, 0);
7139 gst_structure_get_int (s, "bitrate", &bitrate);
7141 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7145 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7149 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7151 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7153 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7157 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7158 16 bits is a byte-swapped wave-style codec identifier,
7159 and we can find a WAVE header internally to a 'wave' atom here.
7160 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7161 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7164 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7165 if (len < offset + 20) {
7166 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7168 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7169 const guint8 *data = stsd_data + offset + 16;
7171 GNode *waveheadernode;
7173 wavenode = g_node_new ((guint8 *) data);
7174 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7175 const guint8 *waveheader;
7178 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7179 if (waveheadernode) {
7180 waveheader = (const guint8 *) waveheadernode->data;
7181 headerlen = QT_UINT32 (waveheader);
7183 if (headerlen > 8) {
7184 gst_riff_strf_auds *header = NULL;
7185 GstBuffer *headerbuf;
7191 headerbuf = gst_buffer_new ();
7192 GST_BUFFER_DATA (headerbuf) = (guint8 *) waveheader;
7193 GST_BUFFER_SIZE (headerbuf) = headerlen;
7195 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7196 headerbuf, &header, &extra)) {
7197 gst_caps_unref (stream->caps);
7198 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7199 header, extra, NULL, NULL);
7202 gst_buffer_unref (extra);
7206 GST_DEBUG ("Didn't find waveheadernode for this codec");
7208 g_node_destroy (wavenode);
7211 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7215 /* FIXME: what is in the chunk? */
7218 gint len = QT_UINT32 (stsd_data);
7220 /* seems to be always = 116 = 0x74 */
7226 gint len = QT_UINT32 (stsd_data);
7229 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7231 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x4C, len - 0x4C);
7232 gst_caps_set_simple (stream->caps,
7233 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7234 gst_buffer_unref (buf);
7236 gst_caps_set_simple (stream->caps,
7237 "samplesize", G_TYPE_INT, samplesize, NULL);
7242 GNode *alac, *wave = NULL;
7244 /* apparently, m4a has this atom appended directly in the stsd entry,
7245 * while mov has it in a wave atom */
7246 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7248 /* alac now refers to stsd entry atom */
7249 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7251 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7253 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7256 gint len = QT_UINT32 (alac->data);
7260 GST_DEBUG_OBJECT (qtdemux,
7261 "discarding alac atom with unexpected len %d", len);
7263 /* codec-data contains alac atom size and prefix,
7264 * ffmpeg likes it that way, not quite gst-ish though ...*/
7265 buf = gst_buffer_new_and_alloc (len);
7266 memcpy (GST_BUFFER_DATA (buf), alac->data, len);
7267 gst_caps_set_simple (stream->caps,
7268 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7269 gst_buffer_unref (buf);
7272 gst_caps_set_simple (stream->caps,
7273 "samplesize", G_TYPE_INT, samplesize, NULL);
7281 gint len = QT_UINT32 (stsd_data);
7284 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7287 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34);
7289 /* If we have enough data, let's try to get the 'damr' atom. See
7290 * the 3GPP container spec (26.244) for more details. */
7291 if ((len - 0x34) > 8 &&
7292 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
7294 list = gst_tag_list_new ();
7295 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7296 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
7299 gst_caps_set_simple (stream->caps,
7300 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7301 gst_buffer_unref (buf);
7309 GST_INFO_OBJECT (qtdemux,
7310 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7311 GST_FOURCC_ARGS (fourcc), stream->caps);
7313 } else if (stream->subtype == FOURCC_strm) {
7314 if (fourcc == FOURCC_rtsp) {
7315 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7317 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7318 GST_FOURCC_ARGS (fourcc));
7319 goto unknown_stream;
7321 stream->sampled = TRUE;
7322 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
7324 stream->sampled = TRUE;
7329 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7331 list = gst_tag_list_new ();
7332 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7333 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7338 /* hunt for sort-of codec data */
7345 /* look for palette */
7346 /* target mp4s atom */
7347 len = QT_UINT32 (stsd_data + offset);
7348 data = stsd_data + offset;
7349 /* verify sufficient length,
7350 * and esds present with decConfigDescr of expected size and position */
7351 if ((len >= 106 + 8)
7352 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7353 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7358 /* move to decConfigDescr data */
7359 data = data + 8 + 42;
7360 for (i = 0; i < 16; i++) {
7361 clut[i] = QT_UINT32 (data);
7365 s = gst_structure_new ("application/x-gst-dvd", "event",
7366 G_TYPE_STRING, "dvd-spu-clut-change",
7367 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7368 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7369 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7370 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7371 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7372 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7373 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7374 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7377 /* store event and trigger custom processing */
7378 stream->pending_event =
7379 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7380 stream->need_process = TRUE;
7388 goto unknown_stream;
7391 /* promote to sampled format */
7392 if (stream->fourcc == FOURCC_samr) {
7393 /* force mono 8000 Hz for AMR */
7394 stream->sampled = TRUE;
7395 stream->n_channels = 1;
7396 stream->rate = 8000;
7397 } else if (stream->fourcc == FOURCC_sawb) {
7398 /* force mono 16000 Hz for AMR-WB */
7399 stream->sampled = TRUE;
7400 stream->n_channels = 1;
7401 stream->rate = 16000;
7402 } else if (stream->fourcc == FOURCC_mp4a) {
7403 stream->sampled = TRUE;
7406 /* collect sample information */
7407 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7408 goto samples_failed;
7410 if (qtdemux->fragmented) {
7414 /* need all moov samples as basis; probably not many if any at all */
7415 /* prevent moof parsing taking of at this time */
7416 offset = qtdemux->moof_offset;
7417 qtdemux->moof_offset = 0;
7418 if (stream->n_samples &&
7419 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7420 qtdemux->moof_offset = offset;
7421 goto samples_failed;
7423 qtdemux->moof_offset = 0;
7424 /* movie duration more reliable in this case (e.g. mehd) */
7425 if (qtdemux->segment.duration &&
7426 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7427 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7428 stream->timescale, GST_SECOND);
7429 /* need defaults for fragments */
7430 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7433 /* configure segments */
7434 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7435 goto segments_failed;
7437 /* add some language tag, if useful */
7438 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7439 strcmp (stream->lang_id, "und")) {
7440 const gchar *lang_code;
7443 list = gst_tag_list_new ();
7445 /* convert ISO 639-2 code to ISO 639-1 */
7446 lang_code = gst_tag_get_language_code (stream->lang_id);
7447 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7448 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7451 /* now we are ready to add the stream */
7452 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7453 goto too_many_streams;
7455 stream->pending_tags = list;
7456 qtdemux->streams[qtdemux->n_streams] = stream;
7457 qtdemux->n_streams++;
7458 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7465 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7466 (_("This file is corrupt and cannot be played.")), (NULL));
7472 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7479 /* we posted an error already */
7480 /* free stbl sub-atoms */
7481 gst_qtdemux_stbl_free (stream);
7487 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7488 GST_FOURCC_ARGS (stream->subtype));
7494 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7495 (_("This file contains too many streams. Only playing first %d"),
7496 GST_QTDEMUX_MAX_STREAMS), (NULL));
7501 /* If we can estimate the overall bitrate, and don't have information about the
7502 * stream bitrate for exactly one stream, this guesses the stream bitrate as
7503 * the overall bitrate minus the sum of the bitrates of all other streams. This
7504 * should be useful for the common case where we have one audio and one video
7505 * stream and can estimate the bitrate of one, but not the other. */
7507 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
7509 GstFormat format = GST_FORMAT_BYTES;
7510 QtDemuxStream *stream = NULL;
7511 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
7515 if (qtdemux->fragmented)
7518 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
7520 if (!gst_pad_query_peer_duration (qtdemux->sinkpad, &format, &size) ||
7521 format != GST_FORMAT_BYTES) {
7522 GST_DEBUG_OBJECT (qtdemux,
7523 "Size in bytes of the stream not known - bailing");
7527 /* Subtract the header size */
7528 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
7529 size, qtdemux->header_size);
7530 g_assert (size >= qtdemux->header_size);
7531 size = size - qtdemux->header_size;
7533 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
7534 duration == GST_CLOCK_TIME_NONE) {
7535 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
7539 for (i = 0; i < qtdemux->n_streams; i++) {
7540 switch (qtdemux->streams[i]->subtype) {
7543 /* retrieve bitrate, prefer avg then max */
7545 if (qtdemux->streams[i]->pending_tags) {
7546 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7547 GST_TAG_MAXIMUM_BITRATE, &bitrate);
7548 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7549 GST_TAG_BITRATE, &bitrate);
7552 sum_bitrate += bitrate;
7555 GST_DEBUG_OBJECT (qtdemux,
7556 ">1 stream with unknown bitrate - bailing");
7559 stream = qtdemux->streams[i];
7563 /* For other subtypes, we assume no significant impact on bitrate */
7569 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
7573 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
7575 if (sys_bitrate < sum_bitrate) {
7576 /* This can happen, since sum_bitrate might be derived from maximum
7577 * bitrates and not average bitrates */
7578 GST_DEBUG_OBJECT (qtdemux,
7579 "System bitrate less than sum bitrate - bailing");
7583 bitrate = sys_bitrate - sum_bitrate;
7584 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
7585 ", Stream bitrate = %u", sys_bitrate, bitrate);
7587 if (!stream->pending_tags)
7588 stream->pending_tags = gst_tag_list_new ();
7590 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
7591 GST_TAG_BITRATE, bitrate, NULL);
7594 static GstFlowReturn
7595 qtdemux_expose_streams (GstQTDemux * qtdemux)
7598 GstFlowReturn ret = GST_FLOW_OK;
7600 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7602 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7603 QtDemuxStream *stream = qtdemux->streams[i];
7604 guint32 sample_num = 0;
7609 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7610 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7612 if (qtdemux->fragmented) {
7613 /* need all moov samples first */
7614 GST_OBJECT_LOCK (qtdemux);
7615 while (stream->n_samples == 0)
7616 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7618 GST_OBJECT_UNLOCK (qtdemux);
7620 /* discard any stray moof */
7621 qtdemux->moof_offset = 0;
7624 /* prepare braking */
7625 if (ret != GST_FLOW_ERROR)
7628 /* in pull mode, we should have parsed some sample info by now;
7629 * and quite some code will not handle no samples.
7630 * in push mode, we'll just have to deal with it */
7631 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7632 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7633 gst_qtdemux_stream_free (qtdemux, stream);
7634 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7635 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7636 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7637 qtdemux->n_streams--;
7642 /* parse number of initial sample to set frame rate cap */
7643 while (sample_num < stream->n_samples && sample_num < samples) {
7644 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7648 /* collect and sort durations */
7649 samples = MIN (stream->stbl_index + 1, samples);
7650 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7652 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7654 while (sample_num < samples) {
7655 g_array_append_val (durations, stream->samples[sample_num].duration);
7658 g_array_sort (durations, less_than);
7659 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7660 g_array_free (durations, TRUE);
7663 /* now we have all info and can expose */
7664 list = stream->pending_tags;
7665 stream->pending_tags = NULL;
7666 gst_qtdemux_add_stream (qtdemux, stream, list);
7669 gst_qtdemux_guess_bitrate (qtdemux);
7671 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7673 /* check if we should post a redirect in case there is a single trak
7674 * and it is a redirecting trak */
7675 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7678 qtdemux_post_global_tags (qtdemux);
7680 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7681 "an external content");
7682 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7683 gst_structure_new ("redirect",
7684 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7686 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7687 qtdemux->posted_redirect = TRUE;
7693 /* check if major or compatible brand is 3GP */
7694 static inline gboolean
7695 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7698 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7699 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7700 } else if (qtdemux->comp_brands != NULL) {
7701 guint8 *data = GST_BUFFER_DATA (qtdemux->comp_brands);
7702 guint size = GST_BUFFER_SIZE (qtdemux->comp_brands);
7703 gboolean res = FALSE;
7706 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7707 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7717 /* check if tag is a spec'ed 3GP tag keyword storing a string */
7718 static inline gboolean
7719 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
7721 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
7722 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
7723 || fourcc == FOURCC_albm;
7727 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
7728 const char *dummy, GNode * node)
7730 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7734 gdouble longitude, latitude, altitude;
7737 len = QT_UINT32 (node->data);
7744 /* TODO: language code skipped */
7746 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
7749 /* do not alarm in trivial case, but bail out otherwise */
7750 if (*(data + offset) != 0) {
7751 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
7755 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7756 GST_TAG_GEO_LOCATION_NAME, name, NULL);
7757 offset += strlen (name);
7761 if (len < offset + 2 + 4 + 4 + 4)
7764 /* +1 +1 = skip null-terminator and location role byte */
7766 /* table in spec says unsigned, semantics say negative has meaning ... */
7767 longitude = QT_SFP32 (data + offset);
7770 latitude = QT_SFP32 (data + offset);
7773 altitude = QT_SFP32 (data + offset);
7775 /* one invalid means all are invalid */
7776 if (longitude >= -180.0 && longitude <= 180.0 &&
7777 latitude >= -90.0 && latitude <= 90.0) {
7778 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7779 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
7780 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
7781 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
7784 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
7791 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
7798 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7805 len = QT_UINT32 (node->data);
7809 y = QT_UINT16 ((guint8 *) node->data + 12);
7811 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
7814 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
7816 date = g_date_new_dmy (1, 1, y);
7817 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
7822 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
7823 const char *dummy, GNode * node)
7826 char *tag_str = NULL;
7831 len = QT_UINT32 (node->data);
7836 entity = (guint8 *) node->data + offset;
7837 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
7838 GST_DEBUG_OBJECT (qtdemux,
7839 "classification info: %c%c%c%c invalid classification entity",
7840 entity[0], entity[1], entity[2], entity[3]);
7845 table = QT_UINT16 ((guint8 *) node->data + offset);
7847 /* Language code skipped */
7851 /* Tag format: "XXXX://Y[YYYY]/classification info string"
7852 * XXXX: classification entity, fixed length 4 chars.
7853 * Y[YYYY]: classification table, max 5 chars.
7855 tag_str = g_strdup_printf ("----://%u/%s",
7856 table, (char *) node->data + offset);
7858 /* memcpy To be sure we're preserving byte order */
7859 memcpy (tag_str, entity, 4);
7860 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
7862 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
7872 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
7878 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
7879 const char *dummy, GNode * node)
7881 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7887 gboolean ret = TRUE;
7889 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7891 len = QT_UINT32 (data->data);
7892 type = QT_UINT32 ((guint8 *) data->data + 8);
7893 if (type == 0x00000001 && len > 16) {
7894 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
7897 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7898 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
7902 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7906 len = QT_UINT32 (node->data);
7907 type = QT_UINT32 ((guint8 *) node->data + 4);
7908 if ((type >> 24) == 0xa9) {
7909 /* Type starts with the (C) symbol, so the next 32 bits are
7910 * the language code, which we ignore */
7912 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
7913 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
7914 QT_FOURCC ((guint8 *) node->data + 4))) {
7915 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
7917 /* we go for 3GP style encoding if major brands claims so,
7918 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
7919 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
7920 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
7921 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
7923 /* 16-bit Language code is ignored here as well */
7924 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
7931 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
7932 ret = FALSE; /* may have to fallback */
7934 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
7935 len - offset, env_vars);
7937 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7938 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
7942 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7949 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
7950 const char *dummy, GNode * node)
7952 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
7956 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
7957 const char *dummy, GNode * node)
7959 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7961 char *s, *t, *k = NULL;
7966 /* first try normal string tag if major brand not 3GP */
7967 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
7968 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
7969 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
7970 * let's try it 3gpp way after minor safety check */
7972 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
7978 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
7982 len = QT_UINT32 (data);
7986 count = QT_UINT8 (data + 14);
7988 for (; count; count--) {
7991 if (offset + 1 > len)
7993 slen = QT_UINT8 (data + offset);
7995 if (offset + slen > len)
7997 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8000 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
8002 t = g_strjoin (",", k, s, NULL);
8010 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
8017 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
8018 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
8027 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
8033 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
8034 const char *tag2, GNode * node)
8041 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8043 len = QT_UINT32 (data->data);
8044 type = QT_UINT32 ((guint8 *) data->data + 8);
8045 if (type == 0x00000000 && len >= 22) {
8046 n1 = QT_UINT16 ((guint8 *) data->data + 18);
8047 n2 = QT_UINT16 ((guint8 *) data->data + 20);
8049 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
8050 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8054 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
8055 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8063 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8071 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8073 len = QT_UINT32 (data->data);
8074 type = QT_UINT32 ((guint8 *) data->data + 8);
8075 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
8076 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8077 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
8078 n1 = QT_UINT16 ((guint8 *) data->data + 16);
8080 /* do not add bpm=0 */
8081 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
8082 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8083 tag1, (gdouble) n1, NULL);
8090 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
8091 const char *dummy, GNode * node)
8098 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8100 len = QT_UINT32 (data->data);
8101 type = QT_UINT32 ((guint8 *) data->data + 8);
8102 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
8103 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8104 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
8105 num = QT_UINT32 ((guint8 *) data->data + 16);
8107 /* do not add num=0 */
8108 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
8109 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8117 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8125 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8127 len = QT_UINT32 (data->data);
8128 type = QT_UINT32 ((guint8 *) data->data + 8);
8129 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
8130 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
8131 if ((buf = gst_tag_image_data_to_image_buffer ((guint8 *) data->data + 16,
8132 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
8133 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
8134 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8136 gst_buffer_unref (buf);
8143 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8151 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8153 len = QT_UINT32 (data->data);
8154 type = QT_UINT32 ((guint8 *) data->data + 8);
8155 if (type == 0x00000001 && len > 16) {
8156 guint y, m = 1, d = 1;
8159 s = g_strndup ((char *) data->data + 16, len - 16);
8160 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
8161 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
8162 if (ret >= 1 && y > 1500 && y < 3000) {
8165 date = g_date_new_dmy (d, m, y);
8166 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
8170 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
8178 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8183 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8185 /* re-route to normal string tag if major brand says so
8186 * or no data atom and compatible brand suggests so */
8187 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8188 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
8189 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
8196 len = QT_UINT32 (data->data);
8197 type = QT_UINT32 ((guint8 *) data->data + 8);
8198 if (type == 0x00000000 && len >= 18) {
8199 n = QT_UINT16 ((guint8 *) data->data + 16);
8203 genre = gst_tag_id3_genre_get (n - 1);
8204 if (genre != NULL) {
8205 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
8206 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8215 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
8216 guint8 * data, guint32 datasize)
8221 /* make a copy to have \0 at the end */
8222 datacopy = g_strndup ((gchar *) data, datasize);
8224 /* convert the str to double */
8225 if (sscanf (datacopy, "%lf", &value) == 1) {
8226 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
8227 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
8229 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
8237 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
8238 const char *tag_bis, GNode * node)
8247 const gchar *meanstr;
8248 const gchar *namestr;
8250 /* checking the whole ---- atom size for consistency */
8251 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8252 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8256 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8258 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8262 meansize = QT_UINT32 (mean->data);
8263 if (meansize <= 12) {
8264 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8267 meanstr = ((gchar *) mean->data) + 12;
8269 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8271 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8275 namesize = QT_UINT32 (name->data);
8276 if (namesize <= 12) {
8277 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8280 namestr = ((gchar *) name->data) + 12;
8287 * uint24 - data type
8291 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8293 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8296 datasize = QT_UINT32 (data->data);
8297 if (datasize <= 16) {
8298 GST_WARNING_OBJECT (demux, "Data atom too small");
8301 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8303 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8306 const gchar name[28];
8307 const gchar tag[28];
8310 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8311 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8312 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8313 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8314 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8315 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8316 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8317 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8321 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8322 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8323 switch (gst_tag_get_type (tags[i].tag)) {
8325 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8326 ((guint8 *) data->data) + 16, datasize - 16);
8329 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8338 if (i == G_N_ELEMENTS (tags))
8352 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8353 namestr_dbg = g_strndup (namestr, namesize - 12);
8355 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8356 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8358 g_free (namestr_dbg);
8359 g_free (meanstr_dbg);
8365 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
8366 const char *tag_bis, GNode * node)
8371 GstTagList *taglist = NULL;
8373 GST_LOG_OBJECT (demux, "parsing ID32");
8376 len = GST_READ_UINT32_BE (data);
8378 /* need at least full box and language tag */
8382 buf = gst_buffer_new ();
8383 GST_BUFFER_DATA (buf) = data + 14;
8384 GST_BUFFER_SIZE (buf) = len - 14;
8386 taglist = gst_tag_list_from_id3v2_tag (buf);
8388 GST_LOG_OBJECT (demux, "parsing ok");
8389 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
8391 GST_LOG_OBJECT (demux, "parsing failed");
8395 gst_tag_list_free (taglist);
8397 gst_buffer_unref (buf);
8400 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8401 const char *tag, const char *tag_bis, GNode * node);
8404 FOURCC_pcst -> if media is a podcast -> bool
8405 FOURCC_cpil -> if media is part of a compilation -> bool
8406 FOURCC_pgap -> if media is part of a gapless context -> bool
8407 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8413 const gchar *gst_tag;
8414 const gchar *gst_tag_bis;
8415 const GstQTDemuxAddTagFunc func;
8418 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8419 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8420 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8421 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8422 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8423 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8424 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8425 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8426 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8427 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8428 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8429 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8430 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8431 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8432 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8433 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8434 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8435 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8436 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8437 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8438 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8439 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8440 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8441 qtdemux_tag_add_num}, {
8442 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8443 qtdemux_tag_add_num}, {
8444 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8445 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8446 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8447 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8448 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8449 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8450 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8451 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8452 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8453 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8454 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8455 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8456 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8457 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8458 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8459 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8460 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8461 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8462 qtdemux_tag_add_classification}, {
8464 /* This is a special case, some tags are stored in this
8465 * 'reverse dns naming', according to:
8466 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8469 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
8470 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
8471 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
8475 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8487 len = QT_UINT32 (data);
8488 buf = gst_buffer_new_and_alloc (len);
8489 memcpy (GST_BUFFER_DATA (buf), data, len);
8491 /* heuristic to determine style of tag */
8492 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8493 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8495 else if (demux->major_brand == FOURCC_qt__)
8496 style = "quicktime";
8497 /* fall back to assuming iso/3gp tag style */
8501 /* santize the name for the caps. */
8502 for (i = 0; i < 4; i++) {
8503 guint8 d = data[4 + i];
8504 if (g_ascii_isalnum (d))
8505 ndata[i] = g_ascii_tolower (d);
8510 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8511 ndata[0], ndata[1], ndata[2], ndata[3]);
8512 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8514 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
8515 gst_buffer_set_caps (buf, caps);
8516 gst_caps_unref (caps);
8517 g_free (media_type);
8519 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
8520 GST_BUFFER_SIZE (buf), caps);
8522 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8523 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
8524 gst_buffer_unref (buf);
8528 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8536 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8538 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8540 GST_LOG_OBJECT (qtdemux, "no ilst");
8545 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8548 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8549 if (!qtdemux->tag_list)
8550 qtdemux->tag_list = gst_tag_list_new ();
8553 while (i < G_N_ELEMENTS (add_funcs)) {
8554 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8558 len = QT_UINT32 (node->data);
8560 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8561 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8563 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8564 add_funcs[i].gst_tag_bis, node);
8566 g_node_destroy (node);
8572 /* parsed nodes have been removed, pass along remainder as blob */
8573 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8574 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8576 /* parse up XMP_ node if existing */
8577 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8580 GstTagList *taglist;
8582 buf = gst_buffer_new ();
8583 GST_BUFFER_DATA (buf) = ((guint8 *) xmp_->data) + 8;
8584 GST_BUFFER_SIZE (buf) = QT_UINT32 ((guint8 *) xmp_->data) - 8;
8586 taglist = gst_tag_list_from_xmp_buffer (buf);
8587 gst_buffer_unref (buf);
8589 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8591 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8598 GstStructure *structure; /* helper for sort function */
8600 guint min_req_bitrate;
8601 guint min_req_qt_version;
8605 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8607 GstQtReference *ref_a = (GstQtReference *) a;
8608 GstQtReference *ref_b = (GstQtReference *) b;
8610 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8611 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8613 /* known bitrates go before unknown; higher bitrates go first */
8614 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8617 /* sort the redirects and post a message for the application.
8620 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8622 GstQtReference *best;
8625 GValue list_val = { 0, };
8628 g_assert (references != NULL);
8630 references = g_list_sort (references, qtdemux_redirects_sort_func);
8632 best = (GstQtReference *) references->data;
8634 g_value_init (&list_val, GST_TYPE_LIST);
8636 for (l = references; l != NULL; l = l->next) {
8637 GstQtReference *ref = (GstQtReference *) l->data;
8638 GValue struct_val = { 0, };
8640 ref->structure = gst_structure_new ("redirect",
8641 "new-location", G_TYPE_STRING, ref->location, NULL);
8643 if (ref->min_req_bitrate > 0) {
8644 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8645 ref->min_req_bitrate, NULL);
8648 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8649 g_value_set_boxed (&struct_val, ref->structure);
8650 gst_value_list_append_value (&list_val, &struct_val);
8651 g_value_unset (&struct_val);
8652 /* don't free anything here yet, since we need best->structure below */
8655 g_assert (best != NULL);
8656 s = gst_structure_copy (best->structure);
8658 if (g_list_length (references) > 1) {
8659 gst_structure_set_value (s, "locations", &list_val);
8662 g_value_unset (&list_val);
8664 for (l = references; l != NULL; l = l->next) {
8665 GstQtReference *ref = (GstQtReference *) l->data;
8667 gst_structure_free (ref->structure);
8668 g_free (ref->location);
8671 g_list_free (references);
8673 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8674 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8675 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8676 qtdemux->posted_redirect = TRUE;
8679 /* look for redirect nodes, collect all redirect information and
8683 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8685 GNode *rmra, *rmda, *rdrf;
8687 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8689 GList *redirects = NULL;
8691 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8693 GstQtReference ref = { NULL, NULL, 0, 0 };
8696 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8697 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8698 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8699 ref.min_req_bitrate);
8702 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
8703 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
8704 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
8706 #ifndef GST_DISABLE_GST_DEBUG
8707 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
8709 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
8711 GST_LOG_OBJECT (qtdemux,
8712 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
8713 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
8714 bitmask, check_type);
8715 if (package == FOURCC_qtim && check_type == 0) {
8716 ref.min_req_qt_version = version;
8720 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
8725 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
8726 ref_data = (guint8 *) rdrf->data + 20;
8727 if (ref_type == FOURCC_alis) {
8728 guint record_len, record_version, fn_len;
8730 /* MacOSX alias record, google for alias-layout.txt */
8731 record_len = QT_UINT16 (ref_data + 4);
8732 record_version = QT_UINT16 (ref_data + 4 + 2);
8733 fn_len = QT_UINT8 (ref_data + 50);
8734 if (record_len > 50 && record_version == 2 && fn_len > 0) {
8735 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
8737 } else if (ref_type == FOURCC_url_) {
8738 ref.location = g_strdup ((gchar *) ref_data);
8740 GST_DEBUG_OBJECT (qtdemux,
8741 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
8742 GST_FOURCC_ARGS (ref_type));
8744 if (ref.location != NULL) {
8745 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
8746 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
8748 GST_WARNING_OBJECT (qtdemux,
8749 "Failed to extract redirect location from rdrf atom");
8753 /* look for others */
8754 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
8757 if (redirects != NULL) {
8758 qtdemux_process_redirects (qtdemux, redirects);
8765 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
8770 tags = gst_tag_list_new ();
8772 if (qtdemux->major_brand == FOURCC_mjp2)
8773 fmt = "Motion JPEG 2000";
8774 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
8776 else if (qtdemux->major_brand == FOURCC_qt__)
8778 else if (qtdemux->fragmented)
8781 fmt = "ISO MP4/M4A";
8783 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
8784 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
8786 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
8792 /* we have read th complete moov node now.
8793 * This function parses all of the relevant info, creates the traks and
8794 * prepares all data structures for playback
8797 qtdemux_parse_tree (GstQTDemux * qtdemux)
8804 guint64 creation_time;
8805 GstDateTime *datetime = NULL;
8808 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
8810 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
8811 return qtdemux_parse_redirects (qtdemux);
8814 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
8816 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
8817 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
8818 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
8819 } else if (version == 0) {
8820 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
8821 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
8822 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
8824 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
8828 /* Moving qt creation time (secs since 1904) to unix time */
8829 if (creation_time != 0) {
8830 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
8831 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
8832 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
8834 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
8835 "please file a bug at http://bugzilla.gnome.org");
8839 if (!qtdemux->tag_list)
8840 qtdemux->tag_list = gst_tag_list_new ();
8842 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
8843 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
8845 gst_date_time_unref (datetime);
8848 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
8849 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
8851 /* check for fragmented file and get some (default) data */
8852 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
8855 GstByteReader mehd_data;
8857 /* let track parsing or anyone know weird stuff might happen ... */
8858 qtdemux->fragmented = TRUE;
8860 /* compensate for total duration */
8861 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
8863 qtdemux_parse_mehd (qtdemux, &mehd_data);
8866 /* set duration in the segment info */
8867 gst_qtdemux_get_duration (qtdemux, &duration);
8869 gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
8871 /* parse all traks */
8872 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
8874 qtdemux_parse_trak (qtdemux, trak);
8875 /* iterate all siblings */
8876 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
8880 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
8882 qtdemux_parse_udta (qtdemux, udta);
8884 GST_LOG_OBJECT (qtdemux, "No udta node found.");
8887 /* maybe also some tags in meta box */
8888 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
8890 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
8891 qtdemux_parse_udta (qtdemux, udta);
8893 GST_LOG_OBJECT (qtdemux, "No meta node found.");
8896 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
8901 /* taken from ffmpeg */
8903 get_size (guint8 * ptr, guint8 ** end)
8912 len = (len << 7) | (c & 0x7f);
8921 /* this can change the codec originally present in @list */
8923 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
8924 GNode * esds, GstTagList * list)
8926 int len = QT_UINT32 (esds->data);
8927 guint8 *ptr = esds->data;
8928 guint8 *end = ptr + len;
8930 guint8 *data_ptr = NULL;
8932 guint8 object_type_id = 0;
8933 const char *codec_name = NULL;
8934 GstCaps *caps = NULL;
8936 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
8938 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
8941 tag = QT_UINT8 (ptr);
8942 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
8944 len = get_size (ptr, &ptr);
8945 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
8949 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
8950 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
8954 guint max_bitrate, avg_bitrate;
8956 object_type_id = QT_UINT8 (ptr);
8957 max_bitrate = QT_UINT32 (ptr + 5);
8958 avg_bitrate = QT_UINT32 (ptr + 9);
8959 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
8960 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
8961 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
8962 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
8963 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
8964 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
8965 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8966 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
8968 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
8969 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
8976 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
8982 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
8986 GST_ERROR_OBJECT (qtdemux, "parse error");
8991 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
8992 * in use, and should also be used to override some other parameters for some
8994 switch (object_type_id) {
8995 case 0x20: /* MPEG-4 */
8996 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
8997 * profile_and_level_indication */
8998 if (data_ptr != NULL && data_len >= 5 &&
8999 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
9000 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
9001 data_ptr + 4, data_len - 4);
9003 break; /* Nothing special needed here */
9004 case 0x21: /* H.264 */
9005 codec_name = "H.264 / AVC";
9006 caps = gst_caps_new_simple ("video/x-h264",
9007 "stream-format", G_TYPE_STRING, "avc",
9008 "alignment", G_TYPE_STRING, "au", NULL);
9010 case 0x40: /* AAC (any) */
9011 case 0x66: /* AAC Main */
9012 case 0x67: /* AAC LC */
9013 case 0x68: /* AAC SSR */
9014 /* Override channels and rate based on the codec_data, as it's often
9016 /* Only do so for basic setup without HE-AAC extension */
9017 if (data_ptr && data_len == 2) {
9018 guint channels, rateindex, rate;
9020 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
9021 channels = (data_ptr[1] & 0x7f) >> 3;
9022 if (channels > 0 && channels < 7) {
9023 stream->n_channels = channels;
9024 } else if (channels == 7) {
9025 stream->n_channels = 8;
9028 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
9029 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
9031 stream->rate = rate;
9034 /* Set level and profile if possible */
9035 if (data_ptr != NULL && data_len >= 2) {
9036 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
9037 data_ptr, data_len);
9040 case 0x60: /* MPEG-2, various profiles */
9046 codec_name = "MPEG-2 video";
9048 gst_caps_unref (stream->caps);
9049 stream->caps = gst_caps_new_simple ("video/mpeg",
9050 "mpegversion", G_TYPE_INT, 2,
9051 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9053 case 0x69: /* MP3 has two different values, accept either */
9055 /* change to mpeg1 layer 3 audio */
9056 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
9057 "mpegversion", G_TYPE_INT, 1, NULL);
9058 codec_name = "MPEG-1 layer 3";
9060 case 0x6A: /* MPEG-1 */
9061 codec_name = "MPEG-1 video";
9063 gst_caps_unref (stream->caps);
9064 stream->caps = gst_caps_new_simple ("video/mpeg",
9065 "mpegversion", G_TYPE_INT, 1,
9066 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9068 case 0x6C: /* MJPEG */
9069 caps = gst_caps_new_simple ("image/jpeg", NULL);
9070 codec_name = "Motion-JPEG";
9072 case 0x6D: /* PNG */
9073 caps = gst_caps_new_simple ("image/png", NULL);
9074 codec_name = "PNG still images";
9076 case 0x6E: /* JPEG2000 */
9077 codec_name = "JPEG-2000";
9078 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9080 case 0xA4: /* Dirac */
9081 codec_name = "Dirac";
9082 caps = gst_caps_new_simple ("video/x-dirac", NULL);
9084 case 0xA5: /* AC3 */
9085 codec_name = "AC-3 audio";
9086 caps = gst_caps_new_simple ("audio/x-ac3",
9087 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9089 case 0xE1: /* QCELP */
9090 /* QCELP, the codec_data is a riff tag (little endian) with
9091 * 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). */
9092 caps = gst_caps_new_simple ("audio/qcelp", NULL);
9093 codec_name = "QCELP";
9099 /* If we have a replacement caps, then change our caps for this stream */
9101 gst_caps_unref (stream->caps);
9102 stream->caps = caps;
9105 if (codec_name && list)
9106 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9107 GST_TAG_AUDIO_CODEC, codec_name, NULL);
9109 /* Add the codec_data attribute to caps, if we have it */
9113 buffer = gst_buffer_new_and_alloc (data_len);
9114 memcpy (GST_BUFFER_DATA (buffer), data_ptr, data_len);
9116 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
9117 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
9119 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
9121 gst_buffer_unref (buffer);
9126 #define _codec(name) \
9129 *codec_name = g_strdup (name); \
9134 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9135 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9138 const GstStructure *s;
9142 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
9143 _codec ("PNG still images");
9144 caps = gst_caps_new_simple ("image/png", NULL);
9146 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
9147 _codec ("JPEG still images");
9148 caps = gst_caps_new_simple ("image/jpeg", NULL);
9150 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
9151 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
9152 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
9153 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
9154 _codec ("Motion-JPEG");
9155 caps = gst_caps_new_simple ("image/jpeg", NULL);
9157 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
9158 _codec ("Motion-JPEG format B");
9159 caps = gst_caps_new_simple ("video/x-mjpeg-b", NULL);
9161 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
9162 _codec ("JPEG-2000");
9163 /* override to what it should be according to spec, avoid palette_data */
9164 stream->bits_per_sample = 24;
9165 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9167 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
9168 _codec ("Sorensen video v.3");
9169 caps = gst_caps_new_simple ("video/x-svq",
9170 "svqversion", G_TYPE_INT, 3, NULL);
9172 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
9173 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
9174 _codec ("Sorensen video v.1");
9175 caps = gst_caps_new_simple ("video/x-svq",
9176 "svqversion", G_TYPE_INT, 1, NULL);
9178 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9182 _codec ("Raw RGB video");
9183 bps = QT_UINT16 (stsd_data + 98);
9184 /* set common stuff */
9185 caps = gst_caps_new_simple ("video/x-raw-rgb",
9186 "endianness", G_TYPE_INT, G_BYTE_ORDER, "depth", G_TYPE_INT, bps,
9191 gst_caps_set_simple (caps,
9192 "bpp", G_TYPE_INT, 16,
9193 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9194 "red_mask", G_TYPE_INT, 0x7c00,
9195 "green_mask", G_TYPE_INT, 0x03e0,
9196 "blue_mask", G_TYPE_INT, 0x001f, NULL);
9199 gst_caps_set_simple (caps,
9200 "bpp", G_TYPE_INT, 16,
9201 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9202 "red_mask", G_TYPE_INT, 0xf800,
9203 "green_mask", G_TYPE_INT, 0x07e0,
9204 "blue_mask", G_TYPE_INT, 0x001f, NULL);
9207 gst_caps_set_simple (caps,
9208 "bpp", G_TYPE_INT, 24,
9209 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9210 "red_mask", G_TYPE_INT, 0xff0000,
9211 "green_mask", G_TYPE_INT, 0x00ff00,
9212 "blue_mask", G_TYPE_INT, 0x0000ff, NULL);
9215 gst_caps_set_simple (caps,
9216 "bpp", G_TYPE_INT, 32,
9217 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9218 "alpha_mask", G_TYPE_INT, 0xff000000,
9219 "red_mask", G_TYPE_INT, 0x00ff0000,
9220 "green_mask", G_TYPE_INT, 0x0000ff00,
9221 "blue_mask", G_TYPE_INT, 0x000000ff, NULL);
9229 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
9230 _codec ("Raw planar YUV 4:2:0");
9231 caps = gst_caps_new_simple ("video/x-raw-yuv",
9232 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
9235 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
9236 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
9237 _codec ("Raw packed YUV 4:2:2");
9238 caps = gst_caps_new_simple ("video/x-raw-yuv",
9239 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'),
9242 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
9243 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
9244 _codec ("Raw packed YUV 4:2:2");
9245 caps = gst_caps_new_simple ("video/x-raw-yuv",
9246 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'),
9249 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
9250 _codec ("Raw packed YUV 10-bit 4:2:2");
9251 caps = gst_caps_new_simple ("video/x-raw-yuv",
9252 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('v', '2', '1', '0'),
9255 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
9256 _codec ("Raw packed RGB 10-bit 4:4:4");
9257 caps = gst_caps_new_simple ("video/x-raw-rgb",
9258 "endianness", G_TYPE_INT, G_BIG_ENDIAN, "depth", G_TYPE_INT, 30,
9259 "bpp", G_TYPE_INT, 32,
9260 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9261 "red_mask", G_TYPE_INT, 0x3ff00000,
9262 "green_mask", G_TYPE_INT, 0x000ffc00,
9263 "blue_mask", G_TYPE_INT, 0x000003ff, NULL);
9265 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
9266 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
9267 _codec ("MPEG-1 video");
9268 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9269 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9271 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
9272 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
9273 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
9274 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
9275 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
9276 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
9277 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
9278 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
9279 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
9280 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
9281 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
9282 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
9283 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
9284 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
9285 _codec ("MPEG-2 video");
9286 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
9287 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9289 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
9290 _codec ("GIF still images");
9291 caps = gst_caps_new_simple ("image/gif", NULL);
9293 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
9294 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
9295 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
9296 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9298 /* ffmpeg uses the height/width props, don't know why */
9299 caps = gst_caps_new_simple ("video/x-h263", NULL);
9301 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9302 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9303 _codec ("MPEG-4 video");
9304 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9305 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9307 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9308 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9309 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9310 caps = gst_caps_new_simple ("video/x-msmpeg",
9311 "msmpegversion", G_TYPE_INT, 43, NULL);
9313 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9314 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9315 _codec ("3ivX video");
9316 caps = gst_caps_new_simple ("video/x-3ivx", NULL);
9318 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9320 caps = gst_caps_new_simple ("video/x-divx",
9321 "divxversion", G_TYPE_INT, 3, NULL);
9323 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9324 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9326 caps = gst_caps_new_simple ("video/x-divx",
9327 "divxversion", G_TYPE_INT, 4, NULL);
9329 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9331 caps = gst_caps_new_simple ("video/x-divx",
9332 "divxversion", G_TYPE_INT, 5, NULL);
9334 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9335 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9336 _codec ("XVID MPEG-4");
9337 caps = gst_caps_new_simple ("video/x-xvid", NULL);
9340 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9341 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9342 caps = gst_caps_new_simple ("video/mpeg",
9343 "mpegversion", G_TYPE_INT, 4, NULL);
9345 *codec_name = g_strdup ("FFmpeg MPEG-4");
9348 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9350 caps = gst_caps_new_simple ("video/x-cinepak", NULL);
9352 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9353 _codec ("Apple QuickDraw");
9354 caps = gst_caps_new_simple ("video/x-qdrw", NULL);
9356 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9357 _codec ("Apple video");
9358 caps = gst_caps_new_simple ("video/x-apple-video", NULL);
9360 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9361 _codec ("H.264 / AVC");
9362 caps = gst_caps_new_simple ("video/x-h264",
9363 "stream-format", G_TYPE_STRING, "avc",
9364 "alignment", G_TYPE_STRING, "au", NULL);
9366 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9367 _codec ("Run-length encoding");
9368 caps = gst_caps_new_simple ("video/x-rle",
9369 "layout", G_TYPE_STRING, "quicktime", NULL);
9371 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9372 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9373 _codec ("Indeo Video 3");
9374 caps = gst_caps_new_simple ("video/x-indeo",
9375 "indeoversion", G_TYPE_INT, 3, NULL);
9377 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9378 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9379 _codec ("Intel Video 4");
9380 caps = gst_caps_new_simple ("video/x-indeo",
9381 "indeoversion", G_TYPE_INT, 4, NULL);
9383 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9384 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9385 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9386 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9387 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9388 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9389 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9390 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9391 _codec ("DV Video");
9392 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9393 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9395 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9396 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9397 _codec ("DVCPro50 Video");
9398 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9399 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9401 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9402 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9403 _codec ("DVCProHD Video");
9404 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9405 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9407 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9408 _codec ("Apple Graphics (SMC)");
9409 caps = gst_caps_new_simple ("video/x-smc", NULL);
9411 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9413 caps = gst_caps_new_simple ("video/x-vp3", NULL);
9415 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9417 caps = gst_caps_new_simple ("video/x-theora", NULL);
9418 /* theora uses one byte of padding in the data stream because it does not
9419 * allow 0 sized packets while theora does */
9420 stream->padding = 1;
9422 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9424 caps = gst_caps_new_simple ("video/x-dirac", NULL);
9426 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9427 _codec ("TIFF still images");
9428 caps = gst_caps_new_simple ("image/tiff", NULL);
9430 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9431 _codec ("Apple Intermediate Codec");
9432 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9434 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9435 _codec ("AVID DNxHD");
9436 caps = gst_caps_from_string ("video/x-dnxhd");
9438 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9440 caps = gst_caps_from_string ("video/x-vp8");
9444 caps = gst_caps_new_simple ("video/x-wmv",
9445 "wmvversion", G_TYPE_INT, 3,
9446 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'V', 'C', '1'),
9449 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9454 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9455 GST_FOURCC_ARGS (fourcc));
9456 caps = gst_caps_new_simple (s, NULL);
9461 /* enable clipping for raw video streams */
9462 s = gst_caps_get_structure (caps, 0);
9463 name = gst_structure_get_name (s);
9464 if (g_str_has_prefix (name, "video/x-raw-")) {
9465 stream->need_clip = TRUE;
9471 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9472 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9475 const GstStructure *s;
9479 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9482 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9483 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9484 _codec ("Raw 8-bit PCM audio");
9485 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 8,
9486 "depth", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
9488 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9489 endian = G_BIG_ENDIAN;
9491 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9497 endian = G_LITTLE_ENDIAN;
9499 depth = stream->bytes_per_packet * 8;
9500 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9503 caps = gst_caps_new_simple ("audio/x-raw-int",
9504 "width", G_TYPE_INT, depth, "depth", G_TYPE_INT, depth,
9505 "endianness", G_TYPE_INT, endian,
9506 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
9509 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9510 _codec ("Raw 64-bit floating-point audio");
9511 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 64,
9512 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
9514 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9515 _codec ("Raw 32-bit floating-point audio");
9516 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 32,
9517 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
9520 _codec ("Raw 24-bit PCM audio");
9521 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9523 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 24,
9524 "depth", G_TYPE_INT, 24,
9525 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9526 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
9528 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9529 _codec ("Raw 32-bit PCM audio");
9530 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 32,
9531 "depth", G_TYPE_INT, 32,
9532 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
9533 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
9535 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9536 _codec ("Mu-law audio");
9537 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
9539 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9540 _codec ("A-law audio");
9541 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
9545 _codec ("Microsoft ADPCM");
9546 /* Microsoft ADPCM-ACM code 2 */
9547 caps = gst_caps_new_simple ("audio/x-adpcm",
9548 "layout", G_TYPE_STRING, "microsoft", NULL);
9552 _codec ("DVI/IMA ADPCM");
9553 caps = gst_caps_new_simple ("audio/x-adpcm",
9554 "layout", G_TYPE_STRING, "dvi", NULL);
9558 _codec ("DVI/Intel IMA ADPCM");
9559 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9560 caps = gst_caps_new_simple ("audio/x-adpcm",
9561 "layout", G_TYPE_STRING, "quicktime", NULL);
9565 /* MPEG layer 3, CBR only (pre QT4.1) */
9566 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9567 _codec ("MPEG-1 layer 3");
9568 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9569 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9570 "mpegversion", G_TYPE_INT, 1, NULL);
9573 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9574 _codec ("EAC-3 audio");
9575 caps = gst_caps_new_simple ("audio/x-eac3",
9576 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9577 stream->sampled = TRUE;
9579 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9580 _codec ("AC-3 audio");
9581 caps = gst_caps_new_simple ("audio/x-ac3",
9582 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9583 stream->sampled = TRUE;
9585 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9587 caps = gst_caps_new_simple ("audio/x-mace",
9588 "maceversion", G_TYPE_INT, 3, NULL);
9590 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9592 caps = gst_caps_new_simple ("audio/x-mace",
9593 "maceversion", G_TYPE_INT, 6, NULL);
9595 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9597 caps = gst_caps_new_simple ("application/ogg", NULL);
9599 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9600 _codec ("DV audio");
9601 caps = gst_caps_new_simple ("audio/x-dv", NULL);
9603 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9604 _codec ("MPEG-4 AAC audio");
9605 caps = gst_caps_new_simple ("audio/mpeg",
9606 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9607 "stream-format", G_TYPE_STRING, "raw", NULL);
9609 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9610 _codec ("QDesign Music");
9611 caps = gst_caps_new_simple ("audio/x-qdm", NULL);
9613 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9614 _codec ("QDesign Music v.2");
9615 /* FIXME: QDesign music version 2 (no constant) */
9617 caps = gst_caps_new_simple ("audio/x-qdm2",
9618 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9619 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9620 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9622 caps = gst_caps_new_simple ("audio/x-qdm2", NULL);
9625 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9626 _codec ("GSM audio");
9627 caps = gst_caps_new_simple ("audio/x-gsm", NULL);
9629 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9630 _codec ("AMR audio");
9631 caps = gst_caps_new_simple ("audio/AMR", NULL);
9633 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9634 _codec ("AMR-WB audio");
9635 caps = gst_caps_new_simple ("audio/AMR-WB", NULL);
9637 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9638 _codec ("Quicktime IMA ADPCM");
9639 caps = gst_caps_new_simple ("audio/x-adpcm",
9640 "layout", G_TYPE_STRING, "quicktime", NULL);
9642 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9643 _codec ("Apple lossless audio");
9644 caps = gst_caps_new_simple ("audio/x-alac", NULL);
9646 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9647 _codec ("QualComm PureVoice");
9648 caps = gst_caps_from_string ("audio/qcelp");
9652 caps = gst_caps_new_simple ("audio/x-wma", NULL);
9654 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
9660 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9661 GST_FOURCC_ARGS (fourcc));
9662 caps = gst_caps_new_simple (s, NULL);
9667 /* enable clipping for raw audio streams */
9668 s = gst_caps_get_structure (caps, 0);
9669 name = gst_structure_get_name (s);
9670 if (g_str_has_prefix (name, "audio/x-raw-")) {
9671 stream->need_clip = TRUE;
9677 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9678 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9682 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9685 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
9686 _codec ("DVD subtitle");
9687 caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
9689 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
9690 _codec ("Quicktime timed text");
9692 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
9693 _codec ("3GPP timed text");
9695 caps = gst_caps_new_simple ("text/plain", NULL);
9696 /* actual text piece needs to be extracted */
9697 stream->need_process = TRUE;
9703 s = g_strdup_printf ("text/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9704 GST_FOURCC_ARGS (fourcc));
9705 caps = gst_caps_new_simple (s, NULL);