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_0 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! 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_%u",
373 GST_STATIC_CAPS_ANY);
375 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
376 GST_STATIC_PAD_TEMPLATE ("audio_%u",
379 GST_STATIC_CAPS_ANY);
381 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
382 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
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 " at offset %" G_GUINT64_FORMAT,
1143 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1145 /* find previous keyframe */
1146 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1148 /* if the keyframe is at a different position, we need to update the
1149 * requested seek time */
1150 if (index != kindex) {
1153 /* get timestamp of keyframe */
1155 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1157 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT
1158 " at offset %" G_GUINT64_FORMAT,
1159 kindex, GST_TIME_ARGS (media_time), str->samples[kindex].offset);
1161 /* keyframes in the segment get a chance to change the
1162 * desired_offset. keyframes out of the segment are
1164 if (media_time >= seg->media_start) {
1167 /* this keyframe is inside the segment, convert back to
1169 seg_time = (media_time - seg->media_start) + seg->time;
1170 if (seg_time < min_offset)
1171 min_offset = seg_time;
1175 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1176 min_byte_offset = str->samples[index].offset;
1180 *key_time = min_offset;
1182 *key_offset = min_byte_offset;
1186 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1187 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1191 g_return_val_if_fail (format != NULL, FALSE);
1192 g_return_val_if_fail (cur != NULL, FALSE);
1193 g_return_val_if_fail (stop != NULL, FALSE);
1195 if (*format == GST_FORMAT_TIME)
1199 if (cur_type != GST_SEEK_TYPE_NONE)
1200 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1201 if (res && stop_type != GST_SEEK_TYPE_NONE)
1202 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1205 *format = GST_FORMAT_TIME;
1210 /* perform seek in push based mode:
1211 find BYTE position to move to based on time and delegate to upstream
1214 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1219 GstSeekType cur_type, stop_type;
1224 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1226 gst_event_parse_seek (event, &rate, &format, &flags,
1227 &cur_type, &cur, &stop_type, &stop);
1229 /* FIXME, always play to the end */
1232 /* only forward streaming and seeking is possible */
1234 goto unsupported_seek;
1236 /* convert to TIME if needed and possible */
1237 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1241 /* find reasonable corresponding BYTE position,
1242 * also try to mind about keyframes, since we can not go back a bit for them
1244 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1249 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1250 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1253 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1254 GST_DEBUG_OBJECT (qtdemux,
1255 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1256 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1257 GST_OBJECT_LOCK (qtdemux);
1258 qtdemux->requested_seek_time = cur;
1259 qtdemux->seek_offset = byte_cur;
1260 GST_OBJECT_UNLOCK (qtdemux);
1263 /* BYTE seek event */
1264 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1266 res = gst_pad_push_event (qtdemux->sinkpad, event);
1273 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1279 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1284 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1289 /* perform the seek.
1291 * We set all segment_indexes in the streams to unknown and
1292 * adjust the time_position to the desired position. this is enough
1293 * to trigger a segment switch in the streaming thread to start
1294 * streaming from the desired position.
1296 * Keyframe seeking is a little more complicated when dealing with
1297 * segments. Ideally we want to move to the previous keyframe in
1298 * the segment but there might not be a keyframe in the segment. In
1299 * fact, none of the segments could contain a keyframe. We take a
1300 * practical approach: seek to the previous keyframe in the segment,
1301 * if there is none, seek to the beginning of the segment.
1303 * Called with STREAM_LOCK
1306 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1308 gint64 desired_offset;
1311 desired_offset = segment->position;
1313 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1314 GST_TIME_ARGS (desired_offset));
1316 /* may not have enough fragmented info to do this adjustment,
1317 * and we can't scan (and probably should not) at this time with
1318 * possibly flushing upstream */
1319 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1322 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1323 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1324 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1325 desired_offset = min_offset;
1328 /* and set all streams to the final position */
1329 for (n = 0; n < qtdemux->n_streams; n++) {
1330 QtDemuxStream *stream = qtdemux->streams[n];
1332 stream->time_position = desired_offset;
1333 stream->sample_index = -1;
1334 stream->segment_index = -1;
1335 stream->last_ret = GST_FLOW_OK;
1336 stream->sent_eos = FALSE;
1338 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1339 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1341 segment->position = desired_offset;
1342 segment->time = desired_offset;
1344 /* we stop at the end */
1345 if (segment->stop == -1)
1346 segment->stop = segment->duration;
1351 /* do a seek in pull based mode */
1353 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1358 GstSeekType cur_type, stop_type;
1362 GstSegment seeksegment;
1366 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1368 gst_event_parse_seek (event, &rate, &format, &flags,
1369 &cur_type, &cur, &stop_type, &stop);
1371 /* we have to have a format as the segment format. Try to convert
1373 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1377 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1379 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1383 flush = flags & GST_SEEK_FLAG_FLUSH;
1385 /* stop streaming, either by flushing or by pausing the task */
1387 /* unlock upstream pull_range */
1388 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1389 /* make sure out loop function exits */
1390 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1392 /* non flushing seek, pause the task */
1393 gst_pad_pause_task (qtdemux->sinkpad);
1396 /* wait for streaming to finish */
1397 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1399 /* copy segment, we need this because we still need the old
1400 * segment when we close the current segment. */
1401 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1404 /* configure the segment with the seek variables */
1405 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1406 gst_segment_do_seek (&seeksegment, rate, format, flags,
1407 cur_type, cur, stop_type, stop, &update);
1410 /* now do the seek, this actually never returns FALSE */
1411 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1413 /* prepare for streaming again */
1415 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop (TRUE));
1416 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop (TRUE));
1419 /* commit the new segment */
1420 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1422 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1423 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1424 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1425 qtdemux->segment.format, qtdemux->segment.position));
1428 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1429 for (i = 0; i < qtdemux->n_streams; i++)
1430 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1432 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1435 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1442 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1448 qtdemux_ensure_index (GstQTDemux * qtdemux)
1452 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1454 /* Build complete index */
1455 for (i = 0; i < qtdemux->n_streams; i++) {
1456 QtDemuxStream *stream = qtdemux->streams[i];
1458 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1466 GST_LOG_OBJECT (qtdemux,
1467 "Building complete index of stream %u for seeking failed!", i);
1473 gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
1475 gboolean res = TRUE;
1476 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
1478 switch (GST_EVENT_TYPE (event)) {
1479 case GST_EVENT_SEEK:
1481 #ifndef GST_DISABLE_GST_DEBUG
1482 GstClockTime ts = gst_util_get_timestamp ();
1484 /* Build complete index for seeking;
1485 * if not a fragmented file at least */
1486 if (!qtdemux->fragmented)
1487 if (!qtdemux_ensure_index (qtdemux))
1489 #ifndef GST_DISABLE_GST_DEBUG
1490 ts = gst_util_get_timestamp () - ts;
1491 GST_INFO_OBJECT (qtdemux,
1492 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1495 if (qtdemux->pullbased) {
1496 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1497 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams &&
1498 !qtdemux->fragmented) {
1499 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1501 GST_DEBUG_OBJECT (qtdemux,
1502 "ignoring seek in push mode in current state");
1505 gst_event_unref (event);
1508 case GST_EVENT_NAVIGATION:
1510 gst_event_unref (event);
1513 res = gst_pad_event_default (pad, event);
1517 gst_object_unref (qtdemux);
1525 GST_ERROR_OBJECT (qtdemux, "Index failed");
1526 gst_event_unref (event);
1532 /* stream/index return sample that is min/max w.r.t. byte position,
1533 * time is min/max w.r.t. time of samples,
1534 * the latter need not be time of the former sample */
1536 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1537 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1540 gint64 time, min_time;
1541 QtDemuxStream *stream;
1547 for (n = 0; n < qtdemux->n_streams; ++n) {
1550 gboolean set_sample;
1552 str = qtdemux->streams[n];
1559 i = str->n_samples - 1;
1562 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1563 if (str->samples[i].size &&
1564 ((fw && (str->samples[i].offset >= byte_pos)) ||
1566 (str->samples[i].offset + str->samples[i].size <=
1568 /* move stream to first available sample */
1570 gst_qtdemux_move_stream (qtdemux, str, i);
1573 /* determine min/max time */
1574 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1575 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1576 if (min_time == -1 || (!fw && time > min_time) ||
1577 (fw && time < min_time)) {
1580 /* determine stream with leading sample, to get its position */
1582 && (str->samples[i].offset < stream->samples[index].offset))
1584 && (str->samples[i].offset > stream->samples[index].offset))) {
1591 /* no sample for this stream, mark eos */
1593 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1605 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
1607 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
1610 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1612 switch (GST_EVENT_TYPE (event)) {
1613 case GST_EVENT_SEGMENT:
1616 QtDemuxStream *stream;
1620 /* some debug output */
1621 gst_event_copy_segment (event, &segment);
1622 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1625 /* chain will send initial newsegment after pads have been added */
1626 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1627 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1631 /* we only expect a BYTE segment, e.g. following a seek */
1632 if (segment.format == GST_FORMAT_BYTES) {
1633 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1634 gint64 requested_seek_time;
1635 guint64 seek_offset;
1637 offset = segment.start;
1639 GST_OBJECT_LOCK (demux);
1640 requested_seek_time = demux->requested_seek_time;
1641 seek_offset = demux->seek_offset;
1642 demux->requested_seek_time = -1;
1643 demux->seek_offset = -1;
1644 GST_OBJECT_UNLOCK (demux);
1646 if (offset == seek_offset) {
1647 segment.start = requested_seek_time;
1649 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1650 NULL, (gint64 *) & segment.start);
1651 if ((gint64) segment.start < 0)
1655 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1656 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1657 NULL, (gint64 *) & segment.stop);
1658 /* keyframe seeking should already arrange for start >= stop,
1659 * but make sure in other rare cases */
1660 segment.stop = MAX (segment.stop, segment.start);
1663 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1667 /* accept upstream's notion of segment and distribute along */
1668 segment.time = segment.start;
1669 segment.duration = demux->segment.duration;
1670 segment.base = gst_segment_to_running_time (&demux->segment,
1671 GST_FORMAT_TIME, demux->segment.position);
1673 gst_segment_copy_into (&segment, &demux->segment);
1674 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
1675 gst_qtdemux_push_event (demux, gst_event_new_segment (&segment));
1677 /* clear leftover in current segment, if any */
1678 gst_adapter_clear (demux->adapter);
1679 /* set up streaming thread */
1680 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1681 demux->offset = offset;
1683 demux->todrop = stream->samples[idx].offset - offset;
1684 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1686 /* set up for EOS */
1687 demux->neededbytes = -1;
1691 gst_event_unref (event);
1696 case GST_EVENT_FLUSH_STOP:
1701 /* clean up, force EOS if no more info follows */
1702 gst_adapter_clear (demux->adapter);
1704 demux->neededbytes = -1;
1705 /* reset flow return, e.g. following seek */
1706 for (i = 0; i < demux->n_streams; i++) {
1707 demux->streams[i]->last_ret = GST_FLOW_OK;
1708 demux->streams[i]->sent_eos = FALSE;
1710 dur = demux->segment.duration;
1711 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1712 demux->segment.duration = dur;
1716 /* If we are in push mode, and get an EOS before we've seen any streams,
1717 * then error out - we have nowhere to send the EOS */
1718 if (!demux->pullbased) {
1720 gboolean has_valid_stream = FALSE;
1721 for (i = 0; i < demux->n_streams; i++) {
1722 if (demux->streams[i]->pad != NULL) {
1723 has_valid_stream = TRUE;
1727 if (!has_valid_stream)
1728 gst_qtdemux_post_no_playable_stream_error (demux);
1735 res = gst_pad_event_default (demux->sinkpad, event);
1742 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1744 GstQTDemux *demux = GST_QTDEMUX (element);
1746 GST_OBJECT_LOCK (demux);
1747 if (demux->element_index)
1748 gst_object_unref (demux->element_index);
1750 demux->element_index = gst_object_ref (index);
1752 demux->element_index = NULL;
1754 GST_OBJECT_UNLOCK (demux);
1755 /* object lock might be taken again */
1757 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1758 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
1759 demux->element_index, demux->index_id);
1763 gst_qtdemux_get_index (GstElement * element)
1765 GstIndex *result = NULL;
1766 GstQTDemux *demux = GST_QTDEMUX (element);
1768 GST_OBJECT_LOCK (demux);
1769 if (demux->element_index)
1770 result = gst_object_ref (demux->element_index);
1771 GST_OBJECT_UNLOCK (demux);
1773 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1779 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1781 g_free ((gpointer) stream->stco.data);
1782 stream->stco.data = NULL;
1783 g_free ((gpointer) stream->stsz.data);
1784 stream->stsz.data = NULL;
1785 g_free ((gpointer) stream->stsc.data);
1786 stream->stsc.data = NULL;
1787 g_free ((gpointer) stream->stts.data);
1788 stream->stts.data = NULL;
1789 g_free ((gpointer) stream->stss.data);
1790 stream->stss.data = NULL;
1791 g_free ((gpointer) stream->stps.data);
1792 stream->stps.data = NULL;
1793 g_free ((gpointer) stream->ctts.data);
1794 stream->ctts.data = NULL;
1798 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
1800 while (stream->buffers) {
1801 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1802 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1805 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
1806 g_free (stream->samples);
1808 gst_caps_unref (stream->caps);
1809 g_free (stream->segments);
1810 if (stream->pending_tags)
1811 gst_tag_list_free (stream->pending_tags);
1812 g_free (stream->redirect_uri);
1813 /* free stbl sub-atoms */
1814 gst_qtdemux_stbl_free (stream);
1818 static GstStateChangeReturn
1819 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1821 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1822 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1824 switch (transition) {
1825 case GST_STATE_CHANGE_PAUSED_TO_READY:
1831 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1833 switch (transition) {
1834 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1837 qtdemux->state = QTDEMUX_STATE_INITIAL;
1838 qtdemux->neededbytes = 16;
1839 qtdemux->todrop = 0;
1840 qtdemux->pullbased = FALSE;
1841 qtdemux->posted_redirect = FALSE;
1842 qtdemux->offset = 0;
1843 qtdemux->first_mdat = -1;
1844 qtdemux->header_size = 0;
1845 qtdemux->got_moov = FALSE;
1846 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1847 if (qtdemux->mdatbuffer)
1848 gst_buffer_unref (qtdemux->mdatbuffer);
1849 qtdemux->mdatbuffer = NULL;
1850 if (qtdemux->comp_brands)
1851 gst_buffer_unref (qtdemux->comp_brands);
1852 qtdemux->comp_brands = NULL;
1853 if (qtdemux->tag_list)
1854 gst_tag_list_free (qtdemux->tag_list);
1855 qtdemux->tag_list = NULL;
1856 if (qtdemux->element_index)
1857 gst_object_unref (qtdemux->element_index);
1858 qtdemux->element_index = NULL;
1859 gst_adapter_clear (qtdemux->adapter);
1860 for (n = 0; n < qtdemux->n_streams; n++) {
1861 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1862 qtdemux->streams[n] = NULL;
1864 qtdemux->major_brand = 0;
1865 qtdemux->n_streams = 0;
1866 qtdemux->n_video_streams = 0;
1867 qtdemux->n_audio_streams = 0;
1868 qtdemux->n_sub_streams = 0;
1869 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1870 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1871 qtdemux->seek_offset = 0;
1872 qtdemux->upstream_seekable = FALSE;
1873 qtdemux->upstream_size = 0;
1884 qtdemux_post_global_tags (GstQTDemux * qtdemux)
1886 if (qtdemux->tag_list) {
1887 /* all header tags ready and parsed, push them */
1888 GST_INFO_OBJECT (qtdemux, "posting global tags: %" GST_PTR_FORMAT,
1890 /* post now, send event on pads later */
1891 gst_element_post_message (GST_ELEMENT (qtdemux),
1892 gst_message_new_tag (GST_OBJECT (qtdemux),
1893 gst_tag_list_copy (qtdemux->tag_list)));
1898 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1900 /* counts as header data */
1901 qtdemux->header_size += length;
1903 /* only consider at least a sufficiently complete ftyp atom */
1907 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1908 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1909 GST_FOURCC_ARGS (qtdemux->major_brand));
1910 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1911 _gst_buffer_copy_into_mem (buf, buffer + 16, 0, length - 16);
1916 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
1918 /* Strip out bogus fields */
1920 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
1922 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
1924 if (qtdemux->tag_list) {
1925 /* prioritize native tags using _KEEP mode */
1926 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
1927 gst_tag_list_free (taglist);
1929 qtdemux->tag_list = taglist;
1934 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1936 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
1937 0x97, 0xA9, 0x42, 0xE8,
1938 0x9C, 0x71, 0x99, 0x94,
1939 0x91, 0xE3, 0xAF, 0xAC
1943 /* counts as header data */
1944 qtdemux->header_size += length;
1946 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
1948 if (length <= offset + 16) {
1949 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
1953 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
1955 GstTagList *taglist;
1957 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
1958 length - offset - 16, NULL);
1959 taglist = gst_tag_list_from_xmp_buffer (buf);
1960 gst_buffer_unref (buf);
1962 qtdemux_handle_xmp_taglist (qtdemux, taglist);
1965 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
1969 /* caller verifies at least 8 bytes in buf */
1971 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1972 guint64 * plength, guint32 * pfourcc)
1977 length = QT_UINT32 (data);
1978 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1979 fourcc = QT_FOURCC (data + 4);
1980 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1983 length = G_MAXUINT32;
1984 } else if (length == 1 && size >= 16) {
1985 /* this means we have an extended size, which is the 64 bit value of
1986 * the next 8 bytes */
1987 length = QT_UINT64 (data + 8);
1988 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1998 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2000 guint32 version = 0;
2001 guint64 duration = 0;
2003 if (!gst_byte_reader_get_uint32_be (br, &version))
2008 if (!gst_byte_reader_get_uint64_be (br, &duration))
2013 if (!gst_byte_reader_get_uint32_be (br, &dur))
2018 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2019 qtdemux->duration = duration;
2025 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2031 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2032 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2034 if (!stream->parsed_trex && qtdemux->moov_node) {
2036 GstByteReader trex_data;
2038 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2040 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2043 guint32 id = 0, dur = 0, size = 0, flags = 0;
2045 /* skip version/flags */
2046 if (!gst_byte_reader_skip (&trex_data, 4))
2048 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2050 if (id != stream->track_id)
2052 /* sample description index; ignore */
2053 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2055 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2057 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2059 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2062 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2063 "duration %d, size %d, flags 0x%x", stream->track_id,
2066 stream->parsed_trex = TRUE;
2067 stream->def_sample_duration = dur;
2068 stream->def_sample_size = size;
2069 stream->def_sample_flags = flags;
2072 /* iterate all siblings */
2073 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2079 *ds_duration = stream->def_sample_duration;
2080 *ds_size = stream->def_sample_size;
2081 *ds_size = stream->def_sample_size;
2083 /* even then, above values are better than random ... */
2084 if (G_UNLIKELY (!stream->parsed_trex)) {
2085 GST_WARNING_OBJECT (qtdemux,
2086 "failed to find fragment defaults for stream %d", stream->track_id);
2094 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2095 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2096 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2097 gint64 * base_offset, gint64 * running_offset)
2100 gint32 data_offset = 0;
2101 guint32 flags = 0, first_flags = 0, samples_count = 0;
2104 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2105 QtDemuxSample *sample;
2106 gboolean ismv = FALSE;
2108 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2109 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2110 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2113 /* presence of stss or not can't really tell us much,
2114 * and flags and so on tend to be marginally reliable in these files */
2115 if (stream->subtype == FOURCC_soun) {
2116 GST_DEBUG_OBJECT (qtdemux,
2117 "sound track in fragmented file; marking all keyframes");
2118 stream->all_keyframe = TRUE;
2121 if (!gst_byte_reader_skip (trun, 1) ||
2122 !gst_byte_reader_get_uint24_be (trun, &flags))
2125 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2128 if (flags & TR_DATA_OFFSET) {
2129 /* note this is really signed */
2130 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2132 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2133 /* default base offset = first byte of moof */
2134 if (*base_offset == -1) {
2135 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2136 *base_offset = moof_offset;
2138 *running_offset = *base_offset + data_offset;
2140 /* if no offset at all, that would mean data starts at moof start,
2141 * which is a bit wrong and is ismv crappy way, so compensate
2142 * assuming data is in mdat following moof */
2143 if (*base_offset == -1) {
2144 *base_offset = moof_offset + moof_length + 8;
2145 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2148 if (*running_offset == -1)
2149 *running_offset = *base_offset;
2152 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2154 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2155 data_offset, flags, samples_count);
2157 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2158 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2159 GST_DEBUG_OBJECT (qtdemux,
2160 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2161 flags ^= TR_FIRST_SAMPLE_FLAGS;
2163 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2165 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2169 /* FIXME ? spec says other bits should also be checked to determine
2170 * entry size (and prefix size for that matter) */
2172 dur_offset = size_offset = 0;
2173 if (flags & TR_SAMPLE_DURATION) {
2174 GST_LOG_OBJECT (qtdemux, "entry duration present");
2175 dur_offset = entry_size;
2178 if (flags & TR_SAMPLE_SIZE) {
2179 GST_LOG_OBJECT (qtdemux, "entry size present");
2180 size_offset = entry_size;
2183 if (flags & TR_SAMPLE_FLAGS) {
2184 GST_LOG_OBJECT (qtdemux, "entry flags present");
2185 flags_offset = entry_size;
2188 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2189 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2190 ct_offset = entry_size;
2194 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2196 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2198 if (stream->n_samples >=
2199 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2202 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2203 stream->n_samples, (guint) sizeof (QtDemuxSample),
2204 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2206 /* create a new array of samples if it's the first sample parsed */
2207 if (stream->n_samples == 0)
2208 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2209 /* or try to reallocate it with space enough to insert the new samples */
2211 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2212 stream->n_samples + samples_count);
2213 if (stream->samples == NULL)
2216 if (G_UNLIKELY (stream->n_samples == 0)) {
2217 /* the timestamp of the first sample is also provided by the tfra entry
2218 * but we shouldn't rely on it as it is at the end of files */
2221 /* subsequent fragments extend stream */
2223 stream->samples[stream->n_samples - 1].timestamp +
2224 stream->samples[stream->n_samples - 1].duration;
2226 sample = stream->samples + stream->n_samples;
2227 for (i = 0; i < samples_count; i++) {
2228 guint32 dur, size, sflags, ct;
2230 /* first read sample data */
2231 if (flags & TR_SAMPLE_DURATION) {
2232 dur = QT_UINT32 (data + dur_offset);
2234 dur = d_sample_duration;
2236 if (flags & TR_SAMPLE_SIZE) {
2237 size = QT_UINT32 (data + size_offset);
2239 size = d_sample_size;
2241 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2243 sflags = first_flags;
2245 sflags = d_sample_flags;
2247 } else if (flags & TR_SAMPLE_FLAGS) {
2248 sflags = QT_UINT32 (data + flags_offset);
2250 sflags = d_sample_flags;
2252 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2253 ct = QT_UINT32 (data + ct_offset);
2259 /* fill the sample information */
2260 sample->offset = *running_offset;
2261 sample->pts_offset = ct;
2262 sample->size = size;
2263 sample->timestamp = timestamp;
2264 sample->duration = dur;
2265 /* sample-is-difference-sample */
2266 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2267 * now idea how it relates to bitfield other than massive LE/BE confusion */
2268 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2269 *running_offset += size;
2274 stream->n_samples += samples_count;
2280 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2285 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2291 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2292 "be larger than %uMB (broken file?)", stream->n_samples,
2293 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2298 /* find stream with @id */
2299 static inline QtDemuxStream *
2300 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2302 QtDemuxStream *stream;
2306 if (G_UNLIKELY (!id)) {
2307 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2311 /* try to get it fast and simple */
2312 if (G_LIKELY (id <= qtdemux->n_streams)) {
2313 stream = qtdemux->streams[id - 1];
2314 if (G_LIKELY (stream->track_id == id))
2318 /* linear search otherwise */
2319 for (i = 0; i < qtdemux->n_streams; i++) {
2320 stream = qtdemux->streams[i];
2321 if (stream->track_id == id)
2329 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2330 QtDemuxStream ** stream, guint32 * default_sample_duration,
2331 guint32 * default_sample_size, guint32 * default_sample_flags,
2332 gint64 * base_offset)
2335 guint32 track_id = 0;
2337 if (!gst_byte_reader_skip (tfhd, 1) ||
2338 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2341 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2344 *stream = qtdemux_find_stream (qtdemux, track_id);
2345 if (G_UNLIKELY (!*stream))
2346 goto unknown_stream;
2348 if (flags & TF_BASE_DATA_OFFSET)
2349 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2352 /* obtain stream defaults */
2353 qtdemux_parse_trex (qtdemux, *stream,
2354 default_sample_duration, default_sample_size, default_sample_flags);
2356 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2357 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2358 if (!gst_byte_reader_skip (tfhd, 4))
2361 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2362 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2365 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2366 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2369 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2370 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2377 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2382 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2388 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2389 guint64 moof_offset, QtDemuxStream * stream)
2391 GNode *moof_node, *traf_node, *tfhd_node, *trun_node;
2392 GstByteReader trun_data, tfhd_data;
2393 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2394 gint64 base_offset, running_offset;
2396 /* NOTE @stream ignored */
2398 moof_node = g_node_new ((guint8 *) buffer);
2399 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2400 qtdemux_node_dump (qtdemux, moof_node);
2402 /* unknown base_offset to start with */
2403 base_offset = running_offset = -1;
2404 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2406 /* Fragment Header node */
2408 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2412 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2413 &ds_size, &ds_flags, &base_offset))
2415 if (G_UNLIKELY (!stream)) {
2416 /* we lost track of offset, we'll need to regain it,
2417 * but can delay complaining until later or avoid doing so altogether */
2421 if (G_UNLIKELY (base_offset < -1))
2423 /* Track Run node */
2425 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2428 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2429 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2431 /* iterate all siblings */
2432 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2435 /* if no new base_offset provided for next traf,
2436 * base is end of current traf */
2437 base_offset = running_offset;
2438 running_offset = -1;
2440 /* iterate all siblings */
2441 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2443 g_node_destroy (moof_node);
2448 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2453 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2458 g_node_destroy (moof_node);
2459 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2460 (_("This file is corrupt and cannot be played.")), (NULL));
2465 /* might be used if some day we actually use mfra & co
2466 * for random access to fragments,
2467 * but that will require quite some modifications and much less relying
2468 * on a sample array */
2471 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2472 QtDemuxStream * stream)
2474 guint64 time = 0, moof_offset = 0;
2475 guint32 ver_flags, track_id, len, num_entries, i;
2476 guint value_size, traf_size, trun_size, sample_size;
2477 GstBuffer *buf = NULL;
2481 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2482 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2484 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2487 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2488 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2489 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2492 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2493 track_id, stream->track_id);
2494 if (track_id != stream->track_id) {
2498 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2499 sample_size = (len & 3) + 1;
2500 trun_size = ((len & 12) >> 2) + 1;
2501 traf_size = ((len & 48) >> 4) + 1;
2503 if (num_entries == 0)
2506 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2507 value_size + value_size + traf_size + trun_size + sample_size))
2510 for (i = 0; i < num_entries; i++) {
2511 qt_atom_parser_get_offset (&tfra, value_size, &time);
2512 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2513 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2514 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2515 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2517 GST_LOG_OBJECT (qtdemux,
2518 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2519 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2520 stream->timescale)), moof_offset);
2522 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2523 if (ret != GST_FLOW_OK)
2525 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2526 moof_offset, stream);
2527 gst_buffer_unref (buf);
2535 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2536 (_("This file is corrupt and cannot be played.")), (NULL));
2541 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2547 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2550 GNode *mfra_node, *tfra_node;
2553 if (!qtdemux->mfra_offset)
2556 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2557 if (ret != GST_FLOW_OK)
2560 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2561 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2562 GST_BUFFER_SIZE (buffer));
2564 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2567 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2568 /* iterate all siblings */
2569 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2571 g_node_destroy (mfra_node);
2572 gst_buffer_unref (buffer);
2578 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2579 (_("This file is corrupt and cannot be played.")), (NULL));
2584 static GstFlowReturn
2585 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2586 guint32 * mfro_size)
2588 GstFlowReturn ret = GST_FLOW_ERROR;
2589 GstBuffer *mfro = NULL;
2592 GstFormat fmt = GST_FORMAT_BYTES;
2594 if (!gst_pad_query_peer_duration (qtdemux->sinkpad, &fmt, &len)) {
2595 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2596 "can not locate mfro");
2600 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2601 if (ret != GST_FLOW_OK)
2604 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2605 if (fourcc != FOURCC_mfro)
2608 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2609 if (GST_BUFFER_SIZE (mfro) >= 16) {
2610 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
2611 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
2612 if (*mfro_size >= len) {
2613 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
2614 ret = GST_FLOW_ERROR;
2617 *mfra_offset = len - *mfro_size;
2622 gst_buffer_unref (mfro);
2628 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
2631 guint32 mfra_size = 0;
2632 guint64 mfra_offset = 0;
2635 qtdemux->fragmented = FALSE;
2637 /* We check here if it is a fragmented mp4 container */
2638 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
2639 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
2640 qtdemux->fragmented = TRUE;
2641 GST_DEBUG_OBJECT (qtdemux,
2642 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
2643 qtdemux->mfra_offset = mfra_offset;
2648 static GstFlowReturn
2649 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
2653 GstBuffer *buf = NULL;
2654 GstFlowReturn ret = GST_FLOW_OK;
2655 guint64 cur_offset = qtdemux->offset;
2659 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
2660 if (G_UNLIKELY (ret != GST_FLOW_OK))
2662 data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
2663 if (G_LIKELY (size >= 8))
2664 extract_initial_length_and_fourcc (data, size, &length, &fourcc);
2665 gst_buffer_unmap (buf, data, size);
2666 gst_buffer_unref (buf);
2668 /* maybe we already got most we needed, so only consider this eof */
2669 if (G_UNLIKELY (length == 0)) {
2670 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
2671 (_("Invalid atom size.")),
2672 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
2673 GST_FOURCC_ARGS (fourcc)));
2674 ret = GST_FLOW_UNEXPECTED;
2680 /* record for later parsing when needed */
2681 if (!qtdemux->moof_offset) {
2682 qtdemux->moof_offset = qtdemux->offset;
2691 GST_LOG_OBJECT (qtdemux,
2692 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
2693 GST_FOURCC_ARGS (fourcc), cur_offset);
2694 qtdemux->offset += length;
2701 if (qtdemux->got_moov) {
2702 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
2703 qtdemux->offset += length;
2707 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
2708 if (ret != GST_FLOW_OK)
2710 data = gst_buffer_map (moov, &size, NULL, GST_MAP_READ);
2711 if (length != size) {
2712 /* Some files have a 'moov' atom at the end of the file which contains
2713 * a terminal 'free' atom where the body of the atom is missing.
2714 * Check for, and permit, this special case.
2717 guint8 *final_data = data + (size - 8);
2718 guint32 final_length = QT_UINT32 (final_data);
2719 guint32 final_fourcc = QT_FOURCC (final_data + 4);
2720 gst_buffer_unmap (moov, data, size);
2721 if (final_fourcc == FOURCC_free && size + final_length - 8 == length) {
2722 /* Ok, we've found that special case. Allocate a new buffer with
2723 * that free atom actually present. */
2724 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
2725 gst_buffer_copy_into (newmoov, moov, 0, 0, size);
2726 data = gst_buffer_map (newmoov, &size, NULL, GST_MAP_WRITE);
2727 memset (data + length - final_length + 8, 0, final_length - 8);
2728 gst_buffer_unref (moov);
2734 if (length != size) {
2735 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2736 (_("This file is incomplete and cannot be played.")),
2737 ("We got less than expected (received %u, wanted %u, offset %"
2738 G_GUINT64_FORMAT ")", size, (guint) length, cur_offset));
2739 gst_buffer_unmap (moov, data, size);
2740 gst_buffer_unref (moov);
2741 ret = GST_FLOW_ERROR;
2744 qtdemux->offset += length;
2746 qtdemux_parse_moov (qtdemux, data, length);
2747 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
2749 qtdemux_parse_tree (qtdemux);
2750 g_node_destroy (qtdemux->moov_node);
2751 gst_buffer_unmap (moov, data, size);
2752 gst_buffer_unref (moov);
2753 qtdemux->moov_node = NULL;
2754 qtdemux->got_moov = TRUE;
2762 /* extract major brand; might come in handy for ISO vs QT issues */
2763 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
2764 if (ret != GST_FLOW_OK)
2766 qtdemux->offset += length;
2767 data = gst_buffer_map (ftyp, &size, NULL, GST_MAP_READ);
2768 qtdemux_parse_ftyp (qtdemux, data, size);
2769 gst_buffer_unmap (ftyp, data, size);
2770 gst_buffer_unref (ftyp);
2777 /* uuid are extension atoms */
2778 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
2779 if (ret != GST_FLOW_OK)
2781 qtdemux->offset += length;
2782 data = gst_buffer_map (uuid, &size, NULL, GST_MAP_READ);
2783 qtdemux_parse_uuid (qtdemux, data, size);
2784 gst_buffer_unmap (uuid, data, size);
2785 gst_buffer_unref (uuid);
2792 GST_LOG_OBJECT (qtdemux,
2793 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
2794 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
2796 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
2797 if (ret != GST_FLOW_OK)
2799 data = gst_buffer_map (unknown, &size, NULL, GST_MAP_READ);
2800 GST_MEMDUMP ("Unknown tag", data, size);
2801 gst_buffer_unmap (unknown, data, size);
2802 gst_buffer_unref (unknown);
2803 qtdemux->offset += length;
2809 if (ret == GST_FLOW_UNEXPECTED && qtdemux->got_moov) {
2810 /* digested all data, show what we have */
2811 ret = qtdemux_expose_streams (qtdemux);
2813 /* Only post, event on pads is done after newsegment */
2814 qtdemux_post_global_tags (qtdemux);
2816 qtdemux->state = QTDEMUX_STATE_MOVIE;
2817 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
2824 /* Seeks to the previous keyframe of the indexed stream and
2825 * aligns other streams with respect to the keyframe timestamp
2826 * of indexed stream. Only called in case of Reverse Playback
2828 static GstFlowReturn
2829 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
2832 guint32 seg_idx = 0, k_index = 0;
2833 guint32 ref_seg_idx, ref_k_index;
2834 guint64 k_pos = 0, last_stop = 0;
2835 QtDemuxSegment *seg = NULL;
2836 QtDemuxStream *ref_str = NULL;
2837 guint64 seg_media_start_mov; /* segment media start time in mov format */
2839 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
2840 * and finally align all the other streams on that timestamp with their
2841 * respective keyframes */
2842 for (n = 0; n < qtdemux->n_streams; n++) {
2843 QtDemuxStream *str = qtdemux->streams[n];
2845 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
2846 qtdemux->segment.position);
2848 /* segment not found, continue with normal flow */
2852 /* No candidate yet, take that one */
2858 /* So that stream has a segment, we prefer video streams */
2859 if (str->subtype == FOURCC_vide) {
2865 if (G_UNLIKELY (!ref_str)) {
2866 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
2870 if (G_UNLIKELY (!ref_str->from_sample)) {
2871 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
2875 /* So that stream has been playing from from_sample to to_sample. We will
2876 * get the timestamp of the previous sample and search for a keyframe before
2877 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
2878 if (ref_str->subtype == FOURCC_vide) {
2879 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
2880 ref_str->from_sample - 1);
2882 if (ref_str->from_sample >= 10)
2883 k_index = ref_str->from_sample - 10;
2888 /* get current segment for that stream */
2889 seg = &ref_str->segments[ref_str->segment_index];
2890 /* convert seg->media_start to mov format time for timestamp comparison */
2891 seg_media_start_mov =
2892 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
2893 /* Crawl back through segments to find the one containing this I frame */
2894 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
2895 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
2896 ref_str->segment_index);
2897 if (G_UNLIKELY (!ref_str->segment_index)) {
2898 /* Reached first segment, let's consider it's EOS */
2901 ref_str->segment_index--;
2902 seg = &ref_str->segments[ref_str->segment_index];
2903 /* convert seg->media_start to mov format time for timestamp comparison */
2904 seg_media_start_mov =
2905 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
2908 /* Calculate time position of the keyframe and where we should stop */
2910 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
2911 ref_str->timescale) - seg->media_start) + seg->time;
2913 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
2914 GST_SECOND, ref_str->timescale);
2915 last_stop = (last_stop - seg->media_start) + seg->time;
2917 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
2918 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
2919 k_index, GST_TIME_ARGS (k_pos));
2921 /* Set last_stop with the keyframe timestamp we pushed of that stream */
2922 qtdemux->segment.position = last_stop;
2923 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
2924 GST_TIME_ARGS (last_stop));
2926 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
2927 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
2931 ref_seg_idx = ref_str->segment_index;
2932 ref_k_index = k_index;
2934 /* Align them all on this */
2935 for (n = 0; n < qtdemux->n_streams; n++) {
2937 guint64 media_start = 0, seg_time = 0;
2938 QtDemuxStream *str = qtdemux->streams[n];
2940 /* aligning reference stream again might lead to backing up to yet another
2941 * keyframe (due to timestamp rounding issues),
2942 * potentially putting more load on downstream; so let's try to avoid */
2943 if (str == ref_str) {
2944 seg_idx = ref_seg_idx;
2945 seg = &str->segments[seg_idx];
2946 k_index = ref_k_index;
2947 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
2948 "sample at index %d", ref_str->segment_index, k_index);
2950 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
2951 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
2953 /* segment not found, continue with normal flow */
2957 /* get segment and time in the segment */
2958 seg = &str->segments[seg_idx];
2959 seg_time = k_pos - seg->time;
2961 /* get the media time in the segment */
2962 media_start = seg->media_start + seg_time;
2964 /* get the index of the sample with media time */
2965 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
2966 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
2967 GST_TIME_ARGS (media_start), index);
2969 /* find previous keyframe */
2970 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
2973 /* Remember until where we want to go */
2974 str->to_sample = str->from_sample - 1;
2975 /* Define our time position */
2976 str->time_position =
2977 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
2978 str->timescale) - seg->media_start) + seg->time;
2979 /* Now seek back in time */
2980 gst_qtdemux_move_stream (qtdemux, str, k_index);
2981 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
2982 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
2983 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
2989 return GST_FLOW_UNEXPECTED;
2992 /* activate the given segment number @seg_idx of @stream at time @offset.
2993 * @offset is an absolute global position over all the segments.
2995 * This will push out a NEWSEGMENT event with the right values and
2996 * position the stream index to the first decodable sample before
3000 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
3001 guint32 seg_idx, guint64 offset)
3004 QtDemuxSegment *segment;
3005 guint32 index, kf_index;
3007 guint64 start, stop, time;
3010 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3013 /* update the current segment */
3014 stream->segment_index = seg_idx;
3016 /* get the segment */
3017 segment = &stream->segments[seg_idx];
3019 if (G_UNLIKELY (offset < segment->time)) {
3020 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3025 /* segment lies beyond total indicated duration */
3026 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3027 segment->time > qtdemux->segment.duration)) {
3028 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3029 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3034 /* get time in this segment */
3035 seg_time = offset - segment->time;
3037 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3038 GST_TIME_ARGS (seg_time));
3040 if (G_UNLIKELY (seg_time > segment->duration)) {
3041 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3042 GST_TIME_ARGS (segment->duration));
3046 /* qtdemux->segment.stop is in outside-time-realm, whereas
3047 * segment->media_stop is in track-time-realm.
3049 * In order to compare the two, we need to bring segment.stop
3050 * into the track-time-realm */
3052 stop = qtdemux->segment.stop;
3054 stop = qtdemux->segment.duration;
3056 stop = segment->media_stop;
3059 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3061 if (qtdemux->segment.rate >= 0) {
3062 start = MIN (segment->media_start + seg_time, stop);
3065 if (segment->media_start >= qtdemux->segment.start) {
3066 start = segment->media_start;
3067 time = segment->time;
3069 start = qtdemux->segment.start;
3070 time = segment->time + (qtdemux->segment.start - segment->media_start);
3073 start = MAX (segment->media_start, qtdemux->segment.start);
3074 stop = MIN (segment->media_start + seg_time, stop);
3077 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3078 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3079 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3081 /* combine global rate with that of the segment */
3082 rate = segment->rate * qtdemux->segment.rate;
3084 /* update the segment values used for clipping */
3085 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
3086 /* accumulate previous segments */
3087 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3088 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3089 ABS (stream->segment.rate);
3090 stream->segment.rate = rate;
3091 stream->segment.start = start;
3092 stream->segment.stop = stop;
3093 stream->segment.time = time;
3095 /* now prepare and send the segment */
3097 event = gst_event_new_segment (&stream->segment);
3098 gst_pad_push_event (stream->pad, event);
3099 /* assume we can send more data now */
3100 stream->last_ret = GST_FLOW_OK;
3101 /* clear to send tags on this pad now */
3102 gst_qtdemux_push_tags (qtdemux, stream);
3105 /* and move to the keyframe before the indicated media time of the
3107 if (qtdemux->segment.rate >= 0) {
3108 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3109 stream->to_sample = G_MAXUINT32;
3110 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3111 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3112 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3113 GST_SECOND, stream->timescale)));
3115 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3116 stream->to_sample = index;
3117 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3118 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3119 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3120 GST_SECOND, stream->timescale)));
3123 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3124 * encountered an error and printed a message so we return appropriately */
3128 /* we're at the right spot */
3129 if (index == stream->sample_index) {
3130 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3134 /* find keyframe of the target index */
3135 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3138 /* indent does stupid stuff with stream->samples[].timestamp */
3140 /* if we move forwards, we don't have to go back to the previous
3141 * keyframe since we already sent that. We can also just jump to
3142 * the keyframe right before the target index if there is one. */
3143 if (index > stream->sample_index) {
3144 /* moving forwards check if we move past a keyframe */
3145 if (kf_index > stream->sample_index) {
3146 GST_DEBUG_OBJECT (qtdemux,
3147 "moving forwards 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);
3153 GST_DEBUG_OBJECT (qtdemux,
3154 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3155 " already sent", kf_index,
3156 GST_TIME_ARGS (gst_util_uint64_scale (
3157 stream->samples[kf_index].timestamp,
3158 GST_SECOND, stream->timescale)));
3161 GST_DEBUG_OBJECT (qtdemux,
3162 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3163 GST_TIME_ARGS (gst_util_uint64_scale (
3164 stream->samples[kf_index].timestamp,
3165 GST_SECOND, stream->timescale)));
3166 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3174 /* prepare to get the current sample of @stream, getting essential values.
3176 * This function will also prepare and send the segment when needed.
3178 * Return FALSE if the stream is EOS.
3181 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3182 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp,
3183 guint64 * duration, gboolean * keyframe)
3185 QtDemuxSample *sample;
3186 guint64 time_position;
3189 g_return_val_if_fail (stream != NULL, FALSE);
3191 time_position = stream->time_position;
3192 if (G_UNLIKELY (time_position == -1))
3195 seg_idx = stream->segment_index;
3196 if (G_UNLIKELY (seg_idx == -1)) {
3197 /* find segment corresponding to time_position if we are looking
3199 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3201 /* nothing found, we're really eos */
3206 /* different segment, activate it, sample_index will be set. */
3207 if (G_UNLIKELY (stream->segment_index != seg_idx))
3208 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3210 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3211 stream->sample_index, stream->n_samples);
3213 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3216 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3217 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3218 stream->sample_index);
3222 /* now get the info for the sample we're at */
3223 sample = &stream->samples[stream->sample_index];
3225 *timestamp = QTSAMPLE_PTS (stream, sample);
3226 *offset = sample->offset;
3227 *size = sample->size;
3228 *duration = QTSAMPLE_DUR_PTS (stream, sample, *timestamp);
3229 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3236 stream->time_position = -1;
3241 /* move to the next sample in @stream.
3243 * Moves to the next segment when needed.
3246 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3248 QtDemuxSample *sample;
3249 QtDemuxSegment *segment;
3251 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3252 /* Mark the stream as EOS */
3253 GST_DEBUG_OBJECT (qtdemux,
3254 "reached max allowed sample %u, mark EOS", stream->to_sample);
3255 stream->time_position = -1;
3259 /* move to next sample */
3260 stream->sample_index++;
3262 /* get current segment */
3263 segment = &stream->segments[stream->segment_index];
3265 /* reached the last sample, we need the next segment */
3266 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3269 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3270 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3271 stream->sample_index);
3275 /* get next sample */
3276 sample = &stream->samples[stream->sample_index];
3278 /* see if we are past the segment */
3279 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3280 GST_SECOND, stream->timescale) >= segment->media_stop))
3283 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3284 stream->timescale) >= segment->media_start) {
3285 /* inside the segment, update time_position, looks very familiar to
3286 * GStreamer segments, doesn't it? */
3287 stream->time_position =
3288 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3289 stream->timescale) - segment->media_start) + segment->time;
3291 /* not yet in segment, time does not yet increment. This means
3292 * that we are still prerolling keyframes to the decoder so it can
3293 * decode the first sample of the segment. */
3294 stream->time_position = segment->time;
3298 /* move to the next segment */
3301 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3303 if (stream->segment_index == stream->n_segments - 1) {
3304 /* are we at the end of the last segment, we're EOS */
3305 stream->time_position = -1;
3307 /* else we're only at the end of the current segment */
3308 stream->time_position = segment->stop_time;
3310 /* make sure we select a new segment */
3311 stream->segment_index = -1;
3316 gst_qtdemux_sync_streams (GstQTDemux * demux)
3320 if (demux->n_streams <= 1)
3323 for (i = 0; i < demux->n_streams; i++) {
3324 QtDemuxStream *stream;
3325 GstClockTime end_time;
3327 stream = demux->streams[i];
3332 /* TODO advance time on subtitle streams here, if any some day */
3334 /* some clips/trailers may have unbalanced streams at the end,
3335 * so send EOS on shorter stream to prevent stalling others */
3337 /* do not mess with EOS if SEGMENT seeking */
3338 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3341 if (demux->pullbased) {
3342 /* loop mode is sample time based */
3343 if (stream->time_position != -1)
3346 /* push mode is byte position based */
3347 if (stream->n_samples &&
3348 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3352 if (stream->sent_eos)
3355 /* only act if some gap */
3356 end_time = stream->segments[stream->n_segments - 1].stop_time;
3357 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3358 ", stream end: %" GST_TIME_FORMAT,
3359 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3360 if (end_time + 2 * GST_SECOND < demux->segment.position) {
3361 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3362 GST_PAD_NAME (stream->pad));
3363 stream->sent_eos = TRUE;
3364 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3369 /* UNEXPECTED and NOT_LINKED need to be combined. This means that we return:
3371 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3372 * GST_FLOW_UNEXPECTED: when all pads UNEXPECTED or NOT_LINKED.
3374 static GstFlowReturn
3375 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3379 gboolean unexpected = FALSE, not_linked = TRUE;
3381 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3383 /* store the value */
3384 stream->last_ret = ret;
3386 /* any other error that is not-linked or eos can be returned right away */
3387 if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
3390 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3391 for (i = 0; i < demux->n_streams; i++) {
3392 QtDemuxStream *ostream = demux->streams[i];
3394 ret = ostream->last_ret;
3396 /* no unexpected or unlinked, return */
3397 if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
3400 /* we check to see if we have at least 1 unexpected or all unlinked */
3401 unexpected |= (ret == GST_FLOW_UNEXPECTED);
3402 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3405 /* when we get here, we all have unlinked or unexpected */
3407 ret = GST_FLOW_NOT_LINKED;
3408 else if (unexpected)
3409 ret = GST_FLOW_UNEXPECTED;
3411 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3415 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3416 * completely cliped */
3418 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3421 guint64 start, stop, cstart, cstop, diff;
3422 GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
3424 gint num_rate, denom_rate;
3429 size = gst_buffer_get_size (buf);
3432 /* depending on the type, setup the clip parameters */
3433 if (stream->subtype == FOURCC_soun) {
3434 frame_size = stream->bytes_per_frame;
3435 num_rate = GST_SECOND;
3436 denom_rate = (gint) stream->rate;
3438 } else if (stream->subtype == FOURCC_vide) {
3440 num_rate = stream->fps_n;
3441 denom_rate = stream->fps_d;
3446 /* we can only clip if we have a valid timestamp */
3447 timestamp = GST_BUFFER_TIMESTAMP (buf);
3448 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
3451 if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf))) {
3452 duration = GST_BUFFER_DURATION (buf);
3455 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3459 stop = start + duration;
3461 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3462 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3465 /* see if some clipping happened */
3466 diff = cstart - start;
3472 /* bring clipped time to samples and to bytes */
3473 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3476 GST_DEBUG_OBJECT (qtdemux,
3477 "clipping start to %" GST_TIME_FORMAT " %"
3478 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3484 diff = stop - cstop;
3489 /* bring clipped time to samples and then to bytes */
3490 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3492 GST_DEBUG_OBJECT (qtdemux,
3493 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3494 " bytes", GST_TIME_ARGS (cstop), diff);
3499 gst_buffer_resize (buf, offset, size);
3500 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3501 GST_BUFFER_DURATION (buf) = duration;
3505 /* dropped buffer */
3508 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3513 GST_DEBUG_OBJECT (qtdemux, "no timestamp on buffer");
3518 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3519 gst_buffer_unref (buf);
3524 /* the input buffer metadata must be writable,
3525 * but time/duration etc not yet set and need not be preserved */
3527 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3535 /* not many cases for now */
3536 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3537 /* send a one time dvd clut event */
3538 if (stream->pending_event && stream->pad)
3539 gst_pad_push_event (stream->pad, stream->pending_event);
3540 stream->pending_event = NULL;
3541 /* no further processing needed */
3542 stream->need_process = FALSE;
3545 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
3549 data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
3551 if (G_LIKELY (size >= 2)) {
3552 nsize = GST_READ_UINT16_BE (data);
3553 nsize = MIN (nsize, size - 2);
3556 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%d", nsize, size);
3558 /* takes care of UTF-8 validation or UTF-16 recognition,
3559 * no other encoding expected */
3560 str = gst_tag_freeform_string_to_utf8 ((gchar *) data + 2, nsize, NULL);
3561 gst_buffer_unmap (buf, data, size);
3563 gst_buffer_unref (buf);
3564 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
3566 /* may be 0-size subtitle, which is also sent to keep pipeline going */
3567 gst_buffer_resize (buf, 2, nsize);
3570 /* FIXME ? convert optional subsequent style info to markup */
3575 /* Sets a buffer's attributes properly and pushes it downstream.
3576 * Also checks for additional actions and custom processing that may
3577 * need to be done first.
3580 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3581 QtDemuxStream * stream, GstBuffer * buf,
3582 guint64 timestamp, guint64 duration, gboolean keyframe, guint64 position,
3583 guint64 byte_position)
3585 GstFlowReturn ret = GST_FLOW_OK;
3587 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
3592 bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
3593 url = g_strndup ((gchar *) bdata, bsize);
3594 gst_buffer_unmap (buf, bdata, bsize);
3595 if (url != NULL && strlen (url) != 0) {
3596 /* we have RTSP redirect now */
3597 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3598 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
3599 gst_structure_new ("redirect",
3600 "new-location", G_TYPE_STRING, url, NULL)));
3601 qtdemux->posted_redirect = TRUE;
3603 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
3609 /* position reporting */
3610 if (qtdemux->segment.rate >= 0) {
3611 qtdemux->segment.position = position;
3612 gst_qtdemux_sync_streams (qtdemux);
3615 if (G_UNLIKELY (!stream->pad)) {
3616 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
3617 gst_buffer_unref (buf);
3621 /* send out pending buffers */
3622 while (stream->buffers) {
3623 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
3625 if (G_UNLIKELY (stream->discont)) {
3626 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3627 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
3628 stream->discont = FALSE;
3631 gst_pad_push (stream->pad, buffer);
3633 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
3636 /* we're going to modify the metadata */
3637 buf = gst_buffer_make_writable (buf);
3639 if (G_UNLIKELY (stream->need_process))
3640 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
3642 GST_BUFFER_TIMESTAMP (buf) = timestamp;
3643 GST_BUFFER_DURATION (buf) = duration;
3644 GST_BUFFER_OFFSET (buf) = -1;
3645 GST_BUFFER_OFFSET_END (buf) = -1;
3647 if (G_UNLIKELY (stream->padding)) {
3648 gst_buffer_resize (buf, stream->padding, -1);
3651 if (G_UNLIKELY (qtdemux->element_index)) {
3652 GstClockTime stream_time;
3655 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
3657 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
3658 GST_LOG_OBJECT (qtdemux,
3659 "adding association %" GST_TIME_FORMAT "-> %"
3660 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
3661 gst_index_add_association (qtdemux->element_index,
3663 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
3664 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
3665 GST_FORMAT_BYTES, byte_position, NULL);
3669 if (stream->need_clip)
3670 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
3672 if (G_UNLIKELY (buf == NULL))
3675 if (G_UNLIKELY (stream->discont)) {
3676 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3677 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3678 stream->discont = FALSE;
3682 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3684 GST_LOG_OBJECT (qtdemux,
3685 "Pushing buffer with time %" GST_TIME_FORMAT ", duration %"
3686 GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
3687 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
3689 ret = gst_pad_push (stream->pad, buf);
3695 static GstFlowReturn
3696 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
3698 GstFlowReturn ret = GST_FLOW_OK;
3699 GstBuffer *buf = NULL;
3700 QtDemuxStream *stream;
3703 guint64 timestamp = GST_CLOCK_TIME_NONE;
3704 guint64 duration = 0;
3705 gboolean keyframe = FALSE;
3710 gst_qtdemux_push_pending_newsegment (qtdemux);
3712 /* Figure out the next stream sample to output, min_time is expressed in
3713 * global time and runs over the edit list segments. */
3714 min_time = G_MAXUINT64;
3716 for (i = 0; i < qtdemux->n_streams; i++) {
3719 stream = qtdemux->streams[i];
3720 position = stream->time_position;
3722 /* position of -1 is EOS */
3723 if (position != -1 && position < min_time) {
3724 min_time = position;
3729 if (G_UNLIKELY (index == -1)) {
3730 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
3734 /* check for segment end */
3735 if (G_UNLIKELY (qtdemux->segment.stop != -1
3736 && qtdemux->segment.stop < min_time)) {
3737 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
3741 stream = qtdemux->streams[index];
3743 /* fetch info for the current sample of this stream */
3744 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
3745 &size, ×tamp, &duration, &keyframe)))
3748 GST_LOG_OBJECT (qtdemux,
3749 "pushing from stream %d, offset %" G_GUINT64_FORMAT
3750 ", size %d, timestamp=%" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
3751 index, offset, size, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
3753 /* hmm, empty sample, skip and move to next sample */
3754 if (G_UNLIKELY (size <= 0))
3757 /* last pushed sample was out of boundary, goto next sample */
3758 if (G_UNLIKELY (stream->last_ret == GST_FLOW_UNEXPECTED))
3761 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
3764 ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
3765 if (G_UNLIKELY (ret != GST_FLOW_OK))
3768 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
3769 timestamp, duration, keyframe, min_time, offset);
3772 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
3773 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
3774 * we have no more data for the pad to push */
3775 if (ret == GST_FLOW_UNEXPECTED)
3779 gst_qtdemux_advance_sample (qtdemux, stream);
3787 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
3788 ret = GST_FLOW_UNEXPECTED;
3793 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
3794 /* EOS will be raised if all are EOS */
3801 gst_qtdemux_loop (GstPad * pad)
3803 GstQTDemux *qtdemux;
3807 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
3809 cur_offset = qtdemux->offset;
3810 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
3811 cur_offset, qtdemux->state);
3813 switch (qtdemux->state) {
3814 case QTDEMUX_STATE_INITIAL:
3815 case QTDEMUX_STATE_HEADER:
3816 ret = gst_qtdemux_loop_state_header (qtdemux);
3818 case QTDEMUX_STATE_MOVIE:
3819 ret = gst_qtdemux_loop_state_movie (qtdemux);
3820 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_UNEXPECTED) {
3821 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
3829 /* if something went wrong, pause */
3830 if (ret != GST_FLOW_OK)
3834 gst_object_unref (qtdemux);
3840 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3841 (NULL), ("streaming stopped, invalid state"));
3842 gst_pad_pause_task (pad);
3843 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3848 const gchar *reason = gst_flow_get_name (ret);
3850 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
3852 gst_pad_pause_task (pad);
3854 /* fatal errors need special actions */
3856 if (ret == GST_FLOW_UNEXPECTED) {
3857 if (qtdemux->n_streams == 0) {
3858 /* we have no streams, post an error */
3859 gst_qtdemux_post_no_playable_stream_error (qtdemux);
3861 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3864 if ((stop = qtdemux->segment.stop) == -1)
3865 stop = qtdemux->segment.duration;
3867 if (qtdemux->segment.rate >= 0) {
3868 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
3869 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3870 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3871 GST_FORMAT_TIME, stop));
3873 /* For Reverse Playback */
3874 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
3875 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3876 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3877 GST_FORMAT_TIME, qtdemux->segment.start));
3880 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
3881 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3883 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
3884 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3885 (NULL), ("streaming stopped, reason %s", reason));
3886 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3895 * Returns the size of the first entry at the current offset.
3896 * If -1, there are none (which means EOS or empty file).
3899 next_entry_size (GstQTDemux * demux)
3901 QtDemuxStream *stream;
3904 guint64 smalloffs = (guint64) - 1;
3905 QtDemuxSample *sample;
3907 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
3910 for (i = 0; i < demux->n_streams; i++) {
3911 stream = demux->streams[i];
3913 if (stream->sample_index == -1)
3914 stream->sample_index = 0;
3916 if (stream->sample_index >= stream->n_samples) {
3917 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
3921 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
3922 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
3923 stream->sample_index);
3927 sample = &stream->samples[stream->sample_index];
3929 GST_LOG_OBJECT (demux,
3930 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3931 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
3932 sample->offset, sample->size);
3934 if (((smalloffs == -1)
3935 || (sample->offset < smalloffs)) && (sample->size)) {
3937 smalloffs = sample->offset;
3941 GST_LOG_OBJECT (demux,
3942 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
3943 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
3948 stream = demux->streams[smallidx];
3949 sample = &stream->samples[stream->sample_index];
3951 if (sample->offset >= demux->offset) {
3952 demux->todrop = sample->offset - demux->offset;
3953 return sample->size + demux->todrop;
3956 GST_DEBUG_OBJECT (demux,
3957 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
3962 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
3964 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
3966 gst_element_post_message (GST_ELEMENT_CAST (demux),
3967 gst_message_new_element (GST_OBJECT_CAST (demux),
3968 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
3972 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
3977 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
3980 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
3981 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
3982 GST_SEEK_TYPE_NONE, -1);
3984 res = gst_pad_push_event (demux->sinkpad, event);
3989 /* check for seekable upstream, above and beyond a mere query */
3991 gst_qtdemux_check_seekability (GstQTDemux * demux)
3994 gboolean seekable = FALSE;
3995 gint64 start = -1, stop = -1;
3997 if (demux->upstream_size)
4000 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4001 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4002 GST_DEBUG_OBJECT (demux, "seeking query failed");
4006 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4008 /* try harder to query upstream size if we didn't get it the first time */
4009 if (seekable && stop == -1) {
4010 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4011 gst_pad_query_peer_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4014 /* if upstream doesn't know the size, it's likely that it's not seekable in
4015 * practice even if it technically may be seekable */
4016 if (seekable && (start != 0 || stop <= start)) {
4017 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4022 gst_query_unref (query);
4024 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4025 G_GUINT64_FORMAT ")", seekable, start, stop);
4026 demux->upstream_seekable = seekable;
4027 demux->upstream_size = seekable ? stop : -1;
4030 /* FIXME, unverified after edit list updates */
4031 static GstFlowReturn
4032 gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
4035 GstFlowReturn ret = GST_FLOW_OK;
4037 demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad));
4039 gst_adapter_push (demux->adapter, inbuf);
4041 /* we never really mean to buffer that much */
4042 if (demux->neededbytes == -1)
4045 GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
4046 inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
4048 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4049 (ret == GST_FLOW_OK)) {
4051 GST_DEBUG_OBJECT (demux,
4052 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4053 demux->state, demux->neededbytes, demux->offset);
4055 switch (demux->state) {
4056 case QTDEMUX_STATE_INITIAL:{
4061 gst_qtdemux_check_seekability (demux);
4063 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4065 /* get fourcc/length, set neededbytes */
4066 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4068 gst_adapter_unmap (demux->adapter, 0);
4070 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4071 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4073 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4074 (_("This file is invalid and cannot be played.")),
4075 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4076 GST_FOURCC_ARGS (fourcc)));
4077 ret = GST_FLOW_ERROR;
4080 if (fourcc == FOURCC_mdat) {
4081 if (demux->n_streams > 0) {
4082 /* we have the headers, start playback */
4083 demux->state = QTDEMUX_STATE_MOVIE;
4084 demux->neededbytes = next_entry_size (demux);
4085 demux->mdatleft = size;
4087 /* Only post, event on pads is done after newsegment */
4088 qtdemux_post_global_tags (demux);
4091 /* no headers yet, try to get them */
4094 guint64 old, target;
4097 old = demux->offset;
4098 target = old + size;
4100 /* try to jump over the atom with a seek */
4101 /* only bother if it seems worth doing so,
4102 * and avoids possible upstream/server problems */
4103 if (demux->upstream_seekable &&
4104 demux->upstream_size > 4 * (1 << 20)) {
4105 res = qtdemux_seek_offset (demux, target);
4107 GST_DEBUG_OBJECT (demux, "skipping seek");
4112 GST_DEBUG_OBJECT (demux, "seek success");
4113 /* remember the offset fo the first mdat so we can seek back to it
4114 * after we have the headers */
4115 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4116 demux->first_mdat = old;
4117 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4120 /* seek worked, continue reading */
4121 demux->offset = target;
4122 demux->neededbytes = 16;
4123 demux->state = QTDEMUX_STATE_INITIAL;
4125 /* seek failed, need to buffer */
4126 demux->offset = old;
4127 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4128 /* there may be multiple mdat (or alike) buffers */
4130 if (demux->mdatbuffer)
4131 bs = gst_buffer_get_size (demux->mdatbuffer);
4134 if (size + bs > 10 * (1 << 20))
4136 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4137 demux->neededbytes = size;
4138 if (!demux->mdatbuffer)
4139 demux->mdatoffset = demux->offset;
4142 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4143 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4144 (_("This file is invalid and cannot be played.")),
4145 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4146 GST_FOURCC_ARGS (fourcc), size));
4147 ret = GST_FLOW_ERROR;
4150 /* this means we already started buffering and still no moov header,
4151 * let's continue buffering everything till we get moov */
4152 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
4154 demux->neededbytes = size;
4155 demux->state = QTDEMUX_STATE_HEADER;
4159 case QTDEMUX_STATE_HEADER:{
4163 GST_DEBUG_OBJECT (demux, "In header");
4165 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4167 /* parse the header */
4168 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4170 if (fourcc == FOURCC_moov) {
4171 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4173 demux->got_moov = TRUE;
4175 /* prepare newsegment to send when streaming actually starts */
4176 if (!demux->pending_newsegment)
4177 demux->pending_newsegment = gst_event_new_segment (&demux->segment);
4179 qtdemux_parse_moov (demux, data, demux->neededbytes);
4180 qtdemux_node_dump (demux, demux->moov_node);
4181 qtdemux_parse_tree (demux);
4182 qtdemux_expose_streams (demux);
4184 g_node_destroy (demux->moov_node);
4185 demux->moov_node = NULL;
4186 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4187 } else if (fourcc == FOURCC_moof) {
4188 if (demux->got_moov && demux->fragmented) {
4189 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4190 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4191 demux->offset, NULL)) {
4192 gst_adapter_unmap (demux->adapter, 0);
4193 ret = GST_FLOW_ERROR;
4197 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4199 } else if (fourcc == FOURCC_ftyp) {
4200 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4201 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4202 } else if (fourcc == FOURCC_uuid) {
4203 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4204 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4206 GST_WARNING_OBJECT (demux,
4207 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4208 GST_FOURCC_ARGS (fourcc));
4209 /* Let's jump that one and go back to initial state */
4211 gst_adapter_unmap (demux->adapter, 0);
4214 if (demux->mdatbuffer && demux->n_streams) {
4215 /* the mdat was before the header */
4216 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4217 demux->n_streams, demux->mdatbuffer);
4218 /* restore our adapter/offset view of things with upstream;
4219 * put preceding buffered data ahead of current moov data.
4220 * This should also handle evil mdat, moov, mdat cases and alike */
4221 gst_adapter_clear (demux->adapter);
4222 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4223 demux->mdatbuffer = NULL;
4224 demux->offset = demux->mdatoffset;
4225 demux->neededbytes = next_entry_size (demux);
4226 demux->state = QTDEMUX_STATE_MOVIE;
4227 demux->mdatleft = gst_adapter_available (demux->adapter);
4229 /* Only post, event on pads is done after newsegment */
4230 qtdemux_post_global_tags (demux);
4233 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4234 gst_adapter_flush (demux->adapter, demux->neededbytes);
4236 if (demux->got_moov && demux->first_mdat != -1) {
4239 /* we need to seek back */
4240 res = qtdemux_seek_offset (demux, demux->first_mdat);
4242 demux->offset = demux->first_mdat;
4244 GST_DEBUG_OBJECT (demux, "Seek back failed");
4247 demux->offset += demux->neededbytes;
4249 demux->neededbytes = 16;
4250 demux->state = QTDEMUX_STATE_INITIAL;
4255 case QTDEMUX_STATE_BUFFER_MDAT:{
4259 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4261 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4262 gst_buffer_extract (buf, 0, fourcc, 4);
4263 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4264 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
4265 if (demux->mdatbuffer)
4266 demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
4268 demux->mdatbuffer = buf;
4269 demux->offset += demux->neededbytes;
4270 demux->neededbytes = 16;
4271 demux->state = QTDEMUX_STATE_INITIAL;
4272 gst_qtdemux_post_progress (demux, 1, 1);
4276 case QTDEMUX_STATE_MOVIE:{
4278 QtDemuxStream *stream = NULL;
4279 QtDemuxSample *sample;
4281 guint64 timestamp, duration, position;
4284 GST_DEBUG_OBJECT (demux,
4285 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4287 if (demux->fragmented) {
4288 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4290 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4291 /* if needed data starts within this atom,
4292 * then it should not exceed this atom */
4293 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4294 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4295 (_("This file is invalid and cannot be played.")),
4296 ("sample data crosses atom boundary"));
4297 ret = GST_FLOW_ERROR;
4300 demux->mdatleft -= demux->neededbytes;
4302 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4303 /* so we are dropping more than left in this atom */
4304 demux->todrop -= demux->mdatleft;
4305 demux->neededbytes -= demux->mdatleft;
4306 demux->mdatleft = 0;
4307 /* need to resume atom parsing so we do not miss any other pieces */
4308 demux->state = QTDEMUX_STATE_INITIAL;
4309 demux->neededbytes = 16;
4314 if (demux->todrop) {
4315 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4316 gst_adapter_flush (demux->adapter, demux->todrop);
4317 demux->neededbytes -= demux->todrop;
4318 demux->offset += demux->todrop;
4322 /* initial newsegment sent here after having added pads,
4323 * possible others in sink_event */
4324 if (G_UNLIKELY (demux->pending_newsegment)) {
4325 gst_qtdemux_push_event (demux, demux->pending_newsegment);
4326 demux->pending_newsegment = NULL;
4327 /* clear to send tags on all streams */
4328 for (i = 0; i < demux->n_streams; i++) {
4329 gst_qtdemux_push_tags (demux, demux->streams[i]);
4333 /* Figure out which stream this is packet belongs to */
4334 for (i = 0; i < demux->n_streams; i++) {
4335 stream = demux->streams[i];
4336 if (stream->sample_index >= stream->n_samples)
4338 GST_LOG_OBJECT (demux,
4339 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4340 " / size:%d)", i, stream->sample_index,
4341 stream->samples[stream->sample_index].offset,
4342 stream->samples[stream->sample_index].size);
4344 if (stream->samples[stream->sample_index].offset == demux->offset)
4348 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4349 goto unknown_stream;
4351 /* Put data in a buffer, set timestamps, caps, ... */
4352 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4353 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4354 GST_FOURCC_ARGS (stream->fourcc));
4356 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4358 sample = &stream->samples[stream->sample_index];
4360 position = QTSAMPLE_DTS (stream, sample);
4361 timestamp = QTSAMPLE_PTS (stream, sample);
4362 duration = QTSAMPLE_DUR_DTS (stream, sample, position);
4363 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4365 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4366 timestamp, duration, keyframe, position, demux->offset);
4369 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4371 stream->sample_index++;
4373 /* update current offset and figure out size of next buffer */
4374 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4375 demux->offset, demux->neededbytes);
4376 demux->offset += demux->neededbytes;
4377 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4380 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4381 if (demux->fragmented) {
4382 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4383 /* there may be more to follow, only finish this atom */
4384 demux->todrop = demux->mdatleft;
4385 demux->neededbytes = demux->todrop;
4397 /* when buffering movie data, at least show user something is happening */
4398 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4399 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4400 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4401 demux->neededbytes);
4404 gst_object_unref (demux);
4411 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4412 ret = GST_FLOW_ERROR;
4417 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4418 ret = GST_FLOW_UNEXPECTED;
4423 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4424 (NULL), ("qtdemuxer invalid state %d", demux->state));
4425 ret = GST_FLOW_ERROR;
4430 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4431 (NULL), ("no 'moov' atom within the first 10 MB"));
4432 ret = GST_FLOW_ERROR;
4438 qtdemux_sink_activate (GstPad * sinkpad)
4443 query = gst_query_new_scheduling ();
4445 if (!gst_pad_peer_query (sinkpad, query)) {
4446 gst_query_unref (query);
4450 gst_query_parse_scheduling (query, &pull_mode, NULL, NULL, NULL, NULL, NULL);
4451 gst_query_unref (query);
4456 GST_DEBUG_OBJECT (sinkpad, "activating pull");
4457 return gst_pad_activate_pull (sinkpad, TRUE);
4461 GST_DEBUG_OBJECT (sinkpad, "activating push");
4462 return gst_pad_activate_push (sinkpad, TRUE);
4467 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
4469 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
4472 demux->pullbased = TRUE;
4473 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4476 return gst_pad_stop_task (sinkpad);
4481 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
4483 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
4485 demux->pullbased = FALSE;
4492 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4494 return g_malloc (items * size);
4498 qtdemux_zfree (void *opaque, void *addr)
4504 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4510 z = g_new0 (z_stream, 1);
4511 z->zalloc = qtdemux_zalloc;
4512 z->zfree = qtdemux_zfree;
4515 z->next_in = z_buffer;
4516 z->avail_in = z_length;
4518 buffer = (guint8 *) g_malloc (length);
4519 ret = inflateInit (z);
4520 while (z->avail_in > 0) {
4521 if (z->avail_out == 0) {
4523 buffer = (guint8 *) g_realloc (buffer, length);
4524 z->next_out = buffer + z->total_out;
4525 z->avail_out = 1024;
4527 ret = inflate (z, Z_SYNC_FLUSH);
4531 if (ret != Z_STREAM_END) {
4532 g_warning ("inflate() returned %d", ret);
4538 #endif /* HAVE_ZLIB */
4541 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4545 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4547 /* counts as header data */
4548 qtdemux->header_size += length;
4550 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4551 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4553 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4559 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4560 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4561 if (dcom == NULL || cmvd == NULL)
4562 goto invalid_compression;
4564 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4567 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4568 guint uncompressed_length;
4569 guint compressed_length;
4572 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4573 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4574 GST_LOG ("length = %u", uncompressed_length);
4577 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4578 compressed_length, uncompressed_length);
4580 qtdemux->moov_node_compressed = qtdemux->moov_node;
4581 qtdemux->moov_node = g_node_new (buf);
4583 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4584 uncompressed_length);
4587 #endif /* HAVE_ZLIB */
4589 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4590 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
4597 invalid_compression:
4599 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
4605 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
4608 while (G_UNLIKELY (buf < end)) {
4612 if (G_UNLIKELY (buf + 4 > end)) {
4613 GST_LOG_OBJECT (qtdemux, "buffer overrun");
4616 len = QT_UINT32 (buf);
4617 if (G_UNLIKELY (len == 0)) {
4618 GST_LOG_OBJECT (qtdemux, "empty container");
4621 if (G_UNLIKELY (len < 8)) {
4622 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
4625 if (G_UNLIKELY (len > (end - buf))) {
4626 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
4627 (gint) (end - buf));
4631 child = g_node_new ((guint8 *) buf);
4632 g_node_append (node, child);
4633 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
4634 qtdemux_parse_node (qtdemux, child, buf, len);
4642 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
4645 int len = QT_UINT32 (xdxt->data);
4646 guint8 *buf = xdxt->data;
4647 guint8 *end = buf + len;
4650 /* skip size and type */
4658 size = QT_UINT32 (buf);
4659 type = QT_FOURCC (buf + 4);
4661 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
4663 if (buf + size > end || size <= 0)
4669 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
4670 GST_FOURCC_ARGS (type));
4674 buffer = gst_buffer_new_and_alloc (size);
4675 _gst_buffer_copy_into_mem (buffer, buf, 0, size);
4676 stream->buffers = g_slist_append (stream->buffers, buffer);
4677 GST_LOG_OBJECT (qtdemux, "parsing theora header");
4680 buffer = gst_buffer_new_and_alloc (size);
4681 _gst_buffer_copy_into_mem (buffer, buf, 0, size);
4682 stream->buffers = g_slist_append (stream->buffers, buffer);
4683 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
4686 buffer = gst_buffer_new_and_alloc (size);
4687 _gst_buffer_copy_into_mem (buffer, buf, 0, size);
4688 stream->buffers = g_slist_append (stream->buffers, buffer);
4689 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
4692 GST_WARNING_OBJECT (qtdemux,
4693 "unknown theora cookie %" GST_FOURCC_FORMAT,
4694 GST_FOURCC_ARGS (type));
4703 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
4707 guint32 node_length = 0;
4708 const QtNodeType *type;
4711 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
4713 if (G_UNLIKELY (length < 8))
4714 goto not_enough_data;
4716 node_length = QT_UINT32 (buffer);
4717 fourcc = QT_FOURCC (buffer + 4);
4719 /* ignore empty nodes */
4720 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
4723 type = qtdemux_type_get (fourcc);
4725 end = buffer + length;
4727 GST_LOG_OBJECT (qtdemux,
4728 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
4729 GST_FOURCC_ARGS (fourcc), node_length, type->name);
4731 if (node_length > length)
4732 goto broken_atom_size;
4734 if (type->flags & QT_FLAG_CONTAINER) {
4735 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
4740 if (node_length < 20) {
4741 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
4744 GST_DEBUG_OBJECT (qtdemux,
4745 "parsing stsd (sample table, sample description) atom");
4746 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
4756 /* also read alac (or whatever) in stead of mp4a in the following,
4757 * since a similar layout is used in other cases as well */
4758 if (fourcc == FOURCC_mp4a)
4763 /* There are two things we might encounter here: a true mp4a atom, and
4764 an mp4a entry in an stsd atom. The latter is what we're interested
4765 in, and it looks like an atom, but isn't really one. The true mp4a
4766 atom is short, so we detect it based on length here. */
4767 if (length < min_size) {
4768 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
4769 GST_FOURCC_ARGS (fourcc));
4773 /* 'version' here is the sound sample description version. Types 0 and
4774 1 are documented in the QTFF reference, but type 2 is not: it's
4775 described in Apple header files instead (struct SoundDescriptionV2
4777 version = QT_UINT16 (buffer + 16);
4779 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
4780 GST_FOURCC_ARGS (fourcc), version);
4782 /* parse any esds descriptors */
4794 GST_WARNING_OBJECT (qtdemux,
4795 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
4796 GST_FOURCC_ARGS (fourcc), version);
4801 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4813 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
4814 GST_FOURCC_ARGS (fourcc));
4815 version = QT_UINT32 (buffer + 16);
4816 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
4817 if (1 || version == 0x00000000) {
4818 buf = buffer + 0x32;
4820 /* FIXME Quicktime uses PASCAL string while
4821 * the iso format uses C strings. Check the file
4822 * type before attempting to parse the string here. */
4823 tlen = QT_UINT8 (buf);
4824 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
4826 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
4827 /* the string has a reserved space of 32 bytes so skip
4828 * the remaining 31 */
4830 buf += 4; /* and 4 bytes reserved */
4832 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
4834 qtdemux_parse_container (qtdemux, node, buf, end);
4840 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
4841 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
4846 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
4851 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
4852 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
4860 version = QT_UINT32 (buffer + 12);
4861 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
4868 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
4873 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4878 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
4882 if (!strcmp (type->name, "unknown"))
4883 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
4887 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
4888 GST_FOURCC_ARGS (fourcc));
4894 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4895 (_("This file is corrupt and cannot be played.")),
4896 ("Not enough data for an atom header, got only %u bytes", length));
4901 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4902 (_("This file is corrupt and cannot be played.")),
4903 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
4904 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
4911 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
4915 guint32 child_fourcc;
4917 for (child = g_node_first_child (node); child;
4918 child = g_node_next_sibling (child)) {
4919 buffer = (guint8 *) child->data;
4921 child_fourcc = QT_FOURCC (buffer + 4);
4923 if (G_UNLIKELY (child_fourcc == fourcc)) {
4931 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
4932 GstByteReader * parser)
4936 guint32 child_fourcc, child_len;
4938 for (child = g_node_first_child (node); child;
4939 child = g_node_next_sibling (child)) {
4940 buffer = (guint8 *) child->data;
4942 child_len = QT_UINT32 (buffer);
4943 child_fourcc = QT_FOURCC (buffer + 4);
4945 if (G_UNLIKELY (child_fourcc == fourcc)) {
4946 if (G_UNLIKELY (child_len < (4 + 4)))
4948 /* FIXME: must verify if atom length < parent atom length */
4949 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4957 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
4958 GstByteReader * parser)
4962 guint32 child_fourcc, child_len;
4964 for (child = g_node_next_sibling (node); child;
4965 child = g_node_next_sibling (child)) {
4966 buffer = (guint8 *) child->data;
4968 child_fourcc = QT_FOURCC (buffer + 4);
4970 if (child_fourcc == fourcc) {
4972 child_len = QT_UINT32 (buffer);
4973 if (G_UNLIKELY (child_len < (4 + 4)))
4975 /* FIXME: must verify if atom length < parent atom length */
4976 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4985 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
4987 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
4991 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
4992 QtDemuxStream * stream, GstTagList * list)
4994 /* consistent default for push based mode */
4995 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
4997 if (stream->subtype == FOURCC_vide) {
4998 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5001 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5004 /* fps is calculated base on the duration of the first frames since
5005 * qt does not have a fixed framerate. */
5006 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
5011 stream->fps_n = stream->timescale;
5012 if (stream->min_duration == 0)
5015 stream->fps_d = stream->min_duration;
5020 gint depth, palette_count;
5021 const guint32 *palette_data = NULL;
5023 gst_caps_set_simple (stream->caps,
5024 "width", G_TYPE_INT, stream->width,
5025 "height", G_TYPE_INT, stream->height,
5026 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5028 /* calculate pixel-aspect-ratio using display width and height */
5029 GST_DEBUG_OBJECT (qtdemux,
5030 "video size %dx%d, target display size %dx%d", stream->width,
5031 stream->height, stream->display_width, stream->display_height);
5033 if (stream->display_width > 0 && stream->display_height > 0 &&
5034 stream->width > 0 && stream->height > 0) {
5037 /* calculate the pixel aspect ratio using the display and pixel w/h */
5038 n = stream->display_width * stream->height;
5039 d = stream->display_height * stream->width;
5042 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5043 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5044 GST_TYPE_FRACTION, n, d, NULL);
5047 /* qt file might have pasp atom */
5048 if (stream->par_w > 0 && stream->par_h > 0) {
5049 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5050 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5051 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5054 depth = stream->bits_per_sample;
5056 /* more than 32 bits means grayscale */
5057 gray = (depth > 32);
5058 /* low 32 bits specify the depth */
5061 /* different number of palette entries is determined by depth. */
5063 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
5064 palette_count = (1 << depth);
5066 switch (palette_count) {
5070 palette_data = ff_qt_default_palette_2;
5073 palette_data = ff_qt_default_palette_4;
5077 palette_data = ff_qt_grayscale_palette_16;
5079 palette_data = ff_qt_default_palette_16;
5083 palette_data = ff_qt_grayscale_palette_256;
5085 palette_data = ff_qt_default_palette_256;
5088 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5089 (_("The video in this file might not play correctly.")),
5090 ("unsupported palette depth %d", depth));
5096 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5097 * don't free any of the buffer data. */
5098 palette = _gst_buffer_new_wrapped ((gpointer) palette_data,
5099 palette_count, NULL);
5101 gst_caps_set_simple (stream->caps, "palette_data",
5102 GST_TYPE_BUFFER, palette, NULL);
5103 gst_buffer_unref (palette);
5104 } else if (palette_count != 0) {
5105 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5106 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5108 gst_object_unref (stream->pad);
5112 qtdemux->n_video_streams++;
5113 } else if (stream->subtype == FOURCC_soun) {
5114 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
5117 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5120 gst_caps_set_simple (stream->caps,
5121 "rate", G_TYPE_INT, (int) stream->rate,
5122 "channels", G_TYPE_INT, stream->n_channels, NULL);
5124 qtdemux->n_audio_streams++;
5125 } else if (stream->subtype == FOURCC_strm) {
5126 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5127 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
5128 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
5131 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5133 qtdemux->n_sub_streams++;
5135 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5140 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5142 gst_pad_use_fixed_caps (stream->pad);
5143 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5144 gst_pad_set_query_type_function (stream->pad,
5145 gst_qtdemux_get_src_query_types);
5146 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5148 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5149 gst_pad_set_caps (stream->pad, stream->caps);
5151 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5152 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5153 gst_pad_set_active (stream->pad, TRUE);
5154 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5155 if (stream->pending_tags)
5156 gst_tag_list_free (stream->pending_tags);
5157 stream->pending_tags = list;
5158 /* global tags go on each pad anyway */
5159 stream->send_global_tags = TRUE;
5165 /* find next atom with @fourcc starting at @offset */
5166 static GstFlowReturn
5167 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5168 guint64 * length, guint32 fourcc)
5174 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5175 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5181 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5182 if (G_UNLIKELY (ret != GST_FLOW_OK))
5184 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
5186 ret = GST_FLOW_UNEXPECTED;
5187 gst_buffer_unref (buf);
5190 bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
5191 extract_initial_length_and_fourcc (bdata, 16, length, &lfourcc);
5192 gst_buffer_unmap (buf, bdata, bsize);
5193 gst_buffer_unref (buf);
5195 if (G_UNLIKELY (*length == 0)) {
5196 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5197 ret = GST_FLOW_ERROR;
5201 if (lfourcc == fourcc) {
5202 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5206 GST_LOG_OBJECT (qtdemux,
5207 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5208 GST_FOURCC_ARGS (fourcc), *offset);
5217 /* might simply have had last one */
5218 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5223 /* should only do something in pull mode */
5224 /* call with OBJECT lock */
5225 static GstFlowReturn
5226 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5228 guint64 length, offset;
5229 GstBuffer *buf = NULL;
5230 GstFlowReturn ret = GST_FLOW_OK;
5231 GstFlowReturn res = GST_FLOW_OK;
5235 offset = qtdemux->moof_offset;
5236 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5239 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5240 return GST_FLOW_UNEXPECTED;
5243 /* best not do pull etc with lock held */
5244 GST_OBJECT_UNLOCK (qtdemux);
5246 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5247 if (ret != GST_FLOW_OK)
5250 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5251 if (G_UNLIKELY (ret != GST_FLOW_OK))
5253 bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
5254 if (!qtdemux_parse_moof (qtdemux, bdata, bsize, offset, NULL)) {
5255 gst_buffer_unmap (buf, bdata, bsize);
5256 gst_buffer_unref (buf);
5261 gst_buffer_unmap (buf, bdata, bsize);
5262 gst_buffer_unref (buf);
5266 /* look for next moof */
5267 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5268 if (G_UNLIKELY (ret != GST_FLOW_OK))
5272 GST_OBJECT_LOCK (qtdemux);
5274 qtdemux->moof_offset = offset;
5280 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5282 res = GST_FLOW_ERROR;
5287 /* maybe upstream temporarily flushing */
5288 if (ret != GST_FLOW_WRONG_STATE) {
5289 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5292 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5293 /* resume at current position next time */
5300 /* initialise bytereaders for stbl sub-atoms */
5302 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5304 stream->stbl_index = -1; /* no samples have yet been parsed */
5306 /* time-to-sample atom */
5307 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5310 /* copy atom data into a new buffer for later use */
5311 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5313 /* skip version + flags */
5314 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5315 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5317 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5319 /* make sure there's enough data */
5320 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 2 * 4))
5323 /* sync sample atom */
5324 stream->stps_present = FALSE;
5325 if ((stream->stss_present =
5326 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5327 &stream->stss) ? TRUE : FALSE) == TRUE) {
5328 /* copy atom data into a new buffer for later use */
5329 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5331 /* skip version + flags */
5332 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5333 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5336 if (stream->n_sample_syncs) {
5337 /* make sure there's enough data */
5338 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5342 /* partial sync sample atom */
5343 if ((stream->stps_present =
5344 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5345 &stream->stps) ? TRUE : FALSE) == TRUE) {
5346 /* copy atom data into a new buffer for later use */
5347 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5349 /* skip version + flags */
5350 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5351 !gst_byte_reader_get_uint32_be (&stream->stps,
5352 &stream->n_sample_partial_syncs))
5355 /* if there are no entries, the stss table contains the real
5357 if (stream->n_sample_partial_syncs) {
5358 /* make sure there's enough data */
5359 if (!qt_atom_parser_has_chunks (&stream->stps,
5360 stream->n_sample_partial_syncs, 4))
5367 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5370 /* copy atom data into a new buffer for later use */
5371 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5373 /* skip version + flags */
5374 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5375 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5378 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5381 if (!stream->n_samples)
5384 /* sample-to-chunk atom */
5385 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5388 /* copy atom data into a new buffer for later use */
5389 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5391 /* skip version + flags */
5392 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5393 !gst_byte_reader_get_uint32_be (&stream->stsc,
5394 &stream->n_samples_per_chunk))
5397 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5398 stream->n_samples_per_chunk);
5400 /* make sure there's enough data */
5401 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5407 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5408 stream->co_size = sizeof (guint32);
5409 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5411 stream->co_size = sizeof (guint64);
5415 /* copy atom data into a new buffer for later use */
5416 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5418 /* skip version + flags */
5419 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5422 /* chunks_are_chunks == 0 means treat chunks as samples */
5423 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5424 if (stream->chunks_are_chunks) {
5425 /* skip number of entries */
5426 if (!gst_byte_reader_skip (&stream->stco, 4))
5429 /* make sure there are enough data in the stsz atom */
5430 if (!stream->sample_size) {
5431 /* different sizes for each sample */
5432 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5436 /* treat chunks as samples */
5437 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5441 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5442 stream->n_samples, (guint) sizeof (QtDemuxSample),
5443 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5445 if (stream->n_samples >=
5446 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5447 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5448 "be larger than %uMB (broken file?)", stream->n_samples,
5449 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5453 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5454 if (!stream->samples) {
5455 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5461 /* composition time-to-sample */
5462 if ((stream->ctts_present =
5463 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5464 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5465 /* copy atom data into a new buffer for later use */
5466 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5468 /* skip version + flags */
5469 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5470 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5471 &stream->n_composition_times))
5474 /* make sure there's enough data */
5475 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5484 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5485 (_("This file is corrupt and cannot be played.")), (NULL));
5490 gst_qtdemux_stbl_free (stream);
5491 if (!qtdemux->fragmented) {
5492 /* not quite good */
5493 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5496 /* may pick up samples elsewhere */
5502 /* collect samples from the next sample to be parsed up to sample @n for @stream
5503 * by reading the info from @stbl
5505 * This code can be executed from both the streaming thread and the seeking
5506 * thread so it takes the object lock to protect itself
5509 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
5512 QtDemuxSample *samples, *first, *cur, *last;
5513 guint32 n_samples_per_chunk;
5516 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
5517 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
5518 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
5520 n_samples = stream->n_samples;
5523 goto out_of_samples;
5525 GST_OBJECT_LOCK (qtdemux);
5526 if (n <= stream->stbl_index)
5527 goto already_parsed;
5529 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
5531 if (!stream->stsz.data) {
5532 /* so we already parsed and passed all the moov samples;
5533 * onto fragmented ones */
5534 g_assert (qtdemux->fragmented);
5538 /* pointer to the sample table */
5539 samples = stream->samples;
5541 /* starts from -1, moves to the next sample index to parse */
5542 stream->stbl_index++;
5544 /* keep track of the first and last sample to fill */
5545 first = &samples[stream->stbl_index];
5548 if (stream->chunks_are_chunks) {
5549 /* set the sample sizes */
5550 if (stream->sample_size == 0) {
5551 /* different sizes for each sample */
5552 for (cur = first; cur <= last; cur++) {
5553 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
5554 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
5555 (guint) (cur - samples), cur->size);
5558 /* samples have the same size */
5559 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
5560 for (cur = first; cur <= last; cur++)
5561 cur->size = stream->sample_size;
5565 n_samples_per_chunk = stream->n_samples_per_chunk;
5568 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
5571 if (stream->stsc_chunk_index >= stream->last_chunk
5572 || stream->stsc_chunk_index < stream->first_chunk) {
5573 stream->first_chunk =
5574 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5575 stream->samples_per_chunk =
5576 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5577 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
5579 /* chunk numbers are counted from 1 it seems */
5580 if (G_UNLIKELY (stream->first_chunk == 0))
5583 --stream->first_chunk;
5585 /* the last chunk of each entry is calculated by taking the first chunk
5586 * of the next entry; except if there is no next, where we fake it with
5588 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
5589 stream->last_chunk = G_MAXUINT32;
5591 stream->last_chunk =
5592 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
5593 if (G_UNLIKELY (stream->last_chunk == 0))
5596 --stream->last_chunk;
5599 GST_LOG_OBJECT (qtdemux,
5600 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
5601 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
5603 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
5606 if (stream->last_chunk != G_MAXUINT32) {
5607 if (!qt_atom_parser_peek_sub (&stream->stco,
5608 stream->first_chunk * stream->co_size,
5609 (stream->last_chunk - stream->first_chunk) * stream->co_size,
5614 stream->co_chunk = stream->stco;
5615 if (!gst_byte_reader_skip (&stream->co_chunk,
5616 stream->first_chunk * stream->co_size))
5620 stream->stsc_chunk_index = stream->first_chunk;
5623 last_chunk = stream->last_chunk;
5625 if (stream->chunks_are_chunks) {
5626 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5627 guint32 samples_per_chunk;
5628 guint64 chunk_offset;
5630 if (!stream->stsc_sample_index
5631 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
5632 &stream->chunk_offset))
5635 samples_per_chunk = stream->samples_per_chunk;
5636 chunk_offset = stream->chunk_offset;
5638 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
5639 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
5640 G_GUINT64_FORMAT, (guint) (cur - samples), stream->chunk_offset);
5642 cur->offset = chunk_offset;
5643 chunk_offset += cur->size;
5646 if (G_UNLIKELY (cur > last)) {
5648 stream->stsc_sample_index = k + 1;
5649 stream->chunk_offset = chunk_offset;
5650 stream->stsc_chunk_index = j;
5654 stream->stsc_sample_index = 0;
5656 stream->stsc_chunk_index = j;
5658 cur = &samples[stream->stsc_chunk_index];
5660 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5663 stream->stsc_chunk_index = j;
5668 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
5671 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
5672 "%" G_GUINT64_FORMAT, j, cur->offset);
5674 if (stream->samples_per_frame * stream->bytes_per_frame) {
5676 (stream->samples_per_chunk * stream->n_channels) /
5677 stream->samples_per_frame * stream->bytes_per_frame;
5679 cur->size = stream->samples_per_chunk;
5682 GST_DEBUG_OBJECT (qtdemux,
5683 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
5684 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
5685 GST_SECOND, stream->timescale)), cur->size);
5687 cur->timestamp = stream->stco_sample_index;
5688 cur->duration = stream->samples_per_chunk;
5689 cur->keyframe = TRUE;
5692 stream->stco_sample_index += stream->samples_per_chunk;
5694 stream->stsc_chunk_index = j;
5696 stream->stsc_index++;
5699 if (!stream->chunks_are_chunks)
5703 guint32 n_sample_times;
5705 n_sample_times = stream->n_sample_times;
5708 for (i = stream->stts_index; i < n_sample_times; i++) {
5709 guint32 stts_samples;
5710 gint32 stts_duration;
5713 if (stream->stts_sample_index >= stream->stts_samples
5714 || !stream->stts_sample_index) {
5716 stream->stts_samples =
5717 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5718 stream->stts_duration =
5719 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5721 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
5722 i, stream->stts_samples, stream->stts_duration);
5724 stream->stts_sample_index = 0;
5727 stts_samples = stream->stts_samples;
5728 stts_duration = stream->stts_duration;
5729 stts_time = stream->stts_time;
5731 for (j = stream->stts_sample_index; j < stts_samples; j++) {
5732 GST_DEBUG_OBJECT (qtdemux,
5733 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
5734 (guint) (cur - samples), j,
5735 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
5736 stream->timescale)));
5738 cur->timestamp = stts_time;
5739 cur->duration = stts_duration;
5741 /* avoid 32-bit wrap-around,
5742 * but still mind possible 'negative' duration */
5743 stts_time += (gint64) stts_duration;
5746 if (G_UNLIKELY (cur > last)) {
5748 stream->stts_time = stts_time;
5749 stream->stts_sample_index = j + 1;
5753 stream->stts_sample_index = 0;
5754 stream->stts_time = stts_time;
5755 stream->stts_index++;
5757 /* fill up empty timestamps with the last timestamp, this can happen when
5758 * the last samples do not decode and so we don't have timestamps for them.
5759 * We however look at the last timestamp to estimate the track length so we
5760 * need something in here. */
5761 for (; cur < last; cur++) {
5762 GST_DEBUG_OBJECT (qtdemux,
5763 "fill sample %d: timestamp %" GST_TIME_FORMAT,
5764 (guint) (cur - samples),
5765 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
5766 stream->timescale)));
5767 cur->timestamp = stream->stts_time;
5773 /* sample sync, can be NULL */
5774 if (stream->stss_present == TRUE) {
5775 guint32 n_sample_syncs;
5777 n_sample_syncs = stream->n_sample_syncs;
5779 if (!n_sample_syncs) {
5780 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
5781 stream->all_keyframe = TRUE;
5783 for (i = stream->stss_index; i < n_sample_syncs; i++) {
5784 /* note that the first sample is index 1, not 0 */
5787 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
5789 if (G_LIKELY (index > 0 && index <= n_samples)) {
5791 samples[index].keyframe = TRUE;
5792 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5793 /* and exit if we have enough samples */
5794 if (G_UNLIKELY (index >= n)) {
5801 stream->stss_index = i;
5804 /* stps marks partial sync frames like open GOP I-Frames */
5805 if (stream->stps_present == TRUE) {
5806 guint32 n_sample_partial_syncs;
5808 n_sample_partial_syncs = stream->n_sample_partial_syncs;
5810 /* if there are no entries, the stss table contains the real
5812 if (n_sample_partial_syncs) {
5813 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
5814 /* note that the first sample is index 1, not 0 */
5817 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
5819 if (G_LIKELY (index > 0 && index <= n_samples)) {
5821 samples[index].keyframe = TRUE;
5822 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5823 /* and exit if we have enough samples */
5824 if (G_UNLIKELY (index >= n)) {
5831 stream->stps_index = i;
5835 /* no stss, all samples are keyframes */
5836 stream->all_keyframe = TRUE;
5837 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
5842 /* composition time to sample */
5843 if (stream->ctts_present == TRUE) {
5844 guint32 n_composition_times;
5846 gint32 ctts_soffset;
5848 /* Fill in the pts_offsets */
5850 n_composition_times = stream->n_composition_times;
5852 for (i = stream->ctts_index; i < n_composition_times; i++) {
5853 if (stream->ctts_sample_index >= stream->ctts_count
5854 || !stream->ctts_sample_index) {
5855 stream->ctts_count =
5856 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
5857 stream->ctts_soffset =
5858 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
5859 stream->ctts_sample_index = 0;
5862 ctts_count = stream->ctts_count;
5863 ctts_soffset = stream->ctts_soffset;
5865 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
5866 cur->pts_offset = ctts_soffset;
5869 if (G_UNLIKELY (cur > last)) {
5871 stream->ctts_sample_index = j + 1;
5875 stream->ctts_sample_index = 0;
5876 stream->ctts_index++;
5880 stream->stbl_index = n;
5881 /* if index has been completely parsed, free data that is no-longer needed */
5882 if (n + 1 == stream->n_samples) {
5883 gst_qtdemux_stbl_free (stream);
5884 GST_DEBUG_OBJECT (qtdemux,
5885 "parsed all available samples; checking for more");
5886 while (n + 1 == stream->n_samples)
5887 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
5890 GST_OBJECT_UNLOCK (qtdemux);
5897 GST_LOG_OBJECT (qtdemux,
5898 "Tried to parse up to sample %u but this sample has already been parsed",
5900 /* if fragmented, there may be more */
5901 if (qtdemux->fragmented && n == stream->stbl_index)
5903 GST_OBJECT_UNLOCK (qtdemux);
5909 GST_LOG_OBJECT (qtdemux,
5910 "Tried to parse up to sample %u but there are only %u samples", n + 1,
5912 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5913 (_("This file is corrupt and cannot be played.")), (NULL));
5918 GST_OBJECT_UNLOCK (qtdemux);
5919 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5920 (_("This file is corrupt and cannot be played.")), (NULL));
5925 /* collect all segment info for @stream.
5928 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
5933 /* parse and prepare segment info from the edit list */
5934 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
5935 stream->n_segments = 0;
5936 stream->segments = NULL;
5937 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
5941 guint64 time, stime;
5944 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
5945 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
5948 buffer = elst->data;
5950 n_segments = QT_UINT32 (buffer + 12);
5952 /* we might allocate a bit too much, at least allocate 1 segment */
5953 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
5955 /* segments always start from 0 */
5959 for (i = 0; i < n_segments; i++) {
5962 QtDemuxSegment *segment;
5965 media_time = QT_UINT32 (buffer + 20 + i * 12);
5967 /* -1 media time is an empty segment, just ignore it */
5968 if (media_time == G_MAXUINT32)
5971 duration = QT_UINT32 (buffer + 16 + i * 12);
5973 segment = &stream->segments[count++];
5975 /* time and duration expressed in global timescale */
5976 segment->time = stime;
5977 /* add non scaled values so we don't cause roundoff errors */
5979 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
5980 segment->stop_time = stime;
5981 segment->duration = stime - segment->time;
5982 /* media_time expressed in stream timescale */
5983 segment->media_start =
5984 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
5985 segment->media_stop = segment->media_start + segment->duration;
5986 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
5988 if (rate_int <= 1) {
5989 /* 0 is not allowed, some programs write 1 instead of the floating point
5991 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
5995 segment->rate = rate_int / 65536.0;
5998 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
5999 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
6000 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
6001 GST_TIME_ARGS (segment->duration),
6002 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
6004 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
6005 stream->n_segments = count;
6009 /* push based does not handle segments, so act accordingly here,
6010 * and warn if applicable */
6011 if (!qtdemux->pullbased) {
6012 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
6013 /* remove and use default one below, we stream like it anyway */
6014 g_free (stream->segments);
6015 stream->segments = NULL;
6016 stream->n_segments = 0;
6019 /* no segments, create one to play the complete trak */
6020 if (stream->n_segments == 0) {
6021 GstClockTime stream_duration =
6022 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6024 if (stream->segments == NULL)
6025 stream->segments = g_new (QtDemuxSegment, 1);
6027 /* represent unknown our way */
6028 if (stream_duration == 0)
6029 stream_duration = -1;
6031 stream->segments[0].time = 0;
6032 stream->segments[0].stop_time = stream_duration;
6033 stream->segments[0].duration = stream_duration;
6034 stream->segments[0].media_start = 0;
6035 stream->segments[0].media_stop = stream_duration;
6036 stream->segments[0].rate = 1.0;
6038 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6039 GST_TIME_ARGS (stream_duration));
6040 stream->n_segments = 1;
6042 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6048 * Parses the stsd atom of a svq3 trak looking for
6049 * the SMI and gama atoms.
6052 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6053 guint8 ** gamma, GstBuffer ** seqh)
6055 guint8 *_gamma = NULL;
6056 GstBuffer *_seqh = NULL;
6057 guint8 *stsd_data = stsd->data;
6058 guint32 length = QT_UINT32 (stsd_data);
6062 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6068 version = QT_UINT16 (stsd_data);
6073 while (length > 8) {
6074 guint32 fourcc, size;
6076 size = QT_UINT32 (stsd_data);
6077 fourcc = QT_FOURCC (stsd_data + 4);
6078 data = stsd_data + 8;
6085 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6086 " for gama atom, expected 12", size);
6091 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6093 if (_seqh != NULL) {
6094 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6095 " found, ignoring");
6097 seqh_size = QT_UINT32 (data + 4);
6098 if (seqh_size > 0) {
6099 _seqh = gst_buffer_new_and_alloc (seqh_size);
6100 _gst_buffer_copy_into_mem (_seqh, data + 8, 0, seqh_size);
6107 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6108 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6112 if (size <= length) {
6118 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6121 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6122 G_GUINT16_FORMAT, version);
6133 gst_buffer_unref (_seqh);
6138 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6145 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6146 * atom that might contain a 'data' atom with the rtsp uri.
6147 * This case was reported in bug #597497, some info about
6148 * the hndl atom can be found in TN1195
6150 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6151 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6154 guint32 dref_num_entries = 0;
6155 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6156 gst_byte_reader_skip (&dref, 4) &&
6157 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6160 /* search dref entries for hndl atom */
6161 for (i = 0; i < dref_num_entries; i++) {
6162 guint32 size = 0, type;
6163 guint8 string_len = 0;
6164 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6165 qt_atom_parser_get_fourcc (&dref, &type)) {
6166 if (type == FOURCC_hndl) {
6167 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6169 /* skip data reference handle bytes and the
6170 * following pascal string and some extra 4
6171 * bytes I have no idea what are */
6172 if (!gst_byte_reader_skip (&dref, 4) ||
6173 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6174 !gst_byte_reader_skip (&dref, string_len + 4)) {
6175 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6179 /* iterate over the atoms to find the data atom */
6180 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6184 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6185 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6186 if (atom_type == FOURCC_data) {
6187 const guint8 *uri_aux = NULL;
6189 /* found the data atom that might contain the rtsp uri */
6190 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6191 "hndl atom, interpreting it as an URI");
6192 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6194 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6195 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6197 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6198 "didn't contain a rtsp address");
6200 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6205 /* skipping to the next entry */
6206 gst_byte_reader_skip (&dref, atom_size - 8);
6208 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6215 /* skip to the next entry */
6216 gst_byte_reader_skip (&dref, size - 8);
6218 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6221 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6228 less_than (gconstpointer a, gconstpointer b)
6230 const guint32 *av = a, *bv = b;
6235 #define AMR_NB_ALL_MODES 0x81ff
6236 #define AMR_WB_ALL_MODES 0x83ff
6238 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
6240 /* The 'damr' atom is of the form:
6242 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
6243 * 32 b 8 b 16 b 8 b 8 b
6245 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
6246 * represents the highest mode used in the stream (and thus the maximum
6247 * bitrate), with a couple of special cases as seen below.
6250 /* Map of frame type ID -> bitrate */
6251 static const guint nb_bitrates[] = {
6252 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
6254 static const guint wb_bitrates[] = {
6255 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
6258 gsize size, max_mode;
6261 data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
6264 GST_DEBUG ("Atom should have size 0x11, not %u", size);
6268 if (QT_FOURCC (data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
6269 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
6270 GST_FOURCC_ARGS (QT_UINT32 (data + 4)));
6274 mode_set = QT_UINT16 (data + 13);
6276 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
6277 max_mode = 7 + (wb ? 1 : 0);
6279 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
6280 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
6282 if (max_mode == -1) {
6283 GST_DEBUG ("No mode indication was found (mode set) = %x",
6288 gst_buffer_unmap (buf, data, size);
6289 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
6292 gst_buffer_unmap (buf, data, size);
6297 * With each track we associate a new QtDemuxStream that contains all the info
6299 * traks that do not decode to something (like strm traks) will not have a pad.
6302 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6317 QtDemuxStream *stream;
6318 GstTagList *list = NULL;
6319 gchar *codec = NULL;
6320 const guint8 *stsd_data;
6321 guint16 lang_code; /* quicktime lang code or packed iso code */
6323 guint32 tkhd_flags = 0;
6324 guint8 tkhd_version = 0;
6326 guint value_size, len;
6328 stream = g_new0 (QtDemuxStream, 1);
6329 /* new streams always need a discont */
6330 stream->discont = TRUE;
6331 /* we enable clipping for raw audio/video streams */
6332 stream->need_clip = FALSE;
6333 stream->need_process = FALSE;
6334 stream->segment_index = -1;
6335 stream->time_position = 0;
6336 stream->sample_index = -1;
6337 stream->last_ret = GST_FLOW_OK;
6339 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6340 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6341 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6344 /* pick between 64 or 32 bits */
6345 value_size = tkhd_version == 1 ? 8 : 4;
6346 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6347 !gst_byte_reader_get_uint32_be (&tkhd, &stream->track_id))
6350 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6351 tkhd_version, tkhd_flags, stream->track_id);
6353 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6356 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6357 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6358 if (qtdemux->major_brand != FOURCC_mjp2 ||
6359 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6363 len = QT_UINT32 ((guint8 *) mdhd->data);
6364 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6365 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6366 if (version == 0x01000000) {
6369 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6370 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6371 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6375 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6376 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6377 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6380 if (lang_code < 0x800) {
6381 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6383 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6384 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6385 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6386 stream->lang_id[3] = 0;
6389 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6391 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6393 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6394 lang_code, stream->lang_id);
6396 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6399 /* fragmented files may have bogus duration in moov */
6400 if (!qtdemux->fragmented &&
6401 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6402 guint64 tdur1, tdur2;
6404 /* don't overflow */
6405 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6406 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6409 * some of those trailers, nowadays, have prologue images that are
6410 * themselves vide tracks as well. I haven't really found a way to
6411 * identify those yet, except for just looking at their duration. */
6412 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6413 GST_WARNING_OBJECT (qtdemux,
6414 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6415 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6416 "found, assuming preview image or something; skipping track",
6417 stream->duration, stream->timescale, qtdemux->duration,
6418 qtdemux->timescale);
6424 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6427 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6428 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6430 len = QT_UINT32 ((guint8 *) hdlr->data);
6432 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6433 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6434 GST_FOURCC_ARGS (stream->subtype));
6436 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6439 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6443 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6445 stsd_data = (const guint8 *) stsd->data;
6447 /* stsd should at least have one entry */
6448 len = QT_UINT32 (stsd_data);
6452 /* and that entry should fit within stsd */
6453 len = QT_UINT32 (stsd_data + 16);
6454 if (len > QT_UINT32 (stsd_data) + 16)
6456 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6458 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6459 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6460 GST_FOURCC_ARGS (stream->fourcc));
6462 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6463 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6464 goto error_encrypted;
6466 if (stream->subtype == FOURCC_vide) {
6467 guint32 w = 0, h = 0;
6469 stream->sampled = TRUE;
6471 /* version 1 uses some 64-bit ints */
6472 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6473 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6474 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6477 stream->display_width = w >> 16;
6478 stream->display_height = h >> 16;
6484 stream->width = QT_UINT16 (stsd_data + offset + 32);
6485 stream->height = QT_UINT16 (stsd_data + offset + 34);
6486 stream->fps_n = 0; /* this is filled in later */
6487 stream->fps_d = 0; /* this is filled in later */
6488 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6489 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6491 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6492 QT_UINT16 (stsd_data + offset + 48));
6495 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6497 list = gst_tag_list_new_empty ();
6498 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6499 GST_TAG_VIDEO_CODEC, codec, NULL);
6506 /* pick 'the' stsd child */
6507 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
6509 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
6510 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
6514 const guint8 *pasp_data = (const guint8 *) pasp->data;
6516 stream->par_w = QT_UINT32 (pasp_data + 8);
6517 stream->par_h = QT_UINT32 (pasp_data + 12);
6524 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
6529 gint len = QT_UINT32 (stsd_data) - 0x66;
6530 const guint8 *avc_data = stsd_data + 0x66;
6533 while (len >= 0x8) {
6536 if (QT_UINT32 (avc_data) <= len)
6537 size = QT_UINT32 (avc_data) - 0x8;
6542 /* No real data, so break out */
6545 switch (QT_FOURCC (avc_data + 0x4)) {
6548 /* parse, if found */
6551 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
6553 /* First 4 bytes are the length of the atom, the next 4 bytes
6554 * are the fourcc, the next 1 byte is the version, and the
6555 * subsequent bytes are sequence parameter set like data. */
6556 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
6557 avc_data + 8 + 1, size - 1);
6559 buf = gst_buffer_new_and_alloc (size);
6560 _gst_buffer_copy_into_mem (buf, avc_data + 0x8, 0, size);
6561 gst_caps_set_simple (stream->caps,
6562 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6563 gst_buffer_unref (buf);
6569 guint avg_bitrate, max_bitrate;
6571 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
6575 max_bitrate = QT_UINT32 (avc_data + 0xc);
6576 avg_bitrate = QT_UINT32 (avc_data + 0x10);
6578 if (!max_bitrate && !avg_bitrate)
6581 /* Some muxers seem to swap the average and maximum bitrates
6582 * (I'm looking at you, YouTube), so we swap for sanity. */
6583 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
6584 guint temp = avg_bitrate;
6586 avg_bitrate = max_bitrate;
6591 list = gst_tag_list_new_empty ();
6593 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6594 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6595 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6597 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6598 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6599 GST_TAG_BITRATE, avg_bitrate, NULL);
6610 avc_data += size + 8;
6622 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
6623 GST_FOURCC_ARGS (fourcc));
6625 /* codec data might be in glbl extension atom */
6627 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
6633 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
6635 len = QT_UINT32 (data);
6638 buf = gst_buffer_new_and_alloc (len);
6639 _gst_buffer_copy_into_mem (buf, data + 8, 0, len);
6640 gst_caps_set_simple (stream->caps,
6641 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6642 gst_buffer_unref (buf);
6649 /* see annex I of the jpeg2000 spec */
6650 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
6652 const gchar *colorspace;
6654 guint32 ncomp_map = 0;
6655 gint32 *comp_map = NULL;
6656 guint32 nchan_def = 0;
6657 gint32 *chan_def = NULL;
6659 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
6660 /* some required atoms */
6661 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
6664 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
6668 /* number of components; redundant with info in codestream, but useful
6670 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
6671 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
6673 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
6675 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
6678 GST_DEBUG_OBJECT (qtdemux, "found colr");
6679 /* extract colour space info */
6680 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
6681 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
6683 colorspace = "sRGB";
6686 colorspace = "GRAY";
6689 colorspace = "sYUV";
6697 /* colr is required, and only values 16, 17, and 18 are specified,
6698 so error if we have no colorspace */
6701 /* extract component mapping */
6702 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
6704 guint32 cmap_len = 0;
6706 cmap_len = QT_UINT32 (cmap->data);
6707 if (cmap_len >= 8) {
6708 /* normal box, subtract off header */
6710 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
6711 if (cmap_len % 4 == 0) {
6712 ncomp_map = (cmap_len / 4);
6713 comp_map = g_new0 (gint32, ncomp_map);
6714 for (i = 0; i < ncomp_map; i++) {
6717 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
6718 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
6719 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
6720 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
6725 /* extract channel definitions */
6726 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
6728 guint32 cdef_len = 0;
6730 cdef_len = QT_UINT32 (cdef->data);
6731 if (cdef_len >= 10) {
6732 /* normal box, subtract off header and len */
6734 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
6735 if (cdef_len % 6 == 0) {
6736 nchan_def = (cdef_len / 6);
6737 chan_def = g_new0 (gint32, nchan_def);
6738 for (i = 0; i < nchan_def; i++)
6740 for (i = 0; i < nchan_def; i++) {
6741 guint16 cn, typ, asoc;
6742 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
6743 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
6744 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
6745 if (cn < nchan_def) {
6748 chan_def[cn] = asoc;
6751 chan_def[cn] = 0; /* alpha */
6754 chan_def[cn] = -typ;
6762 gst_caps_set_simple (stream->caps,
6763 "num-components", G_TYPE_INT, ncomp, NULL);
6764 gst_caps_set_simple (stream->caps,
6765 "colorspace", G_TYPE_STRING, colorspace, NULL);
6768 GValue arr = { 0, };
6769 GValue elt = { 0, };
6771 g_value_init (&arr, GST_TYPE_ARRAY);
6772 g_value_init (&elt, G_TYPE_INT);
6773 for (i = 0; i < ncomp_map; i++) {
6774 g_value_set_int (&elt, comp_map[i]);
6775 gst_value_array_append_value (&arr, &elt);
6777 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6778 "component-map", &arr);
6779 g_value_unset (&elt);
6780 g_value_unset (&arr);
6785 GValue arr = { 0, };
6786 GValue elt = { 0, };
6788 g_value_init (&arr, GST_TYPE_ARRAY);
6789 g_value_init (&elt, G_TYPE_INT);
6790 for (i = 0; i < nchan_def; i++) {
6791 g_value_set_int (&elt, chan_def[i]);
6792 gst_value_array_append_value (&arr, &elt);
6794 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6795 "channel-definitions", &arr);
6796 g_value_unset (&elt);
6797 g_value_unset (&arr);
6801 /* some optional atoms */
6802 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
6803 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
6805 /* indicate possible fields in caps */
6807 data = (guint8 *) field->data + 8;
6809 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
6810 (gint) * data, NULL);
6812 /* add codec_data if provided */
6817 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
6818 data = prefix->data;
6819 len = QT_UINT32 (data);
6822 buf = gst_buffer_new_and_alloc (len);
6823 _gst_buffer_copy_into_mem (buf, data + 8, 0, len);
6824 gst_caps_set_simple (stream->caps,
6825 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6826 gst_buffer_unref (buf);
6835 GstBuffer *seqh = NULL;
6836 guint8 *gamma_data = NULL;
6837 gint len = QT_UINT32 (stsd_data);
6839 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
6841 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
6842 QT_FP32 (gamma_data), NULL);
6845 /* sorry for the bad name, but we don't know what this is, other
6846 * than its own fourcc */
6847 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
6851 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
6852 buf = gst_buffer_new_and_alloc (len);
6853 _gst_buffer_copy_into_mem (buf, stsd_data, 0, len);
6854 gst_caps_set_simple (stream->caps,
6855 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6856 gst_buffer_unref (buf);
6861 gst_caps_set_simple (stream->caps,
6862 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
6869 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
6870 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
6874 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
6878 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
6879 /* collect the headers and store them in a stream list so that we can
6880 * send them out first */
6881 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
6891 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
6892 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
6895 ovc1_data = ovc1->data;
6896 ovc1_len = QT_UINT32 (ovc1_data);
6897 if (ovc1_len <= 198) {
6898 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
6901 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
6902 _gst_buffer_copy_into_mem (buf, ovc1_data + 198, 0, ovc1_len - 198);
6903 gst_caps_set_simple (stream->caps,
6904 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6905 gst_buffer_unref (buf);
6913 GST_INFO_OBJECT (qtdemux,
6914 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
6915 GST_FOURCC_ARGS (fourcc), stream->caps);
6917 } else if (stream->subtype == FOURCC_soun) {
6918 int version, samplesize;
6919 guint16 compression_id;
6920 gboolean amrwb = FALSE;
6926 version = QT_UINT32 (stsd_data + offset);
6927 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
6928 samplesize = QT_UINT16 (stsd_data + offset + 10);
6929 compression_id = QT_UINT16 (stsd_data + offset + 12);
6930 stream->rate = QT_FP32 (stsd_data + offset + 16);
6932 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
6933 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
6934 QT_UINT32 (stsd_data + offset + 4));
6935 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
6936 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
6937 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
6938 GST_LOG_OBJECT (qtdemux, "packet size: %d",
6939 QT_UINT16 (stsd_data + offset + 14));
6940 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
6942 if (compression_id == 0xfffe)
6943 stream->sampled = TRUE;
6945 /* first assume uncompressed audio */
6946 stream->bytes_per_sample = samplesize / 8;
6947 stream->samples_per_frame = stream->n_channels;
6948 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
6949 stream->samples_per_packet = stream->samples_per_frame;
6950 stream->bytes_per_packet = stream->bytes_per_sample;
6954 /* Yes, these have to be hard-coded */
6957 stream->samples_per_packet = 6;
6958 stream->bytes_per_packet = 1;
6959 stream->bytes_per_frame = 1 * stream->n_channels;
6960 stream->bytes_per_sample = 1;
6961 stream->samples_per_frame = 6 * stream->n_channels;
6966 stream->samples_per_packet = 3;
6967 stream->bytes_per_packet = 1;
6968 stream->bytes_per_frame = 1 * stream->n_channels;
6969 stream->bytes_per_sample = 1;
6970 stream->samples_per_frame = 3 * stream->n_channels;
6975 stream->samples_per_packet = 64;
6976 stream->bytes_per_packet = 34;
6977 stream->bytes_per_frame = 34 * stream->n_channels;
6978 stream->bytes_per_sample = 2;
6979 stream->samples_per_frame = 64 * stream->n_channels;
6985 stream->samples_per_packet = 1;
6986 stream->bytes_per_packet = 1;
6987 stream->bytes_per_frame = 1 * stream->n_channels;
6988 stream->bytes_per_sample = 1;
6989 stream->samples_per_frame = 1 * stream->n_channels;
6994 stream->samples_per_packet = 160;
6995 stream->bytes_per_packet = 33;
6996 stream->bytes_per_frame = 33 * stream->n_channels;
6997 stream->bytes_per_sample = 2;
6998 stream->samples_per_frame = 160 * stream->n_channels;
7005 if (version == 0x00010000) {
7013 /* only parse extra decoding config for non-pcm audio */
7014 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7015 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
7016 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
7017 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
7019 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7020 stream->samples_per_packet);
7021 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7022 stream->bytes_per_packet);
7023 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
7024 stream->bytes_per_frame);
7025 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
7026 stream->bytes_per_sample);
7028 if (!stream->sampled && stream->bytes_per_packet) {
7029 stream->samples_per_frame = (stream->bytes_per_frame /
7030 stream->bytes_per_packet) * stream->samples_per_packet;
7031 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
7032 stream->samples_per_frame);
7037 } else if (version == 0x00020000) {
7044 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7045 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
7046 stream->rate = qtfp.fp;
7047 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
7049 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7050 stream->samples_per_packet);
7051 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7052 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7055 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
7058 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
7067 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
7069 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
7071 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
7073 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
7076 gst_caps_set_simple (stream->caps,
7077 "format", G_TYPE_STRING, "S24_3LE", NULL);
7084 const guint8 *owma_data;
7085 const gchar *codec_name = NULL;
7089 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
7090 /* FIXME this should also be gst_riff_strf_auds,
7091 * but the latter one is actually missing bits-per-sample :( */
7096 gint32 nSamplesPerSec;
7097 gint32 nAvgBytesPerSec;
7099 gint16 wBitsPerSample;
7104 GST_DEBUG_OBJECT (qtdemux, "parse owma");
7105 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
7108 owma_data = owma->data;
7109 owma_len = QT_UINT32 (owma_data);
7110 if (owma_len <= 54) {
7111 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
7114 wfex = (WAVEFORMATEX *) (owma_data + 36);
7115 buf = gst_buffer_new_and_alloc (owma_len - 54);
7116 _gst_buffer_copy_into_mem (buf, owma_data + 54, 0, owma_len - 54);
7117 if (wfex->wFormatTag == 0x0161) {
7118 codec_name = "Windows Media Audio";
7120 } else if (wfex->wFormatTag == 0x0162) {
7121 codec_name = "Windows Media Audio 9 Pro";
7123 } else if (wfex->wFormatTag == 0x0163) {
7124 codec_name = "Windows Media Audio 9 Lossless";
7125 /* is that correct? gstffmpegcodecmap.c is missing it, but
7126 * fluendo codec seems to support it */
7130 gst_caps_set_simple (stream->caps,
7131 "codec_data", GST_TYPE_BUFFER, buf,
7132 "wmaversion", G_TYPE_INT, version,
7133 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
7134 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
7135 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7136 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7138 gst_buffer_unref (buf);
7142 codec = g_strdup (codec_name);
7154 list = gst_tag_list_new_empty ();
7155 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7156 GST_TAG_AUDIO_CODEC, codec, NULL);
7160 /* some bitrate info may have ended up in caps */
7161 s = gst_caps_get_structure (stream->caps, 0);
7162 gst_structure_get_int (s, "bitrate", &bitrate);
7164 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7168 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7172 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7174 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7176 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7180 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7181 16 bits is a byte-swapped wave-style codec identifier,
7182 and we can find a WAVE header internally to a 'wave' atom here.
7183 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7184 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7187 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7188 if (len < offset + 20) {
7189 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7191 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7192 const guint8 *data = stsd_data + offset + 16;
7194 GNode *waveheadernode;
7196 wavenode = g_node_new ((guint8 *) data);
7197 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7198 const guint8 *waveheader;
7201 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7202 if (waveheadernode) {
7203 waveheader = (const guint8 *) waveheadernode->data;
7204 headerlen = QT_UINT32 (waveheader);
7206 if (headerlen > 8) {
7207 gst_riff_strf_auds *header = NULL;
7208 GstBuffer *headerbuf;
7214 headerbuf = gst_buffer_new_and_alloc (headerlen);
7215 _gst_buffer_copy_into_mem (headerbuf, waveheader, 0, headerlen);
7217 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7218 headerbuf, &header, &extra)) {
7219 gst_caps_unref (stream->caps);
7220 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7221 header, extra, NULL, NULL);
7224 gst_buffer_unref (extra);
7228 GST_DEBUG ("Didn't find waveheadernode for this codec");
7230 g_node_destroy (wavenode);
7233 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7237 /* FIXME: what is in the chunk? */
7240 gint len = QT_UINT32 (stsd_data);
7242 /* seems to be always = 116 = 0x74 */
7248 gint len = QT_UINT32 (stsd_data);
7251 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7253 _gst_buffer_copy_into_mem (buf, stsd_data + 0x4C, 0, len - 0x4C);
7254 gst_caps_set_simple (stream->caps,
7255 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7256 gst_buffer_unref (buf);
7258 gst_caps_set_simple (stream->caps,
7259 "samplesize", G_TYPE_INT, samplesize, NULL);
7264 GNode *alac, *wave = NULL;
7266 /* apparently, m4a has this atom appended directly in the stsd entry,
7267 * while mov has it in a wave atom */
7268 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7270 /* alac now refers to stsd entry atom */
7271 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7273 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7275 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7278 gint len = QT_UINT32 (alac->data);
7282 GST_DEBUG_OBJECT (qtdemux,
7283 "discarding alac atom with unexpected len %d", len);
7285 /* codec-data contains alac atom size and prefix,
7286 * ffmpeg likes it that way, not quite gst-ish though ...*/
7287 buf = gst_buffer_new_and_alloc (len);
7288 _gst_buffer_copy_into_mem (buf, alac->data, 0, len);
7289 gst_caps_set_simple (stream->caps,
7290 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7291 gst_buffer_unref (buf);
7294 gst_caps_set_simple (stream->caps,
7295 "samplesize", G_TYPE_INT, samplesize, NULL);
7303 gint len = QT_UINT32 (stsd_data);
7306 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7309 _gst_buffer_copy_into_mem (buf, stsd_data + 0x34, 0, len - 0x34);
7311 /* If we have enough data, let's try to get the 'damr' atom. See
7312 * the 3GPP container spec (26.244) for more details. */
7313 if ((len - 0x34) > 8 &&
7314 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
7316 list = gst_tag_list_new_empty ();
7317 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7318 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
7321 gst_caps_set_simple (stream->caps,
7322 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7323 gst_buffer_unref (buf);
7331 GST_INFO_OBJECT (qtdemux,
7332 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7333 GST_FOURCC_ARGS (fourcc), stream->caps);
7335 } else if (stream->subtype == FOURCC_strm) {
7336 if (fourcc == FOURCC_rtsp) {
7337 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7339 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7340 GST_FOURCC_ARGS (fourcc));
7341 goto unknown_stream;
7343 stream->sampled = TRUE;
7344 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
7346 stream->sampled = TRUE;
7351 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7353 list = gst_tag_list_new_empty ();
7354 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7355 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7360 /* hunt for sort-of codec data */
7367 /* look for palette */
7368 /* target mp4s atom */
7369 len = QT_UINT32 (stsd_data + offset);
7370 data = stsd_data + offset;
7371 /* verify sufficient length,
7372 * and esds present with decConfigDescr of expected size and position */
7373 if ((len >= 106 + 8)
7374 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7375 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7380 /* move to decConfigDescr data */
7381 data = data + 8 + 42;
7382 for (i = 0; i < 16; i++) {
7383 clut[i] = QT_UINT32 (data);
7387 s = gst_structure_new ("application/x-gst-dvd", "event",
7388 G_TYPE_STRING, "dvd-spu-clut-change",
7389 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7390 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7391 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7392 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7393 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7394 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7395 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7396 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7399 /* store event and trigger custom processing */
7400 stream->pending_event =
7401 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7402 stream->need_process = TRUE;
7410 goto unknown_stream;
7413 /* promote to sampled format */
7414 if (stream->fourcc == FOURCC_samr) {
7415 /* force mono 8000 Hz for AMR */
7416 stream->sampled = TRUE;
7417 stream->n_channels = 1;
7418 stream->rate = 8000;
7419 } else if (stream->fourcc == FOURCC_sawb) {
7420 /* force mono 16000 Hz for AMR-WB */
7421 stream->sampled = TRUE;
7422 stream->n_channels = 1;
7423 stream->rate = 16000;
7424 } else if (stream->fourcc == FOURCC_mp4a) {
7425 stream->sampled = TRUE;
7428 /* collect sample information */
7429 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7430 goto samples_failed;
7432 if (qtdemux->fragmented) {
7436 /* need all moov samples as basis; probably not many if any at all */
7437 /* prevent moof parsing taking of at this time */
7438 offset = qtdemux->moof_offset;
7439 qtdemux->moof_offset = 0;
7440 if (stream->n_samples &&
7441 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7442 qtdemux->moof_offset = offset;
7443 goto samples_failed;
7445 qtdemux->moof_offset = 0;
7446 /* movie duration more reliable in this case (e.g. mehd) */
7447 if (qtdemux->segment.duration &&
7448 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7449 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7450 stream->timescale, GST_SECOND);
7451 /* need defaults for fragments */
7452 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7455 /* configure segments */
7456 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7457 goto segments_failed;
7459 /* add some language tag, if useful */
7460 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7461 strcmp (stream->lang_id, "und")) {
7462 const gchar *lang_code;
7465 list = gst_tag_list_new_empty ();
7467 /* convert ISO 639-2 code to ISO 639-1 */
7468 lang_code = gst_tag_get_language_code (stream->lang_id);
7469 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7470 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7473 /* now we are ready to add the stream */
7474 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7475 goto too_many_streams;
7477 stream->pending_tags = list;
7478 qtdemux->streams[qtdemux->n_streams] = stream;
7479 qtdemux->n_streams++;
7480 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7487 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7488 (_("This file is corrupt and cannot be played.")), (NULL));
7494 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7501 /* we posted an error already */
7502 /* free stbl sub-atoms */
7503 gst_qtdemux_stbl_free (stream);
7509 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7510 GST_FOURCC_ARGS (stream->subtype));
7516 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7517 (_("This file contains too many streams. Only playing first %d"),
7518 GST_QTDEMUX_MAX_STREAMS), (NULL));
7523 /* If we can estimate the overall bitrate, and don't have information about the
7524 * stream bitrate for exactly one stream, this guesses the stream bitrate as
7525 * the overall bitrate minus the sum of the bitrates of all other streams. This
7526 * should be useful for the common case where we have one audio and one video
7527 * stream and can estimate the bitrate of one, but not the other. */
7529 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
7531 QtDemuxStream *stream = NULL;
7532 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
7536 if (qtdemux->fragmented)
7539 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
7541 if (!gst_pad_query_peer_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)) {
7542 GST_DEBUG_OBJECT (qtdemux,
7543 "Size in bytes of the stream not known - bailing");
7547 /* Subtract the header size */
7548 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
7549 size, qtdemux->header_size);
7550 g_assert (size >= qtdemux->header_size);
7551 size = size - qtdemux->header_size;
7553 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
7554 duration == GST_CLOCK_TIME_NONE) {
7555 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
7559 for (i = 0; i < qtdemux->n_streams; i++) {
7560 switch (qtdemux->streams[i]->subtype) {
7563 /* retrieve bitrate, prefer avg then max */
7565 if (qtdemux->streams[i]->pending_tags) {
7566 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7567 GST_TAG_MAXIMUM_BITRATE, &bitrate);
7568 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7569 GST_TAG_BITRATE, &bitrate);
7572 sum_bitrate += bitrate;
7575 GST_DEBUG_OBJECT (qtdemux,
7576 ">1 stream with unknown bitrate - bailing");
7579 stream = qtdemux->streams[i];
7583 /* For other subtypes, we assume no significant impact on bitrate */
7589 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
7593 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
7595 if (sys_bitrate < sum_bitrate) {
7596 /* This can happen, since sum_bitrate might be derived from maximum
7597 * bitrates and not average bitrates */
7598 GST_DEBUG_OBJECT (qtdemux,
7599 "System bitrate less than sum bitrate - bailing");
7603 bitrate = sys_bitrate - sum_bitrate;
7604 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
7605 ", Stream bitrate = %u", sys_bitrate, bitrate);
7607 if (!stream->pending_tags)
7608 stream->pending_tags = gst_tag_list_new_empty ();
7610 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
7611 GST_TAG_BITRATE, bitrate, NULL);
7614 static GstFlowReturn
7615 qtdemux_expose_streams (GstQTDemux * qtdemux)
7618 GstFlowReturn ret = GST_FLOW_OK;
7620 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7622 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7623 QtDemuxStream *stream = qtdemux->streams[i];
7624 guint32 sample_num = 0;
7629 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7630 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7632 if (qtdemux->fragmented) {
7633 /* need all moov samples first */
7634 GST_OBJECT_LOCK (qtdemux);
7635 while (stream->n_samples == 0)
7636 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7638 GST_OBJECT_UNLOCK (qtdemux);
7640 /* discard any stray moof */
7641 qtdemux->moof_offset = 0;
7644 /* prepare braking */
7645 if (ret != GST_FLOW_ERROR)
7648 /* in pull mode, we should have parsed some sample info by now;
7649 * and quite some code will not handle no samples.
7650 * in push mode, we'll just have to deal with it */
7651 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7652 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7653 gst_qtdemux_stream_free (qtdemux, stream);
7654 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7655 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7656 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7657 qtdemux->n_streams--;
7662 /* parse number of initial sample to set frame rate cap */
7663 while (sample_num < stream->n_samples && sample_num < samples) {
7664 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7668 /* collect and sort durations */
7669 samples = MIN (stream->stbl_index + 1, samples);
7670 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7672 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7674 while (sample_num < samples) {
7675 g_array_append_val (durations, stream->samples[sample_num].duration);
7678 g_array_sort (durations, less_than);
7679 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7680 g_array_free (durations, TRUE);
7683 /* now we have all info and can expose */
7684 list = stream->pending_tags;
7685 stream->pending_tags = NULL;
7686 gst_qtdemux_add_stream (qtdemux, stream, list);
7689 gst_qtdemux_guess_bitrate (qtdemux);
7691 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7693 /* check if we should post a redirect in case there is a single trak
7694 * and it is a redirecting trak */
7695 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7698 qtdemux_post_global_tags (qtdemux);
7700 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7701 "an external content");
7702 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7703 gst_structure_new ("redirect",
7704 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7706 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7707 qtdemux->posted_redirect = TRUE;
7713 /* check if major or compatible brand is 3GP */
7714 static inline gboolean
7715 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7718 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7719 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7720 } else if (qtdemux->comp_brands != NULL) {
7723 gboolean res = FALSE;
7725 data = gst_buffer_map (qtdemux->comp_brands, &size, NULL, GST_MAP_READ);
7727 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7728 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7732 gst_buffer_unmap (qtdemux->comp_brands, data, size);
7739 /* check if tag is a spec'ed 3GP tag keyword storing a string */
7740 static inline gboolean
7741 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
7743 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
7744 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
7745 || fourcc == FOURCC_albm;
7749 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
7750 const char *dummy, GNode * node)
7752 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7756 gdouble longitude, latitude, altitude;
7759 len = QT_UINT32 (node->data);
7766 /* TODO: language code skipped */
7768 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
7771 /* do not alarm in trivial case, but bail out otherwise */
7772 if (*(data + offset) != 0) {
7773 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
7777 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7778 GST_TAG_GEO_LOCATION_NAME, name, NULL);
7779 offset += strlen (name);
7783 if (len < offset + 2 + 4 + 4 + 4)
7786 /* +1 +1 = skip null-terminator and location role byte */
7788 /* table in spec says unsigned, semantics say negative has meaning ... */
7789 longitude = QT_SFP32 (data + offset);
7792 latitude = QT_SFP32 (data + offset);
7795 altitude = QT_SFP32 (data + offset);
7797 /* one invalid means all are invalid */
7798 if (longitude >= -180.0 && longitude <= 180.0 &&
7799 latitude >= -90.0 && latitude <= 90.0) {
7800 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7801 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
7802 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
7803 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
7806 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
7813 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
7820 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7827 len = QT_UINT32 (node->data);
7831 y = QT_UINT16 ((guint8 *) node->data + 12);
7833 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
7836 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
7838 date = g_date_new_dmy (1, 1, y);
7839 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
7844 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
7845 const char *dummy, GNode * node)
7848 char *tag_str = NULL;
7853 len = QT_UINT32 (node->data);
7858 entity = (guint8 *) node->data + offset;
7859 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
7860 GST_DEBUG_OBJECT (qtdemux,
7861 "classification info: %c%c%c%c invalid classification entity",
7862 entity[0], entity[1], entity[2], entity[3]);
7867 table = QT_UINT16 ((guint8 *) node->data + offset);
7869 /* Language code skipped */
7873 /* Tag format: "XXXX://Y[YYYY]/classification info string"
7874 * XXXX: classification entity, fixed length 4 chars.
7875 * Y[YYYY]: classification table, max 5 chars.
7877 tag_str = g_strdup_printf ("----://%u/%s",
7878 table, (char *) node->data + offset);
7880 /* memcpy To be sure we're preserving byte order */
7881 memcpy (tag_str, entity, 4);
7882 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
7884 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
7894 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
7900 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
7901 const char *dummy, GNode * node)
7903 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7909 gboolean ret = TRUE;
7911 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7913 len = QT_UINT32 (data->data);
7914 type = QT_UINT32 ((guint8 *) data->data + 8);
7915 if (type == 0x00000001 && len > 16) {
7916 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
7919 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7920 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
7924 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7928 len = QT_UINT32 (node->data);
7929 type = QT_UINT32 ((guint8 *) node->data + 4);
7930 if ((type >> 24) == 0xa9) {
7931 /* Type starts with the (C) symbol, so the next 32 bits are
7932 * the language code, which we ignore */
7934 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
7935 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
7936 QT_FOURCC ((guint8 *) node->data + 4))) {
7937 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
7939 /* we go for 3GP style encoding if major brands claims so,
7940 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
7941 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
7942 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
7943 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
7945 /* 16-bit Language code is ignored here as well */
7946 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
7953 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
7954 ret = FALSE; /* may have to fallback */
7956 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
7957 len - offset, env_vars);
7959 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7960 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
7964 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7971 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
7972 const char *dummy, GNode * node)
7974 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
7978 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
7979 const char *dummy, GNode * node)
7981 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7983 char *s, *t, *k = NULL;
7988 /* first try normal string tag if major brand not 3GP */
7989 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
7990 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
7991 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
7992 * let's try it 3gpp way after minor safety check */
7994 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
8000 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
8004 len = QT_UINT32 (data);
8008 count = QT_UINT8 (data + 14);
8010 for (; count; count--) {
8013 if (offset + 1 > len)
8015 slen = QT_UINT8 (data + offset);
8017 if (offset + slen > len)
8019 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8022 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
8024 t = g_strjoin (",", k, s, NULL);
8032 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
8039 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
8040 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
8049 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
8055 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
8056 const char *tag2, GNode * node)
8063 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8065 len = QT_UINT32 (data->data);
8066 type = QT_UINT32 ((guint8 *) data->data + 8);
8067 if (type == 0x00000000 && len >= 22) {
8068 n1 = QT_UINT16 ((guint8 *) data->data + 18);
8069 n2 = QT_UINT16 ((guint8 *) data->data + 20);
8071 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
8072 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8076 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
8077 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8085 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8093 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8095 len = QT_UINT32 (data->data);
8096 type = QT_UINT32 ((guint8 *) data->data + 8);
8097 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
8098 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8099 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
8100 n1 = QT_UINT16 ((guint8 *) data->data + 16);
8102 /* do not add bpm=0 */
8103 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
8104 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8105 tag1, (gdouble) n1, NULL);
8112 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
8113 const char *dummy, GNode * node)
8120 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8122 len = QT_UINT32 (data->data);
8123 type = QT_UINT32 ((guint8 *) data->data + 8);
8124 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
8125 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8126 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
8127 num = QT_UINT32 ((guint8 *) data->data + 16);
8129 /* do not add num=0 */
8130 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
8131 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8139 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8147 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8149 len = QT_UINT32 (data->data);
8150 type = QT_UINT32 ((guint8 *) data->data + 8);
8151 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
8152 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
8153 if ((buf = gst_tag_image_data_to_image_buffer ((guint8 *) data->data + 16,
8154 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
8155 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
8156 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8158 gst_buffer_unref (buf);
8165 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8173 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8175 len = QT_UINT32 (data->data);
8176 type = QT_UINT32 ((guint8 *) data->data + 8);
8177 if (type == 0x00000001 && len > 16) {
8178 guint y, m = 1, d = 1;
8181 s = g_strndup ((char *) data->data + 16, len - 16);
8182 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
8183 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
8184 if (ret >= 1 && y > 1500 && y < 3000) {
8187 date = g_date_new_dmy (d, m, y);
8188 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
8192 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
8200 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8205 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8207 /* re-route to normal string tag if major brand says so
8208 * or no data atom and compatible brand suggests so */
8209 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8210 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
8211 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
8218 len = QT_UINT32 (data->data);
8219 type = QT_UINT32 ((guint8 *) data->data + 8);
8220 if (type == 0x00000000 && len >= 18) {
8221 n = QT_UINT16 ((guint8 *) data->data + 16);
8225 genre = gst_tag_id3_genre_get (n - 1);
8226 if (genre != NULL) {
8227 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
8228 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8237 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
8238 guint8 * data, guint32 datasize)
8243 /* make a copy to have \0 at the end */
8244 datacopy = g_strndup ((gchar *) data, datasize);
8246 /* convert the str to double */
8247 if (sscanf (datacopy, "%lf", &value) == 1) {
8248 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
8249 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
8251 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
8259 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
8260 const char *tag_bis, GNode * node)
8269 const gchar *meanstr;
8270 const gchar *namestr;
8272 /* checking the whole ---- atom size for consistency */
8273 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8274 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8278 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8280 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8284 meansize = QT_UINT32 (mean->data);
8285 if (meansize <= 12) {
8286 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8289 meanstr = ((gchar *) mean->data) + 12;
8291 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8293 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8297 namesize = QT_UINT32 (name->data);
8298 if (namesize <= 12) {
8299 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8302 namestr = ((gchar *) name->data) + 12;
8309 * uint24 - data type
8313 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8315 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8318 datasize = QT_UINT32 (data->data);
8319 if (datasize <= 16) {
8320 GST_WARNING_OBJECT (demux, "Data atom too small");
8323 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8325 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8328 const gchar name[28];
8329 const gchar tag[28];
8332 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8333 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8334 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8335 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8336 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8337 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8338 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8339 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8343 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8344 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8345 switch (gst_tag_get_type (tags[i].tag)) {
8347 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8348 ((guint8 *) data->data) + 16, datasize - 16);
8351 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8360 if (i == G_N_ELEMENTS (tags))
8374 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8375 namestr_dbg = g_strndup (namestr, namesize - 12);
8377 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8378 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8380 g_free (namestr_dbg);
8381 g_free (meanstr_dbg);
8387 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
8388 const char *tag_bis, GNode * node)
8393 GstTagList *taglist = NULL;
8395 GST_LOG_OBJECT (demux, "parsing ID32");
8398 len = GST_READ_UINT32_BE (data);
8400 /* need at least full box and language tag */
8404 buf = gst_buffer_new_allocate (NULL, len - 14, 0);
8405 gst_buffer_fill (buf, 0, data + 14, len - 14);
8407 taglist = gst_tag_list_from_id3v2_tag (buf);
8409 GST_LOG_OBJECT (demux, "parsing ok");
8410 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
8412 GST_LOG_OBJECT (demux, "parsing failed");
8416 gst_tag_list_free (taglist);
8418 gst_buffer_unref (buf);
8421 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8422 const char *tag, const char *tag_bis, GNode * node);
8425 FOURCC_pcst -> if media is a podcast -> bool
8426 FOURCC_cpil -> if media is part of a compilation -> bool
8427 FOURCC_pgap -> if media is part of a gapless context -> bool
8428 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8434 const gchar *gst_tag;
8435 const gchar *gst_tag_bis;
8436 const GstQTDemuxAddTagFunc func;
8439 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8440 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8441 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8442 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8443 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8444 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8445 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8446 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8447 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8448 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8449 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8450 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8451 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8452 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8453 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8454 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8455 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8456 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8457 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8458 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8459 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8460 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8461 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8462 qtdemux_tag_add_num}, {
8463 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8464 qtdemux_tag_add_num}, {
8465 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8466 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8467 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8468 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8469 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8470 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8471 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8472 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8473 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8474 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8475 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8476 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8477 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8478 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8479 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8480 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8481 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8482 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8483 qtdemux_tag_add_classification}, {
8485 /* This is a special case, some tags are stored in this
8486 * 'reverse dns naming', according to:
8487 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8490 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
8491 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
8492 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
8496 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8508 len = QT_UINT32 (data);
8509 buf = gst_buffer_new_and_alloc (len);
8510 _gst_buffer_copy_into_mem (buf, data, 0, len);
8512 /* heuristic to determine style of tag */
8513 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8514 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8516 else if (demux->major_brand == FOURCC_qt__)
8517 style = "quicktime";
8518 /* fall back to assuming iso/3gp tag style */
8522 /* santize the name for the caps. */
8523 for (i = 0; i < 4; i++) {
8524 guint8 d = data[4 + i];
8525 if (g_ascii_isalnum (d))
8526 ndata[i] = g_ascii_tolower (d);
8531 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8532 ndata[0], ndata[1], ndata[2], ndata[3]);
8533 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8535 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
8536 // TODO conver to metadata or ???
8537 // gst_buffer_set_caps (buf, caps);
8538 gst_caps_unref (caps);
8539 g_free (media_type);
8541 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
8544 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8545 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
8546 gst_buffer_unref (buf);
8550 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8558 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8560 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8562 GST_LOG_OBJECT (qtdemux, "no ilst");
8567 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8570 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8571 if (!qtdemux->tag_list)
8572 qtdemux->tag_list = gst_tag_list_new_empty ();
8575 while (i < G_N_ELEMENTS (add_funcs)) {
8576 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8580 len = QT_UINT32 (node->data);
8582 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8583 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8585 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8586 add_funcs[i].gst_tag_bis, node);
8588 g_node_destroy (node);
8594 /* parsed nodes have been removed, pass along remainder as blob */
8595 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8596 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8598 /* parse up XMP_ node if existing */
8599 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8602 GstTagList *taglist;
8604 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
8605 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
8606 taglist = gst_tag_list_from_xmp_buffer (buf);
8607 gst_buffer_unref (buf);
8609 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8611 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8618 GstStructure *structure; /* helper for sort function */
8620 guint min_req_bitrate;
8621 guint min_req_qt_version;
8625 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8627 GstQtReference *ref_a = (GstQtReference *) a;
8628 GstQtReference *ref_b = (GstQtReference *) b;
8630 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8631 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8633 /* known bitrates go before unknown; higher bitrates go first */
8634 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8637 /* sort the redirects and post a message for the application.
8640 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8642 GstQtReference *best;
8645 GValue list_val = { 0, };
8648 g_assert (references != NULL);
8650 references = g_list_sort (references, qtdemux_redirects_sort_func);
8652 best = (GstQtReference *) references->data;
8654 g_value_init (&list_val, GST_TYPE_LIST);
8656 for (l = references; l != NULL; l = l->next) {
8657 GstQtReference *ref = (GstQtReference *) l->data;
8658 GValue struct_val = { 0, };
8660 ref->structure = gst_structure_new ("redirect",
8661 "new-location", G_TYPE_STRING, ref->location, NULL);
8663 if (ref->min_req_bitrate > 0) {
8664 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8665 ref->min_req_bitrate, NULL);
8668 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8669 g_value_set_boxed (&struct_val, ref->structure);
8670 gst_value_list_append_value (&list_val, &struct_val);
8671 g_value_unset (&struct_val);
8672 /* don't free anything here yet, since we need best->structure below */
8675 g_assert (best != NULL);
8676 s = gst_structure_copy (best->structure);
8678 if (g_list_length (references) > 1) {
8679 gst_structure_set_value (s, "locations", &list_val);
8682 g_value_unset (&list_val);
8684 for (l = references; l != NULL; l = l->next) {
8685 GstQtReference *ref = (GstQtReference *) l->data;
8687 gst_structure_free (ref->structure);
8688 g_free (ref->location);
8691 g_list_free (references);
8693 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8694 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8695 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8696 qtdemux->posted_redirect = TRUE;
8699 /* look for redirect nodes, collect all redirect information and
8703 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8705 GNode *rmra, *rmda, *rdrf;
8707 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8709 GList *redirects = NULL;
8711 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8713 GstQtReference ref = { NULL, NULL, 0, 0 };
8716 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8717 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8718 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8719 ref.min_req_bitrate);
8722 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
8723 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
8724 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
8726 #ifndef GST_DISABLE_GST_DEBUG
8727 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
8729 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
8731 GST_LOG_OBJECT (qtdemux,
8732 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
8733 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
8734 bitmask, check_type);
8735 if (package == FOURCC_qtim && check_type == 0) {
8736 ref.min_req_qt_version = version;
8740 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
8745 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
8746 ref_data = (guint8 *) rdrf->data + 20;
8747 if (ref_type == FOURCC_alis) {
8748 guint record_len, record_version, fn_len;
8750 /* MacOSX alias record, google for alias-layout.txt */
8751 record_len = QT_UINT16 (ref_data + 4);
8752 record_version = QT_UINT16 (ref_data + 4 + 2);
8753 fn_len = QT_UINT8 (ref_data + 50);
8754 if (record_len > 50 && record_version == 2 && fn_len > 0) {
8755 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
8757 } else if (ref_type == FOURCC_url_) {
8758 ref.location = g_strdup ((gchar *) ref_data);
8760 GST_DEBUG_OBJECT (qtdemux,
8761 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
8762 GST_FOURCC_ARGS (ref_type));
8764 if (ref.location != NULL) {
8765 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
8766 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
8768 GST_WARNING_OBJECT (qtdemux,
8769 "Failed to extract redirect location from rdrf atom");
8773 /* look for others */
8774 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
8777 if (redirects != NULL) {
8778 qtdemux_process_redirects (qtdemux, redirects);
8785 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
8790 tags = gst_tag_list_new_empty ();
8792 if (qtdemux->major_brand == FOURCC_mjp2)
8793 fmt = "Motion JPEG 2000";
8794 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
8796 else if (qtdemux->major_brand == FOURCC_qt__)
8798 else if (qtdemux->fragmented)
8801 fmt = "ISO MP4/M4A";
8803 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
8804 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
8806 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
8812 /* we have read th complete moov node now.
8813 * This function parses all of the relevant info, creates the traks and
8814 * prepares all data structures for playback
8817 qtdemux_parse_tree (GstQTDemux * qtdemux)
8824 guint64 creation_time;
8825 GstDateTime *datetime = NULL;
8828 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
8830 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
8831 return qtdemux_parse_redirects (qtdemux);
8834 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
8836 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
8837 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
8838 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
8839 } else if (version == 0) {
8840 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
8841 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
8842 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
8844 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
8848 /* Moving qt creation time (secs since 1904) to unix time */
8849 if (creation_time != 0) {
8850 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
8851 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
8852 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
8854 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
8855 "please file a bug at http://bugzilla.gnome.org");
8859 if (!qtdemux->tag_list)
8860 qtdemux->tag_list = gst_tag_list_new_empty ();
8862 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
8863 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
8865 gst_date_time_unref (datetime);
8868 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
8869 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
8871 /* check for fragmented file and get some (default) data */
8872 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
8875 GstByteReader mehd_data;
8877 /* let track parsing or anyone know weird stuff might happen ... */
8878 qtdemux->fragmented = TRUE;
8880 /* compensate for total duration */
8881 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
8883 qtdemux_parse_mehd (qtdemux, &mehd_data);
8886 /* set duration in the segment info */
8887 gst_qtdemux_get_duration (qtdemux, &duration);
8889 qtdemux->segment.duration = duration;
8891 /* parse all traks */
8892 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
8894 qtdemux_parse_trak (qtdemux, trak);
8895 /* iterate all siblings */
8896 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
8900 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
8902 qtdemux_parse_udta (qtdemux, udta);
8904 GST_LOG_OBJECT (qtdemux, "No udta node found.");
8907 /* maybe also some tags in meta box */
8908 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
8910 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
8911 qtdemux_parse_udta (qtdemux, udta);
8913 GST_LOG_OBJECT (qtdemux, "No meta node found.");
8916 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
8921 /* taken from ffmpeg */
8923 get_size (guint8 * ptr, guint8 ** end)
8932 len = (len << 7) | (c & 0x7f);
8941 /* this can change the codec originally present in @list */
8943 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
8944 GNode * esds, GstTagList * list)
8946 int len = QT_UINT32 (esds->data);
8947 guint8 *ptr = esds->data;
8948 guint8 *end = ptr + len;
8950 guint8 *data_ptr = NULL;
8952 guint8 object_type_id = 0;
8953 const char *codec_name = NULL;
8954 GstCaps *caps = NULL;
8956 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
8958 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
8961 tag = QT_UINT8 (ptr);
8962 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
8964 len = get_size (ptr, &ptr);
8965 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
8969 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
8970 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
8974 guint max_bitrate, avg_bitrate;
8976 object_type_id = QT_UINT8 (ptr);
8977 max_bitrate = QT_UINT32 (ptr + 5);
8978 avg_bitrate = QT_UINT32 (ptr + 9);
8979 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
8980 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
8981 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
8982 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
8983 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
8984 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
8985 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8986 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
8988 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
8989 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
8996 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
9002 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
9006 GST_ERROR_OBJECT (qtdemux, "parse error");
9011 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
9012 * in use, and should also be used to override some other parameters for some
9014 switch (object_type_id) {
9015 case 0x20: /* MPEG-4 */
9016 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
9017 * profile_and_level_indication */
9018 if (data_ptr != NULL && data_len >= 5 &&
9019 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
9020 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
9021 data_ptr + 4, data_len - 4);
9023 break; /* Nothing special needed here */
9024 case 0x21: /* H.264 */
9025 codec_name = "H.264 / AVC";
9026 caps = gst_caps_new_simple ("video/x-h264",
9027 "stream-format", G_TYPE_STRING, "avc",
9028 "alignment", G_TYPE_STRING, "au", NULL);
9030 case 0x40: /* AAC (any) */
9031 case 0x66: /* AAC Main */
9032 case 0x67: /* AAC LC */
9033 case 0x68: /* AAC SSR */
9034 /* Override channels and rate based on the codec_data, as it's often
9036 /* Only do so for basic setup without HE-AAC extension */
9037 if (data_ptr && data_len == 2) {
9038 guint channels, rateindex, rate;
9040 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
9041 channels = (data_ptr[1] & 0x7f) >> 3;
9042 if (channels > 0 && channels < 7) {
9043 stream->n_channels = channels;
9044 } else if (channels == 7) {
9045 stream->n_channels = 8;
9048 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
9049 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
9051 stream->rate = rate;
9054 /* Set level and profile if possible */
9055 if (data_ptr != NULL && data_len >= 2) {
9056 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
9057 data_ptr, data_len);
9060 case 0x60: /* MPEG-2, various profiles */
9066 codec_name = "MPEG-2 video";
9068 gst_caps_unref (stream->caps);
9069 stream->caps = gst_caps_new_simple ("video/mpeg",
9070 "mpegversion", G_TYPE_INT, 2,
9071 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9073 case 0x69: /* MP3 has two different values, accept either */
9075 /* change to mpeg1 layer 3 audio */
9076 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
9077 "mpegversion", G_TYPE_INT, 1, NULL);
9078 codec_name = "MPEG-1 layer 3";
9080 case 0x6A: /* MPEG-1 */
9081 codec_name = "MPEG-1 video";
9083 gst_caps_unref (stream->caps);
9084 stream->caps = gst_caps_new_simple ("video/mpeg",
9085 "mpegversion", G_TYPE_INT, 1,
9086 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9088 case 0x6C: /* MJPEG */
9089 caps = gst_caps_new_empty_simple ("image/jpeg");
9090 codec_name = "Motion-JPEG";
9092 case 0x6D: /* PNG */
9093 caps = gst_caps_new_empty_simple ("image/png");
9094 codec_name = "PNG still images";
9096 case 0x6E: /* JPEG2000 */
9097 codec_name = "JPEG-2000";
9098 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9100 case 0xA4: /* Dirac */
9101 codec_name = "Dirac";
9102 caps = gst_caps_new_empty_simple ("video/x-dirac");
9104 case 0xA5: /* AC3 */
9105 codec_name = "AC-3 audio";
9106 caps = gst_caps_new_simple ("audio/x-ac3",
9107 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9109 case 0xE1: /* QCELP */
9110 /* QCELP, the codec_data is a riff tag (little endian) with
9111 * 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). */
9112 caps = gst_caps_new_empty_simple ("audio/qcelp");
9113 codec_name = "QCELP";
9119 /* If we have a replacement caps, then change our caps for this stream */
9121 gst_caps_unref (stream->caps);
9122 stream->caps = caps;
9125 if (codec_name && list)
9126 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9127 GST_TAG_AUDIO_CODEC, codec_name, NULL);
9129 /* Add the codec_data attribute to caps, if we have it */
9133 buffer = gst_buffer_new_and_alloc (data_len);
9134 _gst_buffer_copy_into_mem (buffer, data_ptr, 0, data_len);
9136 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
9137 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
9139 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
9141 gst_buffer_unref (buffer);
9146 #define _codec(name) \
9149 *codec_name = g_strdup (name); \
9154 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9155 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9158 const GstStructure *s;
9162 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
9163 _codec ("PNG still images");
9164 caps = gst_caps_new_empty_simple ("image/png");
9166 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
9167 _codec ("JPEG still images");
9168 caps = gst_caps_new_empty_simple ("image/jpeg");
9170 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
9171 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
9172 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
9173 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
9174 _codec ("Motion-JPEG");
9175 caps = gst_caps_new_empty_simple ("image/jpeg");
9177 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
9178 _codec ("Motion-JPEG format B");
9179 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
9181 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
9182 _codec ("JPEG-2000");
9183 /* override to what it should be according to spec, avoid palette_data */
9184 stream->bits_per_sample = 24;
9185 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9187 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
9188 _codec ("Sorensen video v.3");
9189 caps = gst_caps_new_simple ("video/x-svq",
9190 "svqversion", G_TYPE_INT, 3, NULL);
9192 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
9193 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
9194 _codec ("Sorensen video v.1");
9195 caps = gst_caps_new_simple ("video/x-svq",
9196 "svqversion", G_TYPE_INT, 1, NULL);
9198 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9202 _codec ("Raw RGB video");
9203 bps = QT_UINT16 (stsd_data + 98);
9204 /* set common stuff */
9205 caps = gst_caps_new_empty_simple ("video/x-raw");
9209 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB15", NULL);
9212 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB16", NULL);
9215 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB", NULL);
9218 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "ARGB", NULL);
9226 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
9227 _codec ("Raw planar YUV 4:2:0");
9228 caps = gst_caps_new_simple ("video/x-raw",
9229 "format", G_TYPE_STRING, "I420", NULL);
9231 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
9232 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
9233 _codec ("Raw packed YUV 4:2:2");
9234 caps = gst_caps_new_simple ("video/x-raw",
9235 "format", G_TYPE_STRING, "YUY2", NULL);
9237 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
9238 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
9239 _codec ("Raw packed YUV 4:2:2");
9240 caps = gst_caps_new_simple ("video/x-raw",
9241 "format", G_TYPE_STRING, "UYVY", NULL);
9243 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
9244 _codec ("Raw packed YUV 10-bit 4:2:2");
9245 caps = gst_caps_new_simple ("video/x-raw",
9246 "format", G_TYPE_STRING, "v210", NULL);
9248 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
9249 _codec ("Raw packed RGB 10-bit 4:4:4");
9250 caps = gst_caps_new_simple ("video/x-raw",
9251 "format", G_TYPE_STRING, "r210", NULL);
9253 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
9254 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
9255 _codec ("MPEG-1 video");
9256 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9257 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9259 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
9260 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
9261 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
9262 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
9263 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
9264 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
9265 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
9266 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
9267 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
9268 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
9269 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
9270 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
9271 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
9272 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
9273 _codec ("MPEG-2 video");
9274 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
9275 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9277 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
9278 _codec ("GIF still images");
9279 caps = gst_caps_new_empty_simple ("image/gif");
9281 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
9282 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
9283 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
9284 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9286 /* ffmpeg uses the height/width props, don't know why */
9287 caps = gst_caps_new_empty_simple ("video/x-h263");
9289 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9290 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9291 _codec ("MPEG-4 video");
9292 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9293 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9295 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9296 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9297 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9298 caps = gst_caps_new_simple ("video/x-msmpeg",
9299 "msmpegversion", G_TYPE_INT, 43, NULL);
9301 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9302 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9303 _codec ("3ivX video");
9304 caps = gst_caps_new_empty_simple ("video/x-3ivx");
9306 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9308 caps = gst_caps_new_simple ("video/x-divx",
9309 "divxversion", G_TYPE_INT, 3, NULL);
9311 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9312 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9314 caps = gst_caps_new_simple ("video/x-divx",
9315 "divxversion", G_TYPE_INT, 4, NULL);
9317 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9319 caps = gst_caps_new_simple ("video/x-divx",
9320 "divxversion", G_TYPE_INT, 5, NULL);
9322 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9323 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9324 _codec ("XVID MPEG-4");
9325 caps = gst_caps_new_empty_simple ("video/x-xvid");
9328 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9329 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9330 caps = gst_caps_new_simple ("video/mpeg",
9331 "mpegversion", G_TYPE_INT, 4, NULL);
9333 *codec_name = g_strdup ("FFmpeg MPEG-4");
9336 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9338 caps = gst_caps_new_empty_simple ("video/x-cinepak");
9340 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9341 _codec ("Apple QuickDraw");
9342 caps = gst_caps_new_empty_simple ("video/x-qdrw");
9344 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9345 _codec ("Apple video");
9346 caps = gst_caps_new_empty_simple ("video/x-apple-video");
9348 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9349 _codec ("H.264 / AVC");
9350 caps = gst_caps_new_simple ("video/x-h264",
9351 "stream-format", G_TYPE_STRING, "avc",
9352 "alignment", G_TYPE_STRING, "au", NULL);
9354 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9355 _codec ("Run-length encoding");
9356 caps = gst_caps_new_simple ("video/x-rle",
9357 "layout", G_TYPE_STRING, "quicktime", NULL);
9359 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9360 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9361 _codec ("Indeo Video 3");
9362 caps = gst_caps_new_simple ("video/x-indeo",
9363 "indeoversion", G_TYPE_INT, 3, NULL);
9365 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9366 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9367 _codec ("Intel Video 4");
9368 caps = gst_caps_new_simple ("video/x-indeo",
9369 "indeoversion", G_TYPE_INT, 4, NULL);
9371 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9372 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9373 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9374 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9375 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9376 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9377 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9378 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9379 _codec ("DV Video");
9380 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9381 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9383 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9384 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9385 _codec ("DVCPro50 Video");
9386 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9387 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9389 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9390 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9391 _codec ("DVCProHD Video");
9392 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9393 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9395 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9396 _codec ("Apple Graphics (SMC)");
9397 caps = gst_caps_new_empty_simple ("video/x-smc");
9399 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9401 caps = gst_caps_new_empty_simple ("video/x-vp3");
9403 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9405 caps = gst_caps_new_empty_simple ("video/x-theora");
9406 /* theora uses one byte of padding in the data stream because it does not
9407 * allow 0 sized packets while theora does */
9408 stream->padding = 1;
9410 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9412 caps = gst_caps_new_empty_simple ("video/x-dirac");
9414 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9415 _codec ("TIFF still images");
9416 caps = gst_caps_new_empty_simple ("image/tiff");
9418 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9419 _codec ("Apple Intermediate Codec");
9420 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9422 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9423 _codec ("AVID DNxHD");
9424 caps = gst_caps_from_string ("video/x-dnxhd");
9426 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9428 caps = gst_caps_from_string ("video/x-vp8");
9432 caps = gst_caps_new_simple ("video/x-wmv",
9433 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
9435 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9440 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9441 GST_FOURCC_ARGS (fourcc));
9442 caps = gst_caps_new_empty_simple (s);
9447 /* enable clipping for raw video streams */
9448 s = gst_caps_get_structure (caps, 0);
9449 name = gst_structure_get_name (s);
9450 if (g_str_has_prefix (name, "video/x-raw")) {
9451 stream->need_clip = TRUE;
9457 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9458 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9461 const GstStructure *s;
9465 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9468 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9469 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9470 _codec ("Raw 8-bit PCM audio");
9471 caps = gst_caps_new_simple ("audio/x-raw",
9472 "format", G_TYPE_STRING, "U8", NULL);
9474 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9475 endian = G_BIG_ENDIAN;
9477 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9481 GstAudioFormat format;
9484 endian = G_LITTLE_ENDIAN;
9486 depth = stream->bytes_per_packet * 8;
9487 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
9489 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9493 caps = gst_caps_new_simple ("audio/x-raw",
9494 "format", G_TYPE_STRING, gst_audio_format_to_string (format), NULL);
9497 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9498 _codec ("Raw 64-bit floating-point audio");
9499 caps = gst_caps_new_simple ("audio/x-raw",
9500 "format", G_TYPE_STRING, "F64BE", NULL);
9502 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9503 _codec ("Raw 32-bit floating-point audio");
9504 caps = gst_caps_new_simple ("audio/x-raw",
9505 "format", G_TYPE_STRING, "F32BE", NULL);
9508 _codec ("Raw 24-bit PCM audio");
9509 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9511 caps = gst_caps_new_simple ("audio/x-raw",
9512 "format", G_TYPE_STRING, "S24BE", NULL);
9514 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9515 _codec ("Raw 32-bit PCM audio");
9516 caps = gst_caps_new_simple ("audio/x-raw",
9517 "format", G_TYPE_STRING, "S32BE", NULL);
9519 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9520 _codec ("Mu-law audio");
9521 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
9523 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9524 _codec ("A-law audio");
9525 caps = gst_caps_new_empty_simple ("audio/x-alaw");
9529 _codec ("Microsoft ADPCM");
9530 /* Microsoft ADPCM-ACM code 2 */
9531 caps = gst_caps_new_simple ("audio/x-adpcm",
9532 "layout", G_TYPE_STRING, "microsoft", NULL);
9536 _codec ("DVI/IMA ADPCM");
9537 caps = gst_caps_new_simple ("audio/x-adpcm",
9538 "layout", G_TYPE_STRING, "dvi", NULL);
9542 _codec ("DVI/Intel IMA ADPCM");
9543 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9544 caps = gst_caps_new_simple ("audio/x-adpcm",
9545 "layout", G_TYPE_STRING, "quicktime", NULL);
9549 /* MPEG layer 3, CBR only (pre QT4.1) */
9550 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9551 _codec ("MPEG-1 layer 3");
9552 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9553 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9554 "mpegversion", G_TYPE_INT, 1, NULL);
9557 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9558 _codec ("EAC-3 audio");
9559 caps = gst_caps_new_simple ("audio/x-eac3",
9560 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9561 stream->sampled = TRUE;
9563 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9564 _codec ("AC-3 audio");
9565 caps = gst_caps_new_simple ("audio/x-ac3",
9566 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9567 stream->sampled = TRUE;
9569 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9571 caps = gst_caps_new_simple ("audio/x-mace",
9572 "maceversion", G_TYPE_INT, 3, NULL);
9574 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9576 caps = gst_caps_new_simple ("audio/x-mace",
9577 "maceversion", G_TYPE_INT, 6, NULL);
9579 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9581 caps = gst_caps_new_empty_simple ("application/ogg");
9583 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9584 _codec ("DV audio");
9585 caps = gst_caps_new_empty_simple ("audio/x-dv");
9587 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9588 _codec ("MPEG-4 AAC audio");
9589 caps = gst_caps_new_simple ("audio/mpeg",
9590 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9591 "stream-format", G_TYPE_STRING, "raw", NULL);
9593 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9594 _codec ("QDesign Music");
9595 caps = gst_caps_new_empty_simple ("audio/x-qdm");
9597 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9598 _codec ("QDesign Music v.2");
9599 /* FIXME: QDesign music version 2 (no constant) */
9601 caps = gst_caps_new_simple ("audio/x-qdm2",
9602 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9603 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9604 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9606 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
9609 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9610 _codec ("GSM audio");
9611 caps = gst_caps_new_empty_simple ("audio/x-gsm");
9613 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9614 _codec ("AMR audio");
9615 caps = gst_caps_new_empty_simple ("audio/AMR");
9617 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9618 _codec ("AMR-WB audio");
9619 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
9621 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9622 _codec ("Quicktime IMA ADPCM");
9623 caps = gst_caps_new_simple ("audio/x-adpcm",
9624 "layout", G_TYPE_STRING, "quicktime", NULL);
9626 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9627 _codec ("Apple lossless audio");
9628 caps = gst_caps_new_empty_simple ("audio/x-alac");
9630 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9631 _codec ("QualComm PureVoice");
9632 caps = gst_caps_from_string ("audio/qcelp");
9636 caps = gst_caps_new_empty_simple ("audio/x-wma");
9638 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
9644 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9645 GST_FOURCC_ARGS (fourcc));
9646 caps = gst_caps_new_empty_simple (s);
9651 /* enable clipping for raw audio streams */
9652 s = gst_caps_get_structure (caps, 0);
9653 name = gst_structure_get_name (s);
9654 if (g_str_has_prefix (name, "audio/x-raw")) {
9655 stream->need_clip = TRUE;
9661 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9662 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9666 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9669 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
9670 _codec ("DVD subtitle");
9671 caps = gst_caps_new_empty_simple ("video/x-dvd-subpicture");
9673 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
9674 _codec ("Quicktime timed text");
9676 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
9677 _codec ("3GPP timed text");
9679 caps = gst_caps_new_empty_simple ("text/plain");
9680 /* actual text piece needs to be extracted */
9681 stream->need_process = TRUE;
9687 s = g_strdup_printf ("text/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9688 GST_FOURCC_ARGS (fourcc));
9689 caps = gst_caps_new_empty_simple (s);