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>
54 #include <gst/audio/audio.h>
56 #include "qtatomparser.h"
57 #include "qtdemux_types.h"
58 #include "qtdemux_dump.h"
59 #include "qtdemux_fourcc.h"
60 #include "qtdemux_lang.h"
62 #include "qtpalette.h"
64 #include "gst/riff/riff-media.h"
65 #include "gst/riff/riff-read.h"
67 #include <gst/pbutils/pbutils.h>
77 /* max. size considered 'sane' for non-mdat atoms */
78 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
80 /* if the sample index is larger than this, something is likely wrong */
81 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
83 /* For converting qt creation times to unix epoch times */
84 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
85 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
86 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
87 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
89 GST_DEBUG_CATEGORY (qtdemux_debug);
91 /*typedef struct _QtNode QtNode; */
92 typedef struct _QtDemuxSegment QtDemuxSegment;
93 typedef struct _QtDemuxSample QtDemuxSample;
102 struct _QtDemuxSample
105 gint32 pts_offset; /* Add this value to timestamp to get the pts */
107 guint64 timestamp; /* DTS In mov time */
108 guint32 duration; /* In mov time */
109 gboolean keyframe; /* TRUE when this packet is a keyframe */
112 /* timestamp is the DTS */
113 #define QTSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
114 GST_SECOND, (stream)->timescale)
115 /* timestamp + offset is the PTS */
116 #define QTSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
117 (sample)->pts_offset, GST_SECOND, (stream)->timescale)
118 /* timestamp + duration - dts is the duration */
119 #define QTSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
120 (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
121 /* timestamp + offset + duration - pts is the duration */
122 #define QTSAMPLE_DUR_PTS(stream,sample,pts) (gst_util_uint64_scale ((sample)->timestamp + \
123 (sample)->pts_offset + (sample)->duration, GST_SECOND, (stream)->timescale) - (pts));
125 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
128 * Quicktime has tracks and segments. A track is a continuous piece of
129 * multimedia content. The track is not always played from start to finish but
130 * instead, pieces of the track are 'cut out' and played in sequence. This is
131 * what the segments do.
133 * Inside the track we have keyframes (K) and delta frames. The track has its
134 * own timing, which starts from 0 and extends to end. The position in the track
135 * is called the media_time.
137 * The segments now describe the pieces that should be played from this track
138 * and are basically tupples of media_time/duration/rate entries. We can have
139 * multiple segments and they are all played after one another. An example:
141 * segment 1: media_time: 1 second, duration: 1 second, rate 1
142 * segment 2: media_time: 3 second, duration: 2 second, rate 2
144 * To correctly play back this track, one must play: 1 second of media starting
145 * from media_time 1 followed by 2 seconds of media starting from media_time 3
148 * Each of the segments will be played at a specific time, the first segment at
149 * time 0, the second one after the duration of the first one, etc.. Note that
150 * the time in resulting playback is not identical to the media_time of the
153 * Visually, assuming the track has 4 second of media_time:
156 * .-----------------------------------------------------------.
157 * track: | K.....K.........K........K.......K.......K...........K... |
158 * '-----------------------------------------------------------'
160 * .------------^ ^ .----------^ ^
161 * / .-------------' / .------------------'
163 * .--------------. .--------------.
164 * | segment 1 | | segment 2 |
165 * '--------------' '--------------'
167 * The challenge here is to cut out the right pieces of the track for each of
168 * the playback segments. This fortunatly can easily be done with the SEGMENT
169 * events of gstreamer.
171 * For playback of segment 1, we need to provide the decoder with the keyframe
172 * (a), in the above figure, but we must instruct it only to output the decoded
173 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
174 * position set to the time of the segment: 0.
176 * We then proceed to push data from keyframe (a) to frame (b). The decoder
177 * decodes but clips all before media_time 1.
179 * After finishing a segment, we push out a new SEGMENT event with the clipping
180 * boundaries of the new data.
182 * This is a good usecase for the GStreamer accumulated SEGMENT events.
185 struct _QtDemuxSegment
187 /* global time and duration, all gst time */
191 /* media time of trak, all gst time */
197 struct _QtDemuxStream
206 /* if the stream has a redirect URI in its headers, we store it here */
213 guint64 duration; /* in timescale */
217 gchar lang_id[4]; /* ISO 639-2T language code */
221 QtDemuxSample *samples;
222 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
223 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
224 the framerate, in timescale units */
226 /* if we use chunks or samples */
238 /* Numerator/denominator framerate */
241 guint16 bits_per_sample;
242 guint16 color_table_id;
247 guint samples_per_packet;
248 guint samples_per_frame;
249 guint bytes_per_packet;
250 guint bytes_per_sample;
251 guint bytes_per_frame;
254 /* when a discontinuity is pending */
257 /* list of buffers to push first */
260 /* if we need to clip this buffer. This is only needed for uncompressed
264 /* buffer needs some custom processing, e.g. subtitles */
265 gboolean need_process;
267 /* current position */
268 guint32 segment_index;
269 guint32 sample_index;
270 guint64 time_position; /* in gst time */
272 /* the Gst segment we are processing out, used for clipping */
275 /* last GstFlowReturn */
276 GstFlowReturn last_ret;
278 /* quicktime segments */
280 QtDemuxSegment *segments;
285 GstTagList *pending_tags;
286 gboolean send_global_tags;
288 GstEvent *pending_event;
298 gboolean chunks_are_chunks;
302 GstByteReader co_chunk;
304 guint32 current_chunk;
306 guint32 samples_per_chunk;
307 guint32 stco_sample_index;
309 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
312 guint32 n_samples_per_chunk;
313 guint32 stsc_chunk_index;
314 guint32 stsc_sample_index;
315 guint64 chunk_offset;
318 guint32 stts_samples;
319 guint32 n_sample_times;
320 guint32 stts_sample_index;
322 guint32 stts_duration;
324 gboolean stss_present;
325 guint32 n_sample_syncs;
328 gboolean stps_present;
329 guint32 n_sample_partial_syncs;
332 gboolean ctts_present;
333 guint32 n_composition_times;
335 guint32 ctts_sample_index;
340 gboolean parsed_trex;
341 guint32 def_sample_duration;
342 guint32 def_sample_size;
343 guint32 def_sample_flags;
348 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
349 QTDEMUX_STATE_HEADER, /* Parsing the header */
350 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
351 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
354 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
355 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
356 guint32 fourcc, GstByteReader * parser);
357 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
358 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
359 guint32 fourcc, GstByteReader * parser);
361 static GstStaticPadTemplate gst_qtdemux_sink_template =
362 GST_STATIC_PAD_TEMPLATE ("sink",
365 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
369 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
370 GST_STATIC_PAD_TEMPLATE ("video_%02d",
373 GST_STATIC_CAPS_ANY);
375 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
376 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
379 GST_STATIC_CAPS_ANY);
381 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
382 GST_STATIC_PAD_TEMPLATE ("subtitle_%02d",
385 GST_STATIC_CAPS_ANY);
387 #define gst_qtdemux_parent_class parent_class
388 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
390 static void gst_qtdemux_dispose (GObject * object);
393 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
396 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
397 QtDemuxStream * str, gint64 media_offset);
399 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
400 static GstIndex *gst_qtdemux_get_index (GstElement * element);
401 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
402 GstStateChange transition);
403 static gboolean qtdemux_sink_activate (GstPad * sinkpad);
404 static gboolean qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active);
405 static gboolean qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active);
407 static void gst_qtdemux_loop (GstPad * pad);
408 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf);
409 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstEvent * event);
411 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
412 const guint8 * buffer, guint length);
413 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
414 const guint8 * buffer, guint length);
415 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
417 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
418 QtDemuxStream * stream, GNode * esds, GstTagList * list);
419 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
420 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
421 gchar ** codec_name);
422 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
423 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
424 gchar ** codec_name);
425 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
426 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
427 gchar ** codec_name);
428 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
429 QtDemuxStream * stream, guint32 n);
430 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
433 gst_qtdemux_class_init (GstQTDemuxClass * klass)
435 GObjectClass *gobject_class;
436 GstElementClass *gstelement_class;
438 gobject_class = (GObjectClass *) klass;
439 gstelement_class = (GstElementClass *) klass;
441 parent_class = g_type_class_peek_parent (klass);
443 gobject_class->dispose = gst_qtdemux_dispose;
445 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
447 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
448 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
450 gst_tag_register_musicbrainz_tags ();
452 gst_element_class_add_pad_template (gstelement_class,
453 gst_static_pad_template_get (&gst_qtdemux_sink_template));
454 gst_element_class_add_pad_template (gstelement_class,
455 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
456 gst_element_class_add_pad_template (gstelement_class,
457 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
458 gst_element_class_add_pad_template (gstelement_class,
459 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
460 gst_element_class_set_details_simple (gstelement_class, "QuickTime demuxer",
462 "Demultiplex a QuickTime file into audio and video streams",
463 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
465 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
470 gst_qtdemux_init (GstQTDemux * qtdemux)
473 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
474 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
475 gst_pad_set_activatepull_function (qtdemux->sinkpad,
476 qtdemux_sink_activate_pull);
477 gst_pad_set_activatepush_function (qtdemux->sinkpad,
478 qtdemux_sink_activate_push);
479 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
480 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
481 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
483 qtdemux->state = QTDEMUX_STATE_INITIAL;
484 qtdemux->pullbased = FALSE;
485 qtdemux->posted_redirect = FALSE;
486 qtdemux->neededbytes = 16;
488 qtdemux->adapter = gst_adapter_new ();
490 qtdemux->first_mdat = -1;
491 qtdemux->got_moov = FALSE;
492 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
493 qtdemux->mdatbuffer = NULL;
494 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
498 gst_qtdemux_dispose (GObject * object)
500 GstQTDemux *qtdemux = GST_QTDEMUX (object);
502 if (qtdemux->adapter) {
503 g_object_unref (G_OBJECT (qtdemux->adapter));
504 qtdemux->adapter = NULL;
507 G_OBJECT_CLASS (parent_class)->dispose (object);
511 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
513 if (qtdemux->posted_redirect) {
514 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
515 (_("This file contains no playable streams.")),
516 ("no known streams found, a redirect message has been posted"));
518 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
519 (_("This file contains no playable streams.")),
520 ("no known streams found"));
525 _gst_buffer_copy_into_mem (GstBuffer * dest, const guint8 * src,
526 gsize offset, gsize size)
531 g_return_if_fail (gst_buffer_is_writable (dest));
533 bsize = gst_buffer_get_size (dest);
534 g_return_if_fail (bsize >= offset + size);
536 bdata = gst_buffer_map (dest, &bsize, NULL, GST_MAP_WRITE);
537 memcpy (bdata + offset, src, size);
538 gst_buffer_unmap (dest, bdata, bsize);
542 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
546 buf = gst_buffer_new ();
547 gst_buffer_take_memory (buf, -1,
548 gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
549 mem, free_func, size, 0, size));
555 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
562 if (G_UNLIKELY (size == 0)) {
564 GstBuffer *tmp = NULL;
566 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
567 if (ret != GST_FLOW_OK)
570 bdata = gst_buffer_map (tmp, &bsize, NULL, GST_MAP_READ);
571 size = QT_UINT32 (bdata);
572 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
574 gst_buffer_unmap (tmp, bdata, bsize);
575 gst_buffer_unref (tmp);
578 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
579 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
580 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
581 /* we're pulling header but already got most interesting bits,
582 * so never mind the rest (e.g. tags) (that much) */
583 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
585 return GST_FLOW_UNEXPECTED;
587 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
588 (_("This file is invalid and cannot be played.")),
589 ("atom has bogus size %" G_GUINT64_FORMAT, size));
590 return GST_FLOW_ERROR;
594 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
596 if (G_UNLIKELY (flow != GST_FLOW_OK))
599 bsize = gst_buffer_get_size (*buf);
600 /* Catch short reads - we don't want any partial atoms */
601 if (G_UNLIKELY (bsize < size)) {
602 GST_WARNING_OBJECT (qtdemux, "short read: %u < %" G_GUINT64_FORMAT,
604 gst_buffer_unref (*buf);
606 return GST_FLOW_UNEXPECTED;
614 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
615 GstFormat dest_format, gint64 * dest_value)
618 QtDemuxStream *stream = gst_pad_get_element_private (pad);
619 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
622 if (stream->subtype != FOURCC_vide) {
627 switch (src_format) {
628 case GST_FORMAT_TIME:
629 switch (dest_format) {
630 case GST_FORMAT_BYTES:{
631 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
635 *dest_value = stream->samples[index].offset;
637 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
638 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
639 GST_TIME_ARGS (src_value), *dest_value);
647 case GST_FORMAT_BYTES:
648 switch (dest_format) {
649 case GST_FORMAT_TIME:{
651 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
658 gst_util_uint64_scale (stream->samples[index].timestamp,
659 GST_SECOND, stream->timescale);
660 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
661 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
662 src_value, GST_TIME_ARGS (*dest_value));
675 gst_object_unref (qtdemux);
681 static const GstQueryType *
682 gst_qtdemux_get_src_query_types (GstPad * pad)
684 static const GstQueryType src_types[] = {
697 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
701 *duration = GST_CLOCK_TIME_NONE;
703 if (qtdemux->duration != 0) {
704 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
705 *duration = gst_util_uint64_scale (qtdemux->duration,
706 GST_SECOND, qtdemux->timescale);
713 gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
715 gboolean res = FALSE;
716 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
718 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
720 switch (GST_QUERY_TYPE (query)) {
721 case GST_QUERY_POSITION:
722 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
723 gst_query_set_position (query, GST_FORMAT_TIME,
724 qtdemux->segment.position);
728 case GST_QUERY_DURATION:{
731 gst_query_parse_duration (query, &fmt, NULL);
732 if (fmt == GST_FORMAT_TIME) {
733 gint64 duration = -1;
735 gst_qtdemux_get_duration (qtdemux, &duration);
737 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
743 case GST_QUERY_CONVERT:{
744 GstFormat src_fmt, dest_fmt;
745 gint64 src_value, dest_value = 0;
747 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
749 res = gst_qtdemux_src_convert (pad,
750 src_fmt, src_value, dest_fmt, &dest_value);
752 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
757 case GST_QUERY_FORMATS:
758 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
761 case GST_QUERY_SEEKING:{
765 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
766 if (fmt == GST_FORMAT_TIME) {
767 gint64 duration = -1;
769 gst_qtdemux_get_duration (qtdemux, &duration);
771 if (!qtdemux->pullbased) {
774 /* we might be able with help from upstream */
776 q = gst_query_new_seeking (GST_FORMAT_BYTES);
777 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
778 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
779 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
783 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
789 res = gst_pad_query_default (pad, query);
793 gst_object_unref (qtdemux);
799 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
801 if (G_LIKELY (stream->pad)) {
802 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
803 GST_DEBUG_PAD_NAME (stream->pad));
805 if (G_UNLIKELY (stream->pending_tags)) {
806 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
807 stream->pending_tags);
808 gst_pad_push_event (stream->pad,
809 gst_event_new_tag (stream->pending_tags));
810 stream->pending_tags = NULL;
813 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
814 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
816 gst_pad_push_event (stream->pad,
817 gst_event_new_tag (gst_tag_list_copy (qtdemux->tag_list)));
818 stream->send_global_tags = FALSE;
823 /* push event on all source pads; takes ownership of the event */
825 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
828 gboolean has_valid_stream = FALSE;
829 GstEventType etype = GST_EVENT_TYPE (event);
831 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
832 GST_EVENT_TYPE_NAME (event));
834 for (n = 0; n < qtdemux->n_streams; n++) {
836 QtDemuxStream *stream = qtdemux->streams[n];
838 if ((pad = stream->pad)) {
839 has_valid_stream = TRUE;
841 if (etype == GST_EVENT_EOS) {
842 /* let's not send twice */
843 if (stream->sent_eos)
845 stream->sent_eos = TRUE;
848 gst_pad_push_event (pad, gst_event_ref (event));
852 gst_event_unref (event);
854 /* if it is EOS and there are no pads, post an error */
855 if (!has_valid_stream && etype == GST_EVENT_EOS) {
856 gst_qtdemux_post_no_playable_stream_error (qtdemux);
860 /* push a pending newsegment event, if any from the streaming thread */
862 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
864 if (qtdemux->pending_newsegment) {
865 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
866 qtdemux->pending_newsegment = NULL;
876 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
878 if (s1->timestamp > *media_time)
884 /* find the index of the sample that includes the data for @media_time using a
885 * binary search. Only to be called in optimized cases of linear search below.
887 * Returns the index of the sample.
890 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
893 QtDemuxSample *result;
896 /* convert media_time to mov format */
898 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
900 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
901 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
902 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
904 if (G_LIKELY (result))
905 index = result - str->samples;
914 /* find the index of the sample that includes the data for @media_offset using a
917 * Returns the index of the sample.
920 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
921 QtDemuxStream * str, gint64 media_offset)
923 QtDemuxSample *result = str->samples;
926 if (result == NULL || str->n_samples == 0)
929 if (media_offset == result->offset)
933 while (index < str->n_samples - 1) {
934 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
937 if (media_offset < result->offset)
948 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
953 /* find the index of the sample that includes the data for @media_time using a
954 * linear search, and keeping in mind that not all samples may have been parsed
955 * yet. If possible, it will delegate to binary search.
957 * Returns the index of the sample.
960 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
966 /* convert media_time to mov format */
968 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
970 if (mov_time == str->samples[0].timestamp)
973 /* use faster search if requested time in already parsed range */
974 if (str->stbl_index >= 0 &&
975 mov_time <= str->samples[str->stbl_index].timestamp)
976 return gst_qtdemux_find_index (qtdemux, str, media_time);
978 while (index < str->n_samples - 1) {
979 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
982 if (mov_time < str->samples[index + 1].timestamp)
992 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
997 /* find the index of the keyframe needed to decode the sample at @index
1000 * Returns the index of the keyframe.
1003 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1006 guint32 new_index = index;
1008 if (index >= str->n_samples) {
1009 new_index = str->n_samples;
1013 /* all keyframes, return index */
1014 if (str->all_keyframe) {
1019 /* else go back until we have a keyframe */
1021 if (str->samples[new_index].keyframe)
1031 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1032 "gave %u", index, new_index);
1037 /* find the segment for @time_position for @stream
1039 * Returns -1 if the segment cannot be found.
1042 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1043 guint64 time_position)
1048 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1049 GST_TIME_ARGS (time_position));
1051 /* find segment corresponding to time_position if we are looking
1054 for (i = 0; i < stream->n_segments; i++) {
1055 QtDemuxSegment *segment = &stream->segments[i];
1057 GST_LOG_OBJECT (qtdemux,
1058 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1059 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1061 /* For the last segment we include stop_time in the last segment */
1062 if (i < stream->n_segments - 1) {
1063 if (segment->time <= time_position && time_position < segment->stop_time) {
1064 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1069 if (segment->time <= time_position && time_position <= segment->stop_time) {
1070 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1079 /* move the stream @str to the sample position @index.
1081 * Updates @str->sample_index and marks discontinuity if needed.
1084 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1087 /* no change needed */
1088 if (index == str->sample_index)
1091 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1094 /* position changed, we have a discont */
1095 str->sample_index = index;
1096 /* Each time we move in the stream we store the position where we are
1098 str->from_sample = index;
1099 str->discont = TRUE;
1103 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1104 gint64 * key_time, gint64 * key_offset)
1107 gint64 min_byte_offset = -1;
1110 min_offset = desired_time;
1112 /* for each stream, find the index of the sample in the segment
1113 * and move back to the previous keyframe. */
1114 for (n = 0; n < qtdemux->n_streams; n++) {
1116 guint32 index, kindex;
1118 guint64 media_start;
1121 QtDemuxSegment *seg;
1123 str = qtdemux->streams[n];
1125 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1126 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1128 /* segment not found, continue with normal flow */
1132 /* get segment and time in the segment */
1133 seg = &str->segments[seg_idx];
1134 seg_time = desired_time - seg->time;
1136 /* get the media time in the segment */
1137 media_start = seg->media_start + seg_time;
1139 /* get the index of the sample with media time */
1140 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1141 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
1142 GST_TIME_ARGS (media_start), index);
1144 /* find previous keyframe */
1145 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1147 /* if the keyframe is at a different position, we need to update the
1148 * requested seek time */
1149 if (index != kindex) {
1152 /* get timestamp of keyframe */
1154 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1156 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT,
1157 kindex, GST_TIME_ARGS (media_time));
1159 /* keyframes in the segment get a chance to change the
1160 * desired_offset. keyframes out of the segment are
1162 if (media_time >= seg->media_start) {
1165 /* this keyframe is inside the segment, convert back to
1167 seg_time = (media_time - seg->media_start) + seg->time;
1168 if (seg_time < min_offset)
1169 min_offset = seg_time;
1173 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1174 min_byte_offset = str->samples[index].offset;
1178 *key_time = min_offset;
1180 *key_offset = min_byte_offset;
1184 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1185 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1189 g_return_val_if_fail (format != NULL, FALSE);
1190 g_return_val_if_fail (cur != NULL, FALSE);
1191 g_return_val_if_fail (stop != NULL, FALSE);
1193 if (*format == GST_FORMAT_TIME)
1197 if (cur_type != GST_SEEK_TYPE_NONE)
1198 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1199 if (res && stop_type != GST_SEEK_TYPE_NONE)
1200 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1203 *format = GST_FORMAT_TIME;
1208 /* perform seek in push based mode:
1209 find BYTE position to move to based on time and delegate to upstream
1212 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1217 GstSeekType cur_type, stop_type;
1222 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1224 gst_event_parse_seek (event, &rate, &format, &flags,
1225 &cur_type, &cur, &stop_type, &stop);
1227 /* FIXME, always play to the end */
1230 /* only forward streaming and seeking is possible */
1232 goto unsupported_seek;
1234 /* convert to TIME if needed and possible */
1235 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1239 /* find reasonable corresponding BYTE position,
1240 * also try to mind about keyframes, since we can not go back a bit for them
1242 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1247 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1248 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1251 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1252 GST_DEBUG_OBJECT (qtdemux,
1253 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1254 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1255 GST_OBJECT_LOCK (qtdemux);
1256 qtdemux->requested_seek_time = cur;
1257 qtdemux->seek_offset = byte_cur;
1258 GST_OBJECT_UNLOCK (qtdemux);
1261 /* BYTE seek event */
1262 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1264 res = gst_pad_push_event (qtdemux->sinkpad, event);
1271 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1277 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1282 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1287 /* perform the seek.
1289 * We set all segment_indexes in the streams to unknown and
1290 * adjust the time_position to the desired position. this is enough
1291 * to trigger a segment switch in the streaming thread to start
1292 * streaming from the desired position.
1294 * Keyframe seeking is a little more complicated when dealing with
1295 * segments. Ideally we want to move to the previous keyframe in
1296 * the segment but there might not be a keyframe in the segment. In
1297 * fact, none of the segments could contain a keyframe. We take a
1298 * practical approach: seek to the previous keyframe in the segment,
1299 * if there is none, seek to the beginning of the segment.
1301 * Called with STREAM_LOCK
1304 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1306 gint64 desired_offset;
1309 desired_offset = segment->position;
1311 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1312 GST_TIME_ARGS (desired_offset));
1314 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
1317 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1318 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1319 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1320 desired_offset = min_offset;
1323 /* and set all streams to the final position */
1324 for (n = 0; n < qtdemux->n_streams; n++) {
1325 QtDemuxStream *stream = qtdemux->streams[n];
1327 stream->time_position = desired_offset;
1328 stream->sample_index = -1;
1329 stream->segment_index = -1;
1330 stream->last_ret = GST_FLOW_OK;
1331 stream->sent_eos = FALSE;
1333 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1334 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1336 segment->position = desired_offset;
1337 segment->time = desired_offset;
1339 /* we stop at the end */
1340 if (segment->stop == -1)
1341 segment->stop = segment->duration;
1346 /* do a seek in pull based mode */
1348 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1353 GstSeekType cur_type, stop_type;
1357 GstSegment seeksegment;
1361 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1363 gst_event_parse_seek (event, &rate, &format, &flags,
1364 &cur_type, &cur, &stop_type, &stop);
1366 /* we have to have a format as the segment format. Try to convert
1368 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1372 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1374 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1378 flush = flags & GST_SEEK_FLAG_FLUSH;
1380 /* stop streaming, either by flushing or by pausing the task */
1382 /* unlock upstream pull_range */
1383 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1384 /* make sure out loop function exits */
1385 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1387 /* non flushing seek, pause the task */
1388 gst_pad_pause_task (qtdemux->sinkpad);
1391 /* wait for streaming to finish */
1392 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1394 /* copy segment, we need this because we still need the old
1395 * segment when we close the current segment. */
1396 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1399 /* configure the segment with the seek variables */
1400 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1401 gst_segment_do_seek (&seeksegment, rate, format, flags,
1402 cur_type, cur, stop_type, stop, &update);
1405 /* now do the seek, this actually never returns FALSE */
1406 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1408 /* prepare for streaming again */
1410 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop (TRUE));
1411 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop (TRUE));
1414 /* commit the new segment */
1415 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1417 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1418 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1419 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1420 qtdemux->segment.format, qtdemux->segment.position));
1423 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1424 for (i = 0; i < qtdemux->n_streams; i++)
1425 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1427 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1430 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1437 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1443 qtdemux_ensure_index (GstQTDemux * qtdemux)
1447 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1449 /* Build complete index */
1450 for (i = 0; i < qtdemux->n_streams; i++) {
1451 QtDemuxStream *stream = qtdemux->streams[i];
1453 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1461 GST_LOG_OBJECT (qtdemux,
1462 "Building complete index of stream %u for seeking failed!", i);
1468 gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
1470 gboolean res = TRUE;
1471 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
1473 switch (GST_EVENT_TYPE (event)) {
1474 case GST_EVENT_SEEK:
1476 #ifndef GST_DISABLE_GST_DEBUG
1477 GstClockTime ts = gst_util_get_timestamp ();
1479 /* Build complete index for seeking;
1480 * if not a fragmented file at least */
1481 if (!qtdemux->fragmented)
1482 if (!qtdemux_ensure_index (qtdemux))
1484 #ifndef GST_DISABLE_GST_DEBUG
1485 ts = gst_util_get_timestamp () - ts;
1486 GST_INFO_OBJECT (qtdemux,
1487 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1490 if (qtdemux->pullbased) {
1491 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1492 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams &&
1493 !qtdemux->fragmented) {
1494 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1496 GST_DEBUG_OBJECT (qtdemux,
1497 "ignoring seek in push mode in current state");
1500 gst_event_unref (event);
1503 case GST_EVENT_NAVIGATION:
1505 gst_event_unref (event);
1508 res = gst_pad_event_default (pad, event);
1512 gst_object_unref (qtdemux);
1520 GST_ERROR_OBJECT (qtdemux, "Index failed");
1521 gst_event_unref (event);
1527 /* stream/index return sample that is min/max w.r.t. byte position,
1528 * time is min/max w.r.t. time of samples,
1529 * the latter need not be time of the former sample */
1531 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1532 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1535 gint64 time, min_time;
1536 QtDemuxStream *stream;
1542 for (n = 0; n < qtdemux->n_streams; ++n) {
1545 gboolean set_sample;
1547 str = qtdemux->streams[n];
1554 i = str->n_samples - 1;
1557 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1558 if (str->samples[i].size &&
1559 ((fw && (str->samples[i].offset >= byte_pos)) ||
1561 (str->samples[i].offset + str->samples[i].size <=
1563 /* move stream to first available sample */
1565 gst_qtdemux_move_stream (qtdemux, str, i);
1568 /* determine min/max time */
1569 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1570 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1571 if (min_time == -1 || (!fw && time > min_time) ||
1572 (fw && time < min_time)) {
1575 /* determine stream with leading sample, to get its position */
1577 && (str->samples[i].offset < stream->samples[index].offset))
1579 && (str->samples[i].offset > stream->samples[index].offset))) {
1586 /* no sample for this stream, mark eos */
1588 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1600 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
1602 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1605 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1607 switch (GST_EVENT_TYPE (event)) {
1608 case GST_EVENT_SEGMENT:
1611 QtDemuxStream *stream;
1615 /* some debug output */
1616 gst_event_copy_segment (event, &segment);
1617 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1620 /* chain will send initial newsegment after pads have been added */
1621 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1622 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1626 /* we only expect a BYTE segment, e.g. following a seek */
1627 if (segment.format == GST_FORMAT_BYTES) {
1628 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1629 gint64 requested_seek_time;
1630 guint64 seek_offset;
1632 offset = segment.start;
1634 GST_OBJECT_LOCK (demux);
1635 requested_seek_time = demux->requested_seek_time;
1636 seek_offset = demux->seek_offset;
1637 demux->requested_seek_time = -1;
1638 demux->seek_offset = -1;
1639 GST_OBJECT_UNLOCK (demux);
1641 if (offset == seek_offset) {
1642 segment.start = requested_seek_time;
1644 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1645 NULL, (gint64 *) & segment.start);
1646 if ((gint64) segment.start < 0)
1650 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1651 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1652 NULL, (gint64 *) & segment.stop);
1653 /* keyframe seeking should already arrange for start >= stop,
1654 * but make sure in other rare cases */
1655 segment.stop = MAX (segment.stop, segment.start);
1658 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1662 /* accept upstream's notion of segment and distribute along */
1663 segment.time = segment.start;
1664 segment.duration = demux->segment.duration;
1665 segment.base = gst_segment_to_running_time (&demux->segment,
1666 GST_FORMAT_TIME, demux->segment.position);
1668 gst_segment_copy_into (&segment, &demux->segment);
1669 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
1670 gst_qtdemux_push_event (demux, gst_event_new_segment (&segment));
1672 /* clear leftover in current segment, if any */
1673 gst_adapter_clear (demux->adapter);
1674 /* set up streaming thread */
1675 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1676 demux->offset = offset;
1678 demux->todrop = stream->samples[idx].offset - offset;
1679 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1681 /* set up for EOS */
1682 demux->neededbytes = -1;
1686 gst_event_unref (event);
1691 case GST_EVENT_FLUSH_STOP:
1696 /* clean up, force EOS if no more info follows */
1697 gst_adapter_clear (demux->adapter);
1699 demux->neededbytes = -1;
1700 /* reset flow return, e.g. following seek */
1701 for (i = 0; i < demux->n_streams; i++) {
1702 demux->streams[i]->last_ret = GST_FLOW_OK;
1703 demux->streams[i]->sent_eos = FALSE;
1705 dur = demux->segment.duration;
1706 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1707 demux->segment.duration = dur;
1711 /* If we are in push mode, and get an EOS before we've seen any streams,
1712 * then error out - we have nowhere to send the EOS */
1713 if (!demux->pullbased) {
1715 gboolean has_valid_stream = FALSE;
1716 for (i = 0; i < demux->n_streams; i++) {
1717 if (demux->streams[i]->pad != NULL) {
1718 has_valid_stream = TRUE;
1722 if (!has_valid_stream)
1723 gst_qtdemux_post_no_playable_stream_error (demux);
1730 res = gst_pad_event_default (demux->sinkpad, event);
1737 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1739 GstQTDemux *demux = GST_QTDEMUX (element);
1741 GST_OBJECT_LOCK (demux);
1742 if (demux->element_index)
1743 gst_object_unref (demux->element_index);
1745 demux->element_index = gst_object_ref (index);
1747 demux->element_index = NULL;
1749 GST_OBJECT_UNLOCK (demux);
1750 /* object lock might be taken again */
1752 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1753 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
1754 demux->element_index, demux->index_id);
1758 gst_qtdemux_get_index (GstElement * element)
1760 GstIndex *result = NULL;
1761 GstQTDemux *demux = GST_QTDEMUX (element);
1763 GST_OBJECT_LOCK (demux);
1764 if (demux->element_index)
1765 result = gst_object_ref (demux->element_index);
1766 GST_OBJECT_UNLOCK (demux);
1768 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1774 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1776 g_free ((gpointer) stream->stco.data);
1777 stream->stco.data = NULL;
1778 g_free ((gpointer) stream->stsz.data);
1779 stream->stsz.data = NULL;
1780 g_free ((gpointer) stream->stsc.data);
1781 stream->stsc.data = NULL;
1782 g_free ((gpointer) stream->stts.data);
1783 stream->stts.data = NULL;
1784 g_free ((gpointer) stream->stss.data);
1785 stream->stss.data = NULL;
1786 g_free ((gpointer) stream->stps.data);
1787 stream->stps.data = NULL;
1788 g_free ((gpointer) stream->ctts.data);
1789 stream->ctts.data = NULL;
1793 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
1795 while (stream->buffers) {
1796 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1797 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1800 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
1801 g_free (stream->samples);
1803 gst_caps_unref (stream->caps);
1804 g_free (stream->segments);
1805 if (stream->pending_tags)
1806 gst_tag_list_free (stream->pending_tags);
1807 g_free (stream->redirect_uri);
1808 /* free stbl sub-atoms */
1809 gst_qtdemux_stbl_free (stream);
1813 static GstStateChangeReturn
1814 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1816 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1817 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1819 switch (transition) {
1820 case GST_STATE_CHANGE_PAUSED_TO_READY:
1826 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1828 switch (transition) {
1829 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1832 qtdemux->state = QTDEMUX_STATE_INITIAL;
1833 qtdemux->neededbytes = 16;
1834 qtdemux->todrop = 0;
1835 qtdemux->pullbased = FALSE;
1836 qtdemux->posted_redirect = FALSE;
1837 qtdemux->offset = 0;
1838 qtdemux->first_mdat = -1;
1839 qtdemux->header_size = 0;
1840 qtdemux->got_moov = FALSE;
1841 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1842 if (qtdemux->mdatbuffer)
1843 gst_buffer_unref (qtdemux->mdatbuffer);
1844 qtdemux->mdatbuffer = NULL;
1845 if (qtdemux->comp_brands)
1846 gst_buffer_unref (qtdemux->comp_brands);
1847 qtdemux->comp_brands = NULL;
1848 if (qtdemux->tag_list)
1849 gst_tag_list_free (qtdemux->tag_list);
1850 qtdemux->tag_list = NULL;
1851 if (qtdemux->element_index)
1852 gst_object_unref (qtdemux->element_index);
1853 qtdemux->element_index = NULL;
1854 gst_adapter_clear (qtdemux->adapter);
1855 for (n = 0; n < qtdemux->n_streams; n++) {
1856 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1857 qtdemux->streams[n] = NULL;
1859 qtdemux->major_brand = 0;
1860 qtdemux->n_streams = 0;
1861 qtdemux->n_video_streams = 0;
1862 qtdemux->n_audio_streams = 0;
1863 qtdemux->n_sub_streams = 0;
1864 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1865 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1866 qtdemux->seek_offset = 0;
1877 qtdemux_post_global_tags (GstQTDemux * qtdemux)
1879 if (qtdemux->tag_list) {
1880 /* all header tags ready and parsed, push them */
1881 GST_INFO_OBJECT (qtdemux, "posting global tags: %" GST_PTR_FORMAT,
1883 /* post now, send event on pads later */
1884 gst_element_post_message (GST_ELEMENT (qtdemux),
1885 gst_message_new_tag (GST_OBJECT (qtdemux),
1886 gst_tag_list_copy (qtdemux->tag_list)));
1891 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1893 /* counts as header data */
1894 qtdemux->header_size += length;
1896 /* only consider at least a sufficiently complete ftyp atom */
1900 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1901 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1902 GST_FOURCC_ARGS (qtdemux->major_brand));
1903 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1904 _gst_buffer_copy_into_mem (buf, buffer + 16, 0, length - 16);
1909 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
1911 /* Strip out bogus fields */
1913 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
1915 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
1917 if (qtdemux->tag_list) {
1918 /* prioritize native tags using _KEEP mode */
1919 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
1920 gst_tag_list_free (taglist);
1922 qtdemux->tag_list = taglist;
1927 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1929 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
1930 0x97, 0xA9, 0x42, 0xE8,
1931 0x9C, 0x71, 0x99, 0x94,
1932 0x91, 0xE3, 0xAF, 0xAC
1936 /* counts as header data */
1937 qtdemux->header_size += length;
1939 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
1941 if (length <= offset + 16) {
1942 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
1946 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
1948 GstTagList *taglist;
1950 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
1951 length - offset - 16, NULL);
1952 taglist = gst_tag_list_from_xmp_buffer (buf);
1953 gst_buffer_unref (buf);
1955 qtdemux_handle_xmp_taglist (qtdemux, taglist);
1958 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
1962 /* caller verifies at least 8 bytes in buf */
1964 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1965 guint64 * plength, guint32 * pfourcc)
1970 length = QT_UINT32 (data);
1971 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1972 fourcc = QT_FOURCC (data + 4);
1973 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1976 length = G_MAXUINT32;
1977 } else if (length == 1 && size >= 16) {
1978 /* this means we have an extended size, which is the 64 bit value of
1979 * the next 8 bytes */
1980 length = QT_UINT64 (data + 8);
1981 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1991 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
1993 guint32 version = 0;
1994 guint64 duration = 0;
1996 if (!gst_byte_reader_get_uint32_be (br, &version))
2001 if (!gst_byte_reader_get_uint64_be (br, &duration))
2006 if (!gst_byte_reader_get_uint32_be (br, &dur))
2011 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2012 qtdemux->duration = duration;
2018 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2024 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2025 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2027 if (!stream->parsed_trex && qtdemux->moov_node) {
2029 GstByteReader trex_data;
2031 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2033 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2036 guint32 id = 0, dur = 0, size = 0, flags = 0;
2038 /* skip version/flags */
2039 if (!gst_byte_reader_skip (&trex_data, 4))
2041 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2043 if (id != stream->track_id)
2045 /* sample description index; ignore */
2046 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2048 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2050 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2052 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2055 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2056 "duration %d, size %d, flags 0x%x", stream->track_id,
2059 stream->parsed_trex = TRUE;
2060 stream->def_sample_duration = dur;
2061 stream->def_sample_size = size;
2062 stream->def_sample_flags = flags;
2065 /* iterate all siblings */
2066 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2072 *ds_duration = stream->def_sample_duration;
2073 *ds_size = stream->def_sample_size;
2074 *ds_size = stream->def_sample_size;
2076 /* even then, above values are better than random ... */
2077 if (G_UNLIKELY (!stream->parsed_trex)) {
2078 GST_WARNING_OBJECT (qtdemux,
2079 "failed to find fragment defaults for stream %d", stream->track_id);
2087 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2088 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2089 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2090 gint64 * base_offset, gint64 * running_offset)
2093 gint32 data_offset = 0;
2094 guint32 flags = 0, first_flags = 0, samples_count = 0;
2097 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2098 QtDemuxSample *sample;
2099 gboolean ismv = FALSE;
2101 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2102 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2103 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2106 if (!gst_byte_reader_skip (trun, 1) ||
2107 !gst_byte_reader_get_uint24_be (trun, &flags))
2110 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2113 if (flags & TR_DATA_OFFSET) {
2114 /* note this is really signed */
2115 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2117 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2118 /* default base offset = first byte of moof */
2119 if (*base_offset == -1) {
2120 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2121 *base_offset = moof_offset;
2123 *running_offset = *base_offset + data_offset;
2125 /* if no offset at all, that would mean data starts at moof start,
2126 * which is a bit wrong and is ismv crappy way, so compensate
2127 * assuming data is in mdat following moof */
2128 if (*base_offset == -1) {
2129 *base_offset = moof_offset + moof_length + 8;
2130 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2133 if (*running_offset == -1)
2134 *running_offset = *base_offset;
2137 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2139 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2140 data_offset, flags, samples_count);
2142 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2143 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2144 GST_DEBUG_OBJECT (qtdemux,
2145 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2146 flags ^= TR_FIRST_SAMPLE_FLAGS;
2148 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2150 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2154 /* FIXME ? spec says other bits should also be checked to determine
2155 * entry size (and prefix size for that matter) */
2157 dur_offset = size_offset = 0;
2158 if (flags & TR_SAMPLE_DURATION) {
2159 GST_LOG_OBJECT (qtdemux, "entry duration present");
2160 dur_offset = entry_size;
2163 if (flags & TR_SAMPLE_SIZE) {
2164 GST_LOG_OBJECT (qtdemux, "entry size present");
2165 size_offset = entry_size;
2168 if (flags & TR_SAMPLE_FLAGS) {
2169 GST_LOG_OBJECT (qtdemux, "entry flags present");
2170 flags_offset = entry_size;
2173 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2174 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2175 ct_offset = entry_size;
2179 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2181 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2183 if (stream->n_samples >=
2184 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2187 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2188 stream->n_samples, (guint) sizeof (QtDemuxSample),
2189 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2191 /* create a new array of samples if it's the first sample parsed */
2192 if (stream->n_samples == 0)
2193 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2194 /* or try to reallocate it with space enough to insert the new samples */
2196 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2197 stream->n_samples + samples_count);
2198 if (stream->samples == NULL)
2201 if (G_UNLIKELY (stream->n_samples == 0)) {
2202 /* the timestamp of the first sample is also provided by the tfra entry
2203 * but we shouldn't rely on it as it is at the end of files */
2206 /* subsequent fragments extend stream */
2208 stream->samples[stream->n_samples - 1].timestamp +
2209 stream->samples[stream->n_samples - 1].duration;
2211 sample = stream->samples + stream->n_samples;
2212 for (i = 0; i < samples_count; i++) {
2213 guint32 dur, size, sflags, ct;
2215 /* first read sample data */
2216 if (flags & TR_SAMPLE_DURATION) {
2217 dur = QT_UINT32 (data + dur_offset);
2219 dur = d_sample_duration;
2221 if (flags & TR_SAMPLE_SIZE) {
2222 size = QT_UINT32 (data + size_offset);
2224 size = d_sample_size;
2226 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2228 sflags = first_flags;
2230 sflags = d_sample_flags;
2232 } else if (flags & TR_SAMPLE_FLAGS) {
2233 sflags = QT_UINT32 (data + flags_offset);
2235 sflags = d_sample_flags;
2237 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2238 ct = QT_UINT32 (data + ct_offset);
2244 /* fill the sample information */
2245 sample->offset = *running_offset;
2246 sample->pts_offset = ct;
2247 sample->size = size;
2248 sample->timestamp = timestamp;
2249 sample->duration = dur;
2250 /* sample-is-difference-sample */
2251 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2252 * now idea how it relates to bitfield other than massive LE/BE confusion */
2253 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2254 *running_offset += size;
2259 stream->n_samples += samples_count;
2265 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2270 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2276 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2277 "be larger than %uMB (broken file?)", stream->n_samples,
2278 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2283 /* find stream with @id */
2284 static inline QtDemuxStream *
2285 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2287 QtDemuxStream *stream;
2291 if (G_UNLIKELY (!id)) {
2292 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2296 /* try to get it fast and simple */
2297 if (G_LIKELY (id <= qtdemux->n_streams)) {
2298 stream = qtdemux->streams[id - 1];
2299 if (G_LIKELY (stream->track_id == id))
2303 /* linear search otherwise */
2304 for (i = 0; i < qtdemux->n_streams; i++) {
2305 stream = qtdemux->streams[i];
2306 if (stream->track_id == id)
2314 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2315 QtDemuxStream ** stream, guint32 * default_sample_duration,
2316 guint32 * default_sample_size, guint32 * default_sample_flags,
2317 gint64 * base_offset)
2320 guint32 track_id = 0;
2322 if (!gst_byte_reader_skip (tfhd, 1) ||
2323 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2326 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2329 *stream = qtdemux_find_stream (qtdemux, track_id);
2330 if (G_UNLIKELY (!*stream))
2331 goto unknown_stream;
2333 if (flags & TF_BASE_DATA_OFFSET)
2334 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2337 /* obtain stream defaults */
2338 qtdemux_parse_trex (qtdemux, *stream,
2339 default_sample_duration, default_sample_size, default_sample_flags);
2341 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2342 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2343 if (!gst_byte_reader_skip (tfhd, 4))
2346 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2347 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2350 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2351 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2354 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2355 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2362 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2367 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2373 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2374 guint64 moof_offset, QtDemuxStream * stream)
2376 GNode *moof_node, *traf_node, *tfhd_node, *trun_node;
2377 GstByteReader trun_data, tfhd_data;
2378 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2379 gint64 base_offset, running_offset;
2381 /* NOTE @stream ignored */
2383 moof_node = g_node_new ((guint8 *) buffer);
2384 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2385 qtdemux_node_dump (qtdemux, moof_node);
2387 /* unknown base_offset to start with */
2388 base_offset = running_offset = -1;
2389 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2391 /* Fragment Header node */
2393 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2397 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2398 &ds_size, &ds_flags, &base_offset))
2400 if (G_UNLIKELY (!stream)) {
2401 /* we lost track of offset, we'll need to regain it,
2402 * but can delay complaining until later or avoid doing so altogether */
2406 if (G_UNLIKELY (base_offset < -1))
2408 /* Track Run node */
2410 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2413 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2414 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2416 /* iterate all siblings */
2417 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2420 /* if no new base_offset provided for next traf,
2421 * base is end of current traf */
2422 base_offset = running_offset;
2423 running_offset = -1;
2425 /* iterate all siblings */
2426 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2428 g_node_destroy (moof_node);
2433 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2438 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2443 g_node_destroy (moof_node);
2444 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2445 (_("This file is corrupt and cannot be played.")), (NULL));
2450 /* might be used if some day we actually use mfra & co
2451 * for random access to fragments,
2452 * but that will require quite some modifications and much less relying
2453 * on a sample array */
2456 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2457 QtDemuxStream * stream)
2459 guint64 time = 0, moof_offset = 0;
2460 guint32 ver_flags, track_id, len, num_entries, i;
2461 guint value_size, traf_size, trun_size, sample_size;
2462 GstBuffer *buf = NULL;
2466 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2467 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2469 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2472 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2473 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2474 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2477 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2478 track_id, stream->track_id);
2479 if (track_id != stream->track_id) {
2483 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2484 sample_size = (len & 3) + 1;
2485 trun_size = ((len & 12) >> 2) + 1;
2486 traf_size = ((len & 48) >> 4) + 1;
2488 if (num_entries == 0)
2491 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2492 value_size + value_size + traf_size + trun_size + sample_size))
2495 for (i = 0; i < num_entries; i++) {
2496 qt_atom_parser_get_offset (&tfra, value_size, &time);
2497 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2498 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2499 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2500 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2502 GST_LOG_OBJECT (qtdemux,
2503 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2504 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2505 stream->timescale)), moof_offset);
2507 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2508 if (ret != GST_FLOW_OK)
2510 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2511 moof_offset, stream);
2512 gst_buffer_unref (buf);
2520 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2521 (_("This file is corrupt and cannot be played.")), (NULL));
2526 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2532 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2535 GNode *mfra_node, *tfra_node;
2538 if (!qtdemux->mfra_offset)
2541 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2542 if (ret != GST_FLOW_OK)
2545 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2546 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2547 GST_BUFFER_SIZE (buffer));
2549 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2552 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2553 /* iterate all siblings */
2554 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2556 g_node_destroy (mfra_node);
2557 gst_buffer_unref (buffer);
2563 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2564 (_("This file is corrupt and cannot be played.")), (NULL));
2569 static GstFlowReturn
2570 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2571 guint32 * mfro_size)
2573 GstFlowReturn ret = GST_FLOW_ERROR;
2574 GstBuffer *mfro = NULL;
2577 GstFormat fmt = GST_FORMAT_BYTES;
2579 if (!gst_pad_query_peer_duration (qtdemux->sinkpad, &fmt, &len)) {
2580 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2581 "can not locate mfro");
2585 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2586 if (ret != GST_FLOW_OK)
2589 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2590 if (fourcc != FOURCC_mfro)
2593 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2594 if (GST_BUFFER_SIZE (mfro) >= 16) {
2595 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
2596 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
2597 if (*mfro_size >= len) {
2598 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
2599 ret = GST_FLOW_ERROR;
2602 *mfra_offset = len - *mfro_size;
2607 gst_buffer_unref (mfro);
2613 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
2616 guint32 mfra_size = 0;
2617 guint64 mfra_offset = 0;
2620 qtdemux->fragmented = FALSE;
2622 /* We check here if it is a fragmented mp4 container */
2623 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
2624 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
2625 qtdemux->fragmented = TRUE;
2626 GST_DEBUG_OBJECT (qtdemux,
2627 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
2628 qtdemux->mfra_offset = mfra_offset;
2633 static GstFlowReturn
2634 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
2638 GstBuffer *buf = NULL;
2639 GstFlowReturn ret = GST_FLOW_OK;
2640 guint64 cur_offset = qtdemux->offset;
2644 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
2645 if (G_UNLIKELY (ret != GST_FLOW_OK))
2647 data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
2648 if (G_LIKELY (size >= 8))
2649 extract_initial_length_and_fourcc (data, size, &length, &fourcc);
2650 gst_buffer_unmap (buf, data, size);
2651 gst_buffer_unref (buf);
2653 /* maybe we already got most we needed, so only consider this eof */
2654 if (G_UNLIKELY (length == 0)) {
2655 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
2656 (_("Invalid atom size.")),
2657 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
2658 GST_FOURCC_ARGS (fourcc)));
2659 ret = GST_FLOW_UNEXPECTED;
2665 /* record for later parsing when needed */
2666 if (!qtdemux->moof_offset) {
2667 qtdemux->moof_offset = qtdemux->offset;
2676 GST_LOG_OBJECT (qtdemux,
2677 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
2678 GST_FOURCC_ARGS (fourcc), cur_offset);
2679 qtdemux->offset += length;
2686 if (qtdemux->got_moov) {
2687 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
2688 qtdemux->offset += length;
2692 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
2693 if (ret != GST_FLOW_OK)
2695 data = gst_buffer_map (moov, &size, NULL, GST_MAP_READ);
2696 if (length != size) {
2697 /* Some files have a 'moov' atom at the end of the file which contains
2698 * a terminal 'free' atom where the body of the atom is missing.
2699 * Check for, and permit, this special case.
2702 guint8 *final_data = data + (size - 8);
2703 guint32 final_length = QT_UINT32 (final_data);
2704 guint32 final_fourcc = QT_FOURCC (final_data + 4);
2705 gst_buffer_unmap (moov, data, size);
2706 if (final_fourcc == FOURCC_free && size + final_length - 8 == length) {
2707 /* Ok, we've found that special case. Allocate a new buffer with
2708 * that free atom actually present. */
2709 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
2710 gst_buffer_copy_into (newmoov, moov, 0, 0, size);
2711 data = gst_buffer_map (newmoov, &size, NULL, GST_MAP_WRITE);
2712 memset (data + length - final_length + 8, 0, final_length - 8);
2713 gst_buffer_unref (moov);
2719 if (length != size) {
2720 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2721 (_("This file is incomplete and cannot be played.")),
2722 ("We got less than expected (received %u, wanted %u, offset %"
2723 G_GUINT64_FORMAT ")", size, (guint) length, cur_offset));
2724 gst_buffer_unmap (moov, data, size);
2725 gst_buffer_unref (moov);
2726 ret = GST_FLOW_ERROR;
2729 qtdemux->offset += length;
2731 qtdemux_parse_moov (qtdemux, data, length);
2732 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
2734 qtdemux_parse_tree (qtdemux);
2735 g_node_destroy (qtdemux->moov_node);
2736 gst_buffer_unmap (moov, data, size);
2737 gst_buffer_unref (moov);
2738 qtdemux->moov_node = NULL;
2739 qtdemux->got_moov = TRUE;
2747 /* extract major brand; might come in handy for ISO vs QT issues */
2748 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
2749 if (ret != GST_FLOW_OK)
2751 qtdemux->offset += length;
2752 data = gst_buffer_map (ftyp, &size, NULL, GST_MAP_READ);
2753 qtdemux_parse_ftyp (qtdemux, data, size);
2754 gst_buffer_unmap (ftyp, data, size);
2755 gst_buffer_unref (ftyp);
2762 /* uuid are extension atoms */
2763 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
2764 if (ret != GST_FLOW_OK)
2766 qtdemux->offset += length;
2767 data = gst_buffer_map (uuid, &size, NULL, GST_MAP_READ);
2768 qtdemux_parse_uuid (qtdemux, data, size);
2769 gst_buffer_unmap (uuid, data, size);
2770 gst_buffer_unref (uuid);
2777 GST_LOG_OBJECT (qtdemux,
2778 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
2779 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
2781 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
2782 if (ret != GST_FLOW_OK)
2784 data = gst_buffer_map (unknown, &size, NULL, GST_MAP_READ);
2785 GST_MEMDUMP ("Unknown tag", data, size);
2786 gst_buffer_unmap (unknown, data, size);
2787 gst_buffer_unref (unknown);
2788 qtdemux->offset += length;
2794 if (ret == GST_FLOW_UNEXPECTED && qtdemux->got_moov) {
2795 /* digested all data, show what we have */
2796 ret = qtdemux_expose_streams (qtdemux);
2798 /* Only post, event on pads is done after newsegment */
2799 qtdemux_post_global_tags (qtdemux);
2801 qtdemux->state = QTDEMUX_STATE_MOVIE;
2802 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
2809 /* Seeks to the previous keyframe of the indexed stream and
2810 * aligns other streams with respect to the keyframe timestamp
2811 * of indexed stream. Only called in case of Reverse Playback
2813 static GstFlowReturn
2814 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
2817 guint32 seg_idx = 0, k_index = 0;
2818 guint32 ref_seg_idx, ref_k_index;
2819 guint64 k_pos = 0, last_stop = 0;
2820 QtDemuxSegment *seg = NULL;
2821 QtDemuxStream *ref_str = NULL;
2822 guint64 seg_media_start_mov; /* segment media start time in mov format */
2824 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
2825 * and finally align all the other streams on that timestamp with their
2826 * respective keyframes */
2827 for (n = 0; n < qtdemux->n_streams; n++) {
2828 QtDemuxStream *str = qtdemux->streams[n];
2830 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
2831 qtdemux->segment.position);
2833 /* segment not found, continue with normal flow */
2837 /* No candidate yet, take that one */
2843 /* So that stream has a segment, we prefer video streams */
2844 if (str->subtype == FOURCC_vide) {
2850 if (G_UNLIKELY (!ref_str)) {
2851 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
2855 if (G_UNLIKELY (!ref_str->from_sample)) {
2856 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
2860 /* So that stream has been playing from from_sample to to_sample. We will
2861 * get the timestamp of the previous sample and search for a keyframe before
2862 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
2863 if (ref_str->subtype == FOURCC_vide) {
2864 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
2865 ref_str->from_sample - 1);
2867 if (ref_str->from_sample >= 10)
2868 k_index = ref_str->from_sample - 10;
2873 /* get current segment for that stream */
2874 seg = &ref_str->segments[ref_str->segment_index];
2875 /* convert seg->media_start to mov format time for timestamp comparison */
2876 seg_media_start_mov =
2877 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
2878 /* Crawl back through segments to find the one containing this I frame */
2879 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
2880 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
2881 ref_str->segment_index);
2882 if (G_UNLIKELY (!ref_str->segment_index)) {
2883 /* Reached first segment, let's consider it's EOS */
2886 ref_str->segment_index--;
2887 seg = &ref_str->segments[ref_str->segment_index];
2888 /* convert seg->media_start to mov format time for timestamp comparison */
2889 seg_media_start_mov =
2890 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
2893 /* Calculate time position of the keyframe and where we should stop */
2895 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
2896 ref_str->timescale) - seg->media_start) + seg->time;
2898 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
2899 GST_SECOND, ref_str->timescale);
2900 last_stop = (last_stop - seg->media_start) + seg->time;
2902 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
2903 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
2904 k_index, GST_TIME_ARGS (k_pos));
2906 /* Set last_stop with the keyframe timestamp we pushed of that stream */
2907 qtdemux->segment.position = last_stop;
2908 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
2909 GST_TIME_ARGS (last_stop));
2911 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
2912 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
2916 ref_seg_idx = ref_str->segment_index;
2917 ref_k_index = k_index;
2919 /* Align them all on this */
2920 for (n = 0; n < qtdemux->n_streams; n++) {
2922 guint64 media_start = 0, seg_time = 0;
2923 QtDemuxStream *str = qtdemux->streams[n];
2925 /* aligning reference stream again might lead to backing up to yet another
2926 * keyframe (due to timestamp rounding issues),
2927 * potentially putting more load on downstream; so let's try to avoid */
2928 if (str == ref_str) {
2929 seg_idx = ref_seg_idx;
2930 seg = &str->segments[seg_idx];
2931 k_index = ref_k_index;
2932 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
2933 "sample at index %d", ref_str->segment_index, k_index);
2935 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
2936 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
2938 /* segment not found, continue with normal flow */
2942 /* get segment and time in the segment */
2943 seg = &str->segments[seg_idx];
2944 seg_time = k_pos - seg->time;
2946 /* get the media time in the segment */
2947 media_start = seg->media_start + seg_time;
2949 /* get the index of the sample with media time */
2950 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
2951 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
2952 GST_TIME_ARGS (media_start), index);
2954 /* find previous keyframe */
2955 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
2958 /* Remember until where we want to go */
2959 str->to_sample = str->from_sample - 1;
2960 /* Define our time position */
2961 str->time_position =
2962 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
2963 str->timescale) - seg->media_start) + seg->time;
2964 /* Now seek back in time */
2965 gst_qtdemux_move_stream (qtdemux, str, k_index);
2966 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
2967 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
2968 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
2974 return GST_FLOW_UNEXPECTED;
2977 /* activate the given segment number @seg_idx of @stream at time @offset.
2978 * @offset is an absolute global position over all the segments.
2980 * This will push out a NEWSEGMENT event with the right values and
2981 * position the stream index to the first decodable sample before
2985 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
2986 guint32 seg_idx, guint64 offset)
2989 QtDemuxSegment *segment;
2990 guint32 index, kf_index;
2992 guint64 start, stop, time;
2995 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
2998 /* update the current segment */
2999 stream->segment_index = seg_idx;
3001 /* get the segment */
3002 segment = &stream->segments[seg_idx];
3004 if (G_UNLIKELY (offset < segment->time)) {
3005 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3010 /* segment lies beyond total indicated duration */
3011 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3012 segment->time > qtdemux->segment.duration)) {
3013 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3014 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3019 /* get time in this segment */
3020 seg_time = offset - segment->time;
3022 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3023 GST_TIME_ARGS (seg_time));
3025 if (G_UNLIKELY (seg_time > segment->duration)) {
3026 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3027 GST_TIME_ARGS (segment->duration));
3031 /* qtdemux->segment.stop is in outside-time-realm, whereas
3032 * segment->media_stop is in track-time-realm.
3034 * In order to compare the two, we need to bring segment.stop
3035 * into the track-time-realm */
3037 stop = qtdemux->segment.stop;
3039 stop = qtdemux->segment.duration;
3041 stop = segment->media_stop;
3044 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3046 if (qtdemux->segment.rate >= 0) {
3047 start = MIN (segment->media_start + seg_time, stop);
3050 if (segment->media_start >= qtdemux->segment.start) {
3051 start = segment->media_start;
3052 time = segment->time;
3054 start = qtdemux->segment.start;
3055 time = segment->time + (qtdemux->segment.start - segment->media_start);
3058 start = MAX (segment->media_start, qtdemux->segment.start);
3059 stop = MIN (segment->media_start + seg_time, stop);
3062 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3063 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3064 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3066 /* combine global rate with that of the segment */
3067 rate = segment->rate * qtdemux->segment.rate;
3069 /* update the segment values used for clipping */
3070 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
3071 /* accumulate previous segments */
3072 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3073 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3074 ABS (stream->segment.rate);
3075 stream->segment.rate = rate;
3076 stream->segment.start = start;
3077 stream->segment.stop = stop;
3078 stream->segment.time = time;
3080 /* now prepare and send the segment */
3082 event = gst_event_new_segment (&stream->segment);
3083 gst_pad_push_event (stream->pad, event);
3084 /* assume we can send more data now */
3085 stream->last_ret = GST_FLOW_OK;
3086 /* clear to send tags on this pad now */
3087 gst_qtdemux_push_tags (qtdemux, stream);
3090 /* and move to the keyframe before the indicated media time of the
3092 if (qtdemux->segment.rate >= 0) {
3093 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3094 stream->to_sample = G_MAXUINT32;
3095 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3096 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3097 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3098 GST_SECOND, stream->timescale)));
3100 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3101 stream->to_sample = index;
3102 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3103 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3104 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3105 GST_SECOND, stream->timescale)));
3108 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3109 * encountered an error and printed a message so we return appropriately */
3113 /* we're at the right spot */
3114 if (index == stream->sample_index) {
3115 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3119 /* find keyframe of the target index */
3120 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3123 /* indent does stupid stuff with stream->samples[].timestamp */
3125 /* if we move forwards, we don't have to go back to the previous
3126 * keyframe since we already sent that. We can also just jump to
3127 * the keyframe right before the target index if there is one. */
3128 if (index > stream->sample_index) {
3129 /* moving forwards check if we move past a keyframe */
3130 if (kf_index > stream->sample_index) {
3131 GST_DEBUG_OBJECT (qtdemux,
3132 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3133 GST_TIME_ARGS (gst_util_uint64_scale (
3134 stream->samples[kf_index].timestamp,
3135 GST_SECOND, stream->timescale)));
3136 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3138 GST_DEBUG_OBJECT (qtdemux,
3139 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3140 " already sent", kf_index,
3141 GST_TIME_ARGS (gst_util_uint64_scale (
3142 stream->samples[kf_index].timestamp,
3143 GST_SECOND, stream->timescale)));
3146 GST_DEBUG_OBJECT (qtdemux,
3147 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3148 GST_TIME_ARGS (gst_util_uint64_scale (
3149 stream->samples[kf_index].timestamp,
3150 GST_SECOND, stream->timescale)));
3151 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3159 /* prepare to get the current sample of @stream, getting essential values.
3161 * This function will also prepare and send the segment when needed.
3163 * Return FALSE if the stream is EOS.
3166 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3167 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp,
3168 guint64 * duration, gboolean * keyframe)
3170 QtDemuxSample *sample;
3171 guint64 time_position;
3174 g_return_val_if_fail (stream != NULL, FALSE);
3176 time_position = stream->time_position;
3177 if (G_UNLIKELY (time_position == -1))
3180 seg_idx = stream->segment_index;
3181 if (G_UNLIKELY (seg_idx == -1)) {
3182 /* find segment corresponding to time_position if we are looking
3184 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3186 /* nothing found, we're really eos */
3191 /* different segment, activate it, sample_index will be set. */
3192 if (G_UNLIKELY (stream->segment_index != seg_idx))
3193 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3195 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3196 stream->sample_index, stream->n_samples);
3198 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3201 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3202 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3203 stream->sample_index);
3207 /* now get the info for the sample we're at */
3208 sample = &stream->samples[stream->sample_index];
3210 *timestamp = QTSAMPLE_PTS (stream, sample);
3211 *offset = sample->offset;
3212 *size = sample->size;
3213 *duration = QTSAMPLE_DUR_PTS (stream, sample, *timestamp);
3214 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3221 stream->time_position = -1;
3226 /* move to the next sample in @stream.
3228 * Moves to the next segment when needed.
3231 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3233 QtDemuxSample *sample;
3234 QtDemuxSegment *segment;
3236 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3237 /* Mark the stream as EOS */
3238 GST_DEBUG_OBJECT (qtdemux,
3239 "reached max allowed sample %u, mark EOS", stream->to_sample);
3240 stream->time_position = -1;
3244 /* move to next sample */
3245 stream->sample_index++;
3247 /* get current segment */
3248 segment = &stream->segments[stream->segment_index];
3250 /* reached the last sample, we need the next segment */
3251 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3254 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3255 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3256 stream->sample_index);
3260 /* get next sample */
3261 sample = &stream->samples[stream->sample_index];
3263 /* see if we are past the segment */
3264 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3265 GST_SECOND, stream->timescale) >= segment->media_stop))
3268 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3269 stream->timescale) >= segment->media_start) {
3270 /* inside the segment, update time_position, looks very familiar to
3271 * GStreamer segments, doesn't it? */
3272 stream->time_position =
3273 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3274 stream->timescale) - segment->media_start) + segment->time;
3276 /* not yet in segment, time does not yet increment. This means
3277 * that we are still prerolling keyframes to the decoder so it can
3278 * decode the first sample of the segment. */
3279 stream->time_position = segment->time;
3283 /* move to the next segment */
3286 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3288 if (stream->segment_index == stream->n_segments - 1) {
3289 /* are we at the end of the last segment, we're EOS */
3290 stream->time_position = -1;
3292 /* else we're only at the end of the current segment */
3293 stream->time_position = segment->stop_time;
3295 /* make sure we select a new segment */
3296 stream->segment_index = -1;
3301 gst_qtdemux_sync_streams (GstQTDemux * demux)
3305 if (demux->n_streams <= 1)
3308 for (i = 0; i < demux->n_streams; i++) {
3309 QtDemuxStream *stream;
3310 GstClockTime end_time;
3312 stream = demux->streams[i];
3317 /* TODO advance time on subtitle streams here, if any some day */
3319 /* some clips/trailers may have unbalanced streams at the end,
3320 * so send EOS on shorter stream to prevent stalling others */
3322 /* do not mess with EOS if SEGMENT seeking */
3323 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3326 if (demux->pullbased) {
3327 /* loop mode is sample time based */
3328 if (stream->time_position != -1)
3331 /* push mode is byte position based */
3332 if (stream->n_samples &&
3333 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3337 if (stream->sent_eos)
3340 /* only act if some gap */
3341 end_time = stream->segments[stream->n_segments - 1].stop_time;
3342 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3343 ", stream end: %" GST_TIME_FORMAT,
3344 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3345 if (end_time + 2 * GST_SECOND < demux->segment.position) {
3346 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3347 GST_PAD_NAME (stream->pad));
3348 stream->sent_eos = TRUE;
3349 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3354 /* UNEXPECTED and NOT_LINKED need to be combined. This means that we return:
3356 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3357 * GST_FLOW_UNEXPECTED: when all pads UNEXPECTED or NOT_LINKED.
3359 static GstFlowReturn
3360 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3364 gboolean unexpected = FALSE, not_linked = TRUE;
3366 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3368 /* store the value */
3369 stream->last_ret = ret;
3371 /* any other error that is not-linked or eos can be returned right away */
3372 if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
3375 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3376 for (i = 0; i < demux->n_streams; i++) {
3377 QtDemuxStream *ostream = demux->streams[i];
3379 ret = ostream->last_ret;
3381 /* no unexpected or unlinked, return */
3382 if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
3385 /* we check to see if we have at least 1 unexpected or all unlinked */
3386 unexpected |= (ret == GST_FLOW_UNEXPECTED);
3387 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3390 /* when we get here, we all have unlinked or unexpected */
3392 ret = GST_FLOW_NOT_LINKED;
3393 else if (unexpected)
3394 ret = GST_FLOW_UNEXPECTED;
3396 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3400 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3401 * completely cliped */
3403 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3406 guint64 start, stop, cstart, cstop, diff;
3407 GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
3409 gint num_rate, denom_rate;
3414 size = gst_buffer_get_size (buf);
3417 /* depending on the type, setup the clip parameters */
3418 if (stream->subtype == FOURCC_soun) {
3419 frame_size = stream->bytes_per_frame;
3420 num_rate = GST_SECOND;
3421 denom_rate = (gint) stream->rate;
3423 } else if (stream->subtype == FOURCC_vide) {
3425 num_rate = stream->fps_n;
3426 denom_rate = stream->fps_d;
3431 /* we can only clip if we have a valid timestamp */
3432 timestamp = GST_BUFFER_TIMESTAMP (buf);
3433 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
3436 if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf))) {
3437 duration = GST_BUFFER_DURATION (buf);
3440 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3444 stop = start + duration;
3446 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3447 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3450 /* see if some clipping happened */
3451 diff = cstart - start;
3457 /* bring clipped time to samples and to bytes */
3458 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3461 GST_DEBUG_OBJECT (qtdemux,
3462 "clipping start to %" GST_TIME_FORMAT " %"
3463 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3469 diff = stop - cstop;
3474 /* bring clipped time to samples and then to bytes */
3475 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3477 GST_DEBUG_OBJECT (qtdemux,
3478 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3479 " bytes", GST_TIME_ARGS (cstop), diff);
3484 gst_buffer_resize (buf, offset, size);
3485 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3486 GST_BUFFER_DURATION (buf) = duration;
3490 /* dropped buffer */
3493 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3498 GST_DEBUG_OBJECT (qtdemux, "no timestamp on buffer");
3503 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3504 gst_buffer_unref (buf);
3509 /* the input buffer metadata must be writable,
3510 * but time/duration etc not yet set and need not be preserved */
3512 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3520 /* not many cases for now */
3521 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3522 /* send a one time dvd clut event */
3523 if (stream->pending_event && stream->pad)
3524 gst_pad_push_event (stream->pad, stream->pending_event);
3525 stream->pending_event = NULL;
3526 /* no further processing needed */
3527 stream->need_process = FALSE;
3530 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
3534 data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
3536 if (G_LIKELY (size >= 2)) {
3537 nsize = GST_READ_UINT16_BE (data);
3538 nsize = MIN (nsize, size - 2);
3541 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%d", nsize, size);
3543 /* takes care of UTF-8 validation or UTF-16 recognition,
3544 * no other encoding expected */
3545 str = gst_tag_freeform_string_to_utf8 ((gchar *) data + 2, nsize, NULL);
3546 gst_buffer_unmap (buf, data, size);
3548 gst_buffer_unref (buf);
3549 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
3551 /* may be 0-size subtitle, which is also sent to keep pipeline going */
3552 gst_buffer_resize (buf, 2, nsize);
3555 /* FIXME ? convert optional subsequent style info to markup */
3560 /* Sets a buffer's attributes properly and pushes it downstream.
3561 * Also checks for additional actions and custom processing that may
3562 * need to be done first.
3565 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3566 QtDemuxStream * stream, GstBuffer * buf,
3567 guint64 timestamp, guint64 duration, gboolean keyframe, guint64 position,
3568 guint64 byte_position)
3570 GstFlowReturn ret = GST_FLOW_OK;
3572 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
3577 bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
3578 url = g_strndup ((gchar *) bdata, bsize);
3579 gst_buffer_unmap (buf, bdata, bsize);
3580 if (url != NULL && strlen (url) != 0) {
3581 /* we have RTSP redirect now */
3582 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3583 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
3584 gst_structure_new ("redirect",
3585 "new-location", G_TYPE_STRING, url, NULL)));
3586 qtdemux->posted_redirect = TRUE;
3588 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
3594 /* position reporting */
3595 if (qtdemux->segment.rate >= 0) {
3596 qtdemux->segment.position = position;
3597 gst_qtdemux_sync_streams (qtdemux);
3600 if (G_UNLIKELY (!stream->pad)) {
3601 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
3602 gst_buffer_unref (buf);
3606 /* send out pending buffers */
3607 while (stream->buffers) {
3608 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
3610 if (G_UNLIKELY (stream->discont)) {
3611 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3612 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
3613 stream->discont = FALSE;
3616 gst_pad_push (stream->pad, buffer);
3618 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
3621 /* we're going to modify the metadata */
3622 buf = gst_buffer_make_writable (buf);
3624 if (G_UNLIKELY (stream->need_process))
3625 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
3627 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3628 GST_BUFFER_DURATION (buf) = duration;
3629 GST_BUFFER_OFFSET (buf) = -1;
3630 GST_BUFFER_OFFSET_END (buf) = -1;
3632 if (G_UNLIKELY (stream->padding)) {
3633 gst_buffer_resize (buf, stream->padding, -1);
3636 if (G_UNLIKELY (qtdemux->element_index)) {
3637 GstClockTime stream_time;
3640 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
3642 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
3643 GST_LOG_OBJECT (qtdemux,
3644 "adding association %" GST_TIME_FORMAT "-> %"
3645 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
3646 gst_index_add_association (qtdemux->element_index,
3648 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
3649 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
3650 GST_FORMAT_BYTES, byte_position, NULL);
3654 if (stream->need_clip)
3655 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
3657 if (G_UNLIKELY (buf == NULL))
3660 if (G_UNLIKELY (stream->discont)) {
3661 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3662 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3663 stream->discont = FALSE;
3667 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3669 GST_LOG_OBJECT (qtdemux,
3670 "Pushing buffer with time %" GST_TIME_FORMAT ", duration %"
3671 GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
3672 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
3674 ret = gst_pad_push (stream->pad, buf);
3680 static GstFlowReturn
3681 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
3683 GstFlowReturn ret = GST_FLOW_OK;
3684 GstBuffer *buf = NULL;
3685 QtDemuxStream *stream;
3688 guint64 timestamp = GST_CLOCK_TIME_NONE;
3689 guint64 duration = 0;
3690 gboolean keyframe = FALSE;
3695 gst_qtdemux_push_pending_newsegment (qtdemux);
3697 /* Figure out the next stream sample to output, min_time is expressed in
3698 * global time and runs over the edit list segments. */
3699 min_time = G_MAXUINT64;
3701 for (i = 0; i < qtdemux->n_streams; i++) {
3704 stream = qtdemux->streams[i];
3705 position = stream->time_position;
3707 /* position of -1 is EOS */
3708 if (position != -1 && position < min_time) {
3709 min_time = position;
3714 if (G_UNLIKELY (index == -1)) {
3715 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
3719 /* check for segment end */
3720 if (G_UNLIKELY (qtdemux->segment.stop != -1
3721 && qtdemux->segment.stop < min_time)) {
3722 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
3726 stream = qtdemux->streams[index];
3728 /* fetch info for the current sample of this stream */
3729 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
3730 &size, ×tamp, &duration, &keyframe)))
3733 GST_LOG_OBJECT (qtdemux,
3734 "pushing from stream %d, offset %" G_GUINT64_FORMAT
3735 ", size %d, timestamp=%" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
3736 index, offset, size, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
3738 /* hmm, empty sample, skip and move to next sample */
3739 if (G_UNLIKELY (size <= 0))
3742 /* last pushed sample was out of boundary, goto next sample */
3743 if (G_UNLIKELY (stream->last_ret == GST_FLOW_UNEXPECTED))
3746 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
3749 ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
3750 if (G_UNLIKELY (ret != GST_FLOW_OK))
3753 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
3754 timestamp, duration, keyframe, min_time, offset);
3757 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
3758 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
3759 * we have no more data for the pad to push */
3760 if (ret == GST_FLOW_UNEXPECTED)
3764 gst_qtdemux_advance_sample (qtdemux, stream);
3772 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
3773 ret = GST_FLOW_UNEXPECTED;
3778 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
3779 /* EOS will be raised if all are EOS */
3786 gst_qtdemux_loop (GstPad * pad)
3788 GstQTDemux *qtdemux;
3792 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
3794 cur_offset = qtdemux->offset;
3795 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
3796 cur_offset, qtdemux->state);
3798 switch (qtdemux->state) {
3799 case QTDEMUX_STATE_INITIAL:
3800 case QTDEMUX_STATE_HEADER:
3801 ret = gst_qtdemux_loop_state_header (qtdemux);
3803 case QTDEMUX_STATE_MOVIE:
3804 ret = gst_qtdemux_loop_state_movie (qtdemux);
3805 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_UNEXPECTED) {
3806 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
3814 /* if something went wrong, pause */
3815 if (ret != GST_FLOW_OK)
3819 gst_object_unref (qtdemux);
3825 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3826 (NULL), ("streaming stopped, invalid state"));
3827 gst_pad_pause_task (pad);
3828 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3833 const gchar *reason = gst_flow_get_name (ret);
3835 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
3837 gst_pad_pause_task (pad);
3839 /* fatal errors need special actions */
3841 if (ret == GST_FLOW_UNEXPECTED) {
3842 if (qtdemux->n_streams == 0) {
3843 /* we have no streams, post an error */
3844 gst_qtdemux_post_no_playable_stream_error (qtdemux);
3846 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3849 if ((stop = qtdemux->segment.stop) == -1)
3850 stop = qtdemux->segment.duration;
3852 if (qtdemux->segment.rate >= 0) {
3853 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
3854 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3855 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3856 GST_FORMAT_TIME, stop));
3858 /* For Reverse Playback */
3859 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
3860 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3861 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3862 GST_FORMAT_TIME, qtdemux->segment.start));
3865 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
3866 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3868 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
3869 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3870 (NULL), ("streaming stopped, reason %s", reason));
3871 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3880 * Returns the size of the first entry at the current offset.
3881 * If -1, there are none (which means EOS or empty file).
3884 next_entry_size (GstQTDemux * demux)
3886 QtDemuxStream *stream;
3889 guint64 smalloffs = (guint64) - 1;
3890 QtDemuxSample *sample;
3892 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
3895 for (i = 0; i < demux->n_streams; i++) {
3896 stream = demux->streams[i];
3898 if (stream->sample_index == -1)
3899 stream->sample_index = 0;
3901 if (stream->sample_index >= stream->n_samples) {
3902 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
3906 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
3907 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
3908 stream->sample_index);
3912 sample = &stream->samples[stream->sample_index];
3914 GST_LOG_OBJECT (demux,
3915 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3916 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
3917 sample->offset, sample->size);
3919 if (((smalloffs == -1)
3920 || (sample->offset < smalloffs)) && (sample->size)) {
3922 smalloffs = sample->offset;
3926 GST_LOG_OBJECT (demux,
3927 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
3928 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
3933 stream = demux->streams[smallidx];
3934 sample = &stream->samples[stream->sample_index];
3936 if (sample->offset >= demux->offset) {
3937 demux->todrop = sample->offset - demux->offset;
3938 return sample->size + demux->todrop;
3941 GST_DEBUG_OBJECT (demux,
3942 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
3947 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
3949 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
3951 gst_element_post_message (GST_ELEMENT_CAST (demux),
3952 gst_message_new_element (GST_OBJECT_CAST (demux),
3953 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
3957 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
3962 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
3965 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
3966 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
3967 GST_SEEK_TYPE_NONE, -1);
3969 res = gst_pad_push_event (demux->sinkpad, event);
3974 /* FIXME, unverified after edit list updates */
3975 static GstFlowReturn
3976 gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
3979 GstFlowReturn ret = GST_FLOW_OK;
3981 demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad));
3983 gst_adapter_push (demux->adapter, inbuf);
3985 /* we never really mean to buffer that much */
3986 if (demux->neededbytes == -1)
3989 GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
3990 inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
3992 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
3993 (ret == GST_FLOW_OK)) {
3995 GST_DEBUG_OBJECT (demux,
3996 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
3997 demux->state, demux->neededbytes, demux->offset);
3999 switch (demux->state) {
4000 case QTDEMUX_STATE_INITIAL:{
4005 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4007 /* get fourcc/length, set neededbytes */
4008 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4010 gst_adapter_unmap (demux->adapter, 0);
4012 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4013 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4015 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4016 (_("This file is invalid and cannot be played.")),
4017 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4018 GST_FOURCC_ARGS (fourcc)));
4019 ret = GST_FLOW_ERROR;
4022 if (fourcc == FOURCC_mdat) {
4023 if (demux->n_streams > 0) {
4024 /* we have the headers, start playback */
4025 demux->state = QTDEMUX_STATE_MOVIE;
4026 demux->neededbytes = next_entry_size (demux);
4027 demux->mdatleft = size;
4029 /* Only post, event on pads is done after newsegment */
4030 qtdemux_post_global_tags (demux);
4033 /* no headers yet, try to get them */
4036 guint64 old, target;
4039 old = demux->offset;
4040 target = old + size;
4042 /* try to jump over the atom with a seek */
4043 res = qtdemux_seek_offset (demux, target);
4046 GST_DEBUG_OBJECT (demux, "seek success");
4047 /* remember the offset fo the first mdat so we can seek back to it
4048 * after we have the headers */
4049 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4050 demux->first_mdat = old;
4051 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4054 /* seek worked, continue reading */
4055 demux->offset = target;
4056 demux->neededbytes = 16;
4057 demux->state = QTDEMUX_STATE_INITIAL;
4059 /* seek failed, need to buffer */
4060 demux->offset = old;
4061 GST_DEBUG_OBJECT (demux, "seek failed");
4062 /* there may be multiple mdat (or alike) buffers */
4064 if (demux->mdatbuffer)
4065 bs = gst_buffer_get_size (demux->mdatbuffer);
4068 if (size + bs > 10 * (1 << 20))
4070 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4071 demux->neededbytes = size;
4072 if (!demux->mdatbuffer)
4073 demux->mdatoffset = demux->offset;
4076 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4077 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4078 (_("This file is invalid and cannot be played.")),
4079 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4080 GST_FOURCC_ARGS (fourcc), size));
4081 ret = GST_FLOW_ERROR;
4084 /* this means we already started buffering and still no moov header,
4085 * let's continue buffering everything till we get moov */
4086 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
4088 demux->neededbytes = size;
4089 demux->state = QTDEMUX_STATE_HEADER;
4093 case QTDEMUX_STATE_HEADER:{
4097 GST_DEBUG_OBJECT (demux, "In header");
4099 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4101 /* parse the header */
4102 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4104 if (fourcc == FOURCC_moov) {
4105 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4107 demux->got_moov = TRUE;
4109 /* prepare newsegment to send when streaming actually starts */
4110 if (!demux->pending_newsegment)
4111 demux->pending_newsegment = gst_event_new_segment (&demux->segment);
4113 qtdemux_parse_moov (demux, data, demux->neededbytes);
4114 qtdemux_node_dump (demux, demux->moov_node);
4115 qtdemux_parse_tree (demux);
4116 qtdemux_expose_streams (demux);
4118 g_node_destroy (demux->moov_node);
4119 demux->moov_node = NULL;
4120 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4121 } else if (fourcc == FOURCC_moof) {
4122 if (demux->got_moov && demux->fragmented) {
4123 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4124 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4125 demux->offset, NULL)) {
4126 gst_adapter_unmap (demux->adapter, 0);
4127 ret = GST_FLOW_ERROR;
4131 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4133 } else if (fourcc == FOURCC_ftyp) {
4134 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4135 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4136 } else if (fourcc == FOURCC_uuid) {
4137 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4138 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4140 GST_WARNING_OBJECT (demux,
4141 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4142 GST_FOURCC_ARGS (fourcc));
4143 /* Let's jump that one and go back to initial state */
4145 gst_adapter_unmap (demux->adapter, 0);
4148 if (demux->mdatbuffer && demux->n_streams) {
4149 /* the mdat was before the header */
4150 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4151 demux->n_streams, demux->mdatbuffer);
4152 /* restore our adapter/offset view of things with upstream;
4153 * put preceding buffered data ahead of current moov data.
4154 * This should also handle evil mdat, moov, mdat cases and alike */
4155 gst_adapter_clear (demux->adapter);
4156 demux->mdatbuffer = NULL;
4157 demux->offset = demux->mdatoffset;
4158 demux->neededbytes = next_entry_size (demux);
4159 demux->state = QTDEMUX_STATE_MOVIE;
4160 demux->mdatleft = gst_adapter_available (demux->adapter);
4162 /* Only post, event on pads is done after newsegment */
4163 qtdemux_post_global_tags (demux);
4166 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4167 gst_adapter_flush (demux->adapter, demux->neededbytes);
4169 if (demux->got_moov && demux->first_mdat != -1) {
4172 /* we need to seek back */
4173 res = qtdemux_seek_offset (demux, demux->first_mdat);
4175 demux->offset = demux->first_mdat;
4177 GST_DEBUG_OBJECT (demux, "Seek back failed");
4180 demux->offset += demux->neededbytes;
4182 demux->neededbytes = 16;
4183 demux->state = QTDEMUX_STATE_INITIAL;
4188 case QTDEMUX_STATE_BUFFER_MDAT:{
4192 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4194 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4195 gst_buffer_extract (buf, 0, fourcc, 4);
4196 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4197 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
4198 if (demux->mdatbuffer)
4199 demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
4201 demux->mdatbuffer = buf;
4202 demux->offset += demux->neededbytes;
4203 demux->neededbytes = 16;
4204 demux->state = QTDEMUX_STATE_INITIAL;
4205 gst_qtdemux_post_progress (demux, 1, 1);
4209 case QTDEMUX_STATE_MOVIE:{
4211 QtDemuxStream *stream = NULL;
4212 QtDemuxSample *sample;
4214 guint64 timestamp, duration, position;
4217 GST_DEBUG_OBJECT (demux,
4218 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4220 if (demux->fragmented) {
4221 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4223 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4224 /* if needed data starts within this atom,
4225 * then it should not exceed this atom */
4226 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4227 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4228 (_("This file is invalid and cannot be played.")),
4229 ("sample data crosses atom boundary"));
4230 ret = GST_FLOW_ERROR;
4233 demux->mdatleft -= demux->neededbytes;
4235 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4236 /* so we are dropping more than left in this atom */
4237 demux->todrop -= demux->mdatleft;
4238 demux->neededbytes -= demux->mdatleft;
4239 demux->mdatleft = 0;
4240 /* need to resume atom parsing so we do not miss any other pieces */
4241 demux->state = QTDEMUX_STATE_INITIAL;
4242 demux->neededbytes = 16;
4247 if (demux->todrop) {
4248 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4249 gst_adapter_flush (demux->adapter, demux->todrop);
4250 demux->neededbytes -= demux->todrop;
4251 demux->offset += demux->todrop;
4255 /* initial newsegment sent here after having added pads,
4256 * possible others in sink_event */
4257 if (G_UNLIKELY (demux->pending_newsegment)) {
4258 gst_qtdemux_push_event (demux, demux->pending_newsegment);
4259 demux->pending_newsegment = NULL;
4260 /* clear to send tags on all streams */
4261 for (i = 0; i < demux->n_streams; i++) {
4262 gst_qtdemux_push_tags (demux, demux->streams[i]);
4266 /* Figure out which stream this is packet belongs to */
4267 for (i = 0; i < demux->n_streams; i++) {
4268 stream = demux->streams[i];
4269 if (stream->sample_index >= stream->n_samples)
4271 GST_LOG_OBJECT (demux,
4272 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4273 " / size:%d)", i, stream->sample_index,
4274 stream->samples[stream->sample_index].offset,
4275 stream->samples[stream->sample_index].size);
4277 if (stream->samples[stream->sample_index].offset == demux->offset)
4281 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4282 goto unknown_stream;
4284 /* Put data in a buffer, set timestamps, caps, ... */
4285 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4286 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4287 GST_FOURCC_ARGS (stream->fourcc));
4289 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4291 sample = &stream->samples[stream->sample_index];
4293 position = QTSAMPLE_DTS (stream, sample);
4294 timestamp = QTSAMPLE_PTS (stream, sample);
4295 duration = QTSAMPLE_DUR_DTS (stream, sample, position);
4296 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4298 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4299 timestamp, duration, keyframe, position, demux->offset);
4302 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4304 stream->sample_index++;
4306 /* update current offset and figure out size of next buffer */
4307 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4308 demux->offset, demux->neededbytes);
4309 demux->offset += demux->neededbytes;
4310 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4313 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4314 if (demux->fragmented) {
4315 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4316 /* there may be more to follow, only finish this atom */
4317 demux->todrop = demux->mdatleft;
4318 demux->neededbytes = demux->todrop;
4330 /* when buffering movie data, at least show user something is happening */
4331 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4332 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4333 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4334 demux->neededbytes);
4337 gst_object_unref (demux);
4344 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4345 ret = GST_FLOW_ERROR;
4350 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4351 ret = GST_FLOW_UNEXPECTED;
4356 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4357 (NULL), ("qtdemuxer invalid state %d", demux->state));
4358 ret = GST_FLOW_ERROR;
4363 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4364 (NULL), ("no 'moov' atom within the first 10 MB"));
4365 ret = GST_FLOW_ERROR;
4371 qtdemux_sink_activate (GstPad * sinkpad)
4376 query = gst_query_new_scheduling ();
4378 if (!gst_pad_peer_query (sinkpad, query)) {
4379 gst_query_unref (query);
4383 gst_query_parse_scheduling (query, &pull_mode, NULL, NULL, NULL, NULL, NULL);
4384 gst_query_unref (query);
4389 GST_DEBUG_OBJECT (sinkpad, "activating pull");
4390 return gst_pad_activate_pull (sinkpad, TRUE);
4394 GST_DEBUG_OBJECT (sinkpad, "activating push");
4395 return gst_pad_activate_push (sinkpad, TRUE);
4400 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
4402 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
4405 demux->pullbased = TRUE;
4406 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4409 return gst_pad_stop_task (sinkpad);
4414 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
4416 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
4418 demux->pullbased = FALSE;
4425 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4427 return g_malloc (items * size);
4431 qtdemux_zfree (void *opaque, void *addr)
4437 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4443 z = g_new0 (z_stream, 1);
4444 z->zalloc = qtdemux_zalloc;
4445 z->zfree = qtdemux_zfree;
4448 z->next_in = z_buffer;
4449 z->avail_in = z_length;
4451 buffer = (guint8 *) g_malloc (length);
4452 ret = inflateInit (z);
4453 while (z->avail_in > 0) {
4454 if (z->avail_out == 0) {
4456 buffer = (guint8 *) g_realloc (buffer, length);
4457 z->next_out = buffer + z->total_out;
4458 z->avail_out = 1024;
4460 ret = inflate (z, Z_SYNC_FLUSH);
4464 if (ret != Z_STREAM_END) {
4465 g_warning ("inflate() returned %d", ret);
4471 #endif /* HAVE_ZLIB */
4474 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4478 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4480 /* counts as header data */
4481 qtdemux->header_size += length;
4483 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4484 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4486 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4492 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4493 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4494 if (dcom == NULL || cmvd == NULL)
4495 goto invalid_compression;
4497 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4500 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4501 guint uncompressed_length;
4502 guint compressed_length;
4505 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4506 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4507 GST_LOG ("length = %u", uncompressed_length);
4510 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4511 compressed_length, uncompressed_length);
4513 qtdemux->moov_node_compressed = qtdemux->moov_node;
4514 qtdemux->moov_node = g_node_new (buf);
4516 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4517 uncompressed_length);
4520 #endif /* HAVE_ZLIB */
4522 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4523 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
4530 invalid_compression:
4532 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
4538 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
4541 while (G_UNLIKELY (buf < end)) {
4545 if (G_UNLIKELY (buf + 4 > end)) {
4546 GST_LOG_OBJECT (qtdemux, "buffer overrun");
4549 len = QT_UINT32 (buf);
4550 if (G_UNLIKELY (len == 0)) {
4551 GST_LOG_OBJECT (qtdemux, "empty container");
4554 if (G_UNLIKELY (len < 8)) {
4555 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
4558 if (G_UNLIKELY (len > (end - buf))) {
4559 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
4560 (gint) (end - buf));
4564 child = g_node_new ((guint8 *) buf);
4565 g_node_append (node, child);
4566 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
4567 qtdemux_parse_node (qtdemux, child, buf, len);
4575 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
4578 int len = QT_UINT32 (xdxt->data);
4579 guint8 *buf = xdxt->data;
4580 guint8 *end = buf + len;
4583 /* skip size and type */
4591 size = QT_UINT32 (buf);
4592 type = QT_FOURCC (buf + 4);
4594 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
4596 if (buf + size > end || size <= 0)
4602 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
4603 GST_FOURCC_ARGS (type));
4607 buffer = gst_buffer_new_and_alloc (size);
4608 _gst_buffer_copy_into_mem (buffer, buf, 0, size);
4609 stream->buffers = g_slist_append (stream->buffers, buffer);
4610 GST_LOG_OBJECT (qtdemux, "parsing theora header");
4613 buffer = gst_buffer_new_and_alloc (size);
4614 _gst_buffer_copy_into_mem (buffer, buf, 0, size);
4615 stream->buffers = g_slist_append (stream->buffers, buffer);
4616 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
4619 buffer = gst_buffer_new_and_alloc (size);
4620 _gst_buffer_copy_into_mem (buffer, buf, 0, size);
4621 stream->buffers = g_slist_append (stream->buffers, buffer);
4622 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
4625 GST_WARNING_OBJECT (qtdemux,
4626 "unknown theora cookie %" GST_FOURCC_FORMAT,
4627 GST_FOURCC_ARGS (type));
4636 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
4640 guint32 node_length = 0;
4641 const QtNodeType *type;
4644 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
4646 if (G_UNLIKELY (length < 8))
4647 goto not_enough_data;
4649 node_length = QT_UINT32 (buffer);
4650 fourcc = QT_FOURCC (buffer + 4);
4652 /* ignore empty nodes */
4653 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
4656 type = qtdemux_type_get (fourcc);
4658 end = buffer + length;
4660 GST_LOG_OBJECT (qtdemux,
4661 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
4662 GST_FOURCC_ARGS (fourcc), node_length, type->name);
4664 if (node_length > length)
4665 goto broken_atom_size;
4667 if (type->flags & QT_FLAG_CONTAINER) {
4668 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
4673 if (node_length < 20) {
4674 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
4677 GST_DEBUG_OBJECT (qtdemux,
4678 "parsing stsd (sample table, sample description) atom");
4679 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
4689 /* also read alac (or whatever) in stead of mp4a in the following,
4690 * since a similar layout is used in other cases as well */
4691 if (fourcc == FOURCC_mp4a)
4696 /* There are two things we might encounter here: a true mp4a atom, and
4697 an mp4a entry in an stsd atom. The latter is what we're interested
4698 in, and it looks like an atom, but isn't really one. The true mp4a
4699 atom is short, so we detect it based on length here. */
4700 if (length < min_size) {
4701 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
4702 GST_FOURCC_ARGS (fourcc));
4706 /* 'version' here is the sound sample description version. Types 0 and
4707 1 are documented in the QTFF reference, but type 2 is not: it's
4708 described in Apple header files instead (struct SoundDescriptionV2
4710 version = QT_UINT16 (buffer + 16);
4712 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
4713 GST_FOURCC_ARGS (fourcc), version);
4715 /* parse any esds descriptors */
4727 GST_WARNING_OBJECT (qtdemux,
4728 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
4729 GST_FOURCC_ARGS (fourcc), version);
4734 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4746 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
4747 GST_FOURCC_ARGS (fourcc));
4748 version = QT_UINT32 (buffer + 16);
4749 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
4750 if (1 || version == 0x00000000) {
4751 buf = buffer + 0x32;
4753 /* FIXME Quicktime uses PASCAL string while
4754 * the iso format uses C strings. Check the file
4755 * type before attempting to parse the string here. */
4756 tlen = QT_UINT8 (buf);
4757 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
4759 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
4760 /* the string has a reserved space of 32 bytes so skip
4761 * the remaining 31 */
4763 buf += 4; /* and 4 bytes reserved */
4765 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
4767 qtdemux_parse_container (qtdemux, node, buf, end);
4773 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
4774 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
4779 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
4784 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
4785 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
4793 version = QT_UINT32 (buffer + 12);
4794 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
4801 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
4806 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4811 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
4815 if (!strcmp (type->name, "unknown"))
4816 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
4820 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
4821 GST_FOURCC_ARGS (fourcc));
4827 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4828 (_("This file is corrupt and cannot be played.")),
4829 ("Not enough data for an atom header, got only %u bytes", length));
4834 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4835 (_("This file is corrupt and cannot be played.")),
4836 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
4837 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
4844 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
4848 guint32 child_fourcc;
4850 for (child = g_node_first_child (node); child;
4851 child = g_node_next_sibling (child)) {
4852 buffer = (guint8 *) child->data;
4854 child_fourcc = QT_FOURCC (buffer + 4);
4856 if (G_UNLIKELY (child_fourcc == fourcc)) {
4864 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
4865 GstByteReader * parser)
4869 guint32 child_fourcc, child_len;
4871 for (child = g_node_first_child (node); child;
4872 child = g_node_next_sibling (child)) {
4873 buffer = (guint8 *) child->data;
4875 child_len = QT_UINT32 (buffer);
4876 child_fourcc = QT_FOURCC (buffer + 4);
4878 if (G_UNLIKELY (child_fourcc == fourcc)) {
4879 if (G_UNLIKELY (child_len < (4 + 4)))
4881 /* FIXME: must verify if atom length < parent atom length */
4882 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4890 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
4891 GstByteReader * parser)
4895 guint32 child_fourcc, child_len;
4897 for (child = g_node_next_sibling (node); child;
4898 child = g_node_next_sibling (child)) {
4899 buffer = (guint8 *) child->data;
4901 child_fourcc = QT_FOURCC (buffer + 4);
4903 if (child_fourcc == fourcc) {
4905 child_len = QT_UINT32 (buffer);
4906 if (G_UNLIKELY (child_len < (4 + 4)))
4908 /* FIXME: must verify if atom length < parent atom length */
4909 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4918 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
4920 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
4924 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
4925 QtDemuxStream * stream, GstTagList * list)
4927 /* consistent default for push based mode */
4928 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
4930 if (stream->subtype == FOURCC_vide) {
4931 gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
4934 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
4937 /* fps is calculated base on the duration of the first frames since
4938 * qt does not have a fixed framerate. */
4939 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
4944 stream->fps_n = stream->timescale;
4945 if (stream->min_duration == 0)
4948 stream->fps_d = stream->min_duration;
4953 gint depth, palette_count;
4954 const guint32 *palette_data = NULL;
4956 gst_caps_set_simple (stream->caps,
4957 "width", G_TYPE_INT, stream->width,
4958 "height", G_TYPE_INT, stream->height,
4959 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
4961 /* calculate pixel-aspect-ratio using display width and height */
4962 GST_DEBUG_OBJECT (qtdemux,
4963 "video size %dx%d, target display size %dx%d", stream->width,
4964 stream->height, stream->display_width, stream->display_height);
4966 if (stream->display_width > 0 && stream->display_height > 0 &&
4967 stream->width > 0 && stream->height > 0) {
4970 /* calculate the pixel aspect ratio using the display and pixel w/h */
4971 n = stream->display_width * stream->height;
4972 d = stream->display_height * stream->width;
4975 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
4976 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
4977 GST_TYPE_FRACTION, n, d, NULL);
4980 /* qt file might have pasp atom */
4981 if (stream->par_w > 0 && stream->par_h > 0) {
4982 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
4983 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
4984 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
4987 depth = stream->bits_per_sample;
4989 /* more than 32 bits means grayscale */
4990 gray = (depth > 32);
4991 /* low 32 bits specify the depth */
4994 /* different number of palette entries is determined by depth. */
4996 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
4997 palette_count = (1 << depth);
4999 switch (palette_count) {
5003 palette_data = ff_qt_default_palette_2;
5006 palette_data = ff_qt_default_palette_4;
5010 palette_data = ff_qt_grayscale_palette_16;
5012 palette_data = ff_qt_default_palette_16;
5016 palette_data = ff_qt_grayscale_palette_256;
5018 palette_data = ff_qt_default_palette_256;
5021 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5022 (_("The video in this file might not play correctly.")),
5023 ("unsupported palette depth %d", depth));
5029 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5030 * don't free any of the buffer data. */
5031 palette = _gst_buffer_new_wrapped ((gpointer) palette_data,
5032 palette_count, NULL);
5034 gst_caps_set_simple (stream->caps, "palette_data",
5035 GST_TYPE_BUFFER, palette, NULL);
5036 gst_buffer_unref (palette);
5037 } else if (palette_count != 0) {
5038 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5039 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5041 gst_object_unref (stream->pad);
5045 qtdemux->n_video_streams++;
5046 } else if (stream->subtype == FOURCC_soun) {
5047 gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
5050 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5053 gst_caps_set_simple (stream->caps,
5054 "rate", G_TYPE_INT, (int) stream->rate,
5055 "channels", G_TYPE_INT, stream->n_channels, NULL);
5057 qtdemux->n_audio_streams++;
5058 } else if (stream->subtype == FOURCC_strm) {
5059 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5060 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
5061 gchar *name = g_strdup_printf ("subtitle_%02d", qtdemux->n_sub_streams);
5064 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5066 qtdemux->n_sub_streams++;
5068 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5073 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5075 gst_pad_use_fixed_caps (stream->pad);
5076 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5077 gst_pad_set_query_type_function (stream->pad,
5078 gst_qtdemux_get_src_query_types);
5079 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5081 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5082 gst_pad_set_caps (stream->pad, stream->caps);
5084 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5085 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5086 gst_pad_set_active (stream->pad, TRUE);
5087 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5088 if (stream->pending_tags)
5089 gst_tag_list_free (stream->pending_tags);
5090 stream->pending_tags = list;
5091 /* global tags go on each pad anyway */
5092 stream->send_global_tags = TRUE;
5098 /* find next atom with @fourcc starting at @offset */
5099 static GstFlowReturn
5100 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5101 guint64 * length, guint32 fourcc)
5107 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5108 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5114 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5115 if (G_UNLIKELY (ret != GST_FLOW_OK))
5117 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
5119 ret = GST_FLOW_UNEXPECTED;
5120 gst_buffer_unref (buf);
5123 bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
5124 extract_initial_length_and_fourcc (bdata, 16, length, &lfourcc);
5125 gst_buffer_unmap (buf, bdata, bsize);
5126 gst_buffer_unref (buf);
5128 if (G_UNLIKELY (*length == 0)) {
5129 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5130 ret = GST_FLOW_ERROR;
5134 if (lfourcc == fourcc) {
5135 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5139 GST_LOG_OBJECT (qtdemux,
5140 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5141 GST_FOURCC_ARGS (fourcc), *offset);
5150 /* might simply have had last one */
5151 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5156 /* should only do something in pull mode */
5157 /* call with OBJECT lock */
5158 static GstFlowReturn
5159 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5161 guint64 length, offset;
5162 GstBuffer *buf = NULL;
5163 GstFlowReturn ret = GST_FLOW_OK;
5164 GstFlowReturn res = GST_FLOW_OK;
5168 offset = qtdemux->moof_offset;
5169 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5172 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5173 return GST_FLOW_UNEXPECTED;
5176 /* best not do pull etc with lock held */
5177 GST_OBJECT_UNLOCK (qtdemux);
5179 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5180 if (ret != GST_FLOW_OK)
5183 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5184 if (G_UNLIKELY (ret != GST_FLOW_OK))
5186 bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
5187 if (!qtdemux_parse_moof (qtdemux, bdata, bsize, offset, NULL)) {
5188 gst_buffer_unmap (buf, bdata, bsize);
5189 gst_buffer_unref (buf);
5194 gst_buffer_unmap (buf, bdata, bsize);
5195 gst_buffer_unref (buf);
5199 /* look for next moof */
5200 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5201 if (G_UNLIKELY (ret != GST_FLOW_OK))
5205 GST_OBJECT_LOCK (qtdemux);
5207 qtdemux->moof_offset = offset;
5213 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5215 res = GST_FLOW_ERROR;
5220 /* maybe upstream temporarily flushing */
5221 if (ret != GST_FLOW_WRONG_STATE) {
5222 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5225 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5226 /* resume at current position next time */
5233 /* initialise bytereaders for stbl sub-atoms */
5235 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5237 stream->stbl_index = -1; /* no samples have yet been parsed */
5239 /* time-to-sample atom */
5240 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5243 /* copy atom data into a new buffer for later use */
5244 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5246 /* skip version + flags */
5247 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5248 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5250 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5252 /* make sure there's enough data */
5253 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 2 * 4))
5256 /* sync sample atom */
5257 stream->stps_present = FALSE;
5258 if ((stream->stss_present =
5259 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5260 &stream->stss) ? TRUE : FALSE) == TRUE) {
5261 /* copy atom data into a new buffer for later use */
5262 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5264 /* skip version + flags */
5265 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5266 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5269 if (stream->n_sample_syncs) {
5270 /* make sure there's enough data */
5271 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5275 /* partial sync sample atom */
5276 if ((stream->stps_present =
5277 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5278 &stream->stps) ? TRUE : FALSE) == TRUE) {
5279 /* copy atom data into a new buffer for later use */
5280 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5282 /* skip version + flags */
5283 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5284 !gst_byte_reader_get_uint32_be (&stream->stps,
5285 &stream->n_sample_partial_syncs))
5288 /* if there are no entries, the stss table contains the real
5290 if (stream->n_sample_partial_syncs) {
5291 /* make sure there's enough data */
5292 if (!qt_atom_parser_has_chunks (&stream->stps,
5293 stream->n_sample_partial_syncs, 4))
5300 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5303 /* copy atom data into a new buffer for later use */
5304 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5306 /* skip version + flags */
5307 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5308 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5311 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5314 if (!stream->n_samples)
5317 /* sample-to-chunk atom */
5318 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5321 /* copy atom data into a new buffer for later use */
5322 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5324 /* skip version + flags */
5325 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5326 !gst_byte_reader_get_uint32_be (&stream->stsc,
5327 &stream->n_samples_per_chunk))
5330 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5331 stream->n_samples_per_chunk);
5333 /* make sure there's enough data */
5334 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5340 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5341 stream->co_size = sizeof (guint32);
5342 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5344 stream->co_size = sizeof (guint64);
5348 /* copy atom data into a new buffer for later use */
5349 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5351 /* skip version + flags */
5352 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5355 /* chunks_are_chunks == 0 means treat chunks as samples */
5356 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5357 if (stream->chunks_are_chunks) {
5358 /* skip number of entries */
5359 if (!gst_byte_reader_skip (&stream->stco, 4))
5362 /* make sure there are enough data in the stsz atom */
5363 if (!stream->sample_size) {
5364 /* different sizes for each sample */
5365 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5369 /* treat chunks as samples */
5370 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5374 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5375 stream->n_samples, (guint) sizeof (QtDemuxSample),
5376 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5378 if (stream->n_samples >=
5379 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5380 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5381 "be larger than %uMB (broken file?)", stream->n_samples,
5382 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5386 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5387 if (!stream->samples) {
5388 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5394 /* composition time-to-sample */
5395 if ((stream->ctts_present =
5396 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5397 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5398 /* copy atom data into a new buffer for later use */
5399 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5401 /* skip version + flags */
5402 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5403 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5404 &stream->n_composition_times))
5407 /* make sure there's enough data */
5408 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5417 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5418 (_("This file is corrupt and cannot be played.")), (NULL));
5423 gst_qtdemux_stbl_free (stream);
5424 if (!qtdemux->fragmented) {
5425 /* not quite good */
5426 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5429 /* may pick up samples elsewhere */
5435 /* collect samples from the next sample to be parsed up to sample @n for @stream
5436 * by reading the info from @stbl
5438 * This code can be executed from both the streaming thread and the seeking
5439 * thread so it takes the object lock to protect itself
5442 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
5445 QtDemuxSample *samples, *first, *cur, *last;
5446 guint32 n_samples_per_chunk;
5449 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
5450 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
5451 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
5453 n_samples = stream->n_samples;
5456 goto out_of_samples;
5458 GST_OBJECT_LOCK (qtdemux);
5459 if (n <= stream->stbl_index)
5460 goto already_parsed;
5462 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
5464 if (!stream->stsz.data) {
5465 /* so we already parsed and passed all the moov samples;
5466 * onto fragmented ones */
5467 g_assert (qtdemux->fragmented);
5471 /* pointer to the sample table */
5472 samples = stream->samples;
5474 /* starts from -1, moves to the next sample index to parse */
5475 stream->stbl_index++;
5477 /* keep track of the first and last sample to fill */
5478 first = &samples[stream->stbl_index];
5481 if (stream->chunks_are_chunks) {
5482 /* set the sample sizes */
5483 if (stream->sample_size == 0) {
5484 /* different sizes for each sample */
5485 for (cur = first; cur <= last; cur++) {
5486 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
5487 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
5488 (guint) (cur - samples), cur->size);
5491 /* samples have the same size */
5492 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
5493 for (cur = first; cur <= last; cur++)
5494 cur->size = stream->sample_size;
5498 n_samples_per_chunk = stream->n_samples_per_chunk;
5501 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
5504 if (stream->stsc_chunk_index >= stream->last_chunk
5505 || stream->stsc_chunk_index < stream->first_chunk) {
5506 stream->first_chunk =
5507 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5508 stream->samples_per_chunk =
5509 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5510 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
5512 /* chunk numbers are counted from 1 it seems */
5513 if (G_UNLIKELY (stream->first_chunk == 0))
5516 --stream->first_chunk;
5518 /* the last chunk of each entry is calculated by taking the first chunk
5519 * of the next entry; except if there is no next, where we fake it with
5521 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
5522 stream->last_chunk = G_MAXUINT32;
5524 stream->last_chunk =
5525 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
5526 if (G_UNLIKELY (stream->last_chunk == 0))
5529 --stream->last_chunk;
5532 GST_LOG_OBJECT (qtdemux,
5533 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
5534 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
5536 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
5539 if (stream->last_chunk != G_MAXUINT32) {
5540 if (!qt_atom_parser_peek_sub (&stream->stco,
5541 stream->first_chunk * stream->co_size,
5542 (stream->last_chunk - stream->first_chunk) * stream->co_size,
5547 stream->co_chunk = stream->stco;
5548 if (!gst_byte_reader_skip (&stream->co_chunk,
5549 stream->first_chunk * stream->co_size))
5553 stream->stsc_chunk_index = stream->first_chunk;
5556 last_chunk = stream->last_chunk;
5558 if (stream->chunks_are_chunks) {
5559 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5560 guint32 samples_per_chunk;
5561 guint64 chunk_offset;
5563 if (!stream->stsc_sample_index
5564 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
5565 &stream->chunk_offset))
5568 samples_per_chunk = stream->samples_per_chunk;
5569 chunk_offset = stream->chunk_offset;
5571 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
5572 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
5573 G_GUINT64_FORMAT, (guint) (cur - samples), stream->chunk_offset);
5575 cur->offset = chunk_offset;
5576 chunk_offset += cur->size;
5579 if (G_UNLIKELY (cur > last)) {
5581 stream->stsc_sample_index = k + 1;
5582 stream->chunk_offset = chunk_offset;
5583 stream->stsc_chunk_index = j;
5587 stream->stsc_sample_index = 0;
5589 stream->stsc_chunk_index = j;
5591 cur = &samples[stream->stsc_chunk_index];
5593 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5596 stream->stsc_chunk_index = j;
5601 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
5604 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
5605 "%" G_GUINT64_FORMAT, j, cur->offset);
5607 if (stream->samples_per_frame * stream->bytes_per_frame) {
5609 (stream->samples_per_chunk * stream->n_channels) /
5610 stream->samples_per_frame * stream->bytes_per_frame;
5612 cur->size = stream->samples_per_chunk;
5615 GST_DEBUG_OBJECT (qtdemux,
5616 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
5617 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
5618 GST_SECOND, stream->timescale)), cur->size);
5620 cur->timestamp = stream->stco_sample_index;
5621 cur->duration = stream->samples_per_chunk;
5622 cur->keyframe = TRUE;
5625 stream->stco_sample_index += stream->samples_per_chunk;
5627 stream->stsc_chunk_index = j;
5629 stream->stsc_index++;
5632 if (!stream->chunks_are_chunks)
5636 guint32 n_sample_times;
5638 n_sample_times = stream->n_sample_times;
5641 for (i = stream->stts_index; i < n_sample_times; i++) {
5642 guint32 stts_samples;
5643 guint32 stts_duration;
5646 if (stream->stts_sample_index >= stream->stts_samples
5647 || !stream->stts_sample_index) {
5649 stream->stts_samples =
5650 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5651 stream->stts_duration =
5652 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5654 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
5655 i, stream->stts_samples, stream->stts_duration);
5657 stream->stts_sample_index = 0;
5660 stts_samples = stream->stts_samples;
5661 stts_duration = stream->stts_duration;
5662 stts_time = stream->stts_time;
5664 for (j = stream->stts_sample_index; j < stts_samples; j++) {
5665 GST_DEBUG_OBJECT (qtdemux,
5666 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
5667 (guint) (cur - samples), j,
5668 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
5669 stream->timescale)));
5671 cur->timestamp = stts_time;
5672 cur->duration = stts_duration;
5674 stts_time += stts_duration;
5677 if (G_UNLIKELY (cur > last)) {
5679 stream->stts_time = stts_time;
5680 stream->stts_sample_index = j + 1;
5684 stream->stts_sample_index = 0;
5685 stream->stts_time = stts_time;
5686 stream->stts_index++;
5688 /* fill up empty timestamps with the last timestamp, this can happen when
5689 * the last samples do not decode and so we don't have timestamps for them.
5690 * We however look at the last timestamp to estimate the track length so we
5691 * need something in here. */
5692 for (; cur < last; cur++) {
5693 GST_DEBUG_OBJECT (qtdemux,
5694 "fill sample %d: timestamp %" GST_TIME_FORMAT,
5695 (guint) (cur - samples),
5696 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
5697 stream->timescale)));
5698 cur->timestamp = stream->stts_time;
5704 /* sample sync, can be NULL */
5705 if (stream->stss_present == TRUE) {
5706 guint32 n_sample_syncs;
5708 n_sample_syncs = stream->n_sample_syncs;
5710 if (!n_sample_syncs) {
5711 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
5712 stream->all_keyframe = TRUE;
5714 for (i = stream->stss_index; i < n_sample_syncs; i++) {
5715 /* note that the first sample is index 1, not 0 */
5718 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
5720 if (G_LIKELY (index > 0 && index <= n_samples)) {
5722 samples[index].keyframe = TRUE;
5723 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5724 /* and exit if we have enough samples */
5725 if (G_UNLIKELY (index >= n)) {
5732 stream->stss_index = i;
5735 /* stps marks partial sync frames like open GOP I-Frames */
5736 if (stream->stps_present == TRUE) {
5737 guint32 n_sample_partial_syncs;
5739 n_sample_partial_syncs = stream->n_sample_partial_syncs;
5741 /* if there are no entries, the stss table contains the real
5743 if (n_sample_partial_syncs) {
5744 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
5745 /* note that the first sample is index 1, not 0 */
5748 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
5750 if (G_LIKELY (index > 0 && index <= n_samples)) {
5752 samples[index].keyframe = TRUE;
5753 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5754 /* and exit if we have enough samples */
5755 if (G_UNLIKELY (index >= n)) {
5762 stream->stps_index = i;
5766 /* no stss, all samples are keyframes */
5767 stream->all_keyframe = TRUE;
5768 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
5773 /* composition time to sample */
5774 if (stream->ctts_present == TRUE) {
5775 guint32 n_composition_times;
5777 gint32 ctts_soffset;
5779 /* Fill in the pts_offsets */
5781 n_composition_times = stream->n_composition_times;
5783 for (i = stream->ctts_index; i < n_composition_times; i++) {
5784 if (stream->ctts_sample_index >= stream->ctts_count
5785 || !stream->ctts_sample_index) {
5786 stream->ctts_count =
5787 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
5788 stream->ctts_soffset =
5789 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
5790 stream->ctts_sample_index = 0;
5793 ctts_count = stream->ctts_count;
5794 ctts_soffset = stream->ctts_soffset;
5796 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
5797 cur->pts_offset = ctts_soffset;
5800 if (G_UNLIKELY (cur > last)) {
5802 stream->ctts_sample_index = j + 1;
5806 stream->ctts_sample_index = 0;
5807 stream->ctts_index++;
5811 stream->stbl_index = n;
5812 /* if index has been completely parsed, free data that is no-longer needed */
5813 if (n + 1 == stream->n_samples) {
5814 gst_qtdemux_stbl_free (stream);
5815 GST_DEBUG_OBJECT (qtdemux,
5816 "parsed all available samples; checking for more");
5817 while (n + 1 == stream->n_samples)
5818 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
5821 GST_OBJECT_UNLOCK (qtdemux);
5828 GST_LOG_OBJECT (qtdemux,
5829 "Tried to parse up to sample %u but this sample has already been parsed",
5831 /* if fragmented, there may be more */
5832 if (qtdemux->fragmented && n == stream->stbl_index)
5834 GST_OBJECT_UNLOCK (qtdemux);
5840 GST_LOG_OBJECT (qtdemux,
5841 "Tried to parse up to sample %u but there are only %u samples", n + 1,
5843 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5844 (_("This file is corrupt and cannot be played.")), (NULL));
5849 GST_OBJECT_UNLOCK (qtdemux);
5850 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5851 (_("This file is corrupt and cannot be played.")), (NULL));
5856 /* collect all segment info for @stream.
5859 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
5864 /* parse and prepare segment info from the edit list */
5865 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
5866 stream->n_segments = 0;
5867 stream->segments = NULL;
5868 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
5872 guint64 time, stime;
5875 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
5876 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
5879 buffer = elst->data;
5881 n_segments = QT_UINT32 (buffer + 12);
5883 /* we might allocate a bit too much, at least allocate 1 segment */
5884 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
5886 /* segments always start from 0 */
5890 for (i = 0; i < n_segments; i++) {
5893 QtDemuxSegment *segment;
5896 media_time = QT_UINT32 (buffer + 20 + i * 12);
5898 /* -1 media time is an empty segment, just ignore it */
5899 if (media_time == G_MAXUINT32)
5902 duration = QT_UINT32 (buffer + 16 + i * 12);
5904 segment = &stream->segments[count++];
5906 /* time and duration expressed in global timescale */
5907 segment->time = stime;
5908 /* add non scaled values so we don't cause roundoff errors */
5910 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
5911 segment->stop_time = stime;
5912 segment->duration = stime - segment->time;
5913 /* media_time expressed in stream timescale */
5914 segment->media_start =
5915 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
5916 segment->media_stop = segment->media_start + segment->duration;
5917 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
5919 if (rate_int <= 1) {
5920 /* 0 is not allowed, some programs write 1 instead of the floating point
5922 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
5926 segment->rate = rate_int / 65536.0;
5929 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
5930 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
5931 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
5932 GST_TIME_ARGS (segment->duration),
5933 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
5935 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
5936 stream->n_segments = count;
5940 /* push based does not handle segments, so act accordingly here,
5941 * and warn if applicable */
5942 if (!qtdemux->pullbased) {
5943 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
5944 /* remove and use default one below, we stream like it anyway */
5945 g_free (stream->segments);
5946 stream->segments = NULL;
5947 stream->n_segments = 0;
5950 /* no segments, create one to play the complete trak */
5951 if (stream->n_segments == 0) {
5952 GstClockTime stream_duration =
5953 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
5955 if (stream->segments == NULL)
5956 stream->segments = g_new (QtDemuxSegment, 1);
5958 /* represent unknown our way */
5959 if (stream_duration == 0)
5960 stream_duration = -1;
5962 stream->segments[0].time = 0;
5963 stream->segments[0].stop_time = stream_duration;
5964 stream->segments[0].duration = stream_duration;
5965 stream->segments[0].media_start = 0;
5966 stream->segments[0].media_stop = stream_duration;
5967 stream->segments[0].rate = 1.0;
5969 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
5970 GST_TIME_ARGS (stream_duration));
5971 stream->n_segments = 1;
5973 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
5979 * Parses the stsd atom of a svq3 trak looking for
5980 * the SMI and gama atoms.
5983 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
5984 guint8 ** gamma, GstBuffer ** seqh)
5986 guint8 *_gamma = NULL;
5987 GstBuffer *_seqh = NULL;
5988 guint8 *stsd_data = stsd->data;
5989 guint32 length = QT_UINT32 (stsd_data);
5993 GST_WARNING_OBJECT (qtdemux, "stsd too short");
5999 version = QT_UINT16 (stsd_data);
6004 while (length > 8) {
6005 guint32 fourcc, size;
6007 size = QT_UINT32 (stsd_data);
6008 fourcc = QT_FOURCC (stsd_data + 4);
6009 data = stsd_data + 8;
6016 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6017 " for gama atom, expected 12", size);
6022 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6024 if (_seqh != NULL) {
6025 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6026 " found, ignoring");
6028 seqh_size = QT_UINT32 (data + 4);
6029 if (seqh_size > 0) {
6030 _seqh = gst_buffer_new_and_alloc (seqh_size);
6031 _gst_buffer_copy_into_mem (_seqh, data + 8, 0, seqh_size);
6038 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6039 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6043 if (size <= length) {
6049 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6052 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6053 G_GUINT16_FORMAT, version);
6064 gst_buffer_unref (_seqh);
6069 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6076 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6077 * atom that might contain a 'data' atom with the rtsp uri.
6078 * This case was reported in bug #597497, some info about
6079 * the hndl atom can be found in TN1195
6081 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6082 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6085 guint32 dref_num_entries = 0;
6086 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6087 gst_byte_reader_skip (&dref, 4) &&
6088 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6091 /* search dref entries for hndl atom */
6092 for (i = 0; i < dref_num_entries; i++) {
6093 guint32 size = 0, type;
6094 guint8 string_len = 0;
6095 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6096 qt_atom_parser_get_fourcc (&dref, &type)) {
6097 if (type == FOURCC_hndl) {
6098 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6100 /* skip data reference handle bytes and the
6101 * following pascal string and some extra 4
6102 * bytes I have no idea what are */
6103 if (!gst_byte_reader_skip (&dref, 4) ||
6104 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6105 !gst_byte_reader_skip (&dref, string_len + 4)) {
6106 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6110 /* iterate over the atoms to find the data atom */
6111 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6115 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6116 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6117 if (atom_type == FOURCC_data) {
6118 const guint8 *uri_aux = NULL;
6120 /* found the data atom that might contain the rtsp uri */
6121 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6122 "hndl atom, interpreting it as an URI");
6123 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6125 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6126 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6128 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6129 "didn't contain a rtsp address");
6131 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6136 /* skipping to the next entry */
6137 gst_byte_reader_skip (&dref, atom_size - 8);
6139 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6146 /* skip to the next entry */
6147 gst_byte_reader_skip (&dref, size - 8);
6149 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6152 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6159 less_than (gconstpointer a, gconstpointer b)
6161 const guint32 *av = a, *bv = b;
6166 #define AMR_NB_ALL_MODES 0x81ff
6167 #define AMR_WB_ALL_MODES 0x83ff
6169 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
6171 /* The 'damr' atom is of the form:
6173 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
6174 * 32 b 8 b 16 b 8 b 8 b
6176 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
6177 * represents the highest mode used in the stream (and thus the maximum
6178 * bitrate), with a couple of special cases as seen below.
6181 /* Map of frame type ID -> bitrate */
6182 static const guint nb_bitrates[] = {
6183 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
6185 static const guint wb_bitrates[] = {
6186 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
6189 gsize size, max_mode;
6192 data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
6195 GST_DEBUG ("Atom should have size 0x11, not %u", size);
6199 if (QT_FOURCC (data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
6200 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
6201 GST_FOURCC_ARGS (QT_UINT32 (data + 4)));
6205 mode_set = QT_UINT16 (data + 13);
6207 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
6208 max_mode = 7 + (wb ? 1 : 0);
6210 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
6211 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
6213 if (max_mode == -1) {
6214 GST_DEBUG ("No mode indication was found (mode set) = %x",
6219 gst_buffer_unmap (buf, data, size);
6220 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
6223 gst_buffer_unmap (buf, data, size);
6228 * With each track we associate a new QtDemuxStream that contains all the info
6230 * traks that do not decode to something (like strm traks) will not have a pad.
6233 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6248 QtDemuxStream *stream;
6249 GstTagList *list = NULL;
6250 gchar *codec = NULL;
6251 const guint8 *stsd_data;
6252 guint16 lang_code; /* quicktime lang code or packed iso code */
6254 guint32 tkhd_flags = 0;
6255 guint8 tkhd_version = 0;
6257 guint value_size, len;
6259 stream = g_new0 (QtDemuxStream, 1);
6260 /* new streams always need a discont */
6261 stream->discont = TRUE;
6262 /* we enable clipping for raw audio/video streams */
6263 stream->need_clip = FALSE;
6264 stream->need_process = FALSE;
6265 stream->segment_index = -1;
6266 stream->time_position = 0;
6267 stream->sample_index = -1;
6268 stream->last_ret = GST_FLOW_OK;
6270 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6271 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6272 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6275 /* pick between 64 or 32 bits */
6276 value_size = tkhd_version == 1 ? 8 : 4;
6277 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6278 !gst_byte_reader_get_uint32_be (&tkhd, &stream->track_id))
6281 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6282 tkhd_version, tkhd_flags, stream->track_id);
6284 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6287 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6288 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6289 if (qtdemux->major_brand != FOURCC_mjp2 ||
6290 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6294 len = QT_UINT32 ((guint8 *) mdhd->data);
6295 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6296 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6297 if (version == 0x01000000) {
6300 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6301 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6302 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6306 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6307 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6308 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6311 if (lang_code < 0x800) {
6312 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6314 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6315 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6316 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6317 stream->lang_id[3] = 0;
6320 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6322 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6324 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6325 lang_code, stream->lang_id);
6327 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6330 /* fragmented files may have bogus duration in moov */
6331 if (!qtdemux->fragmented &&
6332 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6333 guint64 tdur1, tdur2;
6335 /* don't overflow */
6336 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6337 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6340 * some of those trailers, nowadays, have prologue images that are
6341 * themselves vide tracks as well. I haven't really found a way to
6342 * identify those yet, except for just looking at their duration. */
6343 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6344 GST_WARNING_OBJECT (qtdemux,
6345 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6346 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6347 "found, assuming preview image or something; skipping track",
6348 stream->duration, stream->timescale, qtdemux->duration,
6349 qtdemux->timescale);
6355 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6358 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6359 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6361 len = QT_UINT32 ((guint8 *) hdlr->data);
6363 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6364 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6365 GST_FOURCC_ARGS (stream->subtype));
6367 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6370 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6374 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6376 stsd_data = (const guint8 *) stsd->data;
6378 /* stsd should at least have one entry */
6379 len = QT_UINT32 (stsd_data);
6383 /* and that entry should fit within stsd */
6384 len = QT_UINT32 (stsd_data + 16);
6385 if (len > QT_UINT32 (stsd_data) + 16)
6387 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6389 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6390 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6391 GST_FOURCC_ARGS (stream->fourcc));
6393 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6394 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6395 goto error_encrypted;
6397 if (stream->subtype == FOURCC_vide) {
6398 guint32 w = 0, h = 0;
6400 stream->sampled = TRUE;
6402 /* version 1 uses some 64-bit ints */
6403 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6404 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6405 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6408 stream->display_width = w >> 16;
6409 stream->display_height = h >> 16;
6415 stream->width = QT_UINT16 (stsd_data + offset + 32);
6416 stream->height = QT_UINT16 (stsd_data + offset + 34);
6417 stream->fps_n = 0; /* this is filled in later */
6418 stream->fps_d = 0; /* this is filled in later */
6419 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6420 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6422 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6423 QT_UINT16 (stsd_data + offset + 48));
6426 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6428 list = gst_tag_list_new ();
6429 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6430 GST_TAG_VIDEO_CODEC, codec, NULL);
6437 /* pick 'the' stsd child */
6438 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
6440 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
6441 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
6445 const guint8 *pasp_data = (const guint8 *) pasp->data;
6447 stream->par_w = QT_UINT32 (pasp_data + 8);
6448 stream->par_h = QT_UINT32 (pasp_data + 12);
6455 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
6460 gint len = QT_UINT32 (stsd_data) - 0x66;
6461 const guint8 *avc_data = stsd_data + 0x66;
6464 while (len >= 0x8) {
6467 if (QT_UINT32 (avc_data) <= len)
6468 size = QT_UINT32 (avc_data) - 0x8;
6473 /* No real data, so break out */
6476 switch (QT_FOURCC (avc_data + 0x4)) {
6479 /* parse, if found */
6482 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
6484 /* First 4 bytes are the length of the atom, the next 4 bytes
6485 * are the fourcc, the next 1 byte is the version, and the
6486 * subsequent bytes are sequence parameter set like data. */
6487 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
6488 avc_data + 8 + 1, size - 1);
6490 buf = gst_buffer_new_and_alloc (size);
6491 _gst_buffer_copy_into_mem (buf, avc_data + 0x8, 0, size);
6492 gst_caps_set_simple (stream->caps,
6493 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6494 gst_buffer_unref (buf);
6500 guint avg_bitrate, max_bitrate;
6502 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
6506 max_bitrate = QT_UINT32 (avc_data + 0xc);
6507 avg_bitrate = QT_UINT32 (avc_data + 0x10);
6509 if (!max_bitrate && !avg_bitrate)
6512 /* Some muxers seem to swap the average and maximum bitrates
6513 * (I'm looking at you, YouTube), so we swap for sanity. */
6514 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
6515 guint temp = avg_bitrate;
6517 avg_bitrate = max_bitrate;
6522 list = gst_tag_list_new ();
6524 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6525 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6526 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6528 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6529 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6530 GST_TAG_BITRATE, avg_bitrate, NULL);
6541 avc_data += size + 8;
6553 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
6554 GST_FOURCC_ARGS (fourcc));
6556 /* codec data might be in glbl extension atom */
6558 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
6564 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
6566 len = QT_UINT32 (data);
6569 buf = gst_buffer_new_and_alloc (len);
6570 _gst_buffer_copy_into_mem (buf, data + 8, 0, len);
6571 gst_caps_set_simple (stream->caps,
6572 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6573 gst_buffer_unref (buf);
6580 /* see annex I of the jpeg2000 spec */
6581 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
6583 const gchar *colorspace;
6585 guint32 ncomp_map = 0;
6586 gint32 *comp_map = NULL;
6587 guint32 nchan_def = 0;
6588 gint32 *chan_def = NULL;
6590 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
6591 /* some required atoms */
6592 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
6595 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
6599 /* number of components; redundant with info in codestream, but useful
6601 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
6602 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
6604 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
6606 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
6609 GST_DEBUG_OBJECT (qtdemux, "found colr");
6610 /* extract colour space info */
6611 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
6612 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
6614 colorspace = "sRGB";
6617 colorspace = "GRAY";
6620 colorspace = "sYUV";
6628 /* colr is required, and only values 16, 17, and 18 are specified,
6629 so error if we have no colorspace */
6632 /* extract component mapping */
6633 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
6635 guint32 cmap_len = 0;
6637 cmap_len = QT_UINT32 (cmap->data);
6638 if (cmap_len >= 8) {
6639 /* normal box, subtract off header */
6641 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
6642 if (cmap_len % 4 == 0) {
6643 ncomp_map = (cmap_len / 4);
6644 comp_map = g_new0 (gint32, ncomp_map);
6645 for (i = 0; i < ncomp_map; i++) {
6648 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
6649 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
6650 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
6651 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
6656 /* extract channel definitions */
6657 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
6659 guint32 cdef_len = 0;
6661 cdef_len = QT_UINT32 (cdef->data);
6662 if (cdef_len >= 10) {
6663 /* normal box, subtract off header and len */
6665 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
6666 if (cdef_len % 6 == 0) {
6667 nchan_def = (cdef_len / 6);
6668 chan_def = g_new0 (gint32, nchan_def);
6669 for (i = 0; i < nchan_def; i++)
6671 for (i = 0; i < nchan_def; i++) {
6672 guint16 cn, typ, asoc;
6673 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
6674 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
6675 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
6676 if (cn < nchan_def) {
6679 chan_def[cn] = asoc;
6682 chan_def[cn] = 0; /* alpha */
6685 chan_def[cn] = -typ;
6693 gst_caps_set_simple (stream->caps,
6694 "num-components", G_TYPE_INT, ncomp, NULL);
6695 gst_caps_set_simple (stream->caps,
6696 "colorspace", G_TYPE_STRING, colorspace, NULL);
6699 GValue arr = { 0, };
6700 GValue elt = { 0, };
6702 g_value_init (&arr, GST_TYPE_ARRAY);
6703 g_value_init (&elt, G_TYPE_INT);
6704 for (i = 0; i < ncomp_map; i++) {
6705 g_value_set_int (&elt, comp_map[i]);
6706 gst_value_array_append_value (&arr, &elt);
6708 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6709 "component-map", &arr);
6710 g_value_unset (&elt);
6711 g_value_unset (&arr);
6716 GValue arr = { 0, };
6717 GValue elt = { 0, };
6719 g_value_init (&arr, GST_TYPE_ARRAY);
6720 g_value_init (&elt, G_TYPE_INT);
6721 for (i = 0; i < nchan_def; i++) {
6722 g_value_set_int (&elt, chan_def[i]);
6723 gst_value_array_append_value (&arr, &elt);
6725 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6726 "channel-definitions", &arr);
6727 g_value_unset (&elt);
6728 g_value_unset (&arr);
6732 /* some optional atoms */
6733 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
6734 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
6736 /* indicate possible fields in caps */
6738 data = (guint8 *) field->data + 8;
6740 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
6741 (gint) * data, NULL);
6743 /* add codec_data if provided */
6748 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
6749 data = prefix->data;
6750 len = QT_UINT32 (data);
6753 buf = gst_buffer_new_and_alloc (len);
6754 _gst_buffer_copy_into_mem (buf, data + 8, 0, len);
6755 gst_caps_set_simple (stream->caps,
6756 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6757 gst_buffer_unref (buf);
6766 GstBuffer *seqh = NULL;
6767 guint8 *gamma_data = NULL;
6768 gint len = QT_UINT32 (stsd_data);
6770 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
6772 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
6773 QT_FP32 (gamma_data), NULL);
6776 /* sorry for the bad name, but we don't know what this is, other
6777 * than its own fourcc */
6778 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
6782 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
6783 buf = gst_buffer_new_and_alloc (len);
6784 _gst_buffer_copy_into_mem (buf, stsd_data, 0, len);
6785 gst_caps_set_simple (stream->caps,
6786 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6787 gst_buffer_unref (buf);
6792 gst_caps_set_simple (stream->caps,
6793 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
6800 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
6801 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
6805 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
6809 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
6810 /* collect the headers and store them in a stream list so that we can
6811 * send them out first */
6812 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
6822 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
6823 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
6826 ovc1_data = ovc1->data;
6827 ovc1_len = QT_UINT32 (ovc1_data);
6828 if (ovc1_len <= 198) {
6829 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
6832 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
6833 _gst_buffer_copy_into_mem (buf, ovc1_data + 198, 0, ovc1_len - 198);
6834 gst_caps_set_simple (stream->caps,
6835 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6836 gst_buffer_unref (buf);
6844 GST_INFO_OBJECT (qtdemux,
6845 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
6846 GST_FOURCC_ARGS (fourcc), stream->caps);
6848 } else if (stream->subtype == FOURCC_soun) {
6849 int version, samplesize;
6850 guint16 compression_id;
6851 gboolean amrwb = FALSE;
6857 version = QT_UINT32 (stsd_data + offset);
6858 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
6859 samplesize = QT_UINT16 (stsd_data + offset + 10);
6860 compression_id = QT_UINT16 (stsd_data + offset + 12);
6861 stream->rate = QT_FP32 (stsd_data + offset + 16);
6863 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
6864 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
6865 QT_UINT32 (stsd_data + offset + 4));
6866 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
6867 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
6868 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
6869 GST_LOG_OBJECT (qtdemux, "packet size: %d",
6870 QT_UINT16 (stsd_data + offset + 14));
6871 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
6873 if (compression_id == 0xfffe)
6874 stream->sampled = TRUE;
6876 /* first assume uncompressed audio */
6877 stream->bytes_per_sample = samplesize / 8;
6878 stream->samples_per_frame = stream->n_channels;
6879 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
6880 stream->samples_per_packet = stream->samples_per_frame;
6881 stream->bytes_per_packet = stream->bytes_per_sample;
6885 /* Yes, these have to be hard-coded */
6888 stream->samples_per_packet = 6;
6889 stream->bytes_per_packet = 1;
6890 stream->bytes_per_frame = 1 * stream->n_channels;
6891 stream->bytes_per_sample = 1;
6892 stream->samples_per_frame = 6 * stream->n_channels;
6897 stream->samples_per_packet = 3;
6898 stream->bytes_per_packet = 1;
6899 stream->bytes_per_frame = 1 * stream->n_channels;
6900 stream->bytes_per_sample = 1;
6901 stream->samples_per_frame = 3 * stream->n_channels;
6906 stream->samples_per_packet = 64;
6907 stream->bytes_per_packet = 34;
6908 stream->bytes_per_frame = 34 * stream->n_channels;
6909 stream->bytes_per_sample = 2;
6910 stream->samples_per_frame = 64 * stream->n_channels;
6916 stream->samples_per_packet = 1;
6917 stream->bytes_per_packet = 1;
6918 stream->bytes_per_frame = 1 * stream->n_channels;
6919 stream->bytes_per_sample = 1;
6920 stream->samples_per_frame = 1 * stream->n_channels;
6925 stream->samples_per_packet = 160;
6926 stream->bytes_per_packet = 33;
6927 stream->bytes_per_frame = 33 * stream->n_channels;
6928 stream->bytes_per_sample = 2;
6929 stream->samples_per_frame = 160 * stream->n_channels;
6936 if (version == 0x00010000) {
6944 /* only parse extra decoding config for non-pcm audio */
6945 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
6946 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
6947 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
6948 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
6950 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
6951 stream->samples_per_packet);
6952 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
6953 stream->bytes_per_packet);
6954 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
6955 stream->bytes_per_frame);
6956 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
6957 stream->bytes_per_sample);
6959 if (!stream->sampled && stream->bytes_per_packet) {
6960 stream->samples_per_frame = (stream->bytes_per_frame /
6961 stream->bytes_per_packet) * stream->samples_per_packet;
6962 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
6963 stream->samples_per_frame);
6968 } else if (version == 0x00020000) {
6975 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
6976 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
6977 stream->rate = qtfp.fp;
6978 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
6980 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
6981 stream->samples_per_packet);
6982 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
6983 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
6986 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
6989 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
6998 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
7000 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
7002 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
7004 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
7007 gst_caps_set_simple (stream->caps,
7008 "format", G_TYPE_STRING, "S24_3LE", NULL);
7015 const guint8 *owma_data;
7016 const gchar *codec_name = NULL;
7020 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
7021 /* FIXME this should also be gst_riff_strf_auds,
7022 * but the latter one is actually missing bits-per-sample :( */
7027 gint32 nSamplesPerSec;
7028 gint32 nAvgBytesPerSec;
7030 gint16 wBitsPerSample;
7035 GST_DEBUG_OBJECT (qtdemux, "parse owma");
7036 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
7039 owma_data = owma->data;
7040 owma_len = QT_UINT32 (owma_data);
7041 if (owma_len <= 54) {
7042 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
7045 wfex = (WAVEFORMATEX *) (owma_data + 36);
7046 buf = gst_buffer_new_and_alloc (owma_len - 54);
7047 _gst_buffer_copy_into_mem (buf, owma_data + 54, 0, owma_len - 54);
7048 if (wfex->wFormatTag == 0x0161) {
7049 codec_name = "Windows Media Audio";
7051 } else if (wfex->wFormatTag == 0x0162) {
7052 codec_name = "Windows Media Audio 9 Pro";
7054 } else if (wfex->wFormatTag == 0x0163) {
7055 codec_name = "Windows Media Audio 9 Lossless";
7056 /* is that correct? gstffmpegcodecmap.c is missing it, but
7057 * fluendo codec seems to support it */
7061 gst_caps_set_simple (stream->caps,
7062 "codec_data", GST_TYPE_BUFFER, buf,
7063 "wmaversion", G_TYPE_INT, version,
7064 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
7065 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
7066 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7067 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7069 gst_buffer_unref (buf);
7073 codec = g_strdup (codec_name);
7085 list = gst_tag_list_new ();
7086 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7087 GST_TAG_AUDIO_CODEC, codec, NULL);
7091 /* some bitrate info may have ended up in caps */
7092 s = gst_caps_get_structure (stream->caps, 0);
7093 gst_structure_get_int (s, "bitrate", &bitrate);
7095 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7099 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7103 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7105 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7107 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7111 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7112 16 bits is a byte-swapped wave-style codec identifier,
7113 and we can find a WAVE header internally to a 'wave' atom here.
7114 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7115 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7118 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7119 if (len < offset + 20) {
7120 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7122 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7123 const guint8 *data = stsd_data + offset + 16;
7125 GNode *waveheadernode;
7127 wavenode = g_node_new ((guint8 *) data);
7128 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7129 const guint8 *waveheader;
7132 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7133 if (waveheadernode) {
7134 waveheader = (const guint8 *) waveheadernode->data;
7135 headerlen = QT_UINT32 (waveheader);
7137 if (headerlen > 8) {
7138 gst_riff_strf_auds *header = NULL;
7139 GstBuffer *headerbuf;
7145 headerbuf = gst_buffer_new_and_alloc (headerlen);
7146 _gst_buffer_copy_into_mem (headerbuf, waveheader, 0, headerlen);
7148 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7149 headerbuf, &header, &extra)) {
7150 gst_caps_unref (stream->caps);
7151 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7152 header, extra, NULL, NULL);
7155 gst_buffer_unref (extra);
7159 GST_DEBUG ("Didn't find waveheadernode for this codec");
7161 g_node_destroy (wavenode);
7164 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7168 /* FIXME: what is in the chunk? */
7171 gint len = QT_UINT32 (stsd_data);
7173 /* seems to be always = 116 = 0x74 */
7179 gint len = QT_UINT32 (stsd_data);
7182 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7184 _gst_buffer_copy_into_mem (buf, stsd_data + 0x4C, 0, len - 0x4C);
7185 gst_caps_set_simple (stream->caps,
7186 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7187 gst_buffer_unref (buf);
7189 gst_caps_set_simple (stream->caps,
7190 "samplesize", G_TYPE_INT, samplesize, NULL);
7195 GNode *alac, *wave = NULL;
7197 /* apparently, m4a has this atom appended directly in the stsd entry,
7198 * while mov has it in a wave atom */
7199 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7201 /* alac now refers to stsd entry atom */
7202 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7204 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7206 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7209 gint len = QT_UINT32 (alac->data);
7213 GST_DEBUG_OBJECT (qtdemux,
7214 "discarding alac atom with unexpected len %d", len);
7216 /* codec-data contains alac atom size and prefix,
7217 * ffmpeg likes it that way, not quite gst-ish though ...*/
7218 buf = gst_buffer_new_and_alloc (len);
7219 _gst_buffer_copy_into_mem (buf, alac->data, 0, len);
7220 gst_caps_set_simple (stream->caps,
7221 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7222 gst_buffer_unref (buf);
7225 gst_caps_set_simple (stream->caps,
7226 "samplesize", G_TYPE_INT, samplesize, NULL);
7234 gint len = QT_UINT32 (stsd_data);
7237 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7240 _gst_buffer_copy_into_mem (buf, stsd_data + 0x34, 0, len - 0x34);
7242 /* If we have enough data, let's try to get the 'damr' atom. See
7243 * the 3GPP container spec (26.244) for more details. */
7244 if ((len - 0x34) > 8 &&
7245 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
7247 list = gst_tag_list_new ();
7248 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7249 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
7252 gst_caps_set_simple (stream->caps,
7253 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7254 gst_buffer_unref (buf);
7262 GST_INFO_OBJECT (qtdemux,
7263 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7264 GST_FOURCC_ARGS (fourcc), stream->caps);
7266 } else if (stream->subtype == FOURCC_strm) {
7267 if (fourcc == FOURCC_rtsp) {
7268 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7270 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7271 GST_FOURCC_ARGS (fourcc));
7272 goto unknown_stream;
7274 stream->sampled = TRUE;
7275 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
7277 stream->sampled = TRUE;
7282 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7284 list = gst_tag_list_new ();
7285 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7286 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7291 /* hunt for sort-of codec data */
7298 /* look for palette */
7299 /* target mp4s atom */
7300 len = QT_UINT32 (stsd_data + offset);
7301 data = stsd_data + offset;
7302 /* verify sufficient length,
7303 * and esds present with decConfigDescr of expected size and position */
7304 if ((len >= 106 + 8)
7305 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7306 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7311 /* move to decConfigDescr data */
7312 data = data + 8 + 42;
7313 for (i = 0; i < 16; i++) {
7314 clut[i] = QT_UINT32 (data);
7318 s = gst_structure_new ("application/x-gst-dvd", "event",
7319 G_TYPE_STRING, "dvd-spu-clut-change",
7320 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7321 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7322 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7323 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7324 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7325 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7326 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7327 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7330 /* store event and trigger custom processing */
7331 stream->pending_event =
7332 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7333 stream->need_process = TRUE;
7341 goto unknown_stream;
7344 /* promote to sampled format */
7345 if (stream->fourcc == FOURCC_samr) {
7346 /* force mono 8000 Hz for AMR */
7347 stream->sampled = TRUE;
7348 stream->n_channels = 1;
7349 stream->rate = 8000;
7350 } else if (stream->fourcc == FOURCC_sawb) {
7351 /* force mono 16000 Hz for AMR-WB */
7352 stream->sampled = TRUE;
7353 stream->n_channels = 1;
7354 stream->rate = 16000;
7355 } else if (stream->fourcc == FOURCC_mp4a) {
7356 stream->sampled = TRUE;
7359 /* collect sample information */
7360 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7361 goto samples_failed;
7363 if (qtdemux->fragmented) {
7367 /* need all moov samples as basis; probably not many if any at all */
7368 /* prevent moof parsing taking of at this time */
7369 offset = qtdemux->moof_offset;
7370 qtdemux->moof_offset = 0;
7371 if (stream->n_samples &&
7372 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7373 qtdemux->moof_offset = offset;
7374 goto samples_failed;
7376 qtdemux->moof_offset = 0;
7377 /* movie duration more reliable in this case (e.g. mehd) */
7378 if (qtdemux->segment.duration &&
7379 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7380 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7381 stream->timescale, GST_SECOND);
7382 /* need defaults for fragments */
7383 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7386 /* configure segments */
7387 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7388 goto segments_failed;
7390 /* add some language tag, if useful */
7391 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7392 strcmp (stream->lang_id, "und")) {
7393 const gchar *lang_code;
7396 list = gst_tag_list_new ();
7398 /* convert ISO 639-2 code to ISO 639-1 */
7399 lang_code = gst_tag_get_language_code (stream->lang_id);
7400 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7401 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7404 /* now we are ready to add the stream */
7405 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7406 goto too_many_streams;
7408 stream->pending_tags = list;
7409 qtdemux->streams[qtdemux->n_streams] = stream;
7410 qtdemux->n_streams++;
7411 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7418 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7419 (_("This file is corrupt and cannot be played.")), (NULL));
7425 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7432 /* we posted an error already */
7433 /* free stbl sub-atoms */
7434 gst_qtdemux_stbl_free (stream);
7440 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7441 GST_FOURCC_ARGS (stream->subtype));
7447 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7448 (_("This file contains too many streams. Only playing first %d"),
7449 GST_QTDEMUX_MAX_STREAMS), (NULL));
7454 /* If we can estimate the overall bitrate, and don't have information about the
7455 * stream bitrate for exactly one stream, this guesses the stream bitrate as
7456 * the overall bitrate minus the sum of the bitrates of all other streams. This
7457 * should be useful for the common case where we have one audio and one video
7458 * stream and can estimate the bitrate of one, but not the other. */
7460 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
7462 QtDemuxStream *stream = NULL;
7463 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
7467 if (qtdemux->fragmented)
7470 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
7472 if (!gst_pad_query_peer_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)) {
7473 GST_DEBUG_OBJECT (qtdemux,
7474 "Size in bytes of the stream not known - bailing");
7478 /* Subtract the header size */
7479 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
7480 size, qtdemux->header_size);
7481 g_assert (size >= qtdemux->header_size);
7482 size = size - qtdemux->header_size;
7484 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
7485 duration == GST_CLOCK_TIME_NONE) {
7486 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
7490 for (i = 0; i < qtdemux->n_streams; i++) {
7491 switch (qtdemux->streams[i]->subtype) {
7494 /* retrieve bitrate, prefer avg then max */
7496 if (qtdemux->streams[i]->pending_tags) {
7497 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7498 GST_TAG_MAXIMUM_BITRATE, &bitrate);
7499 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7500 GST_TAG_BITRATE, &bitrate);
7503 sum_bitrate += bitrate;
7506 GST_DEBUG_OBJECT (qtdemux,
7507 ">1 stream with unknown bitrate - bailing");
7510 stream = qtdemux->streams[i];
7514 /* For other subtypes, we assume no significant impact on bitrate */
7520 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
7524 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
7526 if (sys_bitrate < sum_bitrate) {
7527 /* This can happen, since sum_bitrate might be derived from maximum
7528 * bitrates and not average bitrates */
7529 GST_DEBUG_OBJECT (qtdemux,
7530 "System bitrate less than sum bitrate - bailing");
7534 bitrate = sys_bitrate - sum_bitrate;
7535 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
7536 ", Stream bitrate = %u", sys_bitrate, bitrate);
7538 if (!stream->pending_tags)
7539 stream->pending_tags = gst_tag_list_new ();
7541 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
7542 GST_TAG_BITRATE, bitrate, NULL);
7545 static GstFlowReturn
7546 qtdemux_expose_streams (GstQTDemux * qtdemux)
7549 GstFlowReturn ret = GST_FLOW_OK;
7551 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7553 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7554 QtDemuxStream *stream = qtdemux->streams[i];
7555 guint32 sample_num = 0;
7560 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7561 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7563 if (qtdemux->fragmented) {
7564 /* need all moov samples first */
7565 GST_OBJECT_LOCK (qtdemux);
7566 while (stream->n_samples == 0)
7567 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7569 GST_OBJECT_UNLOCK (qtdemux);
7571 /* discard any stray moof */
7572 qtdemux->moof_offset = 0;
7575 /* prepare braking */
7576 if (ret != GST_FLOW_ERROR)
7579 /* in pull mode, we should have parsed some sample info by now;
7580 * and quite some code will not handle no samples.
7581 * in push mode, we'll just have to deal with it */
7582 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7583 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7584 gst_qtdemux_stream_free (qtdemux, stream);
7585 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7586 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7587 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7588 qtdemux->n_streams--;
7593 /* parse number of initial sample to set frame rate cap */
7594 while (sample_num < stream->n_samples && sample_num < samples) {
7595 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7599 /* collect and sort durations */
7600 samples = MIN (stream->stbl_index + 1, samples);
7601 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7603 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7605 while (sample_num < samples) {
7606 g_array_append_val (durations, stream->samples[sample_num].duration);
7609 g_array_sort (durations, less_than);
7610 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7611 g_array_free (durations, TRUE);
7614 /* now we have all info and can expose */
7615 list = stream->pending_tags;
7616 stream->pending_tags = NULL;
7617 gst_qtdemux_add_stream (qtdemux, stream, list);
7620 gst_qtdemux_guess_bitrate (qtdemux);
7622 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7624 /* check if we should post a redirect in case there is a single trak
7625 * and it is a redirecting trak */
7626 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7629 qtdemux_post_global_tags (qtdemux);
7631 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7632 "an external content");
7633 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7634 gst_structure_new ("redirect",
7635 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7637 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7638 qtdemux->posted_redirect = TRUE;
7644 /* check if major or compatible brand is 3GP */
7645 static inline gboolean
7646 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7649 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7650 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7651 } else if (qtdemux->comp_brands != NULL) {
7654 gboolean res = FALSE;
7656 data = gst_buffer_map (qtdemux->comp_brands, &size, NULL, GST_MAP_READ);
7658 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7659 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7663 gst_buffer_unmap (qtdemux->comp_brands, data, size);
7670 /* check if tag is a spec'ed 3GP tag keyword storing a string */
7671 static inline gboolean
7672 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
7674 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
7675 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
7676 || fourcc == FOURCC_albm;
7680 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
7681 const char *dummy, GNode * node)
7683 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7687 gdouble longitude, latitude, altitude;
7690 len = QT_UINT32 (node->data);
7697 /* TODO: language code skipped */
7699 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
7702 /* do not alarm in trivial case, but bail out otherwise */
7703 if (*(data + offset) != 0) {
7704 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
7708 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7709 GST_TAG_GEO_LOCATION_NAME, name, NULL);
7710 offset += strlen (name);
7714 if (len < offset + 2 + 4 + 4 + 4)
7717 /* +1 +1 = skip null-terminator and location role byte */
7719 /* table in spec says unsigned, semantics say negative has meaning ... */
7720 longitude = QT_SFP32 (data + offset);
7723 latitude = QT_SFP32 (data + offset);
7726 altitude = QT_SFP32 (data + offset);
7728 /* one invalid means all are invalid */
7729 if (longitude >= -180.0 && longitude <= 180.0 &&
7730 latitude >= -90.0 && latitude <= 90.0) {
7731 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7732 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
7733 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
7734 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
7737 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
7744 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
7751 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7758 len = QT_UINT32 (node->data);
7762 y = QT_UINT16 ((guint8 *) node->data + 12);
7764 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
7767 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
7769 date = g_date_new_dmy (1, 1, y);
7770 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
7775 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
7776 const char *dummy, GNode * node)
7779 char *tag_str = NULL;
7784 len = QT_UINT32 (node->data);
7789 entity = (guint8 *) node->data + offset;
7790 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
7791 GST_DEBUG_OBJECT (qtdemux,
7792 "classification info: %c%c%c%c invalid classification entity",
7793 entity[0], entity[1], entity[2], entity[3]);
7798 table = QT_UINT16 ((guint8 *) node->data + offset);
7800 /* Language code skipped */
7804 /* Tag format: "XXXX://Y[YYYY]/classification info string"
7805 * XXXX: classification entity, fixed length 4 chars.
7806 * Y[YYYY]: classification table, max 5 chars.
7808 tag_str = g_strdup_printf ("----://%u/%s",
7809 table, (char *) node->data + offset);
7811 /* memcpy To be sure we're preserving byte order */
7812 memcpy (tag_str, entity, 4);
7813 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
7815 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
7825 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
7831 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
7832 const char *dummy, GNode * node)
7834 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7840 gboolean ret = TRUE;
7842 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7844 len = QT_UINT32 (data->data);
7845 type = QT_UINT32 ((guint8 *) data->data + 8);
7846 if (type == 0x00000001 && len > 16) {
7847 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
7850 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7851 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
7855 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7859 len = QT_UINT32 (node->data);
7860 type = QT_UINT32 ((guint8 *) node->data + 4);
7861 if ((type >> 24) == 0xa9) {
7862 /* Type starts with the (C) symbol, so the next 32 bits are
7863 * the language code, which we ignore */
7865 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
7866 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
7867 QT_FOURCC ((guint8 *) node->data + 4))) {
7868 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
7870 /* we go for 3GP style encoding if major brands claims so,
7871 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
7872 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
7873 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
7874 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
7876 /* 16-bit Language code is ignored here as well */
7877 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
7884 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
7885 ret = FALSE; /* may have to fallback */
7887 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
7888 len - offset, env_vars);
7890 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7891 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
7895 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7902 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
7903 const char *dummy, GNode * node)
7905 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
7909 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
7910 const char *dummy, GNode * node)
7912 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7914 char *s, *t, *k = NULL;
7919 /* first try normal string tag if major brand not 3GP */
7920 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
7921 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
7922 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
7923 * let's try it 3gpp way after minor safety check */
7925 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
7931 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
7935 len = QT_UINT32 (data);
7939 count = QT_UINT8 (data + 14);
7941 for (; count; count--) {
7944 if (offset + 1 > len)
7946 slen = QT_UINT8 (data + offset);
7948 if (offset + slen > len)
7950 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
7953 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
7955 t = g_strjoin (",", k, s, NULL);
7963 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
7970 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
7971 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
7980 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
7986 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
7987 const char *tag2, GNode * node)
7994 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7996 len = QT_UINT32 (data->data);
7997 type = QT_UINT32 ((guint8 *) data->data + 8);
7998 if (type == 0x00000000 && len >= 22) {
7999 n1 = QT_UINT16 ((guint8 *) data->data + 18);
8000 n2 = QT_UINT16 ((guint8 *) data->data + 20);
8002 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
8003 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8007 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
8008 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8016 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8024 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8026 len = QT_UINT32 (data->data);
8027 type = QT_UINT32 ((guint8 *) data->data + 8);
8028 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
8029 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8030 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
8031 n1 = QT_UINT16 ((guint8 *) data->data + 16);
8033 /* do not add bpm=0 */
8034 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
8035 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8036 tag1, (gdouble) n1, NULL);
8043 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
8044 const char *dummy, GNode * node)
8051 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8053 len = QT_UINT32 (data->data);
8054 type = QT_UINT32 ((guint8 *) data->data + 8);
8055 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
8056 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8057 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
8058 num = QT_UINT32 ((guint8 *) data->data + 16);
8060 /* do not add num=0 */
8061 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
8062 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8070 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8078 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8080 len = QT_UINT32 (data->data);
8081 type = QT_UINT32 ((guint8 *) data->data + 8);
8082 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
8083 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
8084 if ((buf = gst_tag_image_data_to_image_buffer ((guint8 *) data->data + 16,
8085 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
8086 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
8087 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8089 gst_buffer_unref (buf);
8096 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8104 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8106 len = QT_UINT32 (data->data);
8107 type = QT_UINT32 ((guint8 *) data->data + 8);
8108 if (type == 0x00000001 && len > 16) {
8109 guint y, m = 1, d = 1;
8112 s = g_strndup ((char *) data->data + 16, len - 16);
8113 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
8114 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
8115 if (ret >= 1 && y > 1500 && y < 3000) {
8118 date = g_date_new_dmy (d, m, y);
8119 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
8123 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
8131 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8136 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8138 /* re-route to normal string tag if major brand says so
8139 * or no data atom and compatible brand suggests so */
8140 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8141 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
8142 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
8149 len = QT_UINT32 (data->data);
8150 type = QT_UINT32 ((guint8 *) data->data + 8);
8151 if (type == 0x00000000 && len >= 18) {
8152 n = QT_UINT16 ((guint8 *) data->data + 16);
8156 genre = gst_tag_id3_genre_get (n - 1);
8157 if (genre != NULL) {
8158 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
8159 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8168 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
8169 guint8 * data, guint32 datasize)
8174 /* make a copy to have \0 at the end */
8175 datacopy = g_strndup ((gchar *) data, datasize);
8177 /* convert the str to double */
8178 if (sscanf (datacopy, "%lf", &value) == 1) {
8179 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
8180 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
8182 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
8190 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
8191 const char *tag_bis, GNode * node)
8200 const gchar *meanstr;
8201 const gchar *namestr;
8203 /* checking the whole ---- atom size for consistency */
8204 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8205 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8209 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8211 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8215 meansize = QT_UINT32 (mean->data);
8216 if (meansize <= 12) {
8217 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8220 meanstr = ((gchar *) mean->data) + 12;
8222 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8224 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8228 namesize = QT_UINT32 (name->data);
8229 if (namesize <= 12) {
8230 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8233 namestr = ((gchar *) name->data) + 12;
8240 * uint24 - data type
8244 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8246 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8249 datasize = QT_UINT32 (data->data);
8250 if (datasize <= 16) {
8251 GST_WARNING_OBJECT (demux, "Data atom too small");
8254 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8256 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8259 const gchar name[28];
8260 const gchar tag[28];
8263 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8264 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8265 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8266 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8267 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8268 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8269 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8270 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8274 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8275 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8276 switch (gst_tag_get_type (tags[i].tag)) {
8278 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8279 ((guint8 *) data->data) + 16, datasize - 16);
8282 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8291 if (i == G_N_ELEMENTS (tags))
8305 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8306 namestr_dbg = g_strndup (namestr, namesize - 12);
8308 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8309 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8311 g_free (namestr_dbg);
8312 g_free (meanstr_dbg);
8317 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8318 const char *tag, const char *tag_bis, GNode * node);
8321 FOURCC_pcst -> if media is a podcast -> bool
8322 FOURCC_cpil -> if media is part of a compilation -> bool
8323 FOURCC_pgap -> if media is part of a gapless context -> bool
8324 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8330 const gchar *gst_tag;
8331 const gchar *gst_tag_bis;
8332 const GstQTDemuxAddTagFunc func;
8335 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8336 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8337 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8338 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8339 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8340 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8341 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8342 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8343 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8344 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8345 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8346 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8347 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8348 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8349 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8350 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8351 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8352 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8353 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8354 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8355 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8356 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8357 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8358 qtdemux_tag_add_num}, {
8359 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8360 qtdemux_tag_add_num}, {
8361 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8362 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8363 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8364 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8365 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8366 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8367 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8368 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8369 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8370 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8371 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8372 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8373 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8374 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8375 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8376 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8377 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8378 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8379 qtdemux_tag_add_classification}, {
8381 /* This is a special case, some tags are stored in this
8382 * 'reverse dns naming', according to:
8383 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8386 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}
8390 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8402 len = QT_UINT32 (data);
8403 buf = gst_buffer_new_and_alloc (len);
8404 _gst_buffer_copy_into_mem (buf, data, 0, len);
8406 /* heuristic to determine style of tag */
8407 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8408 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8410 else if (demux->major_brand == FOURCC_qt__)
8411 style = "quicktime";
8412 /* fall back to assuming iso/3gp tag style */
8416 /* santize the name for the caps. */
8417 for (i = 0; i < 4; i++) {
8418 guint8 d = data[4 + i];
8419 if (g_ascii_isalnum (d))
8420 ndata[i] = g_ascii_tolower (d);
8425 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8426 ndata[0], ndata[1], ndata[2], ndata[3]);
8427 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8429 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
8430 // TODO conver to metadata or ???
8431 // gst_buffer_set_caps (buf, caps);
8432 gst_caps_unref (caps);
8433 g_free (media_type);
8435 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
8438 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8439 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
8440 gst_buffer_unref (buf);
8444 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8452 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8454 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8456 GST_LOG_OBJECT (qtdemux, "no ilst");
8461 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8464 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8465 if (!qtdemux->tag_list)
8466 qtdemux->tag_list = gst_tag_list_new ();
8469 while (i < G_N_ELEMENTS (add_funcs)) {
8470 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8474 len = QT_UINT32 (node->data);
8476 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8477 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8479 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8480 add_funcs[i].gst_tag_bis, node);
8482 g_node_destroy (node);
8488 /* parsed nodes have been removed, pass along remainder as blob */
8489 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8490 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8492 /* parse up XMP_ node if existing */
8493 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8496 GstTagList *taglist;
8498 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
8499 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
8500 taglist = gst_tag_list_from_xmp_buffer (buf);
8501 gst_buffer_unref (buf);
8503 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8505 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8512 GstStructure *structure; /* helper for sort function */
8514 guint min_req_bitrate;
8515 guint min_req_qt_version;
8519 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8521 GstQtReference *ref_a = (GstQtReference *) a;
8522 GstQtReference *ref_b = (GstQtReference *) b;
8524 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8525 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8527 /* known bitrates go before unknown; higher bitrates go first */
8528 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8531 /* sort the redirects and post a message for the application.
8534 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8536 GstQtReference *best;
8539 GValue list_val = { 0, };
8542 g_assert (references != NULL);
8544 references = g_list_sort (references, qtdemux_redirects_sort_func);
8546 best = (GstQtReference *) references->data;
8548 g_value_init (&list_val, GST_TYPE_LIST);
8550 for (l = references; l != NULL; l = l->next) {
8551 GstQtReference *ref = (GstQtReference *) l->data;
8552 GValue struct_val = { 0, };
8554 ref->structure = gst_structure_new ("redirect",
8555 "new-location", G_TYPE_STRING, ref->location, NULL);
8557 if (ref->min_req_bitrate > 0) {
8558 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8559 ref->min_req_bitrate, NULL);
8562 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8563 g_value_set_boxed (&struct_val, ref->structure);
8564 gst_value_list_append_value (&list_val, &struct_val);
8565 g_value_unset (&struct_val);
8566 /* don't free anything here yet, since we need best->structure below */
8569 g_assert (best != NULL);
8570 s = gst_structure_copy (best->structure);
8572 if (g_list_length (references) > 1) {
8573 gst_structure_set_value (s, "locations", &list_val);
8576 g_value_unset (&list_val);
8578 for (l = references; l != NULL; l = l->next) {
8579 GstQtReference *ref = (GstQtReference *) l->data;
8581 gst_structure_free (ref->structure);
8582 g_free (ref->location);
8585 g_list_free (references);
8587 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8588 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8589 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8590 qtdemux->posted_redirect = TRUE;
8593 /* look for redirect nodes, collect all redirect information and
8597 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8599 GNode *rmra, *rmda, *rdrf;
8601 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8603 GList *redirects = NULL;
8605 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8607 GstQtReference ref = { NULL, NULL, 0, 0 };
8610 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8611 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8612 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8613 ref.min_req_bitrate);
8616 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
8617 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
8618 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
8620 #ifndef GST_DISABLE_GST_DEBUG
8621 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
8623 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
8625 GST_LOG_OBJECT (qtdemux,
8626 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
8627 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
8628 bitmask, check_type);
8629 if (package == FOURCC_qtim && check_type == 0) {
8630 ref.min_req_qt_version = version;
8634 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
8639 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
8640 ref_data = (guint8 *) rdrf->data + 20;
8641 if (ref_type == FOURCC_alis) {
8642 guint record_len, record_version, fn_len;
8644 /* MacOSX alias record, google for alias-layout.txt */
8645 record_len = QT_UINT16 (ref_data + 4);
8646 record_version = QT_UINT16 (ref_data + 4 + 2);
8647 fn_len = QT_UINT8 (ref_data + 50);
8648 if (record_len > 50 && record_version == 2 && fn_len > 0) {
8649 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
8651 } else if (ref_type == FOURCC_url_) {
8652 ref.location = g_strdup ((gchar *) ref_data);
8654 GST_DEBUG_OBJECT (qtdemux,
8655 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
8656 GST_FOURCC_ARGS (ref_type));
8658 if (ref.location != NULL) {
8659 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
8660 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
8662 GST_WARNING_OBJECT (qtdemux,
8663 "Failed to extract redirect location from rdrf atom");
8667 /* look for others */
8668 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
8671 if (redirects != NULL) {
8672 qtdemux_process_redirects (qtdemux, redirects);
8679 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
8684 tags = gst_tag_list_new ();
8686 if (qtdemux->major_brand == FOURCC_mjp2)
8687 fmt = "Motion JPEG 2000";
8688 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
8690 else if (qtdemux->major_brand == FOURCC_qt__)
8692 else if (qtdemux->fragmented)
8695 fmt = "ISO MP4/M4A";
8697 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
8698 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
8700 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
8706 /* we have read th complete moov node now.
8707 * This function parses all of the relevant info, creates the traks and
8708 * prepares all data structures for playback
8711 qtdemux_parse_tree (GstQTDemux * qtdemux)
8718 guint64 creation_time;
8719 GstDateTime *datetime = NULL;
8722 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
8724 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
8725 return qtdemux_parse_redirects (qtdemux);
8728 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
8730 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
8731 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
8732 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
8733 } else if (version == 0) {
8734 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
8735 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
8736 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
8738 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
8742 /* Moving qt creation time (secs since 1904) to unix time */
8743 if (creation_time != 0) {
8744 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
8745 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
8746 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
8748 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
8749 "please file a bug at http://bugzilla.gnome.org");
8753 if (!qtdemux->tag_list)
8754 qtdemux->tag_list = gst_tag_list_new ();
8756 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
8757 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
8759 gst_date_time_unref (datetime);
8762 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
8763 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
8765 /* check for fragmented file and get some (default) data */
8766 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
8769 GstByteReader mehd_data;
8771 /* let track parsing or anyone know weird stuff might happen ... */
8772 qtdemux->fragmented = TRUE;
8774 /* compensate for total duration */
8775 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
8777 qtdemux_parse_mehd (qtdemux, &mehd_data);
8780 /* set duration in the segment info */
8781 gst_qtdemux_get_duration (qtdemux, &duration);
8783 qtdemux->segment.duration = duration;
8785 /* parse all traks */
8786 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
8788 qtdemux_parse_trak (qtdemux, trak);
8789 /* iterate all siblings */
8790 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
8794 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
8796 qtdemux_parse_udta (qtdemux, udta);
8798 GST_LOG_OBJECT (qtdemux, "No udta node found.");
8801 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
8806 /* taken from ffmpeg */
8808 get_size (guint8 * ptr, guint8 ** end)
8817 len = (len << 7) | (c & 0x7f);
8826 /* this can change the codec originally present in @list */
8828 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
8829 GNode * esds, GstTagList * list)
8831 int len = QT_UINT32 (esds->data);
8832 guint8 *ptr = esds->data;
8833 guint8 *end = ptr + len;
8835 guint8 *data_ptr = NULL;
8837 guint8 object_type_id = 0;
8838 const char *codec_name = NULL;
8839 GstCaps *caps = NULL;
8841 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
8843 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
8846 tag = QT_UINT8 (ptr);
8847 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
8849 len = get_size (ptr, &ptr);
8850 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
8854 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
8855 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
8859 guint max_bitrate, avg_bitrate;
8861 object_type_id = QT_UINT8 (ptr);
8862 max_bitrate = QT_UINT32 (ptr + 5);
8863 avg_bitrate = QT_UINT32 (ptr + 9);
8864 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
8865 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
8866 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
8867 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
8868 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
8869 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
8870 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8871 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
8873 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
8874 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
8881 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
8887 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
8891 GST_ERROR_OBJECT (qtdemux, "parse error");
8896 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
8897 * in use, and should also be used to override some other parameters for some
8899 switch (object_type_id) {
8900 case 0x20: /* MPEG-4 */
8901 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
8902 * profile_and_level_indication */
8903 if (data_ptr != NULL && data_len >= 5 &&
8904 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
8905 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
8906 data_ptr + 4, data_len - 4);
8908 break; /* Nothing special needed here */
8909 case 0x21: /* H.264 */
8910 codec_name = "H.264 / AVC";
8911 caps = gst_caps_new_simple ("video/x-h264",
8912 "stream-format", G_TYPE_STRING, "avc",
8913 "alignment", G_TYPE_STRING, "au", NULL);
8915 case 0x40: /* AAC (any) */
8916 case 0x66: /* AAC Main */
8917 case 0x67: /* AAC LC */
8918 case 0x68: /* AAC SSR */
8919 /* Override channels and rate based on the codec_data, as it's often
8921 /* Only do so for basic setup without HE-AAC extension */
8922 if (data_ptr && data_len == 2) {
8923 guint channels, rateindex, rate;
8925 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
8926 channels = (data_ptr[1] & 0x7f) >> 3;
8927 if (channels > 0 && channels < 7) {
8928 stream->n_channels = channels;
8929 } else if (channels == 7) {
8930 stream->n_channels = 8;
8933 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
8934 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
8936 stream->rate = rate;
8939 /* Set level and profile if possible */
8940 if (data_ptr != NULL && data_len >= 2) {
8941 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
8942 data_ptr, data_len);
8945 case 0x60: /* MPEG-2, various profiles */
8951 codec_name = "MPEG-2 video";
8953 gst_caps_unref (stream->caps);
8954 stream->caps = gst_caps_new_simple ("video/mpeg",
8955 "mpegversion", G_TYPE_INT, 2,
8956 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
8958 case 0x69: /* MP3 has two different values, accept either */
8960 /* change to mpeg1 layer 3 audio */
8961 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
8962 "mpegversion", G_TYPE_INT, 1, NULL);
8963 codec_name = "MPEG-1 layer 3";
8965 case 0x6A: /* MPEG-1 */
8966 codec_name = "MPEG-1 video";
8968 gst_caps_unref (stream->caps);
8969 stream->caps = gst_caps_new_simple ("video/mpeg",
8970 "mpegversion", G_TYPE_INT, 1,
8971 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
8973 case 0x6C: /* MJPEG */
8974 caps = gst_caps_new_simple ("image/jpeg", NULL);
8975 codec_name = "Motion-JPEG";
8977 case 0x6D: /* PNG */
8978 caps = gst_caps_new_simple ("image/png", NULL);
8979 codec_name = "PNG still images";
8981 case 0x6E: /* JPEG2000 */
8982 codec_name = "JPEG-2000";
8983 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
8985 case 0xA4: /* Dirac */
8986 codec_name = "Dirac";
8987 caps = gst_caps_new_simple ("video/x-dirac", NULL);
8989 case 0xA5: /* AC3 */
8990 codec_name = "AC-3 audio";
8991 caps = gst_caps_new_simple ("audio/x-ac3",
8992 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
8994 case 0xE1: /* QCELP */
8995 /* QCELP, the codec_data is a riff tag (little endian) with
8996 * 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). */
8997 caps = gst_caps_new_simple ("audio/qcelp", NULL);
8998 codec_name = "QCELP";
9004 /* If we have a replacement caps, then change our caps for this stream */
9006 gst_caps_unref (stream->caps);
9007 stream->caps = caps;
9010 if (codec_name && list)
9011 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9012 GST_TAG_AUDIO_CODEC, codec_name, NULL);
9014 /* Add the codec_data attribute to caps, if we have it */
9018 buffer = gst_buffer_new_and_alloc (data_len);
9019 _gst_buffer_copy_into_mem (buffer, data_ptr, 0, data_len);
9021 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
9022 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
9024 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
9026 gst_buffer_unref (buffer);
9031 #define _codec(name) \
9034 *codec_name = g_strdup (name); \
9039 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9040 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9043 const GstStructure *s;
9047 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
9048 _codec ("PNG still images");
9049 caps = gst_caps_new_simple ("image/png", NULL);
9051 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
9052 _codec ("JPEG still images");
9053 caps = gst_caps_new_simple ("image/jpeg", NULL);
9055 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
9056 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
9057 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
9058 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
9059 _codec ("Motion-JPEG");
9060 caps = gst_caps_new_simple ("image/jpeg", NULL);
9062 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
9063 _codec ("Motion-JPEG format B");
9064 caps = gst_caps_new_simple ("video/x-mjpeg-b", NULL);
9066 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
9067 _codec ("JPEG-2000");
9068 /* override to what it should be according to spec, avoid palette_data */
9069 stream->bits_per_sample = 24;
9070 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9072 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
9073 _codec ("Sorensen video v.3");
9074 caps = gst_caps_new_simple ("video/x-svq",
9075 "svqversion", G_TYPE_INT, 3, NULL);
9077 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
9078 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
9079 _codec ("Sorensen video v.1");
9080 caps = gst_caps_new_simple ("video/x-svq",
9081 "svqversion", G_TYPE_INT, 1, NULL);
9083 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9087 _codec ("Raw RGB video");
9088 bps = QT_UINT16 (stsd_data + 98);
9089 /* set common stuff */
9090 caps = gst_caps_new_simple ("video/x-raw", NULL);
9094 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB15", NULL);
9097 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB16", NULL);
9100 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB", NULL);
9103 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "ARGB", NULL);
9111 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
9112 _codec ("Raw planar YUV 4:2:0");
9113 caps = gst_caps_new_simple ("video/x-raw",
9114 "format", G_TYPE_STRING, "I420", NULL);
9116 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
9117 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
9118 _codec ("Raw packed YUV 4:2:2");
9119 caps = gst_caps_new_simple ("video/x-raw",
9120 "format", G_TYPE_STRING, "YUY2", NULL);
9122 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
9123 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
9124 _codec ("Raw packed YUV 4:2:2");
9125 caps = gst_caps_new_simple ("video/x-raw",
9126 "format", G_TYPE_STRING, "UYVY", NULL);
9128 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
9129 _codec ("Raw packed YUV 10-bit 4:2:2");
9130 caps = gst_caps_new_simple ("video/x-raw",
9131 "format", G_TYPE_STRING, "v210", NULL);
9133 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
9134 _codec ("Raw packed RGB 10-bit 4:4:4");
9135 caps = gst_caps_new_simple ("video/x-raw",
9136 "format", G_TYPE_STRING, "r210", NULL);
9138 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
9139 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
9140 _codec ("MPEG-1 video");
9141 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9142 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9144 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
9145 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
9146 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
9147 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
9148 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
9149 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
9150 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
9151 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
9152 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
9153 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
9154 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
9155 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
9156 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
9157 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
9158 _codec ("MPEG-2 video");
9159 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
9160 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9162 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
9163 _codec ("GIF still images");
9164 caps = gst_caps_new_simple ("image/gif", NULL);
9166 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
9167 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
9168 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
9169 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9171 /* ffmpeg uses the height/width props, don't know why */
9172 caps = gst_caps_new_simple ("video/x-h263", NULL);
9174 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9175 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9176 _codec ("MPEG-4 video");
9177 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9178 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9180 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9181 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9182 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9183 caps = gst_caps_new_simple ("video/x-msmpeg",
9184 "msmpegversion", G_TYPE_INT, 43, NULL);
9186 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9187 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9188 _codec ("3ivX video");
9189 caps = gst_caps_new_simple ("video/x-3ivx", NULL);
9191 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9193 caps = gst_caps_new_simple ("video/x-divx",
9194 "divxversion", G_TYPE_INT, 3, NULL);
9196 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9197 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9199 caps = gst_caps_new_simple ("video/x-divx",
9200 "divxversion", G_TYPE_INT, 4, NULL);
9202 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9204 caps = gst_caps_new_simple ("video/x-divx",
9205 "divxversion", G_TYPE_INT, 5, NULL);
9207 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9208 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9209 _codec ("XVID MPEG-4");
9210 caps = gst_caps_new_simple ("video/x-xvid", NULL);
9213 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9214 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9215 caps = gst_caps_new_simple ("video/mpeg",
9216 "mpegversion", G_TYPE_INT, 4, NULL);
9218 *codec_name = g_strdup ("FFmpeg MPEG-4");
9221 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9223 caps = gst_caps_new_simple ("video/x-cinepak", NULL);
9225 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9226 _codec ("Apple QuickDraw");
9227 caps = gst_caps_new_simple ("video/x-qdrw", NULL);
9229 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9230 _codec ("Apple video");
9231 caps = gst_caps_new_simple ("video/x-apple-video", NULL);
9233 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9234 _codec ("H.264 / AVC");
9235 caps = gst_caps_new_simple ("video/x-h264",
9236 "stream-format", G_TYPE_STRING, "avc",
9237 "alignment", G_TYPE_STRING, "au", NULL);
9239 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9240 _codec ("Run-length encoding");
9241 caps = gst_caps_new_simple ("video/x-rle",
9242 "layout", G_TYPE_STRING, "quicktime", NULL);
9244 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9245 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9246 _codec ("Indeo Video 3");
9247 caps = gst_caps_new_simple ("video/x-indeo",
9248 "indeoversion", G_TYPE_INT, 3, NULL);
9250 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9251 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9252 _codec ("Intel Video 4");
9253 caps = gst_caps_new_simple ("video/x-indeo",
9254 "indeoversion", G_TYPE_INT, 4, NULL);
9256 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9257 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9258 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9259 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9260 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9261 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9262 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9263 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9264 _codec ("DV Video");
9265 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9266 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9268 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9269 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9270 _codec ("DVCPro50 Video");
9271 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9272 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9274 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9275 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9276 _codec ("DVCProHD Video");
9277 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9278 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9280 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9281 _codec ("Apple Graphics (SMC)");
9282 caps = gst_caps_new_simple ("video/x-smc", NULL);
9284 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9286 caps = gst_caps_new_simple ("video/x-vp3", NULL);
9288 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9290 caps = gst_caps_new_simple ("video/x-theora", NULL);
9291 /* theora uses one byte of padding in the data stream because it does not
9292 * allow 0 sized packets while theora does */
9293 stream->padding = 1;
9295 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9297 caps = gst_caps_new_simple ("video/x-dirac", NULL);
9299 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9300 _codec ("TIFF still images");
9301 caps = gst_caps_new_simple ("image/tiff", NULL);
9303 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9304 _codec ("Apple Intermediate Codec");
9305 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9307 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9308 _codec ("AVID DNxHD");
9309 caps = gst_caps_from_string ("video/x-dnxhd");
9311 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9313 caps = gst_caps_from_string ("video/x-vp8");
9317 caps = gst_caps_new_simple ("video/x-wmv",
9318 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
9320 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9325 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9326 GST_FOURCC_ARGS (fourcc));
9327 caps = gst_caps_new_simple (s, NULL);
9332 /* enable clipping for raw video streams */
9333 s = gst_caps_get_structure (caps, 0);
9334 name = gst_structure_get_name (s);
9335 if (g_str_has_prefix (name, "video/x-raw")) {
9336 stream->need_clip = TRUE;
9342 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9343 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9346 const GstStructure *s;
9350 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9353 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9354 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9355 _codec ("Raw 8-bit PCM audio");
9356 caps = gst_caps_new_simple ("audio/x-raw",
9357 "format", G_TYPE_STRING, "U8", NULL);
9359 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9360 endian = G_BIG_ENDIAN;
9362 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9366 GstAudioFormat format;
9369 endian = G_LITTLE_ENDIAN;
9371 depth = stream->bytes_per_packet * 8;
9372 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
9374 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9378 caps = gst_caps_new_simple ("audio/x-raw",
9379 "format", G_TYPE_STRING, gst_audio_format_to_string (format), NULL);
9382 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9383 _codec ("Raw 64-bit floating-point audio");
9384 caps = gst_caps_new_simple ("audio/x-raw",
9385 "format", G_TYPE_STRING, "F64_BE", NULL);
9387 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9388 _codec ("Raw 32-bit floating-point audio");
9389 caps = gst_caps_new_simple ("audio/x-raw",
9390 "format", G_TYPE_STRING, "F32_BE", NULL);
9393 _codec ("Raw 24-bit PCM audio");
9394 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9396 caps = gst_caps_new_simple ("audio/x-raw",
9397 "format", G_TYPE_STRING, "S24_3BE", NULL);
9399 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9400 _codec ("Raw 32-bit PCM audio");
9401 caps = gst_caps_new_simple ("audio/x-raw",
9402 "format", G_TYPE_STRING, "S32_BE", NULL);
9404 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9405 _codec ("Mu-law audio");
9406 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
9408 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9409 _codec ("A-law audio");
9410 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
9414 _codec ("Microsoft ADPCM");
9415 /* Microsoft ADPCM-ACM code 2 */
9416 caps = gst_caps_new_simple ("audio/x-adpcm",
9417 "layout", G_TYPE_STRING, "microsoft", NULL);
9421 _codec ("DVI/IMA ADPCM");
9422 caps = gst_caps_new_simple ("audio/x-adpcm",
9423 "layout", G_TYPE_STRING, "dvi", NULL);
9427 _codec ("DVI/Intel IMA ADPCM");
9428 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9429 caps = gst_caps_new_simple ("audio/x-adpcm",
9430 "layout", G_TYPE_STRING, "quicktime", NULL);
9434 /* MPEG layer 3, CBR only (pre QT4.1) */
9435 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9436 _codec ("MPEG-1 layer 3");
9437 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9438 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9439 "mpegversion", G_TYPE_INT, 1, NULL);
9442 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9443 _codec ("EAC-3 audio");
9444 caps = gst_caps_new_simple ("audio/x-eac3",
9445 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9446 stream->sampled = TRUE;
9448 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9449 _codec ("AC-3 audio");
9450 caps = gst_caps_new_simple ("audio/x-ac3",
9451 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9452 stream->sampled = TRUE;
9454 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9456 caps = gst_caps_new_simple ("audio/x-mace",
9457 "maceversion", G_TYPE_INT, 3, NULL);
9459 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9461 caps = gst_caps_new_simple ("audio/x-mace",
9462 "maceversion", G_TYPE_INT, 6, NULL);
9464 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9466 caps = gst_caps_new_simple ("application/ogg", NULL);
9468 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9469 _codec ("DV audio");
9470 caps = gst_caps_new_simple ("audio/x-dv", NULL);
9472 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9473 _codec ("MPEG-4 AAC audio");
9474 caps = gst_caps_new_simple ("audio/mpeg",
9475 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9476 "stream-format", G_TYPE_STRING, "raw", NULL);
9478 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9479 _codec ("QDesign Music");
9480 caps = gst_caps_new_simple ("audio/x-qdm", NULL);
9482 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9483 _codec ("QDesign Music v.2");
9484 /* FIXME: QDesign music version 2 (no constant) */
9486 caps = gst_caps_new_simple ("audio/x-qdm2",
9487 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9488 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9489 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9491 caps = gst_caps_new_simple ("audio/x-qdm2", NULL);
9494 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9495 _codec ("GSM audio");
9496 caps = gst_caps_new_simple ("audio/x-gsm", NULL);
9498 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9499 _codec ("AMR audio");
9500 caps = gst_caps_new_simple ("audio/AMR", NULL);
9502 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9503 _codec ("AMR-WB audio");
9504 caps = gst_caps_new_simple ("audio/AMR-WB", NULL);
9506 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9507 _codec ("Quicktime IMA ADPCM");
9508 caps = gst_caps_new_simple ("audio/x-adpcm",
9509 "layout", G_TYPE_STRING, "quicktime", NULL);
9511 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9512 _codec ("Apple lossless audio");
9513 caps = gst_caps_new_simple ("audio/x-alac", NULL);
9515 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9516 _codec ("QualComm PureVoice");
9517 caps = gst_caps_from_string ("audio/qcelp");
9521 caps = gst_caps_new_simple ("audio/x-wma", NULL);
9523 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
9529 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9530 GST_FOURCC_ARGS (fourcc));
9531 caps = gst_caps_new_simple (s, NULL);
9536 /* enable clipping for raw audio streams */
9537 s = gst_caps_get_structure (caps, 0);
9538 name = gst_structure_get_name (s);
9539 if (g_str_has_prefix (name, "audio/x-raw")) {
9540 stream->need_clip = TRUE;
9546 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9547 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9551 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9554 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
9555 _codec ("DVD subtitle");
9556 caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
9558 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
9559 _codec ("Quicktime timed text");
9561 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
9562 _codec ("3GPP timed text");
9564 caps = gst_caps_new_simple ("text/plain", NULL);
9565 /* actual text piece needs to be extracted */
9566 stream->need_process = TRUE;
9572 s = g_strdup_printf ("text/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9573 GST_FOURCC_ARGS (fourcc));
9574 caps = gst_caps_new_simple (s, NULL);