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>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
12 * Copyright (C) <2016> British Broadcasting Corporation
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with this library; if not, write to the
26 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
31 * SECTION:element-qtdemux
34 * Demuxes a .mov file into raw or compressed audio and/or video streams.
36 * This element supports both push and pull-based scheduling, depending on the
37 * capabilities of the upstream elements.
39 * ## Example launch line
41 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
42 * ]| Play (parse and decode) a .mov file and try to output it to
43 * an automatically detected soundcard and videosink. If the MOV file contains
44 * compressed audio or video data, this will only work if you have the
45 * right decoder elements/plugins installed.
53 #include "gst/gst-i18n-plugin.h"
55 #include <glib/gprintf.h>
56 #include <gst/base/base.h>
57 #include <gst/tag/tag.h>
58 #include <gst/audio/audio.h>
59 #include <gst/riff/riff.h>
60 #include <gst/pbutils/pbutils.h>
62 #include "gstisomp4elements.h"
63 #include "qtatomparser.h"
64 #include "qtdemux_types.h"
65 #include "qtdemux_dump.h"
67 #include "descriptors.h"
68 #include "qtdemux_lang.h"
70 #include "qtpalette.h"
71 #include "qtdemux_tags.h"
72 #include "qtdemux_tree.h"
78 #include <gst/math-compat.h>
84 /* max. size considered 'sane' for non-mdat atoms */
85 #define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
87 /* if the sample index is larger than this, something is likely wrong */
88 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
90 /* For converting qt creation times to unix epoch times */
91 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
92 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
93 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
94 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
96 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
98 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
100 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
102 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
103 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
104 #define QTDEMUX_NTH_STREAM(demux,idx) \
105 QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
106 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
107 QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
109 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
111 GST_DEBUG_CATEGORY (qtdemux_debug);
112 #define GST_CAT_DEFAULT qtdemux_debug
114 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
115 typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
117 /* Macros for converting to/from timescale */
118 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
119 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
121 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
122 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
124 /* timestamp is the DTS */
125 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
126 /* timestamp + offset + cslg_shift is the outgoing PTS */
127 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
128 /* timestamp + offset is the PTS used for internal seek calculations */
129 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
130 /* timestamp + duration - dts is the duration */
131 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
133 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
135 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
136 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
137 GST_TRACE("Locking from thread %p", g_thread_self()); \
138 g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
139 GST_TRACE("Locked from thread %p", g_thread_self()); \
142 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
143 GST_TRACE("Unlocking from thread %p", g_thread_self()); \
144 g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
148 * Quicktime has tracks and segments. A track is a continuous piece of
149 * multimedia content. The track is not always played from start to finish but
150 * instead, pieces of the track are 'cut out' and played in sequence. This is
151 * what the segments do.
153 * Inside the track we have keyframes (K) and delta frames. The track has its
154 * own timing, which starts from 0 and extends to end. The position in the track
155 * is called the media_time.
157 * The segments now describe the pieces that should be played from this track
158 * and are basically tuples of media_time/duration/rate entries. We can have
159 * multiple segments and they are all played after one another. An example:
161 * segment 1: media_time: 1 second, duration: 1 second, rate 1
162 * segment 2: media_time: 3 second, duration: 2 second, rate 2
164 * To correctly play back this track, one must play: 1 second of media starting
165 * from media_time 1 followed by 2 seconds of media starting from media_time 3
168 * Each of the segments will be played at a specific time, the first segment at
169 * time 0, the second one after the duration of the first one, etc.. Note that
170 * the time in resulting playback is not identical to the media_time of the
173 * Visually, assuming the track has 4 second of media_time:
176 * .-----------------------------------------------------------.
177 * track: | K.....K.........K........K.......K.......K...........K... |
178 * '-----------------------------------------------------------'
180 * .------------^ ^ .----------^ ^
181 * / .-------------' / .------------------'
183 * .--------------. .--------------.
184 * | segment 1 | | segment 2 |
185 * '--------------' '--------------'
187 * The challenge here is to cut out the right pieces of the track for each of
188 * the playback segments. This fortunately can easily be done with the SEGMENT
189 * events of GStreamer.
191 * For playback of segment 1, we need to provide the decoder with the keyframe
192 * (a), in the above figure, but we must instruct it only to output the decoded
193 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
194 * position set to the time of the segment: 0.
196 * We then proceed to push data from keyframe (a) to frame (b). The decoder
197 * decodes but clips all before media_time 1.
199 * After finishing a segment, we push out a new SEGMENT event with the clipping
200 * boundaries of the new data.
202 * This is a good usecase for the GStreamer accumulated SEGMENT events.
205 struct _QtDemuxSegment
207 /* global time and duration, all gst time */
209 GstClockTime stop_time;
210 GstClockTime duration;
211 /* media time of trak, all gst time */
212 GstClockTime media_start;
213 GstClockTime media_stop;
215 /* Media start time in trak timescale units */
216 guint32 trak_media_start;
219 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
221 /* Used with fragmented MP4 files (mfra atom) */
222 struct _QtDemuxRandomAccessEntry
229 /* Contains properties and cryptographic info for a set of samples from a
230 * track protected using Common Encryption (cenc) */
231 struct _QtDemuxCencSampleSetInfo
233 GstStructure *default_properties;
235 /* @crypto_info holds one GstStructure per sample */
236 GPtrArray *crypto_info;
239 struct _QtDemuxAavdEncryptionInfo
241 GstStructure *default_properties;
245 qt_demux_state_string (enum QtDemuxState state)
248 case QTDEMUX_STATE_INITIAL:
250 case QTDEMUX_STATE_HEADER:
252 case QTDEMUX_STATE_MOVIE:
254 case QTDEMUX_STATE_BUFFER_MDAT:
255 return "<BUFFER_MDAT>";
261 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
263 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
265 static GstStaticPadTemplate gst_qtdemux_sink_template =
266 GST_STATIC_PAD_TEMPLATE ("sink",
269 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
273 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
274 GST_STATIC_PAD_TEMPLATE ("video_%u",
277 GST_STATIC_CAPS_ANY);
279 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
280 GST_STATIC_PAD_TEMPLATE ("audio_%u",
283 GST_STATIC_CAPS_ANY);
285 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
286 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
289 GST_STATIC_CAPS_ANY);
291 #define gst_qtdemux_parent_class parent_class
292 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
293 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
294 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
296 static void gst_qtdemux_dispose (GObject * object);
297 static void gst_qtdemux_finalize (GObject * object);
300 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
301 GstClockTime media_time);
303 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
304 QtDemuxStream * str, gint64 media_offset);
307 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
308 static GstIndex *gst_qtdemux_get_index (GstElement * element);
310 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
311 GstStateChange transition);
312 static void gst_qtdemux_set_context (GstElement * element,
313 GstContext * context);
314 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
315 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
316 GstObject * parent, GstPadMode mode, gboolean active);
318 static void gst_qtdemux_loop (GstPad * pad);
319 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
321 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
323 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
325 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
326 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
327 QtDemuxStream * stream);
328 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
329 QtDemuxStream * stream);
330 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
333 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
335 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
336 const guint8 * buffer, guint length);
337 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
338 const guint8 * buffer, guint length);
339 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
341 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
342 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
344 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
345 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
346 const guint8 * stsd_entry_data, gchar ** codec_name);
347 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
348 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
349 const guint8 * data, int len, gchar ** codec_name);
350 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
351 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
352 gchar ** codec_name);
353 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
354 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
355 const guint8 * stsd_entry_data, gchar ** codec_name);
357 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
358 QtDemuxStream * stream, guint32 n);
359 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
360 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
361 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
362 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
363 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
364 static void qtdemux_do_allocation (QtDemuxStream * stream,
365 GstQTDemux * qtdemux);
366 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
367 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
368 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
369 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
370 GstClockTime * _start, GstClockTime * _stop);
371 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
372 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
374 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
375 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
377 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
379 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
380 QtDemuxStream * stream, guint sample_index);
381 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
383 static void qtdemux_gst_structure_free (GstStructure * gststructure);
384 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
387 gst_qtdemux_class_init (GstQTDemuxClass * klass)
389 GObjectClass *gobject_class;
390 GstElementClass *gstelement_class;
392 gobject_class = (GObjectClass *) klass;
393 gstelement_class = (GstElementClass *) klass;
395 parent_class = g_type_class_peek_parent (klass);
397 gobject_class->dispose = gst_qtdemux_dispose;
398 gobject_class->finalize = gst_qtdemux_finalize;
400 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
402 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
403 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
405 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
407 gst_tag_register_musicbrainz_tags ();
409 gst_element_class_add_static_pad_template (gstelement_class,
410 &gst_qtdemux_sink_template);
411 gst_element_class_add_static_pad_template (gstelement_class,
412 &gst_qtdemux_videosrc_template);
413 gst_element_class_add_static_pad_template (gstelement_class,
414 &gst_qtdemux_audiosrc_template);
415 gst_element_class_add_static_pad_template (gstelement_class,
416 &gst_qtdemux_subsrc_template);
417 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
419 "Demultiplex a QuickTime file into audio and video streams",
420 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
422 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
427 gst_qtdemux_init (GstQTDemux * qtdemux)
430 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
431 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
432 gst_pad_set_activatemode_function (qtdemux->sinkpad,
433 qtdemux_sink_activate_mode);
434 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
435 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
436 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
437 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
439 qtdemux->adapter = gst_adapter_new ();
440 g_queue_init (&qtdemux->protection_event_queue);
441 qtdemux->flowcombiner = gst_flow_combiner_new ();
442 g_mutex_init (&qtdemux->expose_lock);
444 qtdemux->active_streams = g_ptr_array_new_with_free_func
445 ((GDestroyNotify) gst_qtdemux_stream_unref);
446 qtdemux->old_streams = g_ptr_array_new_with_free_func
447 ((GDestroyNotify) gst_qtdemux_stream_unref);
449 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
451 gst_qtdemux_reset (qtdemux, TRUE);
455 gst_qtdemux_finalize (GObject * object)
457 GstQTDemux *qtdemux = GST_QTDEMUX (object);
459 g_free (qtdemux->redirect_location);
461 G_OBJECT_CLASS (parent_class)->finalize (object);
465 gst_qtdemux_dispose (GObject * object)
467 GstQTDemux *qtdemux = GST_QTDEMUX (object);
469 if (qtdemux->adapter) {
470 g_object_unref (G_OBJECT (qtdemux->adapter));
471 qtdemux->adapter = NULL;
473 gst_tag_list_unref (qtdemux->tag_list);
474 gst_flow_combiner_free (qtdemux->flowcombiner);
475 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
477 g_queue_clear (&qtdemux->protection_event_queue);
479 g_free (qtdemux->cenc_aux_info_sizes);
480 qtdemux->cenc_aux_info_sizes = NULL;
481 g_mutex_clear (&qtdemux->expose_lock);
483 g_ptr_array_free (qtdemux->active_streams, TRUE);
484 g_ptr_array_free (qtdemux->old_streams, TRUE);
486 G_OBJECT_CLASS (parent_class)->dispose (object);
490 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
492 if (qtdemux->redirect_location) {
493 GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
494 (_("This file contains no playable streams.")),
495 ("no known streams found, a redirect message has been posted"),
496 ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
498 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
499 (_("This file contains no playable streams.")),
500 ("no known streams found"));
505 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
507 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
508 mem, size, 0, size, mem, free_func);
512 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
519 if (G_UNLIKELY (size == 0)) {
521 GstBuffer *tmp = NULL;
523 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
524 if (ret != GST_FLOW_OK)
527 gst_buffer_map (tmp, &map, GST_MAP_READ);
528 size = QT_UINT32 (map.data);
529 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
531 gst_buffer_unmap (tmp, &map);
532 gst_buffer_unref (tmp);
535 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
536 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
537 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
538 /* we're pulling header but already got most interesting bits,
539 * so never mind the rest (e.g. tags) (that much) */
540 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
544 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
545 (_("This file is invalid and cannot be played.")),
546 ("atom has bogus size %" G_GUINT64_FORMAT, size));
547 return GST_FLOW_ERROR;
551 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
553 if (G_UNLIKELY (flow != GST_FLOW_OK))
556 bsize = gst_buffer_get_size (*buf);
557 /* Catch short reads - we don't want any partial atoms */
558 if (G_UNLIKELY (bsize < size)) {
559 GST_WARNING_OBJECT (qtdemux,
560 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
561 gst_buffer_unref (*buf);
571 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
572 GstFormat src_format, gint64 src_value, GstFormat dest_format,
576 QtDemuxStream *stream = gst_pad_get_element_private (pad);
579 if (stream->subtype != FOURCC_vide) {
584 switch (src_format) {
585 case GST_FORMAT_TIME:
586 switch (dest_format) {
587 case GST_FORMAT_BYTES:{
588 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
594 *dest_value = stream->samples[index].offset;
596 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
597 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
598 GST_TIME_ARGS (src_value), *dest_value);
606 case GST_FORMAT_BYTES:
607 switch (dest_format) {
608 case GST_FORMAT_TIME:{
610 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
619 QTSTREAMTIME_TO_GSTTIME (stream,
620 stream->samples[index].timestamp);
621 GST_DEBUG_OBJECT (qtdemux,
622 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
623 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
642 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
644 gboolean res = FALSE;
646 *duration = GST_CLOCK_TIME_NONE;
648 if (qtdemux->duration != 0 &&
649 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
650 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
653 *duration = GST_CLOCK_TIME_NONE;
660 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
663 gboolean res = FALSE;
664 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
666 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
668 switch (GST_QUERY_TYPE (query)) {
669 case GST_QUERY_POSITION:{
672 gst_query_parse_position (query, &fmt, NULL);
673 if (fmt == GST_FORMAT_TIME
674 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
675 gst_query_set_position (query, GST_FORMAT_TIME,
676 qtdemux->segment.position);
681 case GST_QUERY_DURATION:{
684 gst_query_parse_duration (query, &fmt, NULL);
685 if (fmt == GST_FORMAT_TIME) {
686 /* First try to query upstream */
687 res = gst_pad_query_default (pad, parent, query);
689 GstClockTime duration;
690 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
691 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
698 case GST_QUERY_CONVERT:{
699 GstFormat src_fmt, dest_fmt;
700 gint64 src_value, dest_value = 0;
702 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
704 res = gst_qtdemux_src_convert (qtdemux, pad,
705 src_fmt, src_value, dest_fmt, &dest_value);
707 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
711 case GST_QUERY_FORMATS:
712 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
715 case GST_QUERY_SEEKING:{
719 /* try upstream first */
720 res = gst_pad_query_default (pad, parent, query);
723 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
724 if (fmt == GST_FORMAT_TIME) {
725 GstClockTime duration;
727 gst_qtdemux_get_duration (qtdemux, &duration);
729 if (!qtdemux->pullbased) {
732 /* we might be able with help from upstream */
734 q = gst_query_new_seeking (GST_FORMAT_BYTES);
735 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
736 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
737 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
741 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
747 case GST_QUERY_SEGMENT:
752 format = qtdemux->segment.format;
755 gst_segment_to_stream_time (&qtdemux->segment, format,
756 qtdemux->segment.start);
757 if ((stop = qtdemux->segment.stop) == -1)
758 stop = qtdemux->segment.duration;
760 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
762 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
767 res = gst_pad_query_default (pad, parent, query);
775 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
777 if (G_LIKELY (stream->pad)) {
778 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
779 GST_DEBUG_PAD_NAME (stream->pad));
781 if (!gst_tag_list_is_empty (stream->stream_tags)) {
782 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
783 stream->stream_tags);
784 gst_pad_push_event (stream->pad,
785 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
788 if (G_UNLIKELY (stream->send_global_tags)) {
789 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
791 gst_pad_push_event (stream->pad,
792 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
793 stream->send_global_tags = FALSE;
798 /* push event on all source pads; takes ownership of the event */
800 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
802 gboolean has_valid_stream = FALSE;
803 GstEventType etype = GST_EVENT_TYPE (event);
806 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
807 GST_EVENT_TYPE_NAME (event));
809 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
811 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
812 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
814 if ((pad = stream->pad)) {
815 has_valid_stream = TRUE;
817 if (etype == GST_EVENT_EOS) {
818 /* let's not send twice */
819 if (stream->sent_eos)
821 stream->sent_eos = TRUE;
824 gst_pad_push_event (pad, gst_event_ref (event));
828 gst_event_unref (event);
830 /* if it is EOS and there are no pads, post an error */
831 if (!has_valid_stream && etype == GST_EVENT_EOS) {
832 gst_qtdemux_post_no_playable_stream_error (qtdemux);
842 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
844 if ((gint64) s1->timestamp > *media_time)
846 if ((gint64) s1->timestamp == *media_time)
852 /* find the index of the sample that includes the data for @media_time using a
853 * binary search. Only to be called in optimized cases of linear search below.
855 * Returns the index of the sample with the corresponding *DTS*.
858 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
861 QtDemuxSample *result;
864 /* convert media_time to mov format */
866 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
868 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
869 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
870 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
872 if (G_LIKELY (result))
873 index = result - str->samples;
882 /* find the index of the sample that includes the data for @media_offset using a
885 * Returns the index of the sample.
888 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
889 QtDemuxStream * str, gint64 media_offset)
891 QtDemuxSample *result = str->samples;
894 if (result == NULL || str->n_samples == 0)
897 if (media_offset == result->offset)
901 while (index < str->n_samples - 1) {
902 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
905 if (media_offset < result->offset)
916 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
921 /* find the index of the sample that includes the data for @media_time using a
922 * linear search, and keeping in mind that not all samples may have been parsed
923 * yet. If possible, it will delegate to binary search.
925 * Returns the index of the sample.
928 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
929 GstClockTime media_time)
933 QtDemuxSample *sample;
935 /* convert media_time to mov format */
937 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
939 sample = str->samples;
940 if (mov_time == sample->timestamp + sample->pts_offset)
943 /* use faster search if requested time in already parsed range */
944 sample = str->samples + str->stbl_index;
945 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
946 index = gst_qtdemux_find_index (qtdemux, str, media_time);
947 sample = str->samples + index;
949 while (index < str->n_samples - 1) {
950 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
953 sample = str->samples + index + 1;
954 if (mov_time < sample->timestamp) {
955 sample = str->samples + index;
963 /* sample->timestamp is now <= media_time, need to find the corresponding
964 * PTS now by looking backwards */
965 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
967 sample = str->samples + index;
975 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
980 /* find the index of the keyframe needed to decode the sample at @index
981 * of stream @str, or of a subsequent keyframe (depending on @next)
983 * Returns the index of the keyframe.
986 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
987 guint32 index, gboolean next)
989 guint32 new_index = index;
991 if (index >= str->n_samples) {
992 new_index = str->n_samples;
996 /* all keyframes, return index */
997 if (str->all_keyframe) {
1002 /* else search until we have a keyframe */
1003 while (new_index < str->n_samples) {
1004 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1007 if (str->samples[new_index].keyframe)
1019 if (new_index == str->n_samples) {
1020 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1025 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1026 "gave %u", next ? "after" : "before", index, new_index);
1033 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1038 /* find the segment for @time_position for @stream
1040 * Returns the index of the segment containing @time_position.
1041 * Returns the last segment and sets the @eos variable to TRUE
1042 * if the time is beyond the end. @eos may be NULL
1045 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1046 GstClockTime time_position)
1051 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1052 GST_TIME_ARGS (time_position));
1055 for (i = 0; i < stream->n_segments; i++) {
1056 QtDemuxSegment *segment = &stream->segments[i];
1058 GST_LOG_OBJECT (stream->pad,
1059 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1060 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1062 /* For the last segment we include stop_time in the last segment */
1063 if (i < stream->n_segments - 1) {
1064 if (segment->time <= time_position && time_position < segment->stop_time) {
1065 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1070 /* Last segment always matches */
1078 /* move the stream @str to the sample position @index.
1080 * Updates @str->sample_index and marks discontinuity if needed.
1083 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1086 /* no change needed */
1087 if (index == str->sample_index)
1090 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1093 /* position changed, we have a discont */
1094 str->sample_index = index;
1095 str->offset_in_sample = 0;
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 gboolean use_sparse, gboolean next, 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 (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1116 guint32 index, kindex;
1118 GstClockTime media_start;
1119 GstClockTime media_time;
1120 GstClockTime seg_time;
1121 QtDemuxSegment *seg;
1122 gboolean empty_segment = FALSE;
1124 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1126 if (CUR_STREAM (str)->sparse && !use_sparse)
1129 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1130 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1132 /* get segment and time in the segment */
1133 seg = &str->segments[seg_idx];
1134 seg_time = (desired_time - seg->time) * seg->rate;
1136 while (QTSEGMENT_IS_EMPTY (seg)) {
1138 empty_segment = TRUE;
1139 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1142 if (seg_idx == str->n_segments)
1144 seg = &str->segments[seg_idx];
1147 if (seg_idx == str->n_segments) {
1148 /* FIXME track shouldn't have the last segment as empty, but if it
1149 * happens we better handle it */
1153 /* get the media time in the segment */
1154 media_start = seg->media_start + seg_time;
1156 /* get the index of the sample with media time */
1157 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1158 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1159 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1160 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1163 /* shift to next frame if we are looking for next keyframe */
1164 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1165 && index < str->stbl_index)
1168 if (!empty_segment) {
1169 /* find previous keyframe */
1170 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1172 /* we will settle for one before if none found after */
1173 if (next && kindex == -1)
1174 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1176 /* Update the requested time whenever a keyframe was found, to make it
1177 * accurate and avoid having the first buffer fall outside of the segment
1182 /* get timestamp of keyframe */
1183 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1184 GST_DEBUG_OBJECT (qtdemux,
1185 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1186 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1187 str->samples[kindex].offset);
1189 /* keyframes in the segment get a chance to change the
1190 * desired_offset. keyframes out of the segment are
1192 if (media_time >= seg->media_start) {
1193 GstClockTime seg_time;
1195 /* this keyframe is inside the segment, convert back to
1197 seg_time = (media_time - seg->media_start) + seg->time;
1198 if ((!next && (seg_time < min_offset)) ||
1199 (next && (seg_time > min_offset)))
1200 min_offset = seg_time;
1205 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1206 min_byte_offset = str->samples[index].offset;
1210 *key_time = min_offset;
1212 *key_offset = min_byte_offset;
1216 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1217 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1221 g_return_val_if_fail (format != NULL, FALSE);
1222 g_return_val_if_fail (cur != NULL, FALSE);
1223 g_return_val_if_fail (stop != NULL, FALSE);
1225 if (*format == GST_FORMAT_TIME)
1229 if (cur_type != GST_SEEK_TYPE_NONE)
1230 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1231 if (res && stop_type != GST_SEEK_TYPE_NONE)
1232 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1235 *format = GST_FORMAT_TIME;
1240 /* perform seek in push based mode:
1241 find BYTE position to move to based on time and delegate to upstream
1244 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1249 GstSeekType cur_type, stop_type;
1250 gint64 cur, stop, key_cur;
1253 gint64 original_stop;
1256 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1258 gst_event_parse_seek (event, &rate, &format, &flags,
1259 &cur_type, &cur, &stop_type, &stop);
1260 seqnum = gst_event_get_seqnum (event);
1262 /* Directly send the instant-rate-change event here before taking the
1263 * stream-lock so that it can be applied as soon as possible */
1264 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1267 /* instant rate change only supported if direction does not change. All
1268 * other requirements are already checked before creating the seek event
1269 * but let's double-check here to be sure */
1270 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1271 (qtdemux->segment.rate < 0 && rate > 0) ||
1272 cur_type != GST_SEEK_TYPE_NONE ||
1273 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1274 GST_ERROR_OBJECT (qtdemux,
1275 "Instant rate change seeks only supported in the "
1276 "same direction, without flushing and position change");
1280 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1281 (GstSegmentFlags) flags);
1282 gst_event_set_seqnum (ev, seqnum);
1283 gst_qtdemux_push_event (qtdemux, ev);
1287 /* only forward streaming and seeking is possible */
1289 goto unsupported_seek;
1291 /* convert to TIME if needed and possible */
1292 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1296 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1297 * the original stop position to use when upstream pushes the new segment
1299 original_stop = stop;
1302 /* find reasonable corresponding BYTE position,
1303 * also try to mind about keyframes, since we can not go back a bit for them
1305 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1306 * mostly just work, but let's not yet boldly go there ... */
1307 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1312 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1313 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1316 GST_OBJECT_LOCK (qtdemux);
1317 qtdemux->seek_offset = byte_cur;
1318 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1319 qtdemux->push_seek_start = cur;
1321 qtdemux->push_seek_start = key_cur;
1324 if (stop_type == GST_SEEK_TYPE_NONE) {
1325 qtdemux->push_seek_stop = qtdemux->segment.stop;
1327 qtdemux->push_seek_stop = original_stop;
1329 GST_OBJECT_UNLOCK (qtdemux);
1331 qtdemux->segment_seqnum = seqnum;
1332 /* BYTE seek event */
1333 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1335 gst_event_set_seqnum (event, seqnum);
1336 res = gst_pad_push_event (qtdemux->sinkpad, event);
1343 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1349 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1354 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1359 /* perform the seek.
1361 * We set all segment_indexes in the streams to unknown and
1362 * adjust the time_position to the desired position. this is enough
1363 * to trigger a segment switch in the streaming thread to start
1364 * streaming from the desired position.
1366 * Keyframe seeking is a little more complicated when dealing with
1367 * segments. Ideally we want to move to the previous keyframe in
1368 * the segment but there might not be a keyframe in the segment. In
1369 * fact, none of the segments could contain a keyframe. We take a
1370 * practical approach: seek to the previous keyframe in the segment,
1371 * if there is none, seek to the beginning of the segment.
1373 * Called with STREAM_LOCK
1376 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1377 guint32 seqnum, GstSeekFlags flags)
1379 gint64 desired_offset;
1382 desired_offset = segment->position;
1384 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1385 GST_TIME_ARGS (desired_offset));
1387 /* may not have enough fragmented info to do this adjustment,
1388 * and we can't scan (and probably should not) at this time with
1389 * possibly flushing upstream */
1390 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1392 gboolean next, before, after;
1394 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1395 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1396 next = after && !before;
1397 if (segment->rate < 0)
1400 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1402 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1403 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1404 desired_offset = min_offset;
1407 /* and set all streams to the final position */
1408 GST_OBJECT_LOCK (qtdemux);
1409 gst_flow_combiner_reset (qtdemux->flowcombiner);
1410 GST_OBJECT_UNLOCK (qtdemux);
1411 qtdemux->segment_seqnum = seqnum;
1412 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1413 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1415 stream->time_position = desired_offset;
1416 stream->accumulated_base = 0;
1417 stream->sample_index = -1;
1418 stream->offset_in_sample = 0;
1419 stream->segment_index = -1;
1420 stream->sent_eos = FALSE;
1421 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1423 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1424 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1426 segment->position = desired_offset;
1427 if (segment->rate >= 0) {
1428 segment->start = desired_offset;
1429 /* We need to update time as we update start in that direction */
1430 segment->time = desired_offset;
1432 /* we stop at the end */
1433 if (segment->stop == -1)
1434 segment->stop = segment->duration;
1436 segment->stop = desired_offset;
1439 if (qtdemux->fragmented)
1440 qtdemux->fragmented_seek_pending = TRUE;
1445 /* do a seek in pull based mode */
1447 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1452 GstSeekType cur_type, stop_type;
1454 gboolean flush, instant_rate_change;
1456 GstSegment seeksegment;
1457 guint32 seqnum = GST_SEQNUM_INVALID;
1458 GstEvent *flush_event;
1461 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1463 gst_event_parse_seek (event, &rate, &format, &flags,
1464 &cur_type, &cur, &stop_type, &stop);
1465 seqnum = gst_event_get_seqnum (event);
1467 /* we have to have a format as the segment format. Try to convert
1469 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1473 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1475 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1476 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1478 /* Directly send the instant-rate-change event here before taking the
1479 * stream-lock so that it can be applied as soon as possible */
1480 if (instant_rate_change) {
1483 /* instant rate change only supported if direction does not change. All
1484 * other requirements are already checked before creating the seek event
1485 * but let's double-check here to be sure */
1486 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1487 (qtdemux->segment.rate < 0 && rate > 0) ||
1488 cur_type != GST_SEEK_TYPE_NONE ||
1489 stop_type != GST_SEEK_TYPE_NONE || flush) {
1490 GST_ERROR_OBJECT (qtdemux,
1491 "Instant rate change seeks only supported in the "
1492 "same direction, without flushing and position change");
1496 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1497 (GstSegmentFlags) flags);
1498 gst_event_set_seqnum (ev, seqnum);
1499 gst_qtdemux_push_event (qtdemux, ev);
1503 /* stop streaming, either by flushing or by pausing the task */
1505 flush_event = gst_event_new_flush_start ();
1506 if (seqnum != GST_SEQNUM_INVALID)
1507 gst_event_set_seqnum (flush_event, seqnum);
1508 /* unlock upstream pull_range */
1509 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1510 /* make sure out loop function exits */
1511 gst_qtdemux_push_event (qtdemux, flush_event);
1513 /* non flushing seek, pause the task */
1514 gst_pad_pause_task (qtdemux->sinkpad);
1517 /* wait for streaming to finish */
1518 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1520 /* copy segment, we need this because we still need the old
1521 * segment when we close the current segment. */
1522 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1524 /* configure the segment with the seek variables */
1525 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1526 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1527 cur_type, cur, stop_type, stop, &update)) {
1529 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1531 /* now do the seek */
1532 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1535 /* prepare for streaming again */
1537 flush_event = gst_event_new_flush_stop (TRUE);
1538 if (seqnum != GST_SEQNUM_INVALID)
1539 gst_event_set_seqnum (flush_event, seqnum);
1541 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1542 gst_qtdemux_push_event (qtdemux, flush_event);
1545 /* commit the new segment */
1546 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1548 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1549 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1550 qtdemux->segment.format, qtdemux->segment.position);
1551 if (seqnum != GST_SEQNUM_INVALID)
1552 gst_message_set_seqnum (msg, seqnum);
1553 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1556 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1557 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1558 qtdemux->sinkpad, NULL);
1560 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1567 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1573 qtdemux_ensure_index (GstQTDemux * qtdemux)
1577 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1579 /* Build complete index */
1580 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1581 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1583 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1584 GST_LOG_OBJECT (qtdemux,
1585 "Building complete index of track-id %u for seeking failed!",
1595 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1598 gboolean res = TRUE;
1599 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1601 switch (GST_EVENT_TYPE (event)) {
1602 case GST_EVENT_RECONFIGURE:
1603 GST_OBJECT_LOCK (qtdemux);
1604 gst_flow_combiner_reset (qtdemux->flowcombiner);
1605 GST_OBJECT_UNLOCK (qtdemux);
1606 res = gst_pad_event_default (pad, parent, event);
1608 case GST_EVENT_SEEK:
1610 GstSeekFlags flags = 0;
1611 gboolean instant_rate_change;
1613 #ifndef GST_DISABLE_GST_DEBUG
1614 GstClockTime ts = gst_util_get_timestamp ();
1616 guint32 seqnum = gst_event_get_seqnum (event);
1618 qtdemux->received_seek = TRUE;
1620 gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL);
1621 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1623 if (seqnum == qtdemux->segment_seqnum) {
1624 GST_LOG_OBJECT (pad,
1625 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1626 gst_event_unref (event);
1630 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1631 /* seek should be handled by upstream, we might need to re-download fragments */
1632 GST_DEBUG_OBJECT (qtdemux,
1633 "let upstream handle seek for fragmented playback");
1637 gst_event_parse_seek_trickmode_interval (event,
1638 &qtdemux->trickmode_interval);
1640 /* Build complete index for seeking;
1641 * if not a fragmented file at least and we're really doing a seek,
1642 * not just an instant-rate-change */
1643 if (!qtdemux->fragmented && !instant_rate_change) {
1644 if (!qtdemux_ensure_index (qtdemux))
1647 #ifndef GST_DISABLE_GST_DEBUG
1648 ts = gst_util_get_timestamp () - ts;
1649 GST_INFO_OBJECT (qtdemux,
1650 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1652 if (qtdemux->pullbased) {
1653 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1654 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1655 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1657 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1658 && QTDEMUX_N_STREAMS (qtdemux)
1659 && !qtdemux->fragmented) {
1660 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1662 GST_DEBUG_OBJECT (qtdemux,
1663 "ignoring seek in push mode in current state");
1666 gst_event_unref (event);
1671 res = gst_pad_event_default (pad, parent, event);
1681 GST_ERROR_OBJECT (qtdemux, "Index failed");
1682 gst_event_unref (event);
1688 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1690 * If @fw is false, the coding order is explored backwards.
1692 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1693 * sample is found for that track.
1695 * The stream and sample index of the sample with the minimum offset in the direction explored
1696 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1698 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1699 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1700 * @_stream and @_index. */
1702 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1703 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1706 gint64 time, min_time;
1707 QtDemuxStream *stream;
1714 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1717 gboolean set_sample;
1719 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1726 i = str->n_samples - 1;
1730 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1731 if (str->samples[i].size == 0)
1734 if (fw && (str->samples[i].offset < byte_pos))
1737 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1740 /* move stream to first available sample */
1742 gst_qtdemux_move_stream (qtdemux, str, i);
1746 /* avoid index from sparse streams since they might be far away */
1747 if (!CUR_STREAM (str)->sparse) {
1748 /* determine min/max time */
1749 time = QTSAMPLE_PTS (str, &str->samples[i]);
1750 if (min_time == -1 || (!fw && time > min_time) ||
1751 (fw && time < min_time)) {
1755 /* determine stream with leading sample, to get its position */
1757 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1758 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1766 /* no sample for this stream, mark eos */
1768 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1779 /* Copied from mpegtsbase code */
1780 /* FIXME: replace this function when we add new util function for stream-id creation */
1782 _get_upstream_id (GstQTDemux * demux)
1784 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1787 /* Try to create one from the upstream URI, else use a randome number */
1791 /* Try to generate one from the URI query and
1792 * if it fails take a random number instead */
1793 query = gst_query_new_uri ();
1794 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1795 gst_query_parse_uri (query, &uri);
1801 /* And then generate an SHA256 sum of the URI */
1802 cs = g_checksum_new (G_CHECKSUM_SHA256);
1803 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1805 upstream_id = g_strdup (g_checksum_get_string (cs));
1806 g_checksum_free (cs);
1808 /* Just get some random number if the URI query fails */
1809 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1810 "implementing a deterministic way of creating a stream-id");
1812 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1813 g_random_int (), g_random_int ());
1816 gst_query_unref (query);
1821 static QtDemuxStream *
1822 _create_stream (GstQTDemux * demux, guint32 track_id)
1824 QtDemuxStream *stream;
1827 stream = g_new0 (QtDemuxStream, 1);
1828 stream->demux = demux;
1829 stream->track_id = track_id;
1830 upstream_id = _get_upstream_id (demux);
1831 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1832 g_free (upstream_id);
1833 /* new streams always need a discont */
1834 stream->discont = TRUE;
1835 /* we enable clipping for raw audio/video streams */
1836 stream->need_clip = FALSE;
1837 stream->need_process = FALSE;
1838 stream->segment_index = -1;
1839 stream->time_position = 0;
1840 stream->sample_index = -1;
1841 stream->offset_in_sample = 0;
1842 stream->new_stream = TRUE;
1843 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1844 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1845 stream->protected = FALSE;
1846 stream->protection_scheme_type = 0;
1847 stream->protection_scheme_version = 0;
1848 stream->protection_scheme_info = NULL;
1849 stream->n_samples_moof = 0;
1850 stream->duration_moof = 0;
1851 stream->duration_last_moof = 0;
1852 stream->alignment = 1;
1853 stream->stream_tags = gst_tag_list_new_empty ();
1854 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1855 g_queue_init (&stream->protection_scheme_event_queue);
1856 stream->ref_count = 1;
1857 /* consistent default for push based mode */
1858 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1863 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1865 GstStructure *structure;
1866 const gchar *variant;
1867 const GstCaps *mediacaps = NULL;
1869 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1871 structure = gst_caps_get_structure (caps, 0);
1872 variant = gst_structure_get_string (structure, "variant");
1874 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1875 QtDemuxStream *stream;
1876 const GValue *value;
1878 demux->fragmented = TRUE;
1879 demux->mss_mode = TRUE;
1881 if (QTDEMUX_N_STREAMS (demux) > 1) {
1882 /* can't do this, we can only renegotiate for another mss format */
1886 value = gst_structure_get_value (structure, "media-caps");
1889 const GValue *timescale_v;
1891 /* TODO update when stream changes during playback */
1893 if (QTDEMUX_N_STREAMS (demux) == 0) {
1894 stream = _create_stream (demux, 1);
1895 g_ptr_array_add (demux->active_streams, stream);
1896 /* mss has no stsd/stsd entry, use id 0 as default */
1897 stream->stsd_entries_length = 1;
1898 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1899 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1901 stream = QTDEMUX_NTH_STREAM (demux, 0);
1904 timescale_v = gst_structure_get_value (structure, "timescale");
1906 stream->timescale = g_value_get_uint64 (timescale_v);
1908 /* default mss timescale */
1909 stream->timescale = 10000000;
1911 demux->timescale = stream->timescale;
1913 mediacaps = gst_value_get_caps (value);
1914 if (!CUR_STREAM (stream)->caps
1915 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1916 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1918 stream->new_caps = TRUE;
1920 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1921 structure = gst_caps_get_structure (mediacaps, 0);
1922 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1923 stream->subtype = FOURCC_vide;
1925 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1926 gst_structure_get_int (structure, "height",
1927 &CUR_STREAM (stream)->height);
1928 gst_structure_get_fraction (structure, "framerate",
1929 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1930 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1932 stream->subtype = FOURCC_soun;
1933 gst_structure_get_int (structure, "channels",
1934 &CUR_STREAM (stream)->n_channels);
1935 gst_structure_get_int (structure, "rate", &rate);
1936 CUR_STREAM (stream)->rate = rate;
1937 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1938 if (gst_structure_has_field (structure, "original-media-type")) {
1939 const gchar *media_type =
1940 gst_structure_get_string (structure, "original-media-type");
1941 if (g_str_has_prefix (media_type, "video")) {
1942 stream->subtype = FOURCC_vide;
1943 } else if (g_str_has_prefix (media_type, "audio")) {
1944 stream->subtype = FOURCC_soun;
1949 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1951 demux->mss_mode = FALSE;
1958 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1962 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1963 gst_pad_stop_task (qtdemux->sinkpad);
1965 if (hard || qtdemux->upstream_format_is_time) {
1966 qtdemux->state = QTDEMUX_STATE_INITIAL;
1967 qtdemux->neededbytes = 16;
1968 qtdemux->todrop = 0;
1969 qtdemux->pullbased = FALSE;
1970 g_clear_pointer (&qtdemux->redirect_location, g_free);
1971 qtdemux->first_mdat = -1;
1972 qtdemux->header_size = 0;
1973 qtdemux->mdatoffset = -1;
1974 qtdemux->restoredata_offset = -1;
1975 if (qtdemux->mdatbuffer)
1976 gst_buffer_unref (qtdemux->mdatbuffer);
1977 if (qtdemux->restoredata_buffer)
1978 gst_buffer_unref (qtdemux->restoredata_buffer);
1979 qtdemux->mdatbuffer = NULL;
1980 qtdemux->restoredata_buffer = NULL;
1981 qtdemux->mdatleft = 0;
1982 qtdemux->mdatsize = 0;
1983 if (qtdemux->comp_brands)
1984 gst_buffer_unref (qtdemux->comp_brands);
1985 qtdemux->comp_brands = NULL;
1986 qtdemux->last_moov_offset = -1;
1987 if (qtdemux->moov_node_compressed) {
1988 g_node_destroy (qtdemux->moov_node_compressed);
1989 if (qtdemux->moov_node)
1990 g_free (qtdemux->moov_node->data);
1992 qtdemux->moov_node_compressed = NULL;
1993 if (qtdemux->moov_node)
1994 g_node_destroy (qtdemux->moov_node);
1995 qtdemux->moov_node = NULL;
1996 if (qtdemux->tag_list)
1997 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1998 qtdemux->tag_list = gst_tag_list_new_empty ();
1999 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2001 if (qtdemux->element_index)
2002 gst_object_unref (qtdemux->element_index);
2003 qtdemux->element_index = NULL;
2005 qtdemux->major_brand = 0;
2006 qtdemux->upstream_format_is_time = FALSE;
2007 qtdemux->upstream_seekable = FALSE;
2008 qtdemux->upstream_size = 0;
2010 qtdemux->fragment_start = -1;
2011 qtdemux->fragment_start_offset = -1;
2012 qtdemux->duration = 0;
2013 qtdemux->moof_offset = 0;
2014 qtdemux->chapters_track_id = 0;
2015 qtdemux->have_group_id = FALSE;
2016 qtdemux->group_id = G_MAXUINT;
2018 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2020 g_queue_clear (&qtdemux->protection_event_queue);
2022 qtdemux->received_seek = FALSE;
2023 qtdemux->first_moof_already_parsed = FALSE;
2025 qtdemux->offset = 0;
2026 gst_adapter_clear (qtdemux->adapter);
2027 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2028 qtdemux->need_segment = TRUE;
2031 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2032 qtdemux->trickmode_interval = 0;
2033 g_ptr_array_set_size (qtdemux->active_streams, 0);
2034 g_ptr_array_set_size (qtdemux->old_streams, 0);
2035 qtdemux->n_video_streams = 0;
2036 qtdemux->n_audio_streams = 0;
2037 qtdemux->n_sub_streams = 0;
2038 qtdemux->exposed = FALSE;
2039 qtdemux->fragmented = FALSE;
2040 qtdemux->mss_mode = FALSE;
2041 gst_caps_replace (&qtdemux->media_caps, NULL);
2042 qtdemux->timescale = 0;
2043 qtdemux->got_moov = FALSE;
2044 qtdemux->cenc_aux_info_offset = 0;
2045 qtdemux->cenc_aux_info_sizes = NULL;
2046 qtdemux->cenc_aux_sample_count = 0;
2047 if (qtdemux->protection_system_ids) {
2048 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2049 qtdemux->protection_system_ids = NULL;
2051 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2052 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2053 GST_BIN_FLAG_STREAMS_AWARE);
2055 if (qtdemux->preferred_protection_system_id) {
2056 g_free (qtdemux->preferred_protection_system_id);
2057 qtdemux->preferred_protection_system_id = NULL;
2059 } else if (qtdemux->mss_mode) {
2060 gst_flow_combiner_reset (qtdemux->flowcombiner);
2061 g_ptr_array_foreach (qtdemux->active_streams,
2062 (GFunc) gst_qtdemux_stream_clear, NULL);
2064 gst_flow_combiner_reset (qtdemux->flowcombiner);
2065 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2066 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2067 stream->sent_eos = FALSE;
2068 stream->time_position = 0;
2069 stream->accumulated_base = 0;
2070 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2076 /* Maps the @segment to the qt edts internal segments and pushes
2077 * the corresponding segment event.
2079 * If it ends up being at a empty segment, a gap will be pushed and the next
2080 * edts segment will be activated in sequence.
2082 * To be used in push-mode only */
2084 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2088 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2089 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2091 stream->time_position = segment->start;
2093 /* in push mode we should be guaranteed that we will have empty segments
2094 * at the beginning and then one segment after, other scenarios are not
2095 * supported and are discarded when parsing the edts */
2096 for (i = 0; i < stream->n_segments; i++) {
2097 if (stream->segments[i].stop_time > segment->start) {
2098 /* push the empty segment and move to the next one */
2099 gst_qtdemux_activate_segment (qtdemux, stream, i,
2100 stream->time_position);
2101 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2102 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2103 stream->time_position);
2105 /* accumulate previous segments */
2106 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2107 stream->accumulated_base +=
2108 (stream->segment.stop -
2109 stream->segment.start) / ABS (stream->segment.rate);
2113 g_assert (i == stream->n_segments - 1);
2120 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2131 for (i = 0; i < len; i++) {
2132 QtDemuxStream *stream = g_ptr_array_index (src, i);
2134 #ifndef GST_DISABLE_GST_DEBUG
2135 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2136 stream, GST_STR_NULL (stream->stream_id), dest);
2138 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2141 g_ptr_array_set_size (src, 0);
2145 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2148 GstQTDemux *demux = GST_QTDEMUX (parent);
2149 gboolean res = TRUE;
2151 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2153 switch (GST_EVENT_TYPE (event)) {
2154 case GST_EVENT_SEGMENT:
2157 QtDemuxStream *stream;
2161 /* some debug output */
2162 gst_event_copy_segment (event, &segment);
2163 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2166 if (segment.format == GST_FORMAT_TIME) {
2167 demux->upstream_format_is_time = TRUE;
2168 demux->segment_seqnum = gst_event_get_seqnum (event);
2170 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2171 "not in time format");
2173 /* chain will send initial newsegment after pads have been added */
2174 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2175 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2180 /* check if this matches a time seek we received previously
2181 * FIXME for backwards compatibility reasons we use the
2182 * seek_offset here to compare. In the future we might want to
2183 * change this to use the seqnum as it uniquely should identify
2184 * the segment that corresponds to the seek. */
2185 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2186 ", received segment offset %" G_GINT64_FORMAT,
2187 demux->seek_offset, segment.start);
2188 if (segment.format == GST_FORMAT_BYTES
2189 && demux->seek_offset == segment.start) {
2190 GST_OBJECT_LOCK (demux);
2191 offset = segment.start;
2193 segment.format = GST_FORMAT_TIME;
2194 segment.start = demux->push_seek_start;
2195 segment.stop = demux->push_seek_stop;
2196 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2197 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2198 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2199 GST_OBJECT_UNLOCK (demux);
2202 /* we only expect a BYTE segment, e.g. following a seek */
2203 if (segment.format == GST_FORMAT_BYTES) {
2204 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2205 offset = segment.start;
2207 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2208 NULL, (gint64 *) & segment.start);
2209 if ((gint64) segment.start < 0)
2212 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2213 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2214 NULL, (gint64 *) & segment.stop);
2215 /* keyframe seeking should already arrange for start >= stop,
2216 * but make sure in other rare cases */
2217 segment.stop = MAX (segment.stop, segment.start);
2219 } else if (segment.format == GST_FORMAT_TIME) {
2220 /* push all data on the adapter before starting this
2222 gst_qtdemux_process_adapter (demux, TRUE);
2224 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2228 /* We shouldn't modify upstream driven TIME FORMAT segment */
2229 if (!demux->upstream_format_is_time) {
2230 /* accept upstream's notion of segment and distribute along */
2231 segment.format = GST_FORMAT_TIME;
2232 segment.position = segment.time = segment.start;
2233 segment.duration = demux->segment.duration;
2234 segment.base = gst_segment_to_running_time (&demux->segment,
2235 GST_FORMAT_TIME, demux->segment.position);
2238 gst_segment_copy_into (&segment, &demux->segment);
2239 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2241 /* map segment to internal qt segments and push on each stream */
2242 if (QTDEMUX_N_STREAMS (demux)) {
2243 demux->need_segment = TRUE;
2244 gst_qtdemux_check_send_pending_segment (demux);
2247 /* clear leftover in current segment, if any */
2248 gst_adapter_clear (demux->adapter);
2250 /* set up streaming thread */
2251 demux->offset = offset;
2252 if (demux->upstream_format_is_time) {
2253 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2254 "set values to restart reading from a new atom");
2255 demux->neededbytes = 16;
2258 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2261 demux->todrop = stream->samples[idx].offset - offset;
2262 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2264 /* set up for EOS */
2265 demux->neededbytes = -1;
2270 gst_event_unref (event);
2274 case GST_EVENT_FLUSH_START:
2276 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2277 gst_event_unref (event);
2280 QTDEMUX_EXPOSE_LOCK (demux);
2281 res = gst_pad_event_default (demux->sinkpad, parent, event);
2282 QTDEMUX_EXPOSE_UNLOCK (demux);
2285 case GST_EVENT_FLUSH_STOP:
2289 dur = demux->segment.duration;
2290 gst_qtdemux_reset (demux, FALSE);
2291 demux->segment.duration = dur;
2293 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2294 gst_event_unref (event);
2300 /* If we are in push mode, and get an EOS before we've seen any streams,
2301 * then error out - we have nowhere to send the EOS */
2302 if (!demux->pullbased) {
2304 gboolean has_valid_stream = FALSE;
2305 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2306 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2307 has_valid_stream = TRUE;
2311 if (!has_valid_stream)
2312 gst_qtdemux_post_no_playable_stream_error (demux);
2314 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2315 (guint) gst_adapter_available (demux->adapter));
2316 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2322 case GST_EVENT_CAPS:{
2323 GstCaps *caps = NULL;
2325 gst_event_parse_caps (event, &caps);
2326 gst_qtdemux_setcaps (demux, caps);
2328 gst_event_unref (event);
2331 case GST_EVENT_PROTECTION:
2333 const gchar *system_id = NULL;
2335 gst_event_parse_protection (event, &system_id, NULL, NULL);
2336 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2338 gst_qtdemux_append_protection_system_id (demux, system_id);
2339 /* save the event for later, for source pads that have not been created */
2340 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2341 /* send it to all pads that already exist */
2342 gst_qtdemux_push_event (demux, event);
2346 case GST_EVENT_STREAM_START:
2349 gst_event_unref (event);
2351 /* Drain all the buffers */
2352 gst_qtdemux_process_adapter (demux, TRUE);
2353 gst_qtdemux_reset (demux, FALSE);
2354 /* We expect new moov box after new stream-start event */
2355 if (demux->exposed) {
2356 gst_qtdemux_stream_concat (demux,
2357 demux->old_streams, demux->active_streams);
2366 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2373 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2376 GstQTDemux *demux = GST_QTDEMUX (parent);
2377 gboolean res = FALSE;
2379 switch (GST_QUERY_TYPE (query)) {
2380 case GST_QUERY_BITRATE:
2382 GstClockTime duration;
2384 /* populate demux->upstream_size if not done yet */
2385 gst_qtdemux_check_seekability (demux);
2387 if (demux->upstream_size != -1
2388 && gst_qtdemux_get_duration (demux, &duration)) {
2390 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2393 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2394 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2395 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2397 /* TODO: better results based on ranges/index tables */
2398 gst_query_set_bitrate (query, bitrate);
2404 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2414 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2416 GstQTDemux *demux = GST_QTDEMUX (element);
2418 GST_OBJECT_LOCK (demux);
2419 if (demux->element_index)
2420 gst_object_unref (demux->element_index);
2422 demux->element_index = gst_object_ref (index);
2424 demux->element_index = NULL;
2426 GST_OBJECT_UNLOCK (demux);
2427 /* object lock might be taken again */
2429 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2430 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2431 demux->element_index, demux->index_id);
2435 gst_qtdemux_get_index (GstElement * element)
2437 GstIndex *result = NULL;
2438 GstQTDemux *demux = GST_QTDEMUX (element);
2440 GST_OBJECT_LOCK (demux);
2441 if (demux->element_index)
2442 result = gst_object_ref (demux->element_index);
2443 GST_OBJECT_UNLOCK (demux);
2445 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2452 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2454 g_free ((gpointer) stream->stco.data);
2455 stream->stco.data = NULL;
2456 g_free ((gpointer) stream->stsz.data);
2457 stream->stsz.data = NULL;
2458 g_free ((gpointer) stream->stsc.data);
2459 stream->stsc.data = NULL;
2460 g_free ((gpointer) stream->stts.data);
2461 stream->stts.data = NULL;
2462 g_free ((gpointer) stream->stss.data);
2463 stream->stss.data = NULL;
2464 g_free ((gpointer) stream->stps.data);
2465 stream->stps.data = NULL;
2466 g_free ((gpointer) stream->ctts.data);
2467 stream->ctts.data = NULL;
2471 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2473 g_free (stream->segments);
2474 stream->segments = NULL;
2475 stream->segment_index = -1;
2476 stream->accumulated_base = 0;
2480 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2482 g_free (stream->samples);
2483 stream->samples = NULL;
2484 gst_qtdemux_stbl_free (stream);
2487 g_free (stream->ra_entries);
2488 stream->ra_entries = NULL;
2489 stream->n_ra_entries = 0;
2491 stream->sample_index = -1;
2492 stream->stbl_index = -1;
2493 stream->n_samples = 0;
2494 stream->time_position = 0;
2496 stream->n_samples_moof = 0;
2497 stream->duration_moof = 0;
2498 stream->duration_last_moof = 0;
2502 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2505 if (stream->allocator)
2506 gst_object_unref (stream->allocator);
2507 while (stream->buffers) {
2508 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2509 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2511 for (i = 0; i < stream->stsd_entries_length; i++) {
2512 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2513 if (entry->rgb8_palette) {
2514 gst_memory_unref (entry->rgb8_palette);
2515 entry->rgb8_palette = NULL;
2517 entry->sparse = FALSE;
2520 if (stream->stream_tags)
2521 gst_tag_list_unref (stream->stream_tags);
2523 stream->stream_tags = gst_tag_list_new_empty ();
2524 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2525 g_free (stream->redirect_uri);
2526 stream->redirect_uri = NULL;
2527 stream->sent_eos = FALSE;
2528 stream->protected = FALSE;
2529 if (stream->protection_scheme_info) {
2530 if (stream->protection_scheme_type == FOURCC_cenc
2531 || stream->protection_scheme_type == FOURCC_cbcs) {
2532 QtDemuxCencSampleSetInfo *info =
2533 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2534 if (info->default_properties)
2535 gst_structure_free (info->default_properties);
2536 if (info->crypto_info)
2537 g_ptr_array_free (info->crypto_info, TRUE);
2539 if (stream->protection_scheme_type == FOURCC_aavd) {
2540 QtDemuxAavdEncryptionInfo *info =
2541 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2542 if (info->default_properties)
2543 gst_structure_free (info->default_properties);
2545 g_free (stream->protection_scheme_info);
2546 stream->protection_scheme_info = NULL;
2548 stream->protection_scheme_type = 0;
2549 stream->protection_scheme_version = 0;
2550 g_queue_foreach (&stream->protection_scheme_event_queue,
2551 (GFunc) gst_event_unref, NULL);
2552 g_queue_clear (&stream->protection_scheme_event_queue);
2553 gst_qtdemux_stream_flush_segments_data (stream);
2554 gst_qtdemux_stream_flush_samples_data (stream);
2558 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2561 gst_qtdemux_stream_clear (stream);
2562 for (i = 0; i < stream->stsd_entries_length; i++) {
2563 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2565 gst_caps_unref (entry->caps);
2569 g_free (stream->stsd_entries);
2570 stream->stsd_entries = NULL;
2571 stream->stsd_entries_length = 0;
2574 static QtDemuxStream *
2575 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2577 g_atomic_int_add (&stream->ref_count, 1);
2583 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2585 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2586 gst_qtdemux_stream_reset (stream);
2587 gst_tag_list_unref (stream->stream_tags);
2589 GstQTDemux *demux = stream->demux;
2590 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2591 GST_OBJECT_LOCK (demux);
2592 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2593 GST_OBJECT_UNLOCK (demux);
2595 g_free (stream->stream_id);
2600 static GstStateChangeReturn
2601 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2603 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2604 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2606 switch (transition) {
2607 case GST_STATE_CHANGE_READY_TO_PAUSED:
2608 gst_qtdemux_reset (qtdemux, TRUE);
2614 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2616 switch (transition) {
2617 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2618 gst_qtdemux_reset (qtdemux, TRUE);
2629 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2631 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2633 g_return_if_fail (GST_IS_CONTEXT (context));
2635 if (gst_context_has_context_type (context,
2636 "drm-preferred-decryption-system-id")) {
2637 const GstStructure *s;
2639 s = gst_context_get_structure (context);
2640 g_free (qtdemux->preferred_protection_system_id);
2641 qtdemux->preferred_protection_system_id =
2642 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2643 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2644 qtdemux->preferred_protection_system_id);
2647 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2651 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2653 /* counts as header data */
2654 qtdemux->header_size += length;
2656 /* only consider at least a sufficiently complete ftyp atom */
2660 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2661 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2662 GST_FOURCC_ARGS (qtdemux->major_brand));
2663 if (qtdemux->comp_brands)
2664 gst_buffer_unref (qtdemux->comp_brands);
2665 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2666 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2671 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2672 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2673 guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2674 guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2675 const guint8 * constant_iv)
2677 const gchar *protection_scheme_type_mime =
2678 protection_scheme_type ==
2679 FOURCC_cbcs ? "application/x-cbcs" : "application/x-cenc";
2680 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2681 gst_buffer_fill (kid_buf, 0, kid, 16);
2682 if (info->default_properties)
2683 gst_structure_free (info->default_properties);
2684 info->default_properties =
2685 gst_structure_new (protection_scheme_type_mime,
2686 "iv_size", G_TYPE_UINT, iv_size,
2687 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2688 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2689 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2690 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2691 gst_buffer_unref (kid_buf);
2692 if (protection_scheme_type == FOURCC_cbcs) {
2693 if (crypt_byte_block != 0 || skip_byte_block != 0) {
2694 gst_structure_set (info->default_properties, "crypt_byte_block",
2695 G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2696 skip_byte_block, NULL);
2698 if (constant_iv != NULL) {
2699 GstBuffer *constant_iv_buf =
2700 gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2701 gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2702 gst_structure_set (info->default_properties, "constant_iv_size",
2703 G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2705 gst_buffer_unref (constant_iv_buf);
2711 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2712 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2714 guint32 algorithm_id = 0;
2716 gboolean is_encrypted = TRUE;
2719 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2720 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2725 if (algorithm_id == 0) {
2726 is_encrypted = FALSE;
2727 } else if (algorithm_id == 1) {
2728 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2729 } else if (algorithm_id == 2) {
2730 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2733 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2736 if (!gst_byte_reader_get_data (br, 16, &kid))
2739 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2740 is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2741 gst_structure_set (info->default_properties, "piff_algorithm_id",
2742 G_TYPE_UINT, algorithm_id, NULL);
2748 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2756 QtDemuxStream *stream;
2757 GstStructure *structure;
2758 QtDemuxCencSampleSetInfo *ss_info = NULL;
2759 const gchar *system_id;
2760 gboolean uses_sub_sample_encryption = FALSE;
2761 guint32 sample_count;
2763 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2766 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2768 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2769 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2770 GST_WARNING_OBJECT (qtdemux,
2771 "Attempting PIFF box parsing on an unencrypted stream.");
2775 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2776 G_TYPE_STRING, &system_id, NULL);
2777 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2779 stream->protected = TRUE;
2780 stream->protection_scheme_type = FOURCC_cenc;
2782 if (!stream->protection_scheme_info)
2783 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2785 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2786 if (!ss_info->default_properties) {
2787 ss_info->default_properties =
2788 gst_structure_new ("application/x-cenc",
2789 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2794 if (ss_info->crypto_info) {
2795 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2796 g_ptr_array_free (ss_info->crypto_info, TRUE);
2797 ss_info->crypto_info = NULL;
2801 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2803 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2804 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2808 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2809 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2813 if ((flags & 0x000001)) {
2814 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2817 } else if ((flags & 0x000002)) {
2818 uses_sub_sample_encryption = TRUE;
2821 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2823 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2827 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2828 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2832 ss_info->crypto_info =
2833 g_ptr_array_new_full (sample_count,
2834 (GDestroyNotify) qtdemux_gst_structure_free);
2836 for (i = 0; i < sample_count; ++i) {
2837 GstStructure *properties;
2841 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2842 if (properties == NULL) {
2843 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2844 qtdemux->cenc_aux_sample_count = i;
2848 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2849 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2850 gst_structure_free (properties);
2851 qtdemux->cenc_aux_sample_count = i;
2854 buf = gst_buffer_new_wrapped (data, iv_size);
2855 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2856 gst_buffer_unref (buf);
2858 if (uses_sub_sample_encryption) {
2859 guint16 n_subsamples;
2860 const GValue *kid_buf_value;
2862 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2863 || n_subsamples == 0) {
2864 GST_ERROR_OBJECT (qtdemux,
2865 "failed to get subsample count for sample %u", i);
2866 gst_structure_free (properties);
2867 qtdemux->cenc_aux_sample_count = i;
2870 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2871 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2872 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2874 gst_structure_free (properties);
2875 qtdemux->cenc_aux_sample_count = i;
2878 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2881 gst_structure_get_value (ss_info->default_properties, "kid");
2883 gst_structure_set (properties,
2884 "subsample_count", G_TYPE_UINT, n_subsamples,
2885 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2886 gst_structure_set_value (properties, "kid", kid_buf_value);
2887 gst_buffer_unref (buf);
2889 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2892 g_ptr_array_add (ss_info->crypto_info, properties);
2895 qtdemux->cenc_aux_sample_count = sample_count;
2899 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2901 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2902 0x97, 0xA9, 0x42, 0xE8,
2903 0x9C, 0x71, 0x99, 0x94,
2904 0x91, 0xE3, 0xAF, 0xAC
2906 static const guint8 playready_uuid[] = {
2907 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2908 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2911 static const guint8 piff_sample_encryption_uuid[] = {
2912 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2913 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2918 /* counts as header data */
2919 qtdemux->header_size += length;
2921 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2923 if (length <= offset + 16) {
2924 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2928 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2930 GstTagList *taglist;
2932 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2933 length - offset - 16, NULL);
2934 taglist = gst_tag_list_from_xmp_buffer (buf);
2935 gst_buffer_unref (buf);
2937 /* make sure we have a usable taglist */
2938 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2940 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2942 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2944 const gunichar2 *s_utf16;
2947 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2948 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2949 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2950 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2954 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2955 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2957 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2958 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2960 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2961 GST_READ_UINT32_LE (buffer + offset),
2962 GST_READ_UINT32_LE (buffer + offset + 4),
2963 GST_READ_UINT32_LE (buffer + offset + 8),
2964 GST_READ_UINT32_LE (buffer + offset + 12));
2969 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2971 GstSidxParser sidx_parser;
2972 GstIsoffParserResult res;
2975 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2978 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2980 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2981 if (res == GST_ISOFF_QT_PARSER_DONE) {
2982 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2984 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2987 /* caller verifies at least 8 bytes in buf */
2989 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2990 guint64 * plength, guint32 * pfourcc)
2995 length = QT_UINT32 (data);
2996 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2997 fourcc = QT_FOURCC (data + 4);
2998 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3001 length = G_MAXUINT64;
3002 } else if (length == 1 && size >= 16) {
3003 /* this means we have an extended size, which is the 64 bit value of
3004 * the next 8 bytes */
3005 length = QT_UINT64 (data + 8);
3006 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3016 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3018 guint32 version = 0;
3019 GstClockTime duration = 0;
3021 if (!gst_byte_reader_get_uint32_be (br, &version))
3026 if (!gst_byte_reader_get_uint64_be (br, &duration))
3031 if (!gst_byte_reader_get_uint32_be (br, &dur))
3036 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3037 qtdemux->duration = duration;
3043 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3049 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3050 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3052 if (!stream->parsed_trex && qtdemux->moov_node) {
3054 GstByteReader trex_data;
3056 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3058 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3061 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3063 /* skip version/flags */
3064 if (!gst_byte_reader_skip (&trex_data, 4))
3066 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3068 if (id != stream->track_id)
3070 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3072 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3074 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3076 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3079 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3080 "duration %d, size %d, flags 0x%x", stream->track_id,
3083 stream->parsed_trex = TRUE;
3084 stream->def_sample_description_index = sdi;
3085 stream->def_sample_duration = dur;
3086 stream->def_sample_size = size;
3087 stream->def_sample_flags = flags;
3090 /* iterate all siblings */
3091 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3097 *ds_duration = stream->def_sample_duration;
3098 *ds_size = stream->def_sample_size;
3099 *ds_flags = stream->def_sample_flags;
3101 /* even then, above values are better than random ... */
3102 if (G_UNLIKELY (!stream->parsed_trex)) {
3103 GST_WARNING_OBJECT (qtdemux,
3104 "failed to find fragment defaults for stream %d", stream->track_id);
3111 /* This method should be called whenever a more accurate duration might
3112 * have been found. It will update all relevant variables if/where needed
3115 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3119 GstClockTime prevdur;
3121 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3123 if (movdur > qtdemux->duration) {
3124 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3125 GST_DEBUG_OBJECT (qtdemux,
3126 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3127 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3128 qtdemux->duration = movdur;
3129 GST_DEBUG_OBJECT (qtdemux,
3130 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3131 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3132 GST_TIME_ARGS (qtdemux->segment.stop));
3133 if (qtdemux->segment.duration == prevdur) {
3134 /* If the current segment has duration/stop identical to previous duration
3135 * update them also (because they were set at that point in time with
3136 * the wrong duration */
3137 /* We convert the value *from* the timescale version to avoid rounding errors */
3138 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3139 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3140 qtdemux->segment.duration = fixeddur;
3141 qtdemux->segment.stop = fixeddur;
3145 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3146 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3148 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3149 if (movdur > stream->duration) {
3150 GST_DEBUG_OBJECT (qtdemux,
3151 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3152 GST_TIME_ARGS (duration));
3153 stream->duration = movdur;
3154 /* internal duration tracking state has been updated above, so */
3155 /* preserve an open-ended dummy segment rather than repeatedly updating
3156 * it and spamming downstream accordingly with segment events */
3157 /* also mangle the edit list end time when fragmented with a single edit
3158 * list that may only cover any non-fragmented data */
3159 if ((stream->dummy_segment ||
3160 (qtdemux->fragmented && stream->n_segments == 1)) &&
3161 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3162 /* Update all dummy values to new duration */
3163 stream->segments[0].stop_time = duration;
3164 stream->segments[0].duration = duration;
3165 stream->segments[0].media_stop = duration;
3167 /* let downstream know we possibly have a new stop time */
3168 if (stream->segment_index != -1) {
3171 if (qtdemux->segment.rate >= 0) {
3172 pos = stream->segment.start;
3174 pos = stream->segment.stop;
3177 gst_qtdemux_stream_update_segment (qtdemux, stream,
3178 stream->segment_index, pos, NULL, NULL);
3186 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3187 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3188 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3189 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3192 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3194 gint32 data_offset = 0;
3195 guint32 flags = 0, first_flags = 0, samples_count = 0;
3198 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3199 QtDemuxSample *sample;
3200 gboolean ismv = FALSE;
3201 gint64 initial_offset;
3203 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3204 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3205 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3206 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3208 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3209 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3213 /* presence of stss or not can't really tell us much,
3214 * and flags and so on tend to be marginally reliable in these files */
3215 if (stream->subtype == FOURCC_soun) {
3216 GST_DEBUG_OBJECT (qtdemux,
3217 "sound track in fragmented file; marking all keyframes");
3218 stream->all_keyframe = TRUE;
3221 if (!gst_byte_reader_skip (trun, 1) ||
3222 !gst_byte_reader_get_uint24_be (trun, &flags))
3225 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3228 if (flags & TR_DATA_OFFSET) {
3229 /* note this is really signed */
3230 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3232 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3233 /* default base offset = first byte of moof */
3234 if (*base_offset == -1) {
3235 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3236 *base_offset = moof_offset;
3238 *running_offset = *base_offset + data_offset;
3240 /* if no offset at all, that would mean data starts at moof start,
3241 * which is a bit wrong and is ismv crappy way, so compensate
3242 * assuming data is in mdat following moof */
3243 if (*base_offset == -1) {
3244 *base_offset = moof_offset + moof_length + 8;
3245 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3248 if (*running_offset == -1)
3249 *running_offset = *base_offset;
3252 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3254 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3255 data_offset, flags, samples_count);
3257 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3258 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3259 GST_DEBUG_OBJECT (qtdemux,
3260 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3261 flags ^= TR_FIRST_SAMPLE_FLAGS;
3263 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3265 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3269 /* FIXME ? spec says other bits should also be checked to determine
3270 * entry size (and prefix size for that matter) */
3272 dur_offset = size_offset = 0;
3273 if (flags & TR_SAMPLE_DURATION) {
3274 GST_LOG_OBJECT (qtdemux, "entry duration present");
3275 dur_offset = entry_size;
3278 if (flags & TR_SAMPLE_SIZE) {
3279 GST_LOG_OBJECT (qtdemux, "entry size present");
3280 size_offset = entry_size;
3283 if (flags & TR_SAMPLE_FLAGS) {
3284 GST_LOG_OBJECT (qtdemux, "entry flags present");
3285 flags_offset = entry_size;
3288 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3289 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3290 ct_offset = entry_size;
3294 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3296 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3298 if (stream->n_samples + samples_count >=
3299 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3302 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3303 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3304 (stream->n_samples + samples_count) *
3305 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3307 /* create a new array of samples if it's the first sample parsed */
3308 if (stream->n_samples == 0) {
3309 g_assert (stream->samples == NULL);
3310 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3311 /* or try to reallocate it with space enough to insert the new samples */
3313 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3314 stream->n_samples + samples_count);
3315 if (stream->samples == NULL)
3318 if (qtdemux->fragment_start != -1) {
3319 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3320 qtdemux->fragment_start = -1;
3322 if (stream->n_samples == 0) {
3323 if (decode_ts > 0) {
3324 timestamp = decode_ts;
3325 } else if (stream->pending_seek != NULL) {
3326 /* if we don't have a timestamp from a tfdt box, we'll use the one
3327 * from the mfra seek table */
3328 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3329 GST_TIME_ARGS (stream->pending_seek->ts));
3331 /* FIXME: this is not fully correct, the timestamp refers to the random
3332 * access sample refered to in the tfra entry, which may not necessarily
3333 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3334 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3339 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3340 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3341 GST_TIME_ARGS (gst_ts));
3343 /* subsequent fragments extend stream */
3345 stream->samples[stream->n_samples - 1].timestamp +
3346 stream->samples[stream->n_samples - 1].duration;
3348 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3349 * difference (1 sec.) between decode_ts and timestamp, prefer the
3351 if (has_tfdt && !qtdemux->upstream_format_is_time
3352 && ABSDIFF (decode_ts, timestamp) >
3353 MAX (stream->duration_last_moof / 2,
3354 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3355 GST_INFO_OBJECT (qtdemux,
3356 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3357 ") are significantly different (more than %" GST_TIME_FORMAT
3358 "), using decode_ts",
3359 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3360 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3361 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3362 MAX (stream->duration_last_moof / 2,
3363 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3364 timestamp = decode_ts;
3367 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3368 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3369 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3373 initial_offset = *running_offset;
3375 sample = stream->samples + stream->n_samples;
3376 for (i = 0; i < samples_count; i++) {
3377 guint32 dur, size, sflags, ct;
3379 /* first read sample data */
3380 if (flags & TR_SAMPLE_DURATION) {
3381 dur = QT_UINT32 (data + dur_offset);
3383 dur = d_sample_duration;
3385 if (flags & TR_SAMPLE_SIZE) {
3386 size = QT_UINT32 (data + size_offset);
3388 size = d_sample_size;
3390 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3392 sflags = first_flags;
3394 sflags = d_sample_flags;
3396 } else if (flags & TR_SAMPLE_FLAGS) {
3397 sflags = QT_UINT32 (data + flags_offset);
3399 sflags = d_sample_flags;
3401 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3402 ct = QT_UINT32 (data + ct_offset);
3408 /* fill the sample information */
3409 sample->offset = *running_offset;
3410 sample->pts_offset = ct;
3411 sample->size = size;
3412 sample->timestamp = timestamp;
3413 sample->duration = dur;
3414 /* sample-is-difference-sample */
3415 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3416 * now idea how it relates to bitfield other than massive LE/BE confusion */
3417 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3418 *running_offset += size;
3420 stream->duration_moof += dur;
3424 /* Update total duration if needed */
3425 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3427 /* Pre-emptively figure out size of mdat based on trun information.
3428 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3429 * size, else we will still be able to use this when dealing with gap'ed
3431 qtdemux->mdatleft = *running_offset - initial_offset;
3432 qtdemux->mdatoffset = initial_offset;
3433 qtdemux->mdatsize = qtdemux->mdatleft;
3435 stream->n_samples += samples_count;
3436 stream->n_samples_moof += samples_count;
3438 if (stream->pending_seek != NULL)
3439 stream->pending_seek = NULL;
3445 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3450 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3456 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3457 "be larger than %uMB (broken file?)", stream->n_samples,
3458 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3463 /* find stream with @id */
3464 static inline QtDemuxStream *
3465 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3467 QtDemuxStream *stream;
3471 if (G_UNLIKELY (!id)) {
3472 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3476 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3477 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3478 if (stream->track_id == id)
3481 if (qtdemux->mss_mode) {
3482 /* mss should have only 1 stream anyway */
3483 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3490 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3491 guint32 * fragment_number)
3493 if (!gst_byte_reader_skip (mfhd, 4))
3495 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3500 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3506 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3507 QtDemuxStream ** stream, guint32 * default_sample_duration,
3508 guint32 * default_sample_size, guint32 * default_sample_flags,
3509 gint64 * base_offset)
3512 guint32 track_id = 0;
3514 if (!gst_byte_reader_skip (tfhd, 1) ||
3515 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3518 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3521 *stream = qtdemux_find_stream (qtdemux, track_id);
3522 if (G_UNLIKELY (!*stream))
3523 goto unknown_stream;
3525 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3526 *base_offset = qtdemux->moof_offset;
3528 if (flags & TF_BASE_DATA_OFFSET)
3529 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3532 /* obtain stream defaults */
3533 qtdemux_parse_trex (qtdemux, *stream,
3534 default_sample_duration, default_sample_size, default_sample_flags);
3536 (*stream)->stsd_sample_description_id =
3537 (*stream)->def_sample_description_index - 1;
3539 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3540 guint32 sample_description_index;
3541 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3543 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3546 if (qtdemux->mss_mode) {
3547 /* mss has no stsd entry */
3548 (*stream)->stsd_sample_description_id = 0;
3551 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3552 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3555 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3556 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3559 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3560 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3567 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3572 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3578 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3579 guint64 * decode_time)
3581 guint32 version = 0;
3583 if (!gst_byte_reader_get_uint32_be (br, &version))
3588 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3591 guint32 dec_time = 0;
3592 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3594 *decode_time = dec_time;
3597 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3604 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3609 /* Returns a pointer to a GstStructure containing the properties of
3610 * the stream sample identified by @sample_index. The caller must unref
3611 * the returned object after use. Returns NULL if unsuccessful. */
3612 static GstStructure *
3613 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3614 QtDemuxStream * stream, guint sample_index)
3616 QtDemuxCencSampleSetInfo *info = NULL;
3618 g_return_val_if_fail (stream != NULL, NULL);
3619 g_return_val_if_fail (stream->protected, NULL);
3620 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3622 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3624 /* Currently, cenc properties for groups of samples are not supported, so
3625 * simply return a copy of the default sample properties */
3626 return gst_structure_copy (info->default_properties);
3629 /* Parses the sizes of sample auxiliary information contained within a stream,
3630 * as given in a saiz box. Returns array of sample_count guint8 size values,
3631 * or NULL on failure */
3633 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3634 GstByteReader * br, guint32 * sample_count)
3638 guint8 default_info_size;
3640 g_return_val_if_fail (qtdemux != NULL, NULL);
3641 g_return_val_if_fail (stream != NULL, NULL);
3642 g_return_val_if_fail (br != NULL, NULL);
3643 g_return_val_if_fail (sample_count != NULL, NULL);
3645 if (!gst_byte_reader_get_uint32_be (br, &flags))
3649 /* aux_info_type and aux_info_type_parameter are ignored */
3650 if (!gst_byte_reader_skip (br, 8))
3654 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3656 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3658 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3660 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3663 if (default_info_size == 0) {
3664 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3668 info_sizes = g_new (guint8, *sample_count);
3669 memset (info_sizes, default_info_size, *sample_count);
3675 /* Parses the offset of sample auxiliary information contained within a stream,
3676 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3678 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3679 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3684 guint32 aux_info_type = 0;
3685 guint32 aux_info_type_parameter = 0;
3686 guint32 entry_count;
3689 const guint8 *aux_info_type_data = NULL;
3691 g_return_val_if_fail (qtdemux != NULL, FALSE);
3692 g_return_val_if_fail (stream != NULL, FALSE);
3693 g_return_val_if_fail (br != NULL, FALSE);
3694 g_return_val_if_fail (offset != NULL, FALSE);
3696 if (!gst_byte_reader_get_uint8 (br, &version))
3699 if (!gst_byte_reader_get_uint24_be (br, &flags))
3704 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3706 aux_info_type = QT_FOURCC (aux_info_type_data);
3708 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3710 } else if (stream->protected) {
3711 aux_info_type = stream->protection_scheme_type;
3713 aux_info_type = CUR_STREAM (stream)->fourcc;
3717 *info_type = aux_info_type;
3718 if (info_type_parameter)
3719 *info_type_parameter = aux_info_type_parameter;
3721 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3722 "aux_info_type_parameter: %#06x",
3723 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3725 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3728 if (entry_count != 1) {
3729 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3734 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3736 *offset = (guint64) off_32;
3738 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3743 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3748 qtdemux_gst_structure_free (GstStructure * gststructure)
3751 gst_structure_free (gststructure);
3755 /* Parses auxiliary information relating to samples protected using
3756 * Common Encryption (cenc and cbcs); the format of this information
3757 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3760 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3761 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3763 QtDemuxCencSampleSetInfo *ss_info = NULL;
3766 GPtrArray *old_crypto_info = NULL;
3767 guint old_entries = 0;
3769 g_return_val_if_fail (qtdemux != NULL, FALSE);
3770 g_return_val_if_fail (stream != NULL, FALSE);
3771 g_return_val_if_fail (br != NULL, FALSE);
3772 g_return_val_if_fail (stream->protected, FALSE);
3773 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3775 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3777 if (ss_info->crypto_info) {
3778 old_crypto_info = ss_info->crypto_info;
3779 /* Count number of non-null entries remaining at the tail end */
3780 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3781 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3787 ss_info->crypto_info =
3788 g_ptr_array_new_full (sample_count + old_entries,
3789 (GDestroyNotify) qtdemux_gst_structure_free);
3791 /* We preserve old entries because we parse the next moof in advance
3792 * of consuming all samples from the previous moof, and otherwise
3793 * we'd discard the corresponding crypto info for the samples
3794 * from the previous fragment. */
3796 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3798 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3799 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3801 g_ptr_array_index (old_crypto_info, i) = NULL;
3805 if (old_crypto_info) {
3806 /* Everything now belongs to the new array */
3807 g_ptr_array_free (old_crypto_info, TRUE);
3810 for (i = 0; i < sample_count; ++i) {
3811 GstStructure *properties;
3812 guint16 n_subsamples = 0;
3816 gboolean could_read_iv;
3818 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3819 if (properties == NULL) {
3820 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3823 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3824 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3825 gst_structure_free (properties);
3829 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3830 if (could_read_iv) {
3831 buf = gst_buffer_new_wrapped (data, iv_size);
3832 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3833 gst_buffer_unref (buf);
3834 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3835 const GValue *constant_iv_size_value =
3836 gst_structure_get_value (properties, "constant_iv_size");
3837 const GValue *constant_iv_value =
3838 gst_structure_get_value (properties, "iv");
3839 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3840 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3841 gst_structure_free (properties);
3844 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3845 gst_structure_remove_field (properties, "constant_iv_size");
3846 } else if (stream->protection_scheme_type == FOURCC_cenc) {
3847 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3848 gst_structure_free (properties);
3851 size = info_sizes[i];
3852 if (size > iv_size) {
3853 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3854 || !(n_subsamples > 0)) {
3855 gst_structure_free (properties);
3856 GST_ERROR_OBJECT (qtdemux,
3857 "failed to get subsample count for sample %u", i);
3860 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3861 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3862 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3864 gst_structure_free (properties);
3867 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3869 gst_structure_free (properties);
3872 gst_structure_set (properties,
3873 "subsample_count", G_TYPE_UINT, n_subsamples,
3874 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3875 gst_buffer_unref (buf);
3877 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3879 g_ptr_array_add (ss_info->crypto_info, properties);
3884 /* Converts a UUID in raw byte form to a string representation, as defined in
3885 * RFC 4122. The caller takes ownership of the returned string and is
3886 * responsible for freeing it after use. */
3888 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3890 const guint8 *uuid = (const guint8 *) uuid_bytes;
3892 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3893 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3894 uuid[0], uuid[1], uuid[2], uuid[3],
3895 uuid[4], uuid[5], uuid[6], uuid[7],
3896 uuid[8], uuid[9], uuid[10], uuid[11],
3897 uuid[12], uuid[13], uuid[14], uuid[15]);
3900 /* Parses a Protection System Specific Header box (pssh), as defined in the
3901 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3902 * information needed by a specific content protection system in order to
3903 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3906 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3908 gchar *sysid_string;
3909 guint32 pssh_size = QT_UINT32 (node->data);
3910 GstBuffer *pssh = NULL;
3911 GstEvent *event = NULL;
3912 guint32 parent_box_type;
3915 if (G_UNLIKELY (pssh_size < 32U)) {
3916 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3921 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3923 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3925 pssh = gst_buffer_new_memdup (node->data, pssh_size);
3926 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3927 gst_buffer_get_size (pssh));
3929 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3931 /* Push an event containing the pssh box onto the queues of all streams. */
3932 event = gst_event_new_protection (sysid_string, pssh,
3933 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3934 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3935 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3936 GST_TRACE_OBJECT (qtdemux,
3937 "adding protection event for stream %s and system %s",
3938 stream->stream_id, sysid_string);
3939 g_queue_push_tail (&stream->protection_scheme_event_queue,
3940 gst_event_ref (event));
3942 g_free (sysid_string);
3943 gst_event_unref (event);
3944 gst_buffer_unref (pssh);
3949 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3950 guint64 moof_offset, QtDemuxStream * stream)
3952 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3954 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3955 GNode *saiz_node, *saio_node, *pssh_node;
3956 GstByteReader saiz_data, saio_data;
3957 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3958 gint64 base_offset, running_offset;
3960 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
3962 /* NOTE @stream ignored */
3964 moof_node = g_node_new ((guint8 *) buffer);
3965 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3966 qtdemux_node_dump (qtdemux, moof_node);
3968 /* Get fragment number from mfhd and check it's valid */
3970 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3971 if (mfhd_node == NULL)
3973 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3975 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3977 /* unknown base_offset to start with */
3978 base_offset = running_offset = -1;
3979 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3981 guint64 decode_time = 0;
3983 /* Fragment Header node */
3985 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3989 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3990 &ds_size, &ds_flags, &base_offset))
3993 /* The following code assumes at most a single set of sample auxiliary
3994 * data in the fragment (consisting of a saiz box and a corresponding saio
3995 * box); in theory, however, there could be multiple sets of sample
3996 * auxiliary data in a fragment. */
3998 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4001 guint32 info_type = 0;
4003 guint32 info_type_parameter = 0;
4005 g_free (qtdemux->cenc_aux_info_sizes);
4007 qtdemux->cenc_aux_info_sizes =
4008 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4009 &qtdemux->cenc_aux_sample_count);
4010 if (qtdemux->cenc_aux_info_sizes == NULL) {
4011 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4015 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4018 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4019 g_free (qtdemux->cenc_aux_info_sizes);
4020 qtdemux->cenc_aux_info_sizes = NULL;
4024 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4025 &info_type, &info_type_parameter, &offset))) {
4026 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4027 g_free (qtdemux->cenc_aux_info_sizes);
4028 qtdemux->cenc_aux_info_sizes = NULL;
4031 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4032 offset += (guint64) (base_offset - qtdemux->moof_offset);
4033 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4034 && info_type_parameter == 0U) {
4036 if (offset > length) {
4037 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4038 qtdemux->cenc_aux_info_offset = offset;
4040 gst_byte_reader_init (&br, buffer + offset, length - offset);
4041 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4042 qtdemux->cenc_aux_info_sizes,
4043 qtdemux->cenc_aux_sample_count)) {
4044 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4045 g_free (qtdemux->cenc_aux_info_sizes);
4046 qtdemux->cenc_aux_info_sizes = NULL;
4054 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4057 /* We'll use decode_time to interpolate timestamps
4058 * in case the input timestamps are missing */
4059 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4061 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4062 " (%" GST_TIME_FORMAT ")", decode_time,
4063 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4064 decode_time) : GST_CLOCK_TIME_NONE));
4066 /* Discard the fragment buffer timestamp info to avoid using it.
4067 * Rely on tfdt instead as it is more accurate than the timestamp
4068 * that is fetched from a manifest/playlist and is usually
4070 qtdemux->fragment_start = -1;
4073 if (G_UNLIKELY (!stream)) {
4074 /* we lost track of offset, we'll need to regain it,
4075 * but can delay complaining until later or avoid doing so altogether */
4079 if (G_UNLIKELY (base_offset < -1))
4082 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4084 if (!qtdemux->pullbased) {
4085 /* Sample tables can grow enough to be problematic if the system memory
4086 * is very low (e.g. embedded devices) and the videos very long
4087 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4088 * Fortunately, we can easily discard them for each new fragment when
4089 * we know qtdemux will not receive seeks outside of the current fragment.
4090 * adaptivedemux honors this assumption.
4091 * This optimization is also useful for applications that use qtdemux as
4092 * a push-based simple demuxer, like Media Source Extensions. */
4093 gst_qtdemux_stream_flush_samples_data (stream);
4096 /* initialise moof sample data */
4097 stream->n_samples_moof = 0;
4098 stream->duration_last_moof = stream->duration_moof;
4099 stream->duration_moof = 0;
4101 /* Track Run node */
4103 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4106 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4107 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4108 &running_offset, decode_time, (tfdt_node != NULL));
4109 /* iterate all siblings */
4110 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4114 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4116 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4117 guint32 box_length = QT_UINT32 (uuid_buffer);
4119 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4122 /* if no new base_offset provided for next traf,
4123 * base is end of current traf */
4124 base_offset = running_offset;
4125 running_offset = -1;
4127 if (stream->n_samples_moof && stream->duration_moof)
4128 stream->new_caps = TRUE;
4131 /* iterate all siblings */
4132 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4135 /* parse any protection system info */
4136 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4138 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4139 qtdemux_parse_pssh (qtdemux, pssh_node);
4140 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4143 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4144 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4146 /* Unless the user has explicitly requested another seek, perform an
4147 * internal seek to the time specified in the tfdt.
4149 * This way if the user opens a file where the first tfdt is 1 hour
4150 * into the presentation, they will not have to wait 1 hour for run
4151 * time to catch up and actual playback to start. */
4154 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4155 "performing an internal seek to %" GST_TIME_FORMAT,
4156 GST_TIME_ARGS (min_dts));
4158 qtdemux->segment.start = min_dts;
4159 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4161 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4162 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4163 stream->time_position = min_dts;
4166 /* Before this code was run a segment was already sent when the moov was
4167 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4168 * be emitted after a moov, and we can emit a second segment anyway for
4169 * special cases like this. */
4170 qtdemux->need_segment = TRUE;
4173 qtdemux->first_moof_already_parsed = TRUE;
4175 g_node_destroy (moof_node);
4180 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4185 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4190 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4195 g_node_destroy (moof_node);
4196 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4197 (_("This file is corrupt and cannot be played.")), (NULL));
4203 /* might be used if some day we actually use mfra & co
4204 * for random access to fragments,
4205 * but that will require quite some modifications and much less relying
4206 * on a sample array */
4210 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4212 QtDemuxStream *stream;
4213 guint32 ver_flags, track_id, len, num_entries, i;
4214 guint value_size, traf_size, trun_size, sample_size;
4215 guint64 time = 0, moof_offset = 0;
4217 GstBuffer *buf = NULL;
4222 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4224 if (!gst_byte_reader_skip (&tfra, 8))
4227 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4230 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4231 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4232 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4235 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4237 stream = qtdemux_find_stream (qtdemux, track_id);
4239 goto unknown_trackid;
4241 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4242 sample_size = (len & 3) + 1;
4243 trun_size = ((len & 12) >> 2) + 1;
4244 traf_size = ((len & 48) >> 4) + 1;
4246 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4247 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4249 if (num_entries == 0)
4252 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4253 value_size + value_size + traf_size + trun_size + sample_size))
4256 g_free (stream->ra_entries);
4257 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4258 stream->n_ra_entries = num_entries;
4260 for (i = 0; i < num_entries; i++) {
4261 qt_atom_parser_get_offset (&tfra, value_size, &time);
4262 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4263 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4264 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4265 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4267 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4269 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4270 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4272 stream->ra_entries[i].ts = time;
4273 stream->ra_entries[i].moof_offset = moof_offset;
4275 /* don't want to go through the entire file and read all moofs at startup */
4277 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4278 if (ret != GST_FLOW_OK)
4280 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4281 moof_offset, stream);
4282 gst_buffer_unref (buf);
4286 check_update_duration (qtdemux, time);
4293 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4298 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4303 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4309 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4311 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4312 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4313 GstBuffer *mfro = NULL, *mfra = NULL;
4315 gboolean ret = FALSE;
4316 GNode *mfra_node, *tfra_node;
4317 guint64 mfra_offset = 0;
4318 guint32 fourcc, mfra_size;
4321 /* query upstream size in bytes */
4322 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4323 goto size_query_failed;
4325 /* mfro box should be at the very end of the file */
4326 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4327 if (flow != GST_FLOW_OK)
4330 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4332 fourcc = QT_FOURCC (mfro_map.data + 4);
4333 if (fourcc != FOURCC_mfro)
4336 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4337 if (mfro_map.size < 16)
4338 goto invalid_mfro_size;
4340 mfra_size = QT_UINT32 (mfro_map.data + 12);
4341 if (mfra_size >= len)
4342 goto invalid_mfra_size;
4344 mfra_offset = len - mfra_size;
4346 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4347 mfra_offset, mfra_size);
4349 /* now get and parse mfra box */
4350 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4351 if (flow != GST_FLOW_OK)
4354 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4356 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4357 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4359 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4362 qtdemux_parse_tfra (qtdemux, tfra_node);
4363 /* iterate all siblings */
4364 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4366 g_node_destroy (mfra_node);
4368 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4374 if (mfro_map.memory != NULL)
4375 gst_buffer_unmap (mfro, &mfro_map);
4376 gst_buffer_unref (mfro);
4379 if (mfra_map.memory != NULL)
4380 gst_buffer_unmap (mfra, &mfra_map);
4381 gst_buffer_unref (mfra);
4388 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4393 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4398 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4403 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4409 add_offset (guint64 offset, guint64 advance)
4411 /* Avoid 64-bit overflow by clamping */
4412 if (offset > G_MAXUINT64 - advance)
4414 return offset + advance;
4417 static GstFlowReturn
4418 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4422 GstBuffer *buf = NULL;
4423 GstFlowReturn ret = GST_FLOW_OK;
4424 guint64 cur_offset = qtdemux->offset;
4427 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4428 if (G_UNLIKELY (ret != GST_FLOW_OK))
4430 gst_buffer_map (buf, &map, GST_MAP_READ);
4431 if (G_LIKELY (map.size >= 8))
4432 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4433 gst_buffer_unmap (buf, &map);
4434 gst_buffer_unref (buf);
4436 /* maybe we already got most we needed, so only consider this eof */
4437 if (G_UNLIKELY (length == 0)) {
4438 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4439 (_("Invalid atom size.")),
4440 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4441 GST_FOURCC_ARGS (fourcc)));
4448 /* record for later parsing when needed */
4449 if (!qtdemux->moof_offset) {
4450 qtdemux->moof_offset = qtdemux->offset;
4452 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4455 qtdemux->offset += length; /* skip moof and keep going */
4457 if (qtdemux->got_moov) {
4458 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4470 GST_LOG_OBJECT (qtdemux,
4471 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4472 GST_FOURCC_ARGS (fourcc), cur_offset);
4473 qtdemux->offset = add_offset (qtdemux->offset, length);
4478 GstBuffer *moov = NULL;
4480 if (qtdemux->got_moov) {
4481 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4482 qtdemux->offset = add_offset (qtdemux->offset, length);
4486 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4487 if (ret != GST_FLOW_OK)
4489 gst_buffer_map (moov, &map, GST_MAP_READ);
4491 if (length != map.size) {
4492 /* Some files have a 'moov' atom at the end of the file which contains
4493 * a terminal 'free' atom where the body of the atom is missing.
4494 * Check for, and permit, this special case.
4496 if (map.size >= 8) {
4497 guint8 *final_data = map.data + (map.size - 8);
4498 guint32 final_length = QT_UINT32 (final_data);
4499 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4501 if (final_fourcc == FOURCC_free
4502 && map.size + final_length - 8 == length) {
4503 /* Ok, we've found that special case. Allocate a new buffer with
4504 * that free atom actually present. */
4505 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4506 gst_buffer_fill (newmoov, 0, map.data, map.size);
4507 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4508 gst_buffer_unmap (moov, &map);
4509 gst_buffer_unref (moov);
4511 gst_buffer_map (moov, &map, GST_MAP_READ);
4516 if (length != map.size) {
4517 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4518 (_("This file is incomplete and cannot be played.")),
4519 ("We got less than expected (received %" G_GSIZE_FORMAT
4520 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4521 (guint) length, cur_offset));
4522 gst_buffer_unmap (moov, &map);
4523 gst_buffer_unref (moov);
4524 ret = GST_FLOW_ERROR;
4527 qtdemux->offset += length;
4529 qtdemux_parse_moov (qtdemux, map.data, length);
4530 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4532 qtdemux_parse_tree (qtdemux);
4533 if (qtdemux->moov_node_compressed) {
4534 g_node_destroy (qtdemux->moov_node_compressed);
4535 g_free (qtdemux->moov_node->data);
4537 qtdemux->moov_node_compressed = NULL;
4538 g_node_destroy (qtdemux->moov_node);
4539 qtdemux->moov_node = NULL;
4540 gst_buffer_unmap (moov, &map);
4541 gst_buffer_unref (moov);
4542 qtdemux->got_moov = TRUE;
4548 GstBuffer *ftyp = NULL;
4550 /* extract major brand; might come in handy for ISO vs QT issues */
4551 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4552 if (ret != GST_FLOW_OK)
4554 qtdemux->offset += length;
4555 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4556 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4557 gst_buffer_unmap (ftyp, &map);
4558 gst_buffer_unref (ftyp);
4563 GstBuffer *uuid = NULL;
4565 /* uuid are extension atoms */
4566 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4567 if (ret != GST_FLOW_OK)
4569 qtdemux->offset += length;
4570 gst_buffer_map (uuid, &map, GST_MAP_READ);
4571 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4572 gst_buffer_unmap (uuid, &map);
4573 gst_buffer_unref (uuid);
4578 GstBuffer *sidx = NULL;
4579 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4580 if (ret != GST_FLOW_OK)
4582 qtdemux->offset += length;
4583 gst_buffer_map (sidx, &map, GST_MAP_READ);
4584 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4585 gst_buffer_unmap (sidx, &map);
4586 gst_buffer_unref (sidx);
4591 GstBuffer *unknown = NULL;
4593 GST_LOG_OBJECT (qtdemux,
4594 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4595 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4597 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4598 if (ret != GST_FLOW_OK)
4600 gst_buffer_map (unknown, &map, GST_MAP_READ);
4601 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4602 gst_buffer_unmap (unknown, &map);
4603 gst_buffer_unref (unknown);
4604 qtdemux->offset += length;
4610 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4611 /* digested all data, show what we have */
4612 qtdemux_prepare_streams (qtdemux);
4613 QTDEMUX_EXPOSE_LOCK (qtdemux);
4614 ret = qtdemux_expose_streams (qtdemux);
4615 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4617 qtdemux->state = QTDEMUX_STATE_MOVIE;
4618 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4625 /* Seeks to the previous keyframe of the indexed stream and
4626 * aligns other streams with respect to the keyframe timestamp
4627 * of indexed stream. Only called in case of Reverse Playback
4629 static GstFlowReturn
4630 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4632 guint32 seg_idx = 0, k_index = 0;
4633 guint32 ref_seg_idx, ref_k_index;
4634 GstClockTime k_pos = 0, last_stop = 0;
4635 QtDemuxSegment *seg = NULL;
4636 QtDemuxStream *ref_str = NULL;
4637 guint64 seg_media_start_mov; /* segment media start time in mov format */
4641 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4642 * and finally align all the other streams on that timestamp with their
4643 * respective keyframes */
4644 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4645 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4647 /* No candidate yet, take the first stream */
4653 /* So that stream has a segment, we prefer video streams */
4654 if (str->subtype == FOURCC_vide) {
4660 if (G_UNLIKELY (!ref_str)) {
4661 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4665 if (G_UNLIKELY (!ref_str->from_sample)) {
4666 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4670 /* So that stream has been playing from from_sample to to_sample. We will
4671 * get the timestamp of the previous sample and search for a keyframe before
4672 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4673 if (ref_str->subtype == FOURCC_vide) {
4674 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4675 ref_str->from_sample - 1, FALSE);
4677 if (ref_str->from_sample >= 10)
4678 k_index = ref_str->from_sample - 10;
4684 ref_str->samples[k_index].timestamp +
4685 ref_str->samples[k_index].pts_offset;
4687 /* get current segment for that stream */
4688 seg = &ref_str->segments[ref_str->segment_index];
4689 /* Use segment start in original timescale for comparisons */
4690 seg_media_start_mov = seg->trak_media_start;
4692 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4693 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4694 k_index, target_ts, seg_media_start_mov,
4695 GST_TIME_ARGS (seg->media_start));
4697 /* Crawl back through segments to find the one containing this I frame */
4698 while (target_ts < seg_media_start_mov) {
4699 GST_DEBUG_OBJECT (qtdemux,
4700 "keyframe position (sample %u) is out of segment %u " " target %"
4701 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4702 ref_str->segment_index, target_ts, seg_media_start_mov);
4704 if (G_UNLIKELY (!ref_str->segment_index)) {
4705 /* Reached first segment, let's consider it's EOS */
4708 ref_str->segment_index--;
4709 seg = &ref_str->segments[ref_str->segment_index];
4710 /* Use segment start in original timescale for comparisons */
4711 seg_media_start_mov = seg->trak_media_start;
4713 /* Calculate time position of the keyframe and where we should stop */
4715 QTSTREAMTIME_TO_GSTTIME (ref_str,
4716 target_ts - seg->trak_media_start) + seg->time;
4718 QTSTREAMTIME_TO_GSTTIME (ref_str,
4719 ref_str->samples[ref_str->from_sample].timestamp -
4720 seg->trak_media_start) + seg->time;
4722 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4723 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4724 k_index, GST_TIME_ARGS (k_pos));
4726 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4727 qtdemux->segment.position = last_stop;
4728 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4729 GST_TIME_ARGS (last_stop));
4731 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4732 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4736 ref_seg_idx = ref_str->segment_index;
4737 ref_k_index = k_index;
4739 /* Align them all on this */
4740 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4742 GstClockTime seg_time = 0;
4743 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4745 /* aligning reference stream again might lead to backing up to yet another
4746 * keyframe (due to timestamp rounding issues),
4747 * potentially putting more load on downstream; so let's try to avoid */
4748 if (str == ref_str) {
4749 seg_idx = ref_seg_idx;
4750 seg = &str->segments[seg_idx];
4751 k_index = ref_k_index;
4752 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4753 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4755 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4756 GST_DEBUG_OBJECT (qtdemux,
4757 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4758 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4760 /* get segment and time in the segment */
4761 seg = &str->segments[seg_idx];
4762 seg_time = k_pos - seg->time;
4764 /* get the media time in the segment.
4765 * No adjustment for empty "filler" segments */
4766 if (seg->media_start != GST_CLOCK_TIME_NONE)
4767 seg_time += seg->media_start;
4769 /* get the index of the sample with media time */
4770 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4771 GST_DEBUG_OBJECT (qtdemux,
4772 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4773 GST_TIME_ARGS (seg_time), index);
4775 /* find previous keyframe */
4776 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4779 /* Remember until where we want to go */
4780 str->to_sample = str->from_sample - 1;
4781 /* Define our time position */
4783 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4784 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4785 if (seg->media_start != GST_CLOCK_TIME_NONE)
4786 str->time_position -= seg->media_start;
4788 /* Now seek back in time */
4789 gst_qtdemux_move_stream (qtdemux, str, k_index);
4790 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4791 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4792 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4798 return GST_FLOW_EOS;
4802 * Gets the current qt segment start, stop and position for the
4803 * given time offset. This is used in update_segment()
4806 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4807 QtDemuxStream * stream, GstClockTime offset,
4808 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4810 GstClockTime seg_time;
4811 GstClockTime start, stop, time;
4812 QtDemuxSegment *segment;
4814 segment = &stream->segments[stream->segment_index];
4816 /* get time in this segment */
4817 seg_time = (offset - segment->time) * segment->rate;
4819 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4820 GST_TIME_ARGS (seg_time));
4822 if (G_UNLIKELY (seg_time > segment->duration)) {
4823 GST_LOG_OBJECT (stream->pad,
4824 "seg_time > segment->duration %" GST_TIME_FORMAT,
4825 GST_TIME_ARGS (segment->duration));
4826 seg_time = segment->duration;
4829 /* qtdemux->segment.stop is in outside-time-realm, whereas
4830 * segment->media_stop is in track-time-realm.
4832 * In order to compare the two, we need to bring segment.stop
4833 * into the track-time-realm
4835 * FIXME - does this comment still hold? Don't see any conversion here */
4837 stop = qtdemux->segment.stop;
4838 if (stop == GST_CLOCK_TIME_NONE)
4839 stop = qtdemux->segment.duration;
4840 if (stop == GST_CLOCK_TIME_NONE)
4841 stop = segment->media_stop;
4844 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4846 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4847 start = segment->time + seg_time;
4849 stop = start - seg_time + segment->duration;
4850 } else if (qtdemux->segment.rate >= 0) {
4851 start = MIN (segment->media_start + seg_time, stop);
4854 if (segment->media_start >= qtdemux->segment.start) {
4855 time = segment->time;
4857 time = segment->time + (qtdemux->segment.start - segment->media_start);
4860 start = MAX (segment->media_start, qtdemux->segment.start);
4861 stop = MIN (segment->media_start + seg_time, stop);
4870 * Updates the qt segment used for the stream and pushes a new segment event
4871 * downstream on this stream's pad.
4874 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4875 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4876 GstClockTime * _stop)
4878 QtDemuxSegment *segment;
4879 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4883 /* update the current segment */
4884 stream->segment_index = seg_idx;
4886 /* get the segment */
4887 segment = &stream->segments[seg_idx];
4889 if (G_UNLIKELY (offset < segment->time)) {
4890 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4891 GST_TIME_ARGS (segment->time));
4895 /* segment lies beyond total indicated duration */
4896 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4897 segment->time > qtdemux->segment.duration)) {
4898 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4899 " < segment->time %" GST_TIME_FORMAT,
4900 GST_TIME_ARGS (qtdemux->segment.duration),
4901 GST_TIME_ARGS (segment->time));
4905 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4906 &start, &stop, &time);
4908 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4909 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4910 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4912 /* combine global rate with that of the segment */
4913 rate = segment->rate * qtdemux->segment.rate;
4915 /* Copy flags from main segment */
4916 stream->segment.flags = qtdemux->segment.flags;
4918 /* update the segment values used for clipping */
4919 stream->segment.offset = qtdemux->segment.offset;
4920 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4921 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4922 stream->segment.rate = rate;
4923 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4924 stream->cslg_shift);
4925 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4926 stream->cslg_shift);
4927 stream->segment.time = time;
4928 stream->segment.position = stream->segment.start;
4930 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4933 /* now prepare and send the segment */
4935 event = gst_event_new_segment (&stream->segment);
4936 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4937 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4939 gst_pad_push_event (stream->pad, event);
4940 /* assume we can send more data now */
4941 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4942 /* clear to send tags on this pad now */
4943 gst_qtdemux_push_tags (qtdemux, stream);
4954 /* activate the given segment number @seg_idx of @stream at time @offset.
4955 * @offset is an absolute global position over all the segments.
4957 * This will push out a NEWSEGMENT event with the right values and
4958 * position the stream index to the first decodable sample before
4962 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4963 guint32 seg_idx, GstClockTime offset)
4965 QtDemuxSegment *segment;
4966 guint32 index, kf_index;
4967 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4969 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4970 seg_idx, GST_TIME_ARGS (offset));
4972 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4976 segment = &stream->segments[stream->segment_index];
4978 /* in the fragmented case, we pick a fragment that starts before our
4979 * desired position and rely on downstream to wait for a keyframe
4980 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4981 * tfra entries tells us which trun/sample the key unit is in, but we don't
4982 * make use of this additional information at the moment) */
4983 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
4984 stream->to_sample = G_MAXUINT32;
4987 /* well, it will be taken care of below */
4988 qtdemux->fragmented_seek_pending = FALSE;
4989 /* FIXME ideally the do_fragmented_seek can be done right here,
4990 * rather than at loop level
4991 * (which might even allow handling edit lists in a fragmented file) */
4994 /* We don't need to look for a sample in push-based */
4995 if (!qtdemux->pullbased)
4998 /* and move to the keyframe before the indicated media time of the
5000 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5001 if (qtdemux->segment.rate >= 0) {
5002 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5003 stream->to_sample = G_MAXUINT32;
5004 GST_DEBUG_OBJECT (stream->pad,
5005 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5006 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5007 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5009 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5010 stream->to_sample = index;
5011 GST_DEBUG_OBJECT (stream->pad,
5012 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5013 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5014 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5017 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5018 "this is an empty segment");
5022 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5023 * encountered an error and printed a message so we return appropriately */
5027 /* we're at the right spot */
5028 if (index == stream->sample_index) {
5029 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5033 /* find keyframe of the target index */
5034 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5036 /* go back two frames to provide lead-in for non-raw audio decoders */
5037 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5038 guint32 lead_in = 2;
5039 guint32 old_index = kf_index;
5040 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5042 if (gst_structure_has_name (s, "audio/mpeg")) {
5044 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5045 && mpegversion == 1) {
5046 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5051 kf_index = MAX (kf_index, lead_in) - lead_in;
5052 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5053 GST_DEBUG_OBJECT (stream->pad,
5054 "Moving backwards %u frames to ensure sufficient sound lead-in",
5055 old_index - kf_index);
5057 kf_index = old_index;
5061 /* if we move forwards, we don't have to go back to the previous
5062 * keyframe since we already sent that. We can also just jump to
5063 * the keyframe right before the target index if there is one. */
5064 if (index > stream->sample_index) {
5065 /* moving forwards check if we move past a keyframe */
5066 if (kf_index > stream->sample_index) {
5067 GST_DEBUG_OBJECT (stream->pad,
5068 "moving forwards to keyframe at %u "
5069 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5071 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5072 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5073 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5075 GST_DEBUG_OBJECT (stream->pad,
5076 "moving forwards, keyframe at %u "
5077 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5079 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5080 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5083 GST_DEBUG_OBJECT (stream->pad,
5084 "moving backwards to %sframe at %u "
5085 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5086 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5087 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5088 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5089 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5095 /* prepare to get the current sample of @stream, getting essential values.
5097 * This function will also prepare and send the segment when needed.
5099 * Return FALSE if the stream is EOS.
5104 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5105 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5106 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5107 gboolean * keyframe)
5109 QtDemuxSample *sample;
5110 GstClockTime time_position;
5113 g_return_val_if_fail (stream != NULL, FALSE);
5115 time_position = stream->time_position;
5116 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5119 seg_idx = stream->segment_index;
5120 if (G_UNLIKELY (seg_idx == -1)) {
5121 /* find segment corresponding to time_position if we are looking
5123 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5126 /* different segment, activate it, sample_index will be set. */
5127 if (G_UNLIKELY (stream->segment_index != seg_idx))
5128 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5130 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5131 segments[stream->segment_index]))) {
5132 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5134 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5135 " prepare empty sample");
5138 *pts = *dts = time_position;
5139 *duration = seg->duration - (time_position - seg->time);
5146 if (stream->sample_index == -1)
5147 stream->sample_index = 0;
5149 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5150 stream->sample_index, stream->n_samples);
5152 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5153 if (!qtdemux->fragmented)
5156 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5160 GST_OBJECT_LOCK (qtdemux);
5161 flow = qtdemux_add_fragmented_samples (qtdemux);
5162 GST_OBJECT_UNLOCK (qtdemux);
5164 if (flow != GST_FLOW_OK)
5167 while (stream->sample_index >= stream->n_samples);
5170 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5171 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5172 stream->sample_index);
5176 /* now get the info for the sample we're at */
5177 sample = &stream->samples[stream->sample_index];
5179 *dts = QTSAMPLE_DTS (stream, sample);
5180 *pts = QTSAMPLE_PTS (stream, sample);
5181 *offset = sample->offset;
5182 *size = sample->size;
5183 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5184 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5191 stream->time_position = GST_CLOCK_TIME_NONE;
5196 /* move to the next sample in @stream.
5198 * Moves to the next segment when needed.
5201 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5203 QtDemuxSample *sample;
5204 QtDemuxSegment *segment;
5206 /* get current segment */
5207 segment = &stream->segments[stream->segment_index];
5209 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5210 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5214 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5215 /* Mark the stream as EOS */
5216 GST_DEBUG_OBJECT (qtdemux,
5217 "reached max allowed sample %u, mark EOS", stream->to_sample);
5218 stream->time_position = GST_CLOCK_TIME_NONE;
5222 /* move to next sample */
5223 stream->sample_index++;
5224 stream->offset_in_sample = 0;
5226 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5229 /* reached the last sample, we need the next segment */
5230 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5233 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5234 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5235 stream->sample_index);
5239 /* get next sample */
5240 sample = &stream->samples[stream->sample_index];
5242 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5243 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5244 GST_TIME_ARGS (segment->media_stop));
5246 /* see if we are past the segment */
5247 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5250 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5251 /* inside the segment, update time_position, looks very familiar to
5252 * GStreamer segments, doesn't it? */
5253 stream->time_position =
5254 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5256 /* not yet in segment, time does not yet increment. This means
5257 * that we are still prerolling keyframes to the decoder so it can
5258 * decode the first sample of the segment. */
5259 stream->time_position = segment->time;
5263 /* move to the next segment */
5266 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5268 if (stream->segment_index == stream->n_segments - 1) {
5269 /* are we at the end of the last segment, we're EOS */
5270 stream->time_position = GST_CLOCK_TIME_NONE;
5272 /* else we're only at the end of the current segment */
5273 stream->time_position = segment->stop_time;
5275 /* make sure we select a new segment */
5277 /* accumulate previous segments */
5278 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5279 stream->accumulated_base +=
5280 (stream->segment.stop -
5281 stream->segment.start) / ABS (stream->segment.rate);
5283 stream->segment_index = -1;
5288 gst_qtdemux_sync_streams (GstQTDemux * demux)
5292 if (QTDEMUX_N_STREAMS (demux) <= 1)
5295 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5296 QtDemuxStream *stream;
5297 GstClockTime end_time;
5299 stream = QTDEMUX_NTH_STREAM (demux, i);
5304 /* TODO advance time on subtitle streams here, if any some day */
5306 /* some clips/trailers may have unbalanced streams at the end,
5307 * so send EOS on shorter stream to prevent stalling others */
5309 /* do not mess with EOS if SEGMENT seeking */
5310 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5313 if (demux->pullbased) {
5314 /* loop mode is sample time based */
5315 if (!STREAM_IS_EOS (stream))
5318 /* push mode is byte position based */
5319 if (stream->n_samples &&
5320 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5324 if (stream->sent_eos)
5327 /* only act if some gap */
5328 end_time = stream->segments[stream->n_segments - 1].stop_time;
5329 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5330 ", stream end: %" GST_TIME_FORMAT,
5331 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5332 if (GST_CLOCK_TIME_IS_VALID (end_time)
5333 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5336 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5337 GST_PAD_NAME (stream->pad));
5338 stream->sent_eos = TRUE;
5339 event = gst_event_new_eos ();
5340 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5341 gst_event_set_seqnum (event, demux->segment_seqnum);
5342 gst_pad_push_event (stream->pad, event);
5347 /* EOS and NOT_LINKED need to be combined. This means that we return:
5349 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5350 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5352 static GstFlowReturn
5353 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5356 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5359 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5362 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5364 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5368 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5369 * completely clipped
5371 * Should be used only with raw buffers */
5373 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5376 guint64 start, stop, cstart, cstop, diff;
5377 GstClockTime pts, duration;
5379 gint num_rate, denom_rate;
5384 osize = size = gst_buffer_get_size (buf);
5387 /* depending on the type, setup the clip parameters */
5388 if (stream->subtype == FOURCC_soun) {
5389 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5390 num_rate = GST_SECOND;
5391 denom_rate = (gint) CUR_STREAM (stream)->rate;
5393 } else if (stream->subtype == FOURCC_vide) {
5395 num_rate = CUR_STREAM (stream)->fps_n;
5396 denom_rate = CUR_STREAM (stream)->fps_d;
5401 if (frame_size <= 0)
5402 goto bad_frame_size;
5404 /* we can only clip if we have a valid pts */
5405 pts = GST_BUFFER_PTS (buf);
5406 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5409 duration = GST_BUFFER_DURATION (buf);
5411 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5413 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5417 stop = start + duration;
5419 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5420 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5423 /* see if some clipping happened */
5424 diff = cstart - start;
5430 /* bring clipped time to samples and to bytes */
5431 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5434 GST_DEBUG_OBJECT (qtdemux,
5435 "clipping start to %" GST_TIME_FORMAT " %"
5436 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5442 diff = stop - cstop;
5447 /* bring clipped time to samples and then to bytes */
5448 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5450 GST_DEBUG_OBJECT (qtdemux,
5451 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5452 " bytes", GST_TIME_ARGS (cstop), diff);
5457 if (offset != 0 || size != osize)
5458 gst_buffer_resize (buf, offset, size);
5460 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5461 GST_BUFFER_PTS (buf) = pts;
5462 GST_BUFFER_DURATION (buf) = duration;
5466 /* dropped buffer */
5469 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5474 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5479 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5484 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5485 gst_buffer_unref (buf);
5491 gst_qtdemux_align_buffer (GstQTDemux * demux,
5492 GstBuffer * buffer, gsize alignment)
5496 gst_buffer_map (buffer, &map, GST_MAP_READ);
5498 if (map.size < sizeof (guintptr)) {
5499 gst_buffer_unmap (buffer, &map);
5503 if (((guintptr) map.data) & (alignment - 1)) {
5504 GstBuffer *new_buffer;
5505 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5507 new_buffer = gst_buffer_new_allocate (NULL,
5508 gst_buffer_get_size (buffer), ¶ms);
5510 /* Copy data "by hand", so ensure alignment is kept: */
5511 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5513 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5514 GST_DEBUG_OBJECT (demux,
5515 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5518 gst_buffer_unmap (buffer, &map);
5519 gst_buffer_unref (buffer);
5524 gst_buffer_unmap (buffer, &map);
5529 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5535 /* We are converting from pairs to triplets */
5536 *res = ccpair_size / 2 * 3;
5537 storage = g_malloc (*res);
5538 for (i = 0; i * 2 < ccpair_size; i += 1) {
5539 /* FIXME: Use line offset 0 as we simply can't know here */
5541 storage[i * 3] = 0x80 | 0x00;
5543 storage[i * 3] = 0x00 | 0x00;
5544 storage[i * 3 + 1] = ccpair[i * 2];
5545 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5552 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5556 guint32 atom_length, fourcc;
5557 QtDemuxStreamStsdEntry *stsd_entry;
5559 GST_MEMDUMP ("caption atom", data, size);
5561 /* There might be multiple atoms */
5566 atom_length = QT_UINT32 (data);
5567 fourcc = QT_FOURCC (data + 4);
5568 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5571 GST_DEBUG_OBJECT (stream->pad, "here");
5573 /* Check if we have something compatible */
5574 stsd_entry = CUR_STREAM (stream);
5575 switch (stsd_entry->fourcc) {
5577 guint8 *cdat = NULL, *cdt2 = NULL;
5578 gsize cdat_size = 0, cdt2_size = 0;
5579 /* Should be cdat or cdt2 */
5580 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5581 GST_WARNING_OBJECT (stream->pad,
5582 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5583 GST_FOURCC_ARGS (fourcc));
5587 /* Convert to S334-1 Annex A byte triplet */
5588 if (fourcc == FOURCC_cdat)
5589 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5591 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5592 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5595 /* Check for another atom ? */
5596 if (size > atom_length + 8) {
5597 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5598 if (size >= atom_length + new_atom_length) {
5599 fourcc = QT_FOURCC (data + atom_length + 4);
5600 if (fourcc == FOURCC_cdat) {
5603 convert_to_s334_1a (data + atom_length + 8,
5604 new_atom_length - 8, 1, &cdat_size);
5606 GST_WARNING_OBJECT (stream->pad,
5607 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5611 convert_to_s334_1a (data + atom_length + 8,
5612 new_atom_length - 8, 2, &cdt2_size);
5614 GST_WARNING_OBJECT (stream->pad,
5615 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5620 *cclen = cdat_size + cdt2_size;
5621 res = g_malloc (*cclen);
5623 memcpy (res, cdat, cdat_size);
5625 memcpy (res + cdat_size, cdt2, cdt2_size);
5631 if (fourcc != FOURCC_ccdp) {
5632 GST_WARNING_OBJECT (stream->pad,
5633 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5634 GST_FOURCC_ARGS (fourcc));
5637 *cclen = atom_length - 8;
5638 res = g_memdup2 (data + 8, *cclen);
5641 /* Keep this here in case other closed caption formats are added */
5642 g_assert_not_reached ();
5646 GST_MEMDUMP ("Output", res, *cclen);
5651 GST_WARNING ("[cdat] atom is too small or invalid");
5655 /* the input buffer metadata must be writable,
5656 * but time/duration etc not yet set and need not be preserved */
5658 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5665 /* not many cases for now */
5666 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5667 /* send a one time dvd clut event */
5668 if (stream->pending_event && stream->pad)
5669 gst_pad_push_event (stream->pad, stream->pending_event);
5670 stream->pending_event = NULL;
5673 if (G_UNLIKELY (stream->subtype != FOURCC_text
5674 && stream->subtype != FOURCC_sbtl &&
5675 stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
5679 gst_buffer_map (buf, &map, GST_MAP_READ);
5681 /* empty buffer is sent to terminate previous subtitle */
5682 if (map.size <= 2) {
5683 gst_buffer_unmap (buf, &map);
5684 gst_buffer_unref (buf);
5687 if (stream->subtype == FOURCC_subp) {
5688 /* That's all the processing needed for subpictures */
5689 gst_buffer_unmap (buf, &map);
5693 if (stream->subtype == FOURCC_clcp) {
5696 /* For closed caption, we need to extract the information from the
5697 * [cdat],[cdt2] or [ccdp] atom */
5698 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5699 gst_buffer_unmap (buf, &map);
5700 gst_buffer_unref (buf);
5702 buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5704 /* Conversion failed or there's nothing */
5710 nsize = GST_READ_UINT16_BE (map.data);
5711 nsize = MIN (nsize, map.size - 2);
5713 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5716 /* takes care of UTF-8 validation or UTF-16 recognition,
5717 * no other encoding expected */
5718 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5719 gst_buffer_unmap (buf, &map);
5721 gst_buffer_unref (buf);
5722 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5724 /* this should not really happen unless the subtitle is corrupted */
5725 gst_buffer_unref (buf);
5729 /* FIXME ? convert optional subsequent style info to markup */
5734 static GstFlowReturn
5735 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5738 GstFlowReturn ret = GST_FLOW_OK;
5739 GstClockTime pts, duration;
5741 if (stream->need_clip)
5742 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5744 if (G_UNLIKELY (buf == NULL))
5747 if (G_UNLIKELY (stream->discont)) {
5748 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5749 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5750 stream->discont = FALSE;
5752 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5755 GST_LOG_OBJECT (qtdemux,
5756 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5757 ", duration %" GST_TIME_FORMAT " on pad %s",
5758 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5759 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5760 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5762 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5763 GstStructure *crypto_info;
5764 QtDemuxAavdEncryptionInfo *info =
5765 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5767 crypto_info = gst_structure_copy (info->default_properties);
5768 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5769 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5772 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
5773 || stream->protection_scheme_type == FOURCC_cbcs)) {
5774 GstStructure *crypto_info;
5775 QtDemuxCencSampleSetInfo *info =
5776 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5780 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5781 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5782 GST_PTR_FORMAT, event);
5783 gst_pad_push_event (stream->pad, event);
5786 if (info->crypto_info == NULL) {
5787 if (stream->protection_scheme_type == FOURCC_cbcs) {
5788 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
5789 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
5790 GST_ERROR_OBJECT (qtdemux,
5791 "failed to attach cbcs metadata to buffer");
5792 qtdemux_gst_structure_free (crypto_info);
5794 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
5797 GST_DEBUG_OBJECT (qtdemux,
5798 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5801 /* The end of the crypto_info array matches our n_samples position,
5802 * so count backward from there */
5803 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5804 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5805 /* steal structure from array */
5806 crypto_info = g_ptr_array_index (info->crypto_info, index);
5807 g_ptr_array_index (info->crypto_info, index) = NULL;
5808 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5809 info->crypto_info->len);
5810 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5811 GST_ERROR_OBJECT (qtdemux,
5812 "failed to attach cenc metadata to buffer");
5814 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5815 index, stream->sample_index);
5820 if (stream->alignment > 1)
5821 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5823 pts = GST_BUFFER_PTS (buf);
5824 duration = GST_BUFFER_DURATION (buf);
5826 ret = gst_pad_push (stream->pad, buf);
5828 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5829 /* mark position in stream, we'll need this to know when to send GAP event */
5830 stream->segment.position = pts + duration;
5838 static GstFlowReturn
5839 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5842 GstFlowReturn ret = GST_FLOW_OK;
5844 if (stream->subtype == FOURCC_clcp
5845 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
5847 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
5848 guint n_triplets, i;
5849 guint field1_off = 0, field2_off = 0;
5851 /* We have to split CEA608 buffers so that each outgoing buffer contains
5852 * one byte pair per field according to the framerate of the video track.
5854 * If there is only a single byte pair per field we don't have to do
5858 gst_buffer_map (buf, &map, GST_MAP_READ);
5860 n_triplets = map.size / 3;
5861 for (i = 0; i < n_triplets; i++) {
5862 if (map.data[3 * i] & 0x80)
5868 g_assert (n_field1 || n_field2);
5870 /* If there's more than 1 frame we have to split, otherwise we can just
5872 if (n_field1 > 1 || n_field2 > 1) {
5874 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
5875 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
5877 for (i = 0; i < n_output_buffers; i++) {
5879 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
5883 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
5884 outptr = outmap.data;
5887 gboolean found = FALSE;
5889 while (map.data + field1_off < map.data + map.size) {
5890 if (map.data[field1_off] & 0x80) {
5891 memcpy (outptr, &map.data[field1_off], 3);
5900 const guint8 empty[] = { 0x80, 0x80, 0x80 };
5902 memcpy (outptr, empty, 3);
5909 gboolean found = FALSE;
5911 while (map.data + field2_off < map.data + map.size) {
5912 if ((map.data[field2_off] & 0x80) == 0) {
5913 memcpy (outptr, &map.data[field2_off], 3);
5922 const guint8 empty[] = { 0x00, 0x80, 0x80 };
5924 memcpy (outptr, empty, 3);
5930 gst_buffer_unmap (outbuf, &outmap);
5932 GST_BUFFER_PTS (outbuf) =
5933 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
5934 GST_SECOND * CUR_STREAM (stream)->fps_d,
5935 CUR_STREAM (stream)->fps_n);
5936 GST_BUFFER_DURATION (outbuf) =
5937 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
5938 CUR_STREAM (stream)->fps_n);
5939 GST_BUFFER_OFFSET (outbuf) = -1;
5940 GST_BUFFER_OFFSET_END (outbuf) = -1;
5942 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
5944 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
5947 gst_buffer_unmap (buf, &map);
5948 gst_buffer_unref (buf);
5950 gst_buffer_unmap (buf, &map);
5951 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
5954 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
5960 /* Sets a buffer's attributes properly and pushes it downstream.
5961 * Also checks for additional actions and custom processing that may
5962 * need to be done first.
5964 static GstFlowReturn
5965 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5966 QtDemuxStream * stream, GstBuffer * buf,
5967 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5968 gboolean keyframe, GstClockTime position, guint64 byte_position)
5970 GstFlowReturn ret = GST_FLOW_OK;
5972 /* offset the timestamps according to the edit list */
5974 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5978 gst_buffer_map (buf, &map, GST_MAP_READ);
5979 url = g_strndup ((gchar *) map.data, map.size);
5980 gst_buffer_unmap (buf, &map);
5981 if (url != NULL && strlen (url) != 0) {
5982 /* we have RTSP redirect now */
5983 g_free (qtdemux->redirect_location);
5984 qtdemux->redirect_location = g_strdup (url);
5985 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5986 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5987 gst_structure_new ("redirect",
5988 "new-location", G_TYPE_STRING, url, NULL)));
5990 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5996 /* position reporting */
5997 if (qtdemux->segment.rate >= 0) {
5998 qtdemux->segment.position = position;
5999 gst_qtdemux_sync_streams (qtdemux);
6002 if (G_UNLIKELY (!stream->pad)) {
6003 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6004 gst_buffer_unref (buf);
6008 /* send out pending buffers */
6009 while (stream->buffers) {
6010 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6012 if (G_UNLIKELY (stream->discont)) {
6013 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6014 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6015 stream->discont = FALSE;
6017 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6020 if (stream->alignment > 1)
6021 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6022 gst_pad_push (stream->pad, buffer);
6024 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6027 /* we're going to modify the metadata */
6028 buf = gst_buffer_make_writable (buf);
6030 if (G_UNLIKELY (stream->need_process))
6031 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
6037 GST_BUFFER_DTS (buf) = dts;
6038 GST_BUFFER_PTS (buf) = pts;
6039 GST_BUFFER_DURATION (buf) = duration;
6040 GST_BUFFER_OFFSET (buf) = -1;
6041 GST_BUFFER_OFFSET_END (buf) = -1;
6044 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6045 stream->on_keyframe = FALSE;
6047 stream->on_keyframe = TRUE;
6050 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6051 gst_buffer_append_memory (buf,
6052 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6054 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6055 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6058 if (G_UNLIKELY (qtdemux->element_index)) {
6059 GstClockTime stream_time;
6062 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6064 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6065 GST_LOG_OBJECT (qtdemux,
6066 "adding association %" GST_TIME_FORMAT "-> %"
6067 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6068 gst_index_add_association (qtdemux->element_index,
6070 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6071 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6072 GST_FORMAT_BYTES, byte_position, NULL);
6077 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6083 static const QtDemuxRandomAccessEntry *
6084 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6085 GstClockTime pos, gboolean after)
6087 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6088 guint n_entries = stream->n_ra_entries;
6091 /* we assume the table is sorted */
6092 for (i = 0; i < n_entries; ++i) {
6093 if (entries[i].ts > pos)
6097 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6098 * probably okay to assume that the index lists the very first fragment */
6105 return &entries[i - 1];
6109 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6111 const QtDemuxRandomAccessEntry *best_entry = NULL;
6114 GST_OBJECT_LOCK (qtdemux);
6116 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6118 /* first see if we can determine where to go to using mfra,
6119 * before we start clearing things */
6120 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6121 const QtDemuxRandomAccessEntry *entry;
6122 QtDemuxStream *stream;
6123 gboolean is_audio_or_video;
6125 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6127 if (stream->ra_entries == NULL)
6130 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6131 is_audio_or_video = TRUE;
6133 is_audio_or_video = FALSE;
6136 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6137 stream->time_position, !is_audio_or_video);
6139 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6140 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6142 stream->pending_seek = entry;
6144 /* decide position to jump to just based on audio/video tracks, not subs */
6145 if (!is_audio_or_video)
6148 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6152 /* no luck, will handle seek otherwise */
6153 if (best_entry == NULL) {
6154 GST_OBJECT_UNLOCK (qtdemux);
6158 /* ok, now we can prepare for processing as of located moof */
6159 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6160 QtDemuxStream *stream;
6162 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6164 g_free (stream->samples);
6165 stream->samples = NULL;
6166 stream->n_samples = 0;
6167 stream->stbl_index = -1; /* no samples have yet been parsed */
6168 stream->sample_index = -1;
6170 if (stream->protection_scheme_info) {
6171 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6172 if (stream->protection_scheme_type == FOURCC_cenc
6173 || stream->protection_scheme_type == FOURCC_cbcs) {
6174 QtDemuxCencSampleSetInfo *info =
6175 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6176 if (info->crypto_info) {
6177 g_ptr_array_free (info->crypto_info, TRUE);
6178 info->crypto_info = NULL;
6184 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6185 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6186 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6187 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6189 qtdemux->moof_offset = best_entry->moof_offset;
6191 qtdemux_add_fragmented_samples (qtdemux);
6193 GST_OBJECT_UNLOCK (qtdemux);
6197 static GstFlowReturn
6198 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6200 GstFlowReturn ret = GST_FLOW_OK;
6201 GstBuffer *buf = NULL;
6202 QtDemuxStream *stream, *target_stream = NULL;
6203 GstClockTime min_time;
6205 GstClockTime dts = GST_CLOCK_TIME_NONE;
6206 GstClockTime pts = GST_CLOCK_TIME_NONE;
6207 GstClockTime duration = 0;
6208 gboolean keyframe = FALSE;
6209 guint sample_size = 0;
6210 guint num_samples = 1;
6215 if (qtdemux->fragmented_seek_pending) {
6216 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6217 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6218 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6219 qtdemux->fragmented_seek_pending = FALSE;
6221 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6225 /* Figure out the next stream sample to output, min_time is expressed in
6226 * global time and runs over the edit list segments. */
6227 min_time = G_MAXUINT64;
6228 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6229 GstClockTime position;
6231 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6232 position = stream->time_position;
6234 if (!GST_CLOCK_TIME_IS_VALID (position))
6237 if (stream->segment_index != -1) {
6238 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6239 position += segment->media_start;
6242 /* position of -1 is EOS */
6243 if (position < min_time) {
6244 min_time = position;
6245 target_stream = stream;
6249 if (G_UNLIKELY (target_stream == NULL)) {
6250 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6254 /* check for segment end */
6255 if (G_UNLIKELY (qtdemux->segment.stop != -1
6256 && qtdemux->segment.rate >= 0
6257 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6258 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6259 target_stream->time_position = GST_CLOCK_TIME_NONE;
6263 /* gap events for subtitle streams */
6264 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6265 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6267 GstClockTime gap_threshold;
6269 /* Only send gap events on non-subtitle streams if lagging way behind. */
6270 if (stream->subtype == FOURCC_subp
6271 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)
6272 gap_threshold = 1 * GST_SECOND;
6274 gap_threshold = 3 * GST_SECOND;
6276 /* send gap events until the stream catches up */
6277 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6278 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6279 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6280 stream->segment.position + gap_threshold < min_time) {
6282 gst_event_new_gap (stream->segment.position, gap_threshold);
6283 gst_pad_push_event (stream->pad, gap);
6284 stream->segment.position += gap_threshold;
6289 stream = target_stream;
6290 /* fetch info for the current sample of this stream */
6291 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6292 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6295 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6296 if (stream->new_caps) {
6297 gst_qtdemux_configure_stream (qtdemux, stream);
6298 qtdemux_do_allocation (stream, qtdemux);
6301 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6302 if (G_UNLIKELY (qtdemux->segment.
6303 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6304 if (stream->subtype == FOURCC_vide) {
6306 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6309 } else if (qtdemux->trickmode_interval > 0) {
6310 GstClockTimeDiff interval;
6312 if (qtdemux->segment.rate > 0)
6313 interval = stream->time_position - stream->last_keyframe_dts;
6315 interval = stream->last_keyframe_dts - stream->time_position;
6317 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6318 && interval < qtdemux->trickmode_interval) {
6319 GST_LOG_OBJECT (qtdemux,
6320 "Skipping keyframe within interval on track-id %u",
6324 stream->last_keyframe_dts = stream->time_position;
6330 GST_DEBUG_OBJECT (qtdemux,
6331 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6332 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6333 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6334 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6335 GST_TIME_ARGS (duration));
6337 if (G_UNLIKELY (empty)) {
6338 /* empty segment, push a gap if there's a second or more
6339 * difference and move to the next one */
6340 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6341 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6342 stream->segment.position = pts + duration;
6346 /* hmm, empty sample, skip and move to next sample */
6347 if (G_UNLIKELY (sample_size <= 0))
6350 /* last pushed sample was out of boundary, goto next sample */
6351 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6354 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6355 GST_DEBUG_OBJECT (qtdemux,
6356 "size %d larger than stream max_buffer_size %d, trimming",
6357 sample_size, stream->max_buffer_size);
6359 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6360 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6361 && sample_size < stream->min_buffer_size) {
6362 guint start_sample_index = stream->sample_index;
6363 guint accumulated_size = sample_size;
6364 guint64 expected_next_offset = offset + sample_size;
6366 GST_DEBUG_OBJECT (qtdemux,
6367 "size %d smaller than stream min_buffer_size %d, combining with the next",
6368 sample_size, stream->min_buffer_size);
6370 while (stream->sample_index < stream->to_sample
6371 && stream->sample_index + 1 < stream->n_samples) {
6372 const QtDemuxSample *next_sample;
6374 /* Increment temporarily */
6375 stream->sample_index++;
6377 /* Failed to parse sample so let's go back to the previous one that was
6378 * still successful */
6379 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6380 stream->sample_index--;
6384 next_sample = &stream->samples[stream->sample_index];
6386 /* Not contiguous with the previous sample so let's go back to the
6387 * previous one that was still successful */
6388 if (next_sample->offset != expected_next_offset) {
6389 stream->sample_index--;
6393 accumulated_size += next_sample->size;
6394 expected_next_offset += next_sample->size;
6395 if (accumulated_size >= stream->min_buffer_size)
6399 num_samples = stream->sample_index + 1 - start_sample_index;
6400 stream->sample_index = start_sample_index;
6401 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6402 num_samples, accumulated_size);
6403 size = accumulated_size;
6408 if (qtdemux->cenc_aux_info_offset > 0) {
6411 GstBuffer *aux_info = NULL;
6413 /* pull the data stored before the sample */
6415 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6416 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6417 if (G_UNLIKELY (ret != GST_FLOW_OK))
6419 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6420 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6421 gst_byte_reader_init (&br, map.data + 8, map.size);
6422 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6423 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6424 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6425 gst_buffer_unmap (aux_info, &map);
6426 gst_buffer_unref (aux_info);
6427 ret = GST_FLOW_ERROR;
6430 gst_buffer_unmap (aux_info, &map);
6431 gst_buffer_unref (aux_info);
6434 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6437 if (stream->use_allocator) {
6438 /* if we have a per-stream allocator, use it */
6439 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6442 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6444 if (G_UNLIKELY (ret != GST_FLOW_OK))
6447 /* Update for both splitting and combining of samples */
6448 if (size != sample_size) {
6449 pts += gst_util_uint64_scale_int (GST_SECOND,
6450 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6453 gst_util_uint64_scale_int (GST_SECOND,
6454 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6457 gst_util_uint64_scale_int (GST_SECOND,
6458 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6461 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6462 dts, pts, duration, keyframe, min_time, offset);
6464 if (size < sample_size) {
6465 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6466 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6468 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6470 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6471 if (time_position >= segment->media_start) {
6472 /* inside the segment, update time_position, looks very familiar to
6473 * GStreamer segments, doesn't it? */
6474 stream->time_position = (time_position - segment->media_start) +
6477 /* not yet in segment, time does not yet increment. This means
6478 * that we are still prerolling keyframes to the decoder so it can
6479 * decode the first sample of the segment. */
6480 stream->time_position = segment->time;
6482 } else if (size > sample_size) {
6483 /* Increase to the last sample we already pulled so that advancing
6484 * below brings us to the next sample we need to pull */
6485 stream->sample_index += num_samples - 1;
6489 GST_OBJECT_LOCK (qtdemux);
6490 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6491 GST_OBJECT_UNLOCK (qtdemux);
6492 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6493 * we have no more data for the pad to push */
6494 if (ret == GST_FLOW_EOS)
6497 stream->offset_in_sample += size;
6498 if (stream->offset_in_sample >= sample_size) {
6499 gst_qtdemux_advance_sample (qtdemux, stream);
6504 gst_qtdemux_advance_sample (qtdemux, stream);
6512 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6518 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6519 /* EOS will be raised if all are EOS */
6526 gst_qtdemux_loop (GstPad * pad)
6528 GstQTDemux *qtdemux;
6532 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6534 cur_offset = qtdemux->offset;
6535 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6536 cur_offset, qt_demux_state_string (qtdemux->state));
6538 switch (qtdemux->state) {
6539 case QTDEMUX_STATE_INITIAL:
6540 case QTDEMUX_STATE_HEADER:
6541 ret = gst_qtdemux_loop_state_header (qtdemux);
6543 case QTDEMUX_STATE_MOVIE:
6544 ret = gst_qtdemux_loop_state_movie (qtdemux);
6545 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6546 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6554 /* if something went wrong, pause */
6555 if (ret != GST_FLOW_OK)
6559 gst_object_unref (qtdemux);
6565 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6566 (NULL), ("streaming stopped, invalid state"));
6567 gst_pad_pause_task (pad);
6568 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6573 const gchar *reason = gst_flow_get_name (ret);
6575 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6577 gst_pad_pause_task (pad);
6579 /* fatal errors need special actions */
6581 if (ret == GST_FLOW_EOS) {
6582 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6583 /* we have no streams, post an error */
6584 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6586 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6589 if ((stop = qtdemux->segment.stop) == -1)
6590 stop = qtdemux->segment.duration;
6592 if (qtdemux->segment.rate >= 0) {
6593 GstMessage *message;
6596 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6597 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6598 GST_FORMAT_TIME, stop);
6599 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6600 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6601 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6602 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6604 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6605 gst_qtdemux_push_event (qtdemux, event);
6607 GstMessage *message;
6610 /* For Reverse Playback */
6611 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6612 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6613 GST_FORMAT_TIME, qtdemux->segment.start);
6614 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6615 qtdemux->segment.start);
6616 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6617 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6618 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6620 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6621 gst_qtdemux_push_event (qtdemux, event);
6626 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6627 event = gst_event_new_eos ();
6628 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6629 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6630 gst_qtdemux_push_event (qtdemux, event);
6632 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6633 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6634 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6643 * Returns if there are samples to be played.
6646 has_next_entry (GstQTDemux * demux)
6648 QtDemuxStream *stream;
6651 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6653 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6654 stream = QTDEMUX_NTH_STREAM (demux, i);
6656 if (stream->sample_index == -1) {
6657 stream->sample_index = 0;
6658 stream->offset_in_sample = 0;
6661 if (stream->sample_index >= stream->n_samples) {
6662 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6665 GST_DEBUG_OBJECT (demux, "Found a sample");
6669 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6676 * Returns the size of the first entry at the current offset.
6677 * If -1, there are none (which means EOS or empty file).
6680 next_entry_size (GstQTDemux * demux)
6682 QtDemuxStream *stream, *target_stream = NULL;
6683 guint64 smalloffs = (guint64) - 1;
6684 QtDemuxSample *sample;
6687 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6690 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6691 stream = QTDEMUX_NTH_STREAM (demux, i);
6693 if (stream->sample_index == -1) {
6694 stream->sample_index = 0;
6695 stream->offset_in_sample = 0;
6698 if (stream->sample_index >= stream->n_samples) {
6699 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6703 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6704 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6705 stream->sample_index);
6709 sample = &stream->samples[stream->sample_index];
6711 GST_LOG_OBJECT (demux,
6712 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6713 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6714 stream->sample_index, sample->offset, sample->size);
6716 if (((smalloffs == -1)
6717 || (sample->offset < smalloffs)) && (sample->size)) {
6718 smalloffs = sample->offset;
6719 target_stream = stream;
6726 GST_LOG_OBJECT (demux,
6727 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6728 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6730 stream = target_stream;
6731 sample = &stream->samples[stream->sample_index];
6733 if (sample->offset >= demux->offset) {
6734 demux->todrop = sample->offset - demux->offset;
6735 return sample->size + demux->todrop;
6738 GST_DEBUG_OBJECT (demux,
6739 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6744 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6746 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6748 gst_element_post_message (GST_ELEMENT_CAST (demux),
6749 gst_message_new_element (GST_OBJECT_CAST (demux),
6750 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6754 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6759 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6762 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6763 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6764 GST_SEEK_TYPE_NONE, -1);
6766 /* store seqnum to drop flush events, they don't need to reach downstream */
6767 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6768 res = gst_pad_push_event (demux->sinkpad, event);
6769 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6774 /* check for seekable upstream, above and beyond a mere query */
6776 gst_qtdemux_check_seekability (GstQTDemux * demux)
6779 gboolean seekable = FALSE;
6780 gint64 start = -1, stop = -1;
6782 if (demux->upstream_size)
6785 if (demux->upstream_format_is_time)
6788 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6789 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6790 GST_DEBUG_OBJECT (demux, "seeking query failed");
6794 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6796 /* try harder to query upstream size if we didn't get it the first time */
6797 if (seekable && stop == -1) {
6798 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6799 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6802 /* if upstream doesn't know the size, it's likely that it's not seekable in
6803 * practice even if it technically may be seekable */
6804 if (seekable && (start != 0 || stop <= start)) {
6805 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6810 gst_query_unref (query);
6812 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6813 G_GUINT64_FORMAT ")", seekable, start, stop);
6814 demux->upstream_seekable = seekable;
6815 demux->upstream_size = seekable ? stop : -1;
6819 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6821 g_return_if_fail (bytes <= demux->todrop);
6823 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6824 gst_adapter_flush (demux->adapter, bytes);
6825 demux->neededbytes -= bytes;
6826 demux->offset += bytes;
6827 demux->todrop -= bytes;
6830 /* PUSH-MODE only: Send a segment, if not done already. */
6832 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6834 if (G_UNLIKELY (demux->need_segment)) {
6837 if (!demux->upstream_format_is_time) {
6838 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6840 GstEvent *segment_event;
6841 segment_event = gst_event_new_segment (&demux->segment);
6842 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6843 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6844 gst_qtdemux_push_event (demux, segment_event);
6847 demux->need_segment = FALSE;
6849 /* clear to send tags on all streams */
6850 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6851 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6852 gst_qtdemux_push_tags (demux, stream);
6853 if (CUR_STREAM (stream)->sparse) {
6854 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6855 gst_pad_push_event (stream->pad,
6856 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6862 /* Used for push mode only. */
6864 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6865 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6867 GstClockTime ts, dur;
6871 stream->segments[segment_index].duration - (pos -
6872 stream->segments[segment_index].time);
6873 stream->time_position += dur;
6875 /* Only gaps with a duration of at least one second are propagated.
6876 * Same workaround as in pull mode.
6877 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6878 if (dur >= GST_SECOND) {
6880 gap = gst_event_new_gap (ts, dur);
6882 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6883 "segment: %" GST_PTR_FORMAT, gap);
6884 gst_pad_push_event (stream->pad, gap);
6888 static GstFlowReturn
6889 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6893 demux = GST_QTDEMUX (parent);
6895 GST_DEBUG_OBJECT (demux,
6896 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6897 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6898 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6899 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6900 gst_buffer_get_size (inbuf), demux->offset);
6902 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6903 gboolean is_gap_input = FALSE;
6906 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6908 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6909 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
6912 /* Check if we can land back on our feet in the case where upstream is
6913 * handling the seeking/pushing of samples with gaps in between (like
6914 * in the case of trick-mode DASH for example) */
6915 if (demux->upstream_format_is_time
6916 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6917 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6919 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6920 GST_LOG_OBJECT (demux,
6921 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
6922 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
6924 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6925 stream, GST_BUFFER_OFFSET (inbuf));
6927 QtDemuxSample *sample = &stream->samples[res];
6928 GST_LOG_OBJECT (demux,
6929 "Checking if sample %d from track-id %u is valid (offset:%"
6930 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
6931 stream->track_id, sample->offset, sample->size);
6932 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6933 GST_LOG_OBJECT (demux,
6934 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6936 is_gap_input = TRUE;
6937 /* We can go back to standard playback mode */
6938 demux->state = QTDEMUX_STATE_MOVIE;
6939 /* Remember which sample this stream is at */
6940 stream->sample_index = res;
6941 /* Finally update all push-based values to the expected values */
6942 demux->neededbytes = stream->samples[res].size;
6943 demux->offset = GST_BUFFER_OFFSET (inbuf);
6945 demux->mdatsize - demux->offset + demux->mdatoffset;
6950 if (!is_gap_input) {
6951 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6952 /* Reset state if it's a real discont */
6953 demux->neededbytes = 16;
6954 demux->state = QTDEMUX_STATE_INITIAL;
6955 demux->offset = GST_BUFFER_OFFSET (inbuf);
6956 gst_adapter_clear (demux->adapter);
6959 /* Reverse fragmented playback, need to flush all we have before
6960 * consuming a new fragment.
6961 * The samples array have the timestamps calculated by accumulating the
6962 * durations but this won't work for reverse playback of fragments as
6963 * the timestamps of a subsequent fragment should be smaller than the
6964 * previously received one. */
6965 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6966 gst_qtdemux_process_adapter (demux, TRUE);
6967 g_ptr_array_foreach (demux->active_streams,
6968 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
6972 gst_adapter_push (demux->adapter, inbuf);
6974 GST_DEBUG_OBJECT (demux,
6975 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6976 demux->neededbytes, gst_adapter_available (demux->adapter));
6978 return gst_qtdemux_process_adapter (demux, FALSE);
6981 static GstFlowReturn
6982 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6984 GstFlowReturn ret = GST_FLOW_OK;
6986 /* we never really mean to buffer that much */
6987 if (demux->neededbytes == -1) {
6991 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6992 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6994 #ifndef GST_DISABLE_GST_DEBUG
6996 guint64 discont_offset, distance_from_discont;
6998 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6999 distance_from_discont =
7000 gst_adapter_distance_from_discont (demux->adapter);
7002 GST_DEBUG_OBJECT (demux,
7003 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7004 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7005 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7006 demux->offset, discont_offset, distance_from_discont);
7010 switch (demux->state) {
7011 case QTDEMUX_STATE_INITIAL:{
7016 gst_qtdemux_check_seekability (demux);
7018 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7020 /* get fourcc/length, set neededbytes */
7021 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7023 gst_adapter_unmap (demux->adapter);
7025 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7026 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7028 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7029 (_("This file is invalid and cannot be played.")),
7030 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7031 GST_FOURCC_ARGS (fourcc)));
7032 ret = GST_FLOW_ERROR;
7035 if (fourcc == FOURCC_mdat) {
7036 gint next_entry = next_entry_size (demux);
7037 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7038 || !demux->fragmented)) {
7039 /* we have the headers, start playback */
7040 demux->state = QTDEMUX_STATE_MOVIE;
7041 demux->neededbytes = next_entry;
7042 demux->mdatleft = size;
7043 demux->mdatsize = demux->mdatleft;
7045 /* no headers yet, try to get them */
7048 guint64 old, target;
7051 old = demux->offset;
7052 target = old + size;
7054 /* try to jump over the atom with a seek */
7055 /* only bother if it seems worth doing so,
7056 * and avoids possible upstream/server problems */
7057 if (demux->upstream_seekable &&
7058 demux->upstream_size > 4 * (1 << 20)) {
7059 res = qtdemux_seek_offset (demux, target);
7061 GST_DEBUG_OBJECT (demux, "skipping seek");
7066 GST_DEBUG_OBJECT (demux, "seek success");
7067 /* remember the offset fo the first mdat so we can seek back to it
7068 * after we have the headers */
7069 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7070 demux->first_mdat = old;
7071 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7074 /* seek worked, continue reading */
7075 demux->offset = target;
7076 demux->neededbytes = 16;
7077 demux->state = QTDEMUX_STATE_INITIAL;
7079 /* seek failed, need to buffer */
7080 demux->offset = old;
7081 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7082 /* there may be multiple mdat (or alike) buffers */
7084 if (demux->mdatbuffer)
7085 bs = gst_buffer_get_size (demux->mdatbuffer);
7088 if (size + bs > 10 * (1 << 20))
7090 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7091 demux->neededbytes = size;
7092 if (!demux->mdatbuffer)
7093 demux->mdatoffset = demux->offset;
7096 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7097 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7098 (_("This file is invalid and cannot be played.")),
7099 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7100 GST_FOURCC_ARGS (fourcc), size));
7101 ret = GST_FLOW_ERROR;
7104 /* this means we already started buffering and still no moov header,
7105 * let's continue buffering everything till we get moov */
7106 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7107 || fourcc == FOURCC_moof))
7109 demux->neededbytes = size;
7110 demux->state = QTDEMUX_STATE_HEADER;
7114 case QTDEMUX_STATE_HEADER:{
7118 GST_DEBUG_OBJECT (demux, "In header");
7120 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7122 /* parse the header */
7123 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7125 if (fourcc == FOURCC_moov) {
7126 /* in usual fragmented setup we could try to scan for more
7127 * and end up at the the moov (after mdat) again */
7128 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7130 || demux->last_moov_offset == demux->offset)) {
7131 GST_DEBUG_OBJECT (demux,
7132 "Skipping moov atom as we have (this) one already");
7134 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7136 if (demux->got_moov && demux->fragmented) {
7137 GST_DEBUG_OBJECT (demux,
7138 "Got a second moov, clean up data from old one");
7139 if (demux->moov_node_compressed) {
7140 g_node_destroy (demux->moov_node_compressed);
7141 if (demux->moov_node)
7142 g_free (demux->moov_node->data);
7144 demux->moov_node_compressed = NULL;
7145 if (demux->moov_node)
7146 g_node_destroy (demux->moov_node);
7147 demux->moov_node = NULL;
7150 demux->last_moov_offset = demux->offset;
7152 /* Update streams with new moov */
7153 gst_qtdemux_stream_concat (demux,
7154 demux->old_streams, demux->active_streams);
7156 qtdemux_parse_moov (demux, data, demux->neededbytes);
7157 qtdemux_node_dump (demux, demux->moov_node);
7158 qtdemux_parse_tree (demux);
7159 qtdemux_prepare_streams (demux);
7160 QTDEMUX_EXPOSE_LOCK (demux);
7161 qtdemux_expose_streams (demux);
7162 QTDEMUX_EXPOSE_UNLOCK (demux);
7164 demux->got_moov = TRUE;
7166 gst_qtdemux_check_send_pending_segment (demux);
7168 if (demux->moov_node_compressed) {
7169 g_node_destroy (demux->moov_node_compressed);
7170 g_free (demux->moov_node->data);
7172 demux->moov_node_compressed = NULL;
7173 g_node_destroy (demux->moov_node);
7174 demux->moov_node = NULL;
7175 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7177 } else if (fourcc == FOURCC_moof) {
7178 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7180 GstClockTime prev_pts;
7181 guint64 prev_offset;
7182 guint64 adapter_discont_offset, adapter_discont_dist;
7184 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7187 * The timestamp of the moof buffer is relevant as some scenarios
7188 * won't have the initial timestamp in the atoms. Whenever a new
7189 * buffer has started, we get that buffer's PTS and use it as a base
7190 * timestamp for the trun entries.
7192 * To keep track of the current buffer timestamp and starting point
7193 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7194 * from the beginning of the buffer, with the distance and demux->offset
7195 * we know if it is still the same buffer or not.
7197 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7198 prev_offset = demux->offset - dist;
7199 if (demux->fragment_start_offset == -1
7200 || prev_offset > demux->fragment_start_offset) {
7201 demux->fragment_start_offset = prev_offset;
7202 demux->fragment_start = prev_pts;
7203 GST_DEBUG_OBJECT (demux,
7204 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7205 GST_TIME_FORMAT, demux->fragment_start_offset,
7206 GST_TIME_ARGS (demux->fragment_start));
7209 /* We can't use prev_offset() here because this would require
7210 * upstream to set consistent and correct offsets on all buffers
7211 * since the discont. Nothing ever did that in the past and we
7212 * would break backwards compatibility here then.
7213 * Instead take the offset we had at the last discont and count
7214 * the bytes from there. This works with old code as there would
7215 * be no discont between moov and moof, and also works with
7216 * adaptivedemux which correctly sets offset and will set the
7217 * DISCONT flag accordingly when needed.
7219 * We also only do this for upstream TIME segments as otherwise
7220 * there are potential backwards compatibility problems with
7221 * seeking in PUSH mode and upstream providing inconsistent
7223 adapter_discont_offset =
7224 gst_adapter_offset_at_discont (demux->adapter);
7225 adapter_discont_dist =
7226 gst_adapter_distance_from_discont (demux->adapter);
7228 GST_DEBUG_OBJECT (demux,
7229 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7230 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7231 demux->offset, adapter_discont_offset, adapter_discont_dist);
7233 if (demux->upstream_format_is_time) {
7234 demux->moof_offset = adapter_discont_offset;
7235 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7236 demux->moof_offset += adapter_discont_dist;
7237 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7238 demux->moof_offset = demux->offset;
7240 demux->moof_offset = demux->offset;
7243 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7244 demux->moof_offset, NULL)) {
7245 gst_adapter_unmap (demux->adapter);
7246 ret = GST_FLOW_ERROR;
7250 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7251 if (demux->mss_mode && !demux->exposed) {
7252 QTDEMUX_EXPOSE_LOCK (demux);
7253 qtdemux_expose_streams (demux);
7254 QTDEMUX_EXPOSE_UNLOCK (demux);
7257 gst_qtdemux_check_send_pending_segment (demux);
7259 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7261 } else if (fourcc == FOURCC_ftyp) {
7262 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7263 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7264 } else if (fourcc == FOURCC_uuid) {
7265 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7266 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7267 } else if (fourcc == FOURCC_sidx) {
7268 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7269 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7273 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7277 /* [free] and [skip] are padding atoms */
7278 GST_DEBUG_OBJECT (demux,
7279 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7280 GST_FOURCC_ARGS (fourcc));
7283 GST_WARNING_OBJECT (demux,
7284 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7285 GST_FOURCC_ARGS (fourcc));
7286 /* Let's jump that one and go back to initial state */
7290 gst_adapter_unmap (demux->adapter);
7293 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7294 gsize remaining_data_size = 0;
7296 /* the mdat was before the header */
7297 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7298 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7299 /* restore our adapter/offset view of things with upstream;
7300 * put preceding buffered data ahead of current moov data.
7301 * This should also handle evil mdat, moov, mdat cases and alike */
7302 gst_adapter_flush (demux->adapter, demux->neededbytes);
7304 /* Store any remaining data after the mdat for later usage */
7305 remaining_data_size = gst_adapter_available (demux->adapter);
7306 if (remaining_data_size > 0) {
7307 g_assert (demux->restoredata_buffer == NULL);
7308 demux->restoredata_buffer =
7309 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7310 demux->restoredata_offset = demux->offset + demux->neededbytes;
7311 GST_DEBUG_OBJECT (demux,
7312 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7313 G_GUINT64_FORMAT, remaining_data_size,
7314 demux->restoredata_offset);
7317 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7318 demux->mdatbuffer = NULL;
7319 demux->offset = demux->mdatoffset;
7320 demux->neededbytes = next_entry_size (demux);
7321 demux->state = QTDEMUX_STATE_MOVIE;
7322 demux->mdatleft = gst_adapter_available (demux->adapter);
7323 demux->mdatsize = demux->mdatleft;
7325 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7326 gst_adapter_flush (demux->adapter, demux->neededbytes);
7328 /* only go back to the mdat if there are samples to play */
7329 if (demux->got_moov && demux->first_mdat != -1
7330 && has_next_entry (demux)) {
7333 /* we need to seek back */
7334 res = qtdemux_seek_offset (demux, demux->first_mdat);
7336 demux->offset = demux->first_mdat;
7338 GST_DEBUG_OBJECT (demux, "Seek back failed");
7341 demux->offset += demux->neededbytes;
7343 demux->neededbytes = 16;
7344 demux->state = QTDEMUX_STATE_INITIAL;
7349 case QTDEMUX_STATE_BUFFER_MDAT:{
7353 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7355 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7356 gst_buffer_extract (buf, 0, fourcc, 4);
7357 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7358 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7359 if (demux->mdatbuffer)
7360 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7362 demux->mdatbuffer = buf;
7363 demux->offset += demux->neededbytes;
7364 demux->neededbytes = 16;
7365 demux->state = QTDEMUX_STATE_INITIAL;
7366 gst_qtdemux_post_progress (demux, 1, 1);
7370 case QTDEMUX_STATE_MOVIE:{
7371 QtDemuxStream *stream = NULL;
7372 QtDemuxSample *sample;
7373 GstClockTime dts, pts, duration;
7377 GST_DEBUG_OBJECT (demux,
7378 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7380 if (demux->fragmented) {
7381 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7383 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7384 /* if needed data starts within this atom,
7385 * then it should not exceed this atom */
7386 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7387 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7388 (_("This file is invalid and cannot be played.")),
7389 ("sample data crosses atom boundary"));
7390 ret = GST_FLOW_ERROR;
7393 demux->mdatleft -= demux->neededbytes;
7395 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7396 /* so we are dropping more than left in this atom */
7397 gst_qtdemux_drop_data (demux, demux->mdatleft);
7398 demux->mdatleft = 0;
7400 /* need to resume atom parsing so we do not miss any other pieces */
7401 demux->state = QTDEMUX_STATE_INITIAL;
7402 demux->neededbytes = 16;
7404 /* check if there was any stored post mdat data from previous buffers */
7405 if (demux->restoredata_buffer) {
7406 g_assert (gst_adapter_available (demux->adapter) == 0);
7408 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7409 demux->restoredata_buffer = NULL;
7410 demux->offset = demux->restoredata_offset;
7417 if (demux->todrop) {
7418 if (demux->cenc_aux_info_offset > 0) {
7422 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7423 data = gst_adapter_map (demux->adapter, demux->todrop);
7424 gst_byte_reader_init (&br, data + 8, demux->todrop);
7425 if (!qtdemux_parse_cenc_aux_info (demux,
7426 QTDEMUX_NTH_STREAM (demux, 0), &br,
7427 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7428 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7429 ret = GST_FLOW_ERROR;
7430 gst_adapter_unmap (demux->adapter);
7431 g_free (demux->cenc_aux_info_sizes);
7432 demux->cenc_aux_info_sizes = NULL;
7435 demux->cenc_aux_info_offset = 0;
7436 g_free (demux->cenc_aux_info_sizes);
7437 demux->cenc_aux_info_sizes = NULL;
7438 gst_adapter_unmap (demux->adapter);
7440 gst_qtdemux_drop_data (demux, demux->todrop);
7444 /* initial newsegment sent here after having added pads,
7445 * possible others in sink_event */
7446 gst_qtdemux_check_send_pending_segment (demux);
7448 /* Figure out which stream this packet belongs to */
7449 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7450 stream = QTDEMUX_NTH_STREAM (demux, i);
7451 if (stream->sample_index >= stream->n_samples) {
7452 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7456 GST_LOG_OBJECT (demux,
7457 "Checking track-id %u (sample_index:%d / offset:%"
7458 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7459 stream->sample_index,
7460 stream->samples[stream->sample_index].offset,
7461 stream->samples[stream->sample_index].size);
7463 if (stream->samples[stream->sample_index].offset == demux->offset)
7467 if (G_UNLIKELY (stream == NULL))
7468 goto unknown_stream;
7470 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7472 if (stream->new_caps) {
7473 gst_qtdemux_configure_stream (demux, stream);
7476 /* Put data in a buffer, set timestamps, caps, ... */
7477 sample = &stream->samples[stream->sample_index];
7479 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7480 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7481 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7483 dts = QTSAMPLE_DTS (stream, sample);
7484 pts = QTSAMPLE_PTS (stream, sample);
7485 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7486 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7488 /* check for segment end */
7489 if (G_UNLIKELY (demux->segment.stop != -1
7490 && demux->segment.stop <= pts && stream->on_keyframe)
7491 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7492 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7493 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7495 /* skip this data, stream is EOS */
7496 gst_adapter_flush (demux->adapter, demux->neededbytes);
7497 demux->offset += demux->neededbytes;
7499 /* check if all streams are eos */
7501 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7502 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7511 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7513 /* FIXME: should either be an assert or a plain check */
7514 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7516 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7517 dts, pts, duration, keyframe, dts, demux->offset);
7521 GST_OBJECT_LOCK (demux);
7522 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7523 GST_OBJECT_UNLOCK (demux);
7525 /* skip this data, stream is EOS */
7526 gst_adapter_flush (demux->adapter, demux->neededbytes);
7529 stream->sample_index++;
7530 stream->offset_in_sample = 0;
7532 /* update current offset and figure out size of next buffer */
7533 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7534 demux->offset, demux->neededbytes);
7535 demux->offset += demux->neededbytes;
7536 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7540 if (ret == GST_FLOW_EOS) {
7541 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7542 demux->neededbytes = -1;
7546 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7547 if (demux->fragmented) {
7548 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7549 /* there may be more to follow, only finish this atom */
7550 demux->todrop = demux->mdatleft;
7551 demux->neededbytes = demux->todrop;
7556 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7557 goto non_ok_unlinked_flow;
7566 /* when buffering movie data, at least show user something is happening */
7567 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7568 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7569 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7570 demux->neededbytes);
7577 non_ok_unlinked_flow:
7579 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7580 gst_flow_get_name (ret));
7585 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7586 ret = GST_FLOW_ERROR;
7591 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7597 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7598 (NULL), ("qtdemuxer invalid state %d", demux->state));
7599 ret = GST_FLOW_ERROR;
7604 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7605 (NULL), ("no 'moov' atom within the first 10 MB"));
7606 ret = GST_FLOW_ERROR;
7612 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7617 query = gst_query_new_scheduling ();
7619 if (!gst_pad_peer_query (sinkpad, query)) {
7620 gst_query_unref (query);
7624 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7625 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7626 gst_query_unref (query);
7631 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7632 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7636 GST_DEBUG_OBJECT (sinkpad, "activating push");
7637 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7642 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7643 GstPadMode mode, gboolean active)
7646 GstQTDemux *demux = GST_QTDEMUX (parent);
7649 case GST_PAD_MODE_PUSH:
7650 demux->pullbased = FALSE;
7653 case GST_PAD_MODE_PULL:
7655 demux->pullbased = TRUE;
7656 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7659 res = gst_pad_stop_task (sinkpad);
7671 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7677 memset (&z, 0, sizeof (z));
7682 if ((ret = inflateInit (&z)) != Z_OK) {
7683 GST_ERROR ("inflateInit() returned %d", ret);
7687 z.next_in = z_buffer;
7688 z.avail_in = z_length;
7690 buffer = (guint8 *) g_malloc (*length);
7691 z.avail_out = *length;
7692 z.next_out = (Bytef *) buffer;
7694 ret = inflate (&z, Z_NO_FLUSH);
7695 if (ret == Z_STREAM_END) {
7697 } else if (ret != Z_OK) {
7698 GST_WARNING ("inflate() returned %d", ret);
7703 buffer = (guint8 *) g_realloc (buffer, *length);
7704 z.next_out = (Bytef *) (buffer + z.total_out);
7705 z.avail_out += 4096;
7706 } while (z.avail_in > 0);
7708 if (ret != Z_STREAM_END) {
7713 *length = z.total_out;
7720 #endif /* HAVE_ZLIB */
7723 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7727 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7729 /* counts as header data */
7730 qtdemux->header_size += length;
7732 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7733 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7735 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7742 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7743 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7744 if (dcom == NULL || cmvd == NULL)
7745 goto invalid_compression;
7747 dcom_len = QT_UINT32 (dcom->data);
7749 goto invalid_compression;
7751 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7755 guint uncompressed_length;
7756 guint compressed_length;
7760 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7762 goto invalid_compression;
7764 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7765 compressed_length = cmvd_len - 12;
7766 GST_LOG ("length = %u", uncompressed_length);
7769 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7770 compressed_length, &uncompressed_length);
7773 qtdemux->moov_node_compressed = qtdemux->moov_node;
7774 qtdemux->moov_node = g_node_new (buf);
7776 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7777 uncompressed_length);
7781 #endif /* HAVE_ZLIB */
7783 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7784 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7791 invalid_compression:
7793 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7799 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7802 while (G_UNLIKELY (buf < end)) {
7806 if (G_UNLIKELY (buf + 4 > end)) {
7807 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7810 len = QT_UINT32 (buf);
7811 if (G_UNLIKELY (len == 0)) {
7812 GST_LOG_OBJECT (qtdemux, "empty container");
7815 if (G_UNLIKELY (len < 8)) {
7816 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7819 if (G_UNLIKELY (len > (end - buf))) {
7820 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7821 (gint) (end - buf));
7825 child = g_node_new ((guint8 *) buf);
7826 g_node_append (node, child);
7827 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7828 qtdemux_parse_node (qtdemux, child, buf, len);
7836 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7839 int len = QT_UINT32 (xdxt->data);
7840 guint8 *buf = xdxt->data;
7841 guint8 *end = buf + len;
7844 /* skip size and type */
7852 size = QT_UINT32 (buf);
7853 type = QT_FOURCC (buf + 4);
7855 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7857 if (buf + size > end || size <= 0)
7863 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7864 GST_FOURCC_ARGS (type));
7868 buffer = gst_buffer_new_and_alloc (size);
7869 gst_buffer_fill (buffer, 0, buf, size);
7870 stream->buffers = g_slist_append (stream->buffers, buffer);
7871 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7874 buffer = gst_buffer_new_and_alloc (size);
7875 gst_buffer_fill (buffer, 0, buf, size);
7876 stream->buffers = g_slist_append (stream->buffers, buffer);
7877 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7880 buffer = gst_buffer_new_and_alloc (size);
7881 gst_buffer_fill (buffer, 0, buf, size);
7882 stream->buffers = g_slist_append (stream->buffers, buffer);
7883 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7886 GST_WARNING_OBJECT (qtdemux,
7887 "unknown theora cookie %" GST_FOURCC_FORMAT,
7888 GST_FOURCC_ARGS (type));
7897 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7901 guint32 node_length = 0;
7902 const QtNodeType *type;
7905 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7907 if (G_UNLIKELY (length < 8))
7908 goto not_enough_data;
7910 node_length = QT_UINT32 (buffer);
7911 fourcc = QT_FOURCC (buffer + 4);
7913 /* ignore empty nodes */
7914 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7917 type = qtdemux_type_get (fourcc);
7919 end = buffer + length;
7921 GST_LOG_OBJECT (qtdemux,
7922 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7923 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7925 if (node_length > length)
7926 goto broken_atom_size;
7928 if (type->flags & QT_FLAG_CONTAINER) {
7929 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7934 if (node_length < 20) {
7935 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7938 GST_DEBUG_OBJECT (qtdemux,
7939 "parsing stsd (sample table, sample description) atom");
7940 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7941 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7953 /* also read alac (or whatever) in stead of mp4a in the following,
7954 * since a similar layout is used in other cases as well */
7955 if (fourcc == FOURCC_mp4a)
7957 else if (fourcc == FOURCC_fLaC)
7962 /* There are two things we might encounter here: a true mp4a atom, and
7963 an mp4a entry in an stsd atom. The latter is what we're interested
7964 in, and it looks like an atom, but isn't really one. The true mp4a
7965 atom is short, so we detect it based on length here. */
7966 if (length < min_size) {
7967 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7968 GST_FOURCC_ARGS (fourcc));
7972 /* 'version' here is the sound sample description version. Types 0 and
7973 1 are documented in the QTFF reference, but type 2 is not: it's
7974 described in Apple header files instead (struct SoundDescriptionV2
7976 version = QT_UINT16 (buffer + 16);
7978 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7979 GST_FOURCC_ARGS (fourcc), version);
7981 /* parse any esds descriptors */
7993 GST_WARNING_OBJECT (qtdemux,
7994 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7995 GST_FOURCC_ARGS (fourcc), version);
8000 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8028 /* codec_data is contained inside these atoms, which all have
8029 * the same format. */
8030 /* video sample description size is 86 bytes without extension.
8031 * node_length have to be bigger than 86 bytes because video sample
8032 * description can include extensions such as esds, fiel, glbl, etc. */
8033 if (node_length < 86) {
8034 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8035 " sample description length too short (%u < 86)",
8036 GST_FOURCC_ARGS (fourcc), node_length);
8040 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8041 GST_FOURCC_ARGS (fourcc));
8043 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8045 * revision level (2 bytes) : must be set to 0. */
8046 version = QT_UINT32 (buffer + 16);
8047 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8049 /* compressor name : PASCAL string and informative purposes
8050 * first byte : the number of bytes to be displayed.
8051 * it has to be less than 32 because it is reserved
8052 * space of 32 bytes total including itself. */
8053 str_len = QT_UINT8 (buffer + 50);
8055 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8056 (char *) buffer + 51);
8058 GST_WARNING_OBJECT (qtdemux,
8059 "compressorname length too big (%u > 31)", str_len);
8061 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8063 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8068 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8070 /* You are reading this correctly. QTFF specifies that the
8071 * metadata atom is a short atom, whereas ISO BMFF specifies
8072 * it's a full atom. But since so many people are doing things
8073 * differently, we actually peek into the atom to see which
8076 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8077 GST_FOURCC_ARGS (fourcc));
8080 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8081 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8082 * starts with a 'hdlr' atom */
8083 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8084 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8085 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8086 * with version/flags both set to zero */
8087 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8089 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8094 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8095 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8096 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8105 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8106 GST_FOURCC_ARGS (fourcc));
8110 version = QT_UINT32 (buffer + 12);
8111 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8118 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8123 if (length < offset) {
8124 GST_WARNING_OBJECT (qtdemux,
8125 "skipping too small %" GST_FOURCC_FORMAT " box",
8126 GST_FOURCC_ARGS (fourcc));
8129 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8135 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8140 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8145 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8149 if (!strcmp (type->name, "unknown"))
8150 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8154 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8155 GST_FOURCC_ARGS (fourcc));
8161 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8162 (_("This file is corrupt and cannot be played.")),
8163 ("Not enough data for an atom header, got only %u bytes", length));
8168 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8169 (_("This file is corrupt and cannot be played.")),
8170 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8171 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8178 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8180 /* FIXME: This can only reliably work if demuxers have a
8181 * separate streaming thread per srcpad. This should be
8182 * done in a demuxer base class, which integrates parts
8185 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8190 query = gst_query_new_allocation (stream->caps, FALSE);
8192 if (!gst_pad_peer_query (stream->pad, query)) {
8193 /* not a problem, just debug a little */
8194 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8197 if (stream->allocator)
8198 gst_object_unref (stream->allocator);
8200 if (gst_query_get_n_allocation_params (query) > 0) {
8201 /* try the allocator */
8202 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8204 stream->use_allocator = TRUE;
8206 stream->allocator = NULL;
8207 gst_allocation_params_init (&stream->params);
8208 stream->use_allocator = FALSE;
8210 gst_query_unref (query);
8215 pad_query (const GValue * item, GValue * value, gpointer user_data)
8217 GstPad *pad = g_value_get_object (item);
8218 GstQuery *query = user_data;
8221 res = gst_pad_peer_query (pad, query);
8224 g_value_set_boolean (value, TRUE);
8228 GST_INFO_OBJECT (pad, "pad peer query failed");
8233 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8234 GstPadDirection direction)
8237 GstIteratorFoldFunction func = pad_query;
8238 GValue res = { 0, };
8240 g_value_init (&res, G_TYPE_BOOLEAN);
8241 g_value_set_boolean (&res, FALSE);
8244 if (direction == GST_PAD_SRC)
8245 it = gst_element_iterate_src_pads (element);
8247 it = gst_element_iterate_sink_pads (element);
8249 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8250 gst_iterator_resync (it);
8252 gst_iterator_free (it);
8254 return g_value_get_boolean (&res);
8258 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8259 QtDemuxStream * stream)
8263 GstElement *element = GST_ELEMENT (qtdemux);
8265 gchar **filtered_sys_ids;
8266 GValue event_list = G_VALUE_INIT;
8269 /* 1. Check if we already have the context. */
8270 if (qtdemux->preferred_protection_system_id != NULL) {
8271 GST_LOG_OBJECT (element,
8272 "already have the protection context, no need to request it again");
8276 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8277 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8278 (const gchar **) qtdemux->protection_system_ids->pdata);
8280 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8281 qtdemux->protection_system_ids->len - 1);
8282 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8283 "decryptors for %u of them, running context request",
8284 qtdemux->protection_system_ids->len,
8285 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8288 if (stream->protection_scheme_event_queue.length) {
8289 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8290 stream->protection_scheme_event_queue.length);
8291 walk = stream->protection_scheme_event_queue.tail;
8293 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8294 qtdemux->protection_event_queue.length);
8295 walk = qtdemux->protection_event_queue.tail;
8298 g_value_init (&event_list, GST_TYPE_LIST);
8299 for (; walk; walk = g_list_previous (walk)) {
8300 GValue *event_value = g_new0 (GValue, 1);
8301 g_value_init (event_value, GST_TYPE_EVENT);
8302 g_value_set_boxed (event_value, walk->data);
8303 gst_value_list_append_and_take_value (&event_list, event_value);
8306 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8307 * check if downstream already has a context of the specific type
8308 * 2b) Query upstream as above.
8310 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8311 st = gst_query_writable_structure (query);
8312 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8313 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8315 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8316 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8317 gst_query_parse_context (query, &ctxt);
8318 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8319 gst_element_set_context (element, ctxt);
8320 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8321 gst_query_parse_context (query, &ctxt);
8322 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8323 gst_element_set_context (element, ctxt);
8325 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8326 * the required context type and afterwards check if a
8327 * usable context was set now as in 1). The message could
8328 * be handled by the parent bins of the element and the
8333 GST_INFO_OBJECT (element, "posting need context message");
8334 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8335 "drm-preferred-decryption-system-id");
8336 st = (GstStructure *) gst_message_get_structure (msg);
8337 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8338 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8341 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8342 gst_element_post_message (element, msg);
8345 g_strfreev (filtered_sys_ids);
8346 g_value_unset (&event_list);
8347 gst_query_unref (query);
8351 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8352 QtDemuxStream * stream)
8355 const gchar *selected_system = NULL;
8357 g_return_val_if_fail (qtdemux != NULL, FALSE);
8358 g_return_val_if_fail (stream != NULL, FALSE);
8359 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8362 if (stream->protection_scheme_type == FOURCC_aavd) {
8363 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8364 if (!gst_structure_has_name (s, "application/x-aavd")) {
8365 gst_structure_set (s,
8366 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8368 gst_structure_set_name (s, "application/x-aavd");
8373 if (stream->protection_scheme_type != FOURCC_cenc
8374 && stream->protection_scheme_type != FOURCC_cbcs) {
8375 GST_ERROR_OBJECT (qtdemux,
8376 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8377 GST_FOURCC_ARGS (stream->protection_scheme_type));
8381 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8382 if (!gst_structure_has_name (s, "application/x-cenc")
8383 && !gst_structure_has_name (s, "application/x-cbcs")) {
8384 gst_structure_set (s,
8385 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8386 gst_structure_set_name (s,
8387 stream->protection_scheme_type ==
8388 FOURCC_cbcs ? "application/x-cbcs" : "application/x-cenc");
8391 if (qtdemux->protection_system_ids == NULL) {
8392 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8393 "cenc protection system information has been found, not setting a "
8394 "protection system UUID");
8398 gst_qtdemux_request_protection_context (qtdemux, stream);
8399 if (qtdemux->preferred_protection_system_id != NULL) {
8400 const gchar *preferred_system_array[] =
8401 { qtdemux->preferred_protection_system_id, NULL };
8403 selected_system = gst_protection_select_system (preferred_system_array);
8405 if (selected_system) {
8406 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8407 qtdemux->preferred_protection_system_id);
8409 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8410 "because there is no available decryptor",
8411 qtdemux->preferred_protection_system_id);
8415 if (!selected_system) {
8416 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8417 selected_system = gst_protection_select_system ((const gchar **)
8418 qtdemux->protection_system_ids->pdata);
8419 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8420 qtdemux->protection_system_ids->len - 1);
8423 if (!selected_system) {
8424 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8425 "suitable decryptor element has been found");
8429 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8432 gst_structure_set (s,
8433 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8440 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8442 /* fps is calculated base on the duration of the average framerate since
8443 * qt does not have a fixed framerate. */
8444 gboolean fps_available = TRUE;
8445 guint32 first_duration = 0;
8447 if (stream->n_samples > 0)
8448 first_duration = stream->samples[0].duration;
8450 if ((stream->n_samples == 1 && first_duration == 0)
8451 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8453 CUR_STREAM (stream)->fps_n = 0;
8454 CUR_STREAM (stream)->fps_d = 1;
8456 if (stream->duration == 0 || stream->n_samples < 2) {
8457 CUR_STREAM (stream)->fps_n = stream->timescale;
8458 CUR_STREAM (stream)->fps_d = 1;
8459 fps_available = FALSE;
8461 GstClockTime avg_duration;
8465 /* duration and n_samples can be updated for fragmented format
8466 * so, framerate of fragmented format is calculated using data in a moof */
8467 if (qtdemux->fragmented && stream->n_samples_moof > 0
8468 && stream->duration_moof > 0) {
8469 n_samples = stream->n_samples_moof;
8470 duration = stream->duration_moof;
8472 n_samples = stream->n_samples;
8473 duration = stream->duration;
8476 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8477 /* stream->duration is guint64, timescale, n_samples are guint32 */
8479 gst_util_uint64_scale_round (duration -
8480 first_duration, GST_SECOND,
8481 (guint64) (stream->timescale) * (n_samples - 1));
8483 GST_LOG_OBJECT (qtdemux,
8484 "Calculating avg sample duration based on stream (or moof) duration %"
8486 " minus first sample %u, leaving %d samples gives %"
8487 GST_TIME_FORMAT, duration, first_duration,
8488 n_samples - 1, GST_TIME_ARGS (avg_duration));
8491 gst_video_guess_framerate (avg_duration,
8492 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8494 GST_DEBUG_OBJECT (qtdemux,
8495 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8496 stream->timescale, CUR_STREAM (stream)->fps_n,
8497 CUR_STREAM (stream)->fps_d);
8501 return fps_available;
8505 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8507 if (stream->subtype == FOURCC_vide) {
8508 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8510 if (CUR_STREAM (stream)->caps) {
8511 CUR_STREAM (stream)->caps =
8512 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8514 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8515 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8516 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8517 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8519 /* set framerate if calculated framerate is reliable */
8520 if (fps_available) {
8521 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8522 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8523 CUR_STREAM (stream)->fps_d, NULL);
8526 /* calculate pixel-aspect-ratio using display width and height */
8527 GST_DEBUG_OBJECT (qtdemux,
8528 "video size %dx%d, target display size %dx%d",
8529 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8530 stream->display_width, stream->display_height);
8531 /* qt file might have pasp atom */
8532 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8533 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8534 CUR_STREAM (stream)->par_h);
8535 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8536 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8537 CUR_STREAM (stream)->par_h, NULL);
8538 } else if (stream->display_width > 0 && stream->display_height > 0
8539 && CUR_STREAM (stream)->width > 0
8540 && CUR_STREAM (stream)->height > 0) {
8543 /* calculate the pixel aspect ratio using the display and pixel w/h */
8544 n = stream->display_width * CUR_STREAM (stream)->height;
8545 d = stream->display_height * CUR_STREAM (stream)->width;
8548 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8549 CUR_STREAM (stream)->par_w = n;
8550 CUR_STREAM (stream)->par_h = d;
8551 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8552 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8553 CUR_STREAM (stream)->par_h, NULL);
8556 if (CUR_STREAM (stream)->interlace_mode > 0) {
8557 if (CUR_STREAM (stream)->interlace_mode == 1) {
8558 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8559 G_TYPE_STRING, "progressive", NULL);
8560 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8561 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8562 G_TYPE_STRING, "interleaved", NULL);
8563 if (CUR_STREAM (stream)->field_order == 9) {
8564 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8565 G_TYPE_STRING, "top-field-first", NULL);
8566 } else if (CUR_STREAM (stream)->field_order == 14) {
8567 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8568 G_TYPE_STRING, "bottom-field-first", NULL);
8573 /* Create incomplete colorimetry here if needed */
8574 if (CUR_STREAM (stream)->colorimetry.range ||
8575 CUR_STREAM (stream)->colorimetry.matrix ||
8576 CUR_STREAM (stream)->colorimetry.transfer
8577 || CUR_STREAM (stream)->colorimetry.primaries) {
8578 gchar *colorimetry =
8579 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8580 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8581 G_TYPE_STRING, colorimetry, NULL);
8582 g_free (colorimetry);
8585 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8586 guint par_w = 1, par_h = 1;
8588 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8589 par_w = CUR_STREAM (stream)->par_w;
8590 par_h = CUR_STREAM (stream)->par_h;
8593 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8594 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8596 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8599 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8600 "multiview-mode", G_TYPE_STRING,
8601 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8602 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8603 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8608 else if (stream->subtype == FOURCC_soun) {
8609 if (CUR_STREAM (stream)->caps) {
8610 CUR_STREAM (stream)->caps =
8611 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8612 if (CUR_STREAM (stream)->rate > 0)
8613 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8614 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8615 if (CUR_STREAM (stream)->n_channels > 0)
8616 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8617 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8618 if (CUR_STREAM (stream)->n_channels > 2) {
8619 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8620 * correctly; this is just the minimum we can do - assume
8621 * we don't actually have any channel positions. */
8622 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8623 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8628 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8629 const GstStructure *s;
8630 QtDemuxStream *fps_stream = NULL;
8631 gboolean fps_available = FALSE;
8633 /* CEA608 closed caption tracks are a bit special in that each sample
8634 * can contain CCs for multiple frames, and CCs can be omitted and have to
8635 * be inferred from the duration of the sample then.
8637 * As such we take the framerate from the (first) video track here for
8638 * CEA608 as there must be one CC byte pair for every video frame
8639 * according to the spec.
8641 * For CEA708 all is fine and there is one sample per frame.
8644 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8645 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8648 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8649 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8651 if (tmp->subtype == FOURCC_vide) {
8658 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8659 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8660 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8663 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8664 fps_stream = stream;
8667 CUR_STREAM (stream)->caps =
8668 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8670 /* set framerate if calculated framerate is reliable */
8671 if (fps_available) {
8672 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8673 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8674 CUR_STREAM (stream)->fps_d, NULL);
8679 GstCaps *prev_caps = NULL;
8681 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8682 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8683 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8684 gst_pad_set_active (stream->pad, TRUE);
8686 gst_pad_use_fixed_caps (stream->pad);
8688 if (stream->protected) {
8689 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8690 GST_ERROR_OBJECT (qtdemux,
8691 "Failed to configure protected stream caps.");
8696 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8697 CUR_STREAM (stream)->caps);
8698 if (stream->new_stream) {
8700 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8703 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8706 gst_event_parse_stream_flags (event, &stream_flags);
8707 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8708 qtdemux->have_group_id = TRUE;
8710 qtdemux->have_group_id = FALSE;
8711 gst_event_unref (event);
8712 } else if (!qtdemux->have_group_id) {
8713 qtdemux->have_group_id = TRUE;
8714 qtdemux->group_id = gst_util_group_id_next ();
8717 stream->new_stream = FALSE;
8718 event = gst_event_new_stream_start (stream->stream_id);
8719 if (qtdemux->have_group_id)
8720 gst_event_set_group_id (event, qtdemux->group_id);
8721 if (stream->disabled)
8722 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8723 if (CUR_STREAM (stream)->sparse) {
8724 stream_flags |= GST_STREAM_FLAG_SPARSE;
8726 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8728 gst_event_set_stream_flags (event, stream_flags);
8729 gst_pad_push_event (stream->pad, event);
8732 prev_caps = gst_pad_get_current_caps (stream->pad);
8734 if (CUR_STREAM (stream)->caps) {
8736 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8737 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8738 CUR_STREAM (stream)->caps);
8739 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8741 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8744 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8748 gst_caps_unref (prev_caps);
8749 stream->new_caps = FALSE;
8755 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8756 QtDemuxStream * stream)
8758 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8761 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8762 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8763 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8764 stream->stsd_entries_length)) {
8765 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8766 (_("This file is invalid and cannot be played.")),
8767 ("New sample description id is out of bounds (%d >= %d)",
8768 stream->stsd_sample_description_id, stream->stsd_entries_length));
8770 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8771 stream->new_caps = TRUE;
8776 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8777 QtDemuxStream * stream, GstTagList * list)
8779 gboolean ret = TRUE;
8781 if (stream->subtype == FOURCC_vide) {
8782 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8785 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8788 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8789 gst_object_unref (stream->pad);
8795 qtdemux->n_video_streams++;
8796 } else if (stream->subtype == FOURCC_soun) {
8797 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8800 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8802 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8803 gst_object_unref (stream->pad);
8808 qtdemux->n_audio_streams++;
8809 } else if (stream->subtype == FOURCC_strm) {
8810 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8811 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8812 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8813 || stream->subtype == FOURCC_clcp) {
8814 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8817 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8819 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8820 gst_object_unref (stream->pad);
8825 qtdemux->n_sub_streams++;
8826 } else if (CUR_STREAM (stream)->caps) {
8827 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8830 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8832 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8833 gst_object_unref (stream->pad);
8838 qtdemux->n_video_streams++;
8840 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8847 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8848 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8849 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8850 GST_OBJECT_LOCK (qtdemux);
8851 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8852 GST_OBJECT_UNLOCK (qtdemux);
8854 if (stream->stream_tags)
8855 gst_tag_list_unref (stream->stream_tags);
8856 stream->stream_tags = list;
8858 /* global tags go on each pad anyway */
8859 stream->send_global_tags = TRUE;
8860 /* send upstream GST_EVENT_PROTECTION events that were received before
8861 this source pad was created */
8862 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8863 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8867 gst_tag_list_unref (list);
8871 /* find next atom with @fourcc starting at @offset */
8872 static GstFlowReturn
8873 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8874 guint64 * length, guint32 fourcc)
8880 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8881 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8887 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8888 if (G_UNLIKELY (ret != GST_FLOW_OK))
8890 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8893 gst_buffer_unref (buf);
8896 gst_buffer_map (buf, &map, GST_MAP_READ);
8897 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8898 gst_buffer_unmap (buf, &map);
8899 gst_buffer_unref (buf);
8901 if (G_UNLIKELY (*length == 0)) {
8902 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8903 ret = GST_FLOW_ERROR;
8907 if (lfourcc == fourcc) {
8908 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
8909 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8912 GST_LOG_OBJECT (qtdemux,
8913 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8914 GST_FOURCC_ARGS (lfourcc), *offset);
8915 if (*offset == G_MAXUINT64)
8925 /* might simply have had last one */
8926 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8931 /* should only do something in pull mode */
8932 /* call with OBJECT lock */
8933 static GstFlowReturn
8934 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8936 guint64 length, offset;
8937 GstBuffer *buf = NULL;
8938 GstFlowReturn ret = GST_FLOW_OK;
8939 GstFlowReturn res = GST_FLOW_OK;
8942 offset = qtdemux->moof_offset;
8943 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8946 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8947 return GST_FLOW_EOS;
8950 /* best not do pull etc with lock held */
8951 GST_OBJECT_UNLOCK (qtdemux);
8953 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8954 if (ret != GST_FLOW_OK)
8957 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8958 if (G_UNLIKELY (ret != GST_FLOW_OK))
8960 gst_buffer_map (buf, &map, GST_MAP_READ);
8961 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8962 gst_buffer_unmap (buf, &map);
8963 gst_buffer_unref (buf);
8968 gst_buffer_unmap (buf, &map);
8969 gst_buffer_unref (buf);
8973 /* look for next moof */
8974 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8975 if (G_UNLIKELY (ret != GST_FLOW_OK))
8979 GST_OBJECT_LOCK (qtdemux);
8981 qtdemux->moof_offset = offset;
8987 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8989 res = GST_FLOW_ERROR;
8994 /* maybe upstream temporarily flushing */
8995 if (ret != GST_FLOW_FLUSHING) {
8996 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8999 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9000 /* resume at current position next time */
9008 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9012 gint32 stts_duration;
9013 GstByteWriter stsc, stts, stsz;
9015 /* Each sample has a different size, which we don't support for merging */
9016 if (stream->sample_size == 0) {
9017 GST_DEBUG_OBJECT (qtdemux,
9018 "Not all samples have the same size, not merging");
9022 /* The stream has a ctts table, we don't support that */
9023 if (stream->ctts_present) {
9024 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9028 /* If there's a sync sample table also ignore this stream */
9029 if (stream->stps_present || stream->stss_present) {
9030 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9034 /* If chunks are considered samples already ignore this stream */
9035 if (stream->chunks_are_samples) {
9036 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9040 /* Require that all samples have the same duration */
9041 if (stream->n_sample_times > 1) {
9042 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9046 /* Parse the stts to get the sample duration and number of samples */
9047 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9048 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9050 /* Parse the number of chunks from the stco manually because the
9051 * reader is already behind that */
9052 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9054 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9057 /* Now parse stsc, convert chunks into single samples and generate a
9058 * new stsc, stts and stsz from this information */
9059 gst_byte_writer_init (&stsc);
9060 gst_byte_writer_init (&stts);
9061 gst_byte_writer_init (&stsz);
9063 /* Note: we skip fourccs, size, version, flags and other fields of the new
9064 * atoms as the byte readers with them are already behind that position
9065 * anyway and only update the values of those inside the stream directly.
9067 stream->n_sample_times = 0;
9068 stream->n_samples = 0;
9069 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9071 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9073 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9074 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9075 sample_description_id =
9076 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9078 if (i == stream->n_samples_per_chunk - 1) {
9079 /* +1 because first_chunk is 1-based */
9080 last_chunk = num_chunks + 1;
9082 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9085 GST_DEBUG_OBJECT (qtdemux,
9086 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9087 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9089 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9090 /* One sample in this chunk */
9091 gst_byte_writer_put_uint32_be (&stsc, 1);
9092 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9094 /* For each chunk write a stts and stsz entry now */
9095 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9096 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9097 for (j = first_chunk; j < last_chunk; j++) {
9098 gst_byte_writer_put_uint32_be (&stsz,
9099 stream->sample_size * samples_per_chunk);
9102 stream->n_sample_times += 1;
9103 stream->n_samples += last_chunk - first_chunk;
9106 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9108 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9109 stream->n_samples, stream->n_sample_times);
9111 /* We don't have a fixed sample size anymore */
9112 stream->sample_size = 0;
9114 /* Free old data for the atoms */
9115 g_free ((gpointer) stream->stsz.data);
9116 stream->stsz.data = NULL;
9117 g_free ((gpointer) stream->stsc.data);
9118 stream->stsc.data = NULL;
9119 g_free ((gpointer) stream->stts.data);
9120 stream->stts.data = NULL;
9122 /* Store new data and replace byte readers */
9123 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9124 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9125 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9126 stream->stts.size = gst_byte_writer_get_size (&stts);
9127 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9128 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9129 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9130 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9131 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9134 /* initialise bytereaders for stbl sub-atoms */
9136 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9138 stream->stbl_index = -1; /* no samples have yet been parsed */
9139 stream->sample_index = -1;
9141 /* time-to-sample atom */
9142 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9145 /* copy atom data into a new buffer for later use */
9146 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9148 /* skip version + flags */
9149 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9150 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9152 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9154 /* make sure there's enough data */
9155 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9156 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9157 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9158 stream->n_sample_times);
9159 if (!stream->n_sample_times)
9163 /* sync sample atom */
9164 stream->stps_present = FALSE;
9165 if ((stream->stss_present =
9166 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9167 &stream->stss) ? TRUE : FALSE) == TRUE) {
9168 /* copy atom data into a new buffer for later use */
9169 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9171 /* skip version + flags */
9172 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9173 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9176 if (stream->n_sample_syncs) {
9177 /* make sure there's enough data */
9178 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9182 /* partial sync sample atom */
9183 if ((stream->stps_present =
9184 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9185 &stream->stps) ? TRUE : FALSE) == TRUE) {
9186 /* copy atom data into a new buffer for later use */
9187 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9189 /* skip version + flags */
9190 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9191 !gst_byte_reader_get_uint32_be (&stream->stps,
9192 &stream->n_sample_partial_syncs))
9195 /* if there are no entries, the stss table contains the real
9197 if (stream->n_sample_partial_syncs) {
9198 /* make sure there's enough data */
9199 if (!qt_atom_parser_has_chunks (&stream->stps,
9200 stream->n_sample_partial_syncs, 4))
9207 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9210 /* copy atom data into a new buffer for later use */
9211 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9213 /* skip version + flags */
9214 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9215 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9218 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9221 if (!stream->n_samples)
9224 /* sample-to-chunk atom */
9225 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9228 /* copy atom data into a new buffer for later use */
9229 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9231 /* skip version + flags */
9232 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9233 !gst_byte_reader_get_uint32_be (&stream->stsc,
9234 &stream->n_samples_per_chunk))
9237 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9238 stream->n_samples_per_chunk);
9240 /* make sure there's enough data */
9241 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9247 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9248 stream->co_size = sizeof (guint32);
9249 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9251 stream->co_size = sizeof (guint64);
9255 /* copy atom data into a new buffer for later use */
9256 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9258 /* skip version + flags */
9259 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9262 /* chunks_are_samples == TRUE means treat chunks as samples */
9263 stream->chunks_are_samples = stream->sample_size
9264 && !CUR_STREAM (stream)->sampled;
9265 if (stream->chunks_are_samples) {
9266 /* treat chunks as samples */
9267 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9270 /* skip number of entries */
9271 if (!gst_byte_reader_skip (&stream->stco, 4))
9274 /* make sure there are enough data in the stsz atom */
9275 if (!stream->sample_size) {
9276 /* different sizes for each sample */
9277 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9282 /* composition time-to-sample */
9283 if ((stream->ctts_present =
9284 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9285 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9286 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9288 /* copy atom data into a new buffer for later use */
9289 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9291 /* skip version + flags */
9292 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
9293 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9294 &stream->n_composition_times))
9297 /* make sure there's enough data */
9298 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9302 /* This is optional, if missing we iterate the ctts */
9303 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9304 if (!gst_byte_reader_skip (&cslg, 1 + 3)
9305 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
9306 g_free ((gpointer) cslg.data);
9310 gint32 cslg_least = 0;
9311 guint num_entries, pos;
9314 pos = gst_byte_reader_get_pos (&stream->ctts);
9315 num_entries = stream->n_composition_times;
9317 stream->cslg_shift = 0;
9319 for (i = 0; i < num_entries; i++) {
9322 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9323 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9324 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9325 * slightly inaccurate PTS could be more usable than corrupted one */
9326 if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
9327 GST_WARNING_OBJECT (qtdemux,
9328 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9329 " larger than duration %" G_GUINT64_FORMAT,
9330 offset, stream->duration);
9332 stream->cslg_shift = 0;
9333 stream->ctts_present = FALSE;
9337 if (offset < cslg_least)
9338 cslg_least = offset;
9342 stream->cslg_shift = ABS (cslg_least);
9344 stream->cslg_shift = 0;
9346 /* reset the reader so we can generate sample table */
9347 gst_byte_reader_set_pos (&stream->ctts, pos);
9350 /* Ensure the cslg_shift value is consistent so we can use it
9351 * unconditionally to produce TS and Segment */
9352 stream->cslg_shift = 0;
9355 /* For raw audio streams especially we might want to merge the samples
9356 * to not output one audio sample per buffer. We're doing this here
9357 * before allocating the sample tables so that from this point onwards
9358 * the number of container samples are static */
9359 if (stream->min_buffer_size > 0) {
9360 qtdemux_merge_sample_table (qtdemux, stream);
9364 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9365 stream->n_samples, (guint) sizeof (QtDemuxSample),
9366 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9368 if (stream->n_samples >=
9369 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9370 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9371 "be larger than %uMB (broken file?)", stream->n_samples,
9372 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9376 g_assert (stream->samples == NULL);
9377 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9378 if (!stream->samples) {
9379 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9388 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9389 (_("This file is corrupt and cannot be played.")), (NULL));
9394 gst_qtdemux_stbl_free (stream);
9395 if (!qtdemux->fragmented) {
9396 /* not quite good */
9397 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9400 /* may pick up samples elsewhere */
9406 /* collect samples from the next sample to be parsed up to sample @n for @stream
9407 * by reading the info from @stbl
9409 * This code can be executed from both the streaming thread and the seeking
9410 * thread so it takes the object lock to protect itself
9413 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9416 QtDemuxSample *samples, *first, *cur, *last;
9417 guint32 n_samples_per_chunk;
9420 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9421 GST_FOURCC_FORMAT ", pad %s",
9422 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9423 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9425 n_samples = stream->n_samples;
9428 goto out_of_samples;
9430 GST_OBJECT_LOCK (qtdemux);
9431 if (n <= stream->stbl_index)
9432 goto already_parsed;
9434 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9436 if (!stream->stsz.data) {
9437 /* so we already parsed and passed all the moov samples;
9438 * onto fragmented ones */
9439 g_assert (qtdemux->fragmented);
9443 /* pointer to the sample table */
9444 samples = stream->samples;
9446 /* starts from -1, moves to the next sample index to parse */
9447 stream->stbl_index++;
9449 /* keep track of the first and last sample to fill */
9450 first = &samples[stream->stbl_index];
9453 if (!stream->chunks_are_samples) {
9454 /* set the sample sizes */
9455 if (stream->sample_size == 0) {
9456 /* different sizes for each sample */
9457 for (cur = first; cur <= last; cur++) {
9458 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9459 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9460 (guint) (cur - samples), cur->size);
9463 /* samples have the same size */
9464 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9465 for (cur = first; cur <= last; cur++)
9466 cur->size = stream->sample_size;
9470 n_samples_per_chunk = stream->n_samples_per_chunk;
9473 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9476 if (stream->stsc_chunk_index >= stream->last_chunk
9477 || stream->stsc_chunk_index < stream->first_chunk) {
9478 stream->first_chunk =
9479 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9480 stream->samples_per_chunk =
9481 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9483 stream->stsd_sample_description_id =
9484 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9486 /* chunk numbers are counted from 1 it seems */
9487 if (G_UNLIKELY (stream->first_chunk == 0))
9490 --stream->first_chunk;
9492 /* the last chunk of each entry is calculated by taking the first chunk
9493 * of the next entry; except if there is no next, where we fake it with
9495 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9496 stream->last_chunk = G_MAXUINT32;
9498 stream->last_chunk =
9499 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9500 if (G_UNLIKELY (stream->last_chunk == 0))
9503 --stream->last_chunk;
9506 GST_LOG_OBJECT (qtdemux,
9507 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9508 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9509 stream->samples_per_chunk, stream->stsd_sample_description_id);
9511 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9514 if (stream->last_chunk != G_MAXUINT32) {
9515 if (!qt_atom_parser_peek_sub (&stream->stco,
9516 stream->first_chunk * stream->co_size,
9517 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9522 stream->co_chunk = stream->stco;
9523 if (!gst_byte_reader_skip (&stream->co_chunk,
9524 stream->first_chunk * stream->co_size))
9528 stream->stsc_chunk_index = stream->first_chunk;
9531 last_chunk = stream->last_chunk;
9533 if (stream->chunks_are_samples) {
9534 cur = &samples[stream->stsc_chunk_index];
9536 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9539 stream->stsc_chunk_index = j;
9544 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9547 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9548 "%" G_GUINT64_FORMAT, j, cur->offset);
9550 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9551 CUR_STREAM (stream)->bytes_per_frame > 0) {
9553 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9554 CUR_STREAM (stream)->samples_per_frame *
9555 CUR_STREAM (stream)->bytes_per_frame;
9557 cur->size = stream->samples_per_chunk;
9560 GST_DEBUG_OBJECT (qtdemux,
9561 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9562 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9563 stream->stco_sample_index)), cur->size);
9565 cur->timestamp = stream->stco_sample_index;
9566 cur->duration = stream->samples_per_chunk;
9567 cur->keyframe = TRUE;
9570 stream->stco_sample_index += stream->samples_per_chunk;
9572 stream->stsc_chunk_index = j;
9574 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9575 guint32 samples_per_chunk;
9576 guint64 chunk_offset;
9578 if (!stream->stsc_sample_index
9579 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9580 &stream->chunk_offset))
9583 samples_per_chunk = stream->samples_per_chunk;
9584 chunk_offset = stream->chunk_offset;
9586 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9587 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9588 G_GUINT64_FORMAT " and size %d",
9589 (guint) (cur - samples), chunk_offset, cur->size);
9591 cur->offset = chunk_offset;
9592 chunk_offset += cur->size;
9595 if (G_UNLIKELY (cur > last)) {
9597 stream->stsc_sample_index = k + 1;
9598 stream->chunk_offset = chunk_offset;
9599 stream->stsc_chunk_index = j;
9603 stream->stsc_sample_index = 0;
9605 stream->stsc_chunk_index = j;
9607 stream->stsc_index++;
9610 if (stream->chunks_are_samples)
9614 guint32 n_sample_times;
9616 n_sample_times = stream->n_sample_times;
9619 for (i = stream->stts_index; i < n_sample_times; i++) {
9620 guint32 stts_samples;
9621 gint32 stts_duration;
9624 if (stream->stts_sample_index >= stream->stts_samples
9625 || !stream->stts_sample_index) {
9627 stream->stts_samples =
9628 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9629 stream->stts_duration =
9630 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9632 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9633 i, stream->stts_samples, stream->stts_duration);
9635 stream->stts_sample_index = 0;
9638 stts_samples = stream->stts_samples;
9639 stts_duration = stream->stts_duration;
9640 stts_time = stream->stts_time;
9642 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9643 GST_DEBUG_OBJECT (qtdemux,
9644 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9645 (guint) (cur - samples), j,
9646 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9648 cur->timestamp = stts_time;
9649 cur->duration = stts_duration;
9651 /* avoid 32-bit wrap-around,
9652 * but still mind possible 'negative' duration */
9653 stts_time += (gint64) stts_duration;
9656 if (G_UNLIKELY (cur > last)) {
9658 stream->stts_time = stts_time;
9659 stream->stts_sample_index = j + 1;
9660 if (stream->stts_sample_index >= stream->stts_samples)
9661 stream->stts_index++;
9665 stream->stts_sample_index = 0;
9666 stream->stts_time = stts_time;
9667 stream->stts_index++;
9669 /* fill up empty timestamps with the last timestamp, this can happen when
9670 * the last samples do not decode and so we don't have timestamps for them.
9671 * We however look at the last timestamp to estimate the track length so we
9672 * need something in here. */
9673 for (; cur < last; cur++) {
9674 GST_DEBUG_OBJECT (qtdemux,
9675 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9676 (guint) (cur - samples),
9677 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9678 cur->timestamp = stream->stts_time;
9684 /* sample sync, can be NULL */
9685 if (stream->stss_present == TRUE) {
9686 guint32 n_sample_syncs;
9688 n_sample_syncs = stream->n_sample_syncs;
9690 if (!n_sample_syncs) {
9691 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9692 stream->all_keyframe = TRUE;
9694 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9695 /* note that the first sample is index 1, not 0 */
9698 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9700 if (G_LIKELY (index > 0 && index <= n_samples)) {
9702 samples[index].keyframe = TRUE;
9703 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9704 /* and exit if we have enough samples */
9705 if (G_UNLIKELY (index >= n)) {
9712 stream->stss_index = i;
9715 /* stps marks partial sync frames like open GOP I-Frames */
9716 if (stream->stps_present == TRUE) {
9717 guint32 n_sample_partial_syncs;
9719 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9721 /* if there are no entries, the stss table contains the real
9723 if (n_sample_partial_syncs) {
9724 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9725 /* note that the first sample is index 1, not 0 */
9728 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9730 if (G_LIKELY (index > 0 && index <= n_samples)) {
9732 samples[index].keyframe = TRUE;
9733 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9734 /* and exit if we have enough samples */
9735 if (G_UNLIKELY (index >= n)) {
9742 stream->stps_index = i;
9746 /* no stss, all samples are keyframes */
9747 stream->all_keyframe = TRUE;
9748 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9753 /* composition time to sample */
9754 if (stream->ctts_present == TRUE) {
9755 guint32 n_composition_times;
9757 gint32 ctts_soffset;
9759 /* Fill in the pts_offsets */
9761 n_composition_times = stream->n_composition_times;
9763 for (i = stream->ctts_index; i < n_composition_times; i++) {
9764 if (stream->ctts_sample_index >= stream->ctts_count
9765 || !stream->ctts_sample_index) {
9766 stream->ctts_count =
9767 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9768 stream->ctts_soffset =
9769 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9770 stream->ctts_sample_index = 0;
9773 ctts_count = stream->ctts_count;
9774 ctts_soffset = stream->ctts_soffset;
9776 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9777 cur->pts_offset = ctts_soffset;
9780 if (G_UNLIKELY (cur > last)) {
9782 stream->ctts_sample_index = j + 1;
9786 stream->ctts_sample_index = 0;
9787 stream->ctts_index++;
9791 stream->stbl_index = n;
9792 /* if index has been completely parsed, free data that is no-longer needed */
9793 if (n + 1 == stream->n_samples) {
9794 gst_qtdemux_stbl_free (stream);
9795 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9796 if (qtdemux->pullbased) {
9797 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9798 while (n + 1 == stream->n_samples)
9799 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9803 GST_OBJECT_UNLOCK (qtdemux);
9810 GST_LOG_OBJECT (qtdemux,
9811 "Tried to parse up to sample %u but this sample has already been parsed",
9813 /* if fragmented, there may be more */
9814 if (qtdemux->fragmented && n == stream->stbl_index)
9816 GST_OBJECT_UNLOCK (qtdemux);
9822 GST_LOG_OBJECT (qtdemux,
9823 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9825 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9826 (_("This file is corrupt and cannot be played.")), (NULL));
9831 GST_OBJECT_UNLOCK (qtdemux);
9832 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9833 (_("This file is corrupt and cannot be played.")), (NULL));
9838 /* collect all segment info for @stream.
9841 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9845 /* accept edts if they contain gaps at start and there is only
9846 * one media segment */
9847 gboolean allow_pushbased_edts = TRUE;
9848 gint media_segments_count = 0;
9850 /* parse and prepare segment info from the edit list */
9851 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9852 stream->n_segments = 0;
9853 stream->segments = NULL;
9854 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9857 gint segment_number, entry_size;
9860 const guint8 *buffer;
9864 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9865 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9868 buffer = elst->data;
9870 size = QT_UINT32 (buffer);
9871 /* version, flags, n_segments */
9873 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9876 version = QT_UINT8 (buffer + 8);
9877 entry_size = (version == 1) ? 20 : 12;
9879 n_segments = QT_UINT32 (buffer + 12);
9881 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9882 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9886 /* we might allocate a bit too much, at least allocate 1 segment */
9887 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9889 /* segments always start from 0 */
9893 for (segment_number = 0; segment_number < n_segments; segment_number++) {
9896 gboolean empty_edit = FALSE;
9897 QtDemuxSegment *segment;
9899 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9902 media_time = QT_UINT64 (buffer + 8);
9903 duration = QT_UINT64 (buffer);
9904 if (media_time == G_MAXUINT64)
9907 media_time = QT_UINT32 (buffer + 4);
9908 duration = QT_UINT32 (buffer);
9909 if (media_time == G_MAXUINT32)
9914 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9916 segment = &stream->segments[segment_number];
9918 /* time and duration expressed in global timescale */
9919 segment->time = stime;
9920 if (duration != 0 || empty_edit) {
9921 /* edge case: empty edits with duration=zero are treated here.
9922 * (files should not have these anyway). */
9924 /* add non scaled values so we don't cause roundoff errors */
9926 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9927 segment->duration = stime - segment->time;
9929 /* zero duration does not imply media_start == media_stop
9930 * but, only specify media_start. The edit ends with the track. */
9931 stime = segment->duration = GST_CLOCK_TIME_NONE;
9932 /* Don't allow more edits after this one. */
9933 n_segments = segment_number + 1;
9935 segment->stop_time = stime;
9937 segment->trak_media_start = media_time;
9938 /* media_time expressed in stream timescale */
9940 segment->media_start = media_start;
9941 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
9942 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
9943 media_segments_count++;
9945 segment->media_start = GST_CLOCK_TIME_NONE;
9946 segment->media_stop = GST_CLOCK_TIME_NONE;
9948 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9950 if (rate_int <= 1) {
9951 /* 0 is not allowed, some programs write 1 instead of the floating point
9953 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9957 segment->rate = rate_int / 65536.0;
9960 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9961 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9962 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9963 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9964 segment_number, GST_TIME_ARGS (segment->time),
9965 GST_TIME_ARGS (segment->duration),
9966 GST_TIME_ARGS (segment->media_start), media_time,
9967 GST_TIME_ARGS (segment->media_stop),
9968 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9970 if (segment->stop_time > qtdemux->segment.stop &&
9971 !qtdemux->upstream_format_is_time) {
9972 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9973 " extends to %" GST_TIME_FORMAT
9974 " past the end of the declared movie duration %" GST_TIME_FORMAT
9975 " movie segment will be extended", segment_number,
9976 GST_TIME_ARGS (segment->stop_time),
9977 GST_TIME_ARGS (qtdemux->segment.stop));
9978 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
9981 buffer += entry_size;
9983 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
9984 stream->n_segments = n_segments;
9985 if (media_segments_count != 1)
9986 allow_pushbased_edts = FALSE;
9990 /* push based does not handle segments, so act accordingly here,
9991 * and warn if applicable */
9992 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9993 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9994 /* remove and use default one below, we stream like it anyway */
9995 g_free (stream->segments);
9996 stream->segments = NULL;
9997 stream->n_segments = 0;
10000 /* no segments, create one to play the complete trak */
10001 if (stream->n_segments == 0) {
10002 GstClockTime stream_duration =
10003 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10005 if (stream->segments == NULL)
10006 stream->segments = g_new (QtDemuxSegment, 1);
10008 /* represent unknown our way */
10009 if (stream_duration == 0)
10010 stream_duration = GST_CLOCK_TIME_NONE;
10012 stream->segments[0].time = 0;
10013 stream->segments[0].stop_time = stream_duration;
10014 stream->segments[0].duration = stream_duration;
10015 stream->segments[0].media_start = 0;
10016 stream->segments[0].media_stop = stream_duration;
10017 stream->segments[0].rate = 1.0;
10018 stream->segments[0].trak_media_start = 0;
10020 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10021 GST_TIME_ARGS (stream_duration));
10022 stream->n_segments = 1;
10023 stream->dummy_segment = TRUE;
10025 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10031 * Parses the stsd atom of a svq3 trak looking for
10032 * the SMI and gama atoms.
10035 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10036 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10038 const guint8 *_gamma = NULL;
10039 GstBuffer *_seqh = NULL;
10040 const guint8 *stsd_data = stsd_entry_data;
10041 guint32 length = QT_UINT32 (stsd_data);
10045 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10051 version = QT_UINT16 (stsd_data);
10052 if (version == 3) {
10053 if (length >= 70) {
10056 while (length > 8) {
10057 guint32 fourcc, size;
10058 const guint8 *data;
10059 size = QT_UINT32 (stsd_data);
10060 fourcc = QT_FOURCC (stsd_data + 4);
10061 data = stsd_data + 8;
10064 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10065 "svq3 atom parsing");
10074 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10075 " for gama atom, expected 12", size);
10080 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10082 if (_seqh != NULL) {
10083 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10084 " found, ignoring");
10086 seqh_size = QT_UINT32 (data + 4);
10087 if (seqh_size > 0) {
10088 _seqh = gst_buffer_new_and_alloc (seqh_size);
10089 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10096 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10097 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10101 if (size <= length) {
10107 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10110 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10111 G_GUINT16_FORMAT, version);
10121 } else if (_seqh) {
10122 gst_buffer_unref (_seqh);
10127 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10130 GstByteReader dref;
10134 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10135 * atom that might contain a 'data' atom with the rtsp uri.
10136 * This case was reported in bug #597497, some info about
10137 * the hndl atom can be found in TN1195
10139 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10140 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10143 guint32 dref_num_entries = 0;
10144 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10145 gst_byte_reader_skip (&dref, 4) &&
10146 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10149 /* search dref entries for hndl atom */
10150 for (i = 0; i < dref_num_entries; i++) {
10151 guint32 size = 0, type;
10152 guint8 string_len = 0;
10153 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10154 qt_atom_parser_get_fourcc (&dref, &type)) {
10155 if (type == FOURCC_hndl) {
10156 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10158 /* skip data reference handle bytes and the
10159 * following pascal string and some extra 4
10160 * bytes I have no idea what are */
10161 if (!gst_byte_reader_skip (&dref, 4) ||
10162 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10163 !gst_byte_reader_skip (&dref, string_len + 4)) {
10164 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10168 /* iterate over the atoms to find the data atom */
10169 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10173 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10174 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10175 if (atom_type == FOURCC_data) {
10176 const guint8 *uri_aux = NULL;
10178 /* found the data atom that might contain the rtsp uri */
10179 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10180 "hndl atom, interpreting it as an URI");
10181 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10183 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10184 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10186 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10187 "didn't contain a rtsp address");
10189 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10194 /* skipping to the next entry */
10195 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10198 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10205 /* skip to the next entry */
10206 if (!gst_byte_reader_skip (&dref, size - 8))
10209 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10212 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10218 #define AMR_NB_ALL_MODES 0x81ff
10219 #define AMR_WB_ALL_MODES 0x83ff
10221 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10223 /* The 'damr' atom is of the form:
10225 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10226 * 32 b 8 b 16 b 8 b 8 b
10228 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10229 * represents the highest mode used in the stream (and thus the maximum
10230 * bitrate), with a couple of special cases as seen below.
10233 /* Map of frame type ID -> bitrate */
10234 static const guint nb_bitrates[] = {
10235 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10237 static const guint wb_bitrates[] = {
10238 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10244 gst_buffer_map (buf, &map, GST_MAP_READ);
10246 if (map.size != 0x11) {
10247 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10251 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10252 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10253 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10257 mode_set = QT_UINT16 (map.data + 13);
10259 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10260 max_mode = 7 + (wb ? 1 : 0);
10262 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10263 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10265 if (max_mode == -1) {
10266 GST_DEBUG ("No mode indication was found (mode set) = %x",
10271 gst_buffer_unmap (buf, &map);
10272 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10275 gst_buffer_unmap (buf, &map);
10280 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10281 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10284 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10290 if (gst_byte_reader_get_remaining (reader) < 36)
10293 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10294 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10295 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10296 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10297 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10298 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10299 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10300 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10301 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10303 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10304 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10305 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10307 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10308 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10310 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10311 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10318 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10319 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10326 * This macro will only compare value abdegh, it expects cfi to have already
10329 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10330 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10332 /* only handle the cases where the last column has standard values */
10333 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10334 const gchar *rotation_tag = NULL;
10336 /* no rotation needed */
10337 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10339 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10340 rotation_tag = "rotate-90";
10341 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10342 rotation_tag = "rotate-180";
10343 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10344 rotation_tag = "rotate-270";
10346 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10349 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10350 GST_STR_NULL (rotation_tag));
10351 if (rotation_tag != NULL) {
10352 if (*taglist == NULL)
10353 *taglist = gst_tag_list_new_empty ();
10354 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10355 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10358 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10363 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10364 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10368 GstBuffer *adrm_buf = NULL;
10369 QtDemuxAavdEncryptionInfo *info;
10371 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10372 if (G_UNLIKELY (!adrm)) {
10373 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10376 adrm_size = QT_UINT32 (adrm->data);
10377 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10379 stream->protection_scheme_type = FOURCC_aavd;
10381 if (!stream->protection_scheme_info)
10382 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10384 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10386 if (info->default_properties)
10387 gst_structure_free (info->default_properties);
10388 info->default_properties = gst_structure_new ("application/x-aavd",
10389 "encrypted", G_TYPE_BOOLEAN, TRUE,
10390 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10391 gst_buffer_unref (adrm_buf);
10393 *original_fmt = FOURCC_mp4a;
10397 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10398 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10399 * Common Encryption (cenc), the function will also parse the tenc box (defined
10400 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10401 * (typically an enc[v|a|t|s] sample entry); the function will set
10402 * @original_fmt to the fourcc of the original unencrypted stream format.
10403 * Returns TRUE if successful; FALSE otherwise. */
10405 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10406 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10412 QtDemuxCencSampleSetInfo *info;
10414 const guint8 *tenc_data;
10416 g_return_val_if_fail (qtdemux != NULL, FALSE);
10417 g_return_val_if_fail (stream != NULL, FALSE);
10418 g_return_val_if_fail (container != NULL, FALSE);
10419 g_return_val_if_fail (original_fmt != NULL, FALSE);
10421 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10422 if (G_UNLIKELY (!sinf)) {
10423 if (stream->protection_scheme_type == FOURCC_cenc
10424 || stream->protection_scheme_type == FOURCC_cbcs) {
10425 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10426 "mandatory for Common Encryption");
10432 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10433 if (G_UNLIKELY (!frma)) {
10434 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10438 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10439 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10440 GST_FOURCC_ARGS (*original_fmt));
10442 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10444 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10447 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10448 stream->protection_scheme_version =
10449 QT_UINT32 ((const guint8 *) schm->data + 16);
10451 GST_DEBUG_OBJECT (qtdemux,
10452 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10453 "protection_scheme_version: %#010x",
10454 GST_FOURCC_ARGS (stream->protection_scheme_type),
10455 stream->protection_scheme_version);
10457 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10459 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10462 if (stream->protection_scheme_type != FOURCC_cenc &&
10463 stream->protection_scheme_type != FOURCC_piff &&
10464 stream->protection_scheme_type != FOURCC_cbcs) {
10465 GST_ERROR_OBJECT (qtdemux,
10466 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10467 GST_FOURCC_ARGS (stream->protection_scheme_type));
10471 if (G_UNLIKELY (!stream->protection_scheme_info))
10472 stream->protection_scheme_info =
10473 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10475 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10477 if (stream->protection_scheme_type == FOURCC_cenc
10478 || stream->protection_scheme_type == FOURCC_cbcs) {
10479 guint8 is_encrypted;
10481 guint8 constant_iv_size = 0;
10482 const guint8 *default_kid;
10483 guint8 crypt_byte_block = 0;
10484 guint8 skip_byte_block = 0;
10485 const guint8 *constant_iv = NULL;
10487 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10489 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10490 "which is mandatory for Common Encryption");
10493 tenc_data = (const guint8 *) tenc->data + 12;
10494 is_encrypted = QT_UINT8 (tenc_data + 2);
10495 iv_size = QT_UINT8 (tenc_data + 3);
10496 default_kid = (tenc_data + 4);
10497 if (stream->protection_scheme_type == FOURCC_cbcs) {
10498 guint8 possible_pattern_info;
10499 if (iv_size == 0) {
10500 constant_iv_size = QT_UINT8 (tenc_data + 20);
10501 if (constant_iv_size != 8 && constant_iv_size != 16) {
10502 GST_ERROR_OBJECT (qtdemux,
10503 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10506 constant_iv = (tenc_data + 21);
10508 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10509 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10510 skip_byte_block = possible_pattern_info & 0x0f;
10512 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10513 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10514 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10515 } else if (stream->protection_scheme_type == FOURCC_piff) {
10517 static const guint8 piff_track_encryption_uuid[] = {
10518 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10519 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10522 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10524 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10525 "which is mandatory for Common Encryption");
10529 tenc_data = (const guint8 *) tenc->data + 8;
10530 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10531 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10532 GST_ERROR_OBJECT (qtdemux,
10533 "Unsupported track encryption box with uuid: %s", box_uuid);
10537 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10538 gst_byte_reader_init (&br, tenc_data, 20);
10539 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10540 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10543 stream->protection_scheme_type = FOURCC_cenc;
10550 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10551 QtDemuxStream ** stream2)
10553 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10557 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10562 /*parse svmi header if existing */
10563 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10565 guint len = QT_UINT32 ((guint8 *) svmi->data);
10566 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10568 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10569 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10570 guint8 frame_type, frame_layout;
10571 guint32 stereo_mono_change_count;
10576 /* MPEG-A stereo video */
10577 if (qtdemux->major_brand == FOURCC_ss02)
10578 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10580 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10581 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10582 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10584 switch (frame_type) {
10586 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10589 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10592 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10595 /* mode 3 is primary/secondary view sequence, ie
10596 * left/right views in separate tracks. See section 7.2
10597 * of ISO/IEC 23000-11:2009 */
10598 /* In the future this might be supported using related
10599 * streams, like an enhancement track - if files like this
10601 GST_FIXME_OBJECT (qtdemux,
10602 "Implement stereo video in separate streams");
10605 if ((frame_layout & 0x1) == 0)
10606 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10608 GST_LOG_OBJECT (qtdemux,
10609 "StereoVideo: composition type: %u, is_left_first: %u",
10610 frame_type, frame_layout);
10612 if (stereo_mono_change_count > 1) {
10613 GST_FIXME_OBJECT (qtdemux,
10614 "Mixed-mono flags are not yet supported in qtdemux.");
10617 stream->multiview_mode = mode;
10618 stream->multiview_flags = flags;
10625 /* parse the traks.
10626 * With each track we associate a new QtDemuxStream that contains all the info
10628 * traks that do not decode to something (like strm traks) will not have a pad.
10631 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10633 GstByteReader tkhd;
10647 QtDemuxStream *stream = NULL;
10648 const guint8 *stsd_data;
10649 const guint8 *stsd_entry_data;
10650 guint remaining_stsd_len;
10651 guint stsd_entry_count;
10653 guint16 lang_code; /* quicktime lang code or packed iso code */
10655 guint32 tkhd_flags = 0;
10656 guint8 tkhd_version = 0;
10657 guint32 w = 0, h = 0;
10658 guint value_size, stsd_len, len;
10662 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10664 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10665 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10666 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10669 /* pick between 64 or 32 bits */
10670 value_size = tkhd_version == 1 ? 8 : 4;
10671 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10672 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10675 /* Check if current moov has duplicated track_id */
10676 if (qtdemux_find_stream (qtdemux, track_id))
10677 goto existing_stream;
10679 stream = _create_stream (qtdemux, track_id);
10680 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10682 /* need defaults for fragments */
10683 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10685 if ((tkhd_flags & 1) == 0)
10686 stream->disabled = TRUE;
10688 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10689 tkhd_version, tkhd_flags, stream->track_id);
10691 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10694 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10695 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10696 if (qtdemux->major_brand != FOURCC_mjp2 ||
10697 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10701 len = QT_UINT32 ((guint8 *) mdhd->data);
10702 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10703 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10704 if (version == 0x01000000) {
10707 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10708 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10709 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
10713 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10714 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10715 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10718 if (lang_code < 0x400) {
10719 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10720 } else if (lang_code == 0x7fff) {
10721 stream->lang_id[0] = 0; /* unspecified */
10723 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10724 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10725 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10726 stream->lang_id[3] = 0;
10729 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10730 stream->timescale);
10731 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10733 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10734 lang_code, stream->lang_id);
10736 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10739 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10740 /* chapters track reference */
10741 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10743 gsize length = GST_READ_UINT32_BE (chap->data);
10744 if (qtdemux->chapters_track_id)
10745 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10747 if (length >= 12) {
10748 qtdemux->chapters_track_id =
10749 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10754 /* fragmented files may have bogus duration in moov */
10755 if (!qtdemux->fragmented &&
10756 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10757 guint64 tdur1, tdur2;
10759 /* don't overflow */
10760 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10761 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10764 * some of those trailers, nowadays, have prologue images that are
10765 * themselves video tracks as well. I haven't really found a way to
10766 * identify those yet, except for just looking at their duration. */
10767 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10768 GST_WARNING_OBJECT (qtdemux,
10769 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10770 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10771 "found, assuming preview image or something; skipping track",
10772 stream->duration, stream->timescale, qtdemux->duration,
10773 qtdemux->timescale);
10774 gst_qtdemux_stream_unref (stream);
10779 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10782 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10783 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10785 len = QT_UINT32 ((guint8 *) hdlr->data);
10787 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10788 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10789 GST_FOURCC_ARGS (stream->subtype));
10791 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10794 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10797 /* Parse out svmi (and later st3d/sv3d) atoms */
10798 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
10801 /* parse rest of tkhd */
10802 if (stream->subtype == FOURCC_vide) {
10805 /* version 1 uses some 64-bit ints */
10806 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10809 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10812 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10813 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10816 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10817 &stream->stream_tags);
10821 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10823 stsd_data = (const guint8 *) stsd->data;
10825 /* stsd should at least have one entry */
10826 stsd_len = QT_UINT32 (stsd_data);
10827 if (stsd_len < 24) {
10828 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10829 if (stream->subtype == FOURCC_vivo) {
10830 gst_qtdemux_stream_unref (stream);
10837 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10838 /* each stsd entry must contain at least 8 bytes */
10839 if (stream->stsd_entries_length == 0
10840 || stream->stsd_entries_length > stsd_len / 8) {
10841 stream->stsd_entries_length = 0;
10844 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10845 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
10846 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
10848 stsd_entry_data = stsd_data + 16;
10849 remaining_stsd_len = stsd_len - 16;
10850 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10852 gchar *codec = NULL;
10853 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10855 /* and that entry should fit within stsd */
10856 len = QT_UINT32 (stsd_entry_data);
10857 if (len > remaining_stsd_len)
10860 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10861 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
10862 GST_FOURCC_ARGS (entry->fourcc));
10863 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
10865 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10866 goto error_encrypted;
10868 if (fourcc == FOURCC_aavd) {
10869 if (stream->subtype != FOURCC_soun) {
10870 GST_ERROR_OBJECT (qtdemux,
10871 "Unexpeced stsd type 'aavd' outside 'soun' track");
10873 /* encrypted audio with sound sample description v0 */
10874 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10875 stream->protected = TRUE;
10876 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
10877 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10881 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10882 /* FIXME this looks wrong, there might be multiple children
10883 * with the same type */
10884 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10885 stream->protected = TRUE;
10886 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10887 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10890 if (stream->subtype == FOURCC_vide) {
10895 gint depth, palette_size, palette_count;
10896 guint32 *palette_data = NULL;
10898 entry->sampled = TRUE;
10900 stream->display_width = w >> 16;
10901 stream->display_height = h >> 16;
10904 if (len < 86) /* TODO verify */
10907 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10908 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10909 entry->fps_n = 0; /* this is filled in later */
10910 entry->fps_d = 0; /* this is filled in later */
10911 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10912 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10914 /* if color_table_id is 0, ctab atom must follow; however some files
10915 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10916 * if color table is not present we'll correct the value */
10917 if (entry->color_table_id == 0 &&
10919 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10920 entry->color_table_id = -1;
10923 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10924 entry->width, entry->height, entry->bits_per_sample,
10925 entry->color_table_id);
10927 depth = entry->bits_per_sample;
10929 /* more than 32 bits means grayscale */
10930 gray = (depth > 32);
10931 /* low 32 bits specify the depth */
10934 /* different number of palette entries is determined by depth. */
10936 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10937 palette_count = (1 << depth);
10938 palette_size = palette_count * 4;
10940 if (entry->color_table_id) {
10941 switch (palette_count) {
10945 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
10948 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
10953 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
10955 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
10960 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
10963 g_memdup2 (ff_qt_default_palette_256, palette_size);
10966 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10967 (_("The video in this file might not play correctly.")),
10968 ("unsupported palette depth %d", depth));
10972 gint i, j, start, end;
10978 start = QT_UINT32 (stsd_entry_data + offset + 70);
10979 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10980 end = QT_UINT16 (stsd_entry_data + offset + 76);
10982 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10983 start, end, palette_count);
10990 if (len < 94 + (end - start) * 8)
10993 /* palette is always the same size */
10994 palette_data = g_malloc0 (256 * 4);
10995 palette_size = 256 * 4;
10997 for (j = 0, i = start; i <= end; j++, i++) {
10998 guint32 a, r, g, b;
11000 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11001 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11002 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11003 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11005 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11006 (g & 0xff00) | (b >> 8);
11011 gst_caps_unref (entry->caps);
11014 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11016 if (G_UNLIKELY (!entry->caps)) {
11017 g_free (palette_data);
11018 goto unknown_stream;
11022 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11023 GST_TAG_VIDEO_CODEC, codec, NULL);
11028 if (palette_data) {
11031 if (entry->rgb8_palette)
11032 gst_memory_unref (entry->rgb8_palette);
11033 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11034 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11036 s = gst_caps_get_structure (entry->caps, 0);
11038 /* non-raw video has a palette_data property. raw video has the palette as
11039 * an extra plane that we append to the output buffers before we push
11041 if (!gst_structure_has_name (s, "video/x-raw")) {
11042 GstBuffer *palette;
11044 palette = gst_buffer_new ();
11045 gst_buffer_append_memory (palette, entry->rgb8_palette);
11046 entry->rgb8_palette = NULL;
11048 gst_caps_set_simple (entry->caps, "palette_data",
11049 GST_TYPE_BUFFER, palette, NULL);
11050 gst_buffer_unref (palette);
11052 } else if (palette_count != 0) {
11053 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11054 (NULL), ("Unsupported palette depth %d", depth));
11057 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11058 QT_UINT16 (stsd_entry_data + offset + 32));
11064 /* pick 'the' stsd child */
11065 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11066 // We should skip parsing the stsd for non-protected streams if
11067 // the entry doesn't match the fourcc, since they don't change
11068 // format. However, for protected streams we can have partial
11069 // encryption, where parts of the stream are encrypted and parts
11070 // not. For both parts of such streams, we should ensure the
11071 // esds overrides are parsed for both from the stsd.
11072 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11073 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11075 else if (!stream->protected)
11080 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11081 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11082 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11083 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11087 const guint8 *pasp_data = (const guint8 *) pasp->data;
11088 gint len = QT_UINT32 (pasp_data);
11091 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11092 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11094 CUR_STREAM (stream)->par_w = 0;
11095 CUR_STREAM (stream)->par_h = 0;
11098 CUR_STREAM (stream)->par_w = 0;
11099 CUR_STREAM (stream)->par_h = 0;
11103 const guint8 *fiel_data = (const guint8 *) fiel->data;
11104 gint len = QT_UINT32 (fiel_data);
11107 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11108 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11113 const guint8 *colr_data = (const guint8 *) colr->data;
11114 gint len = QT_UINT32 (colr_data);
11116 if (len == 19 || len == 18) {
11117 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11119 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11120 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11121 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11122 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11123 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11125 CUR_STREAM (stream)->colorimetry.primaries =
11126 gst_video_color_primaries_from_iso (primaries);
11127 CUR_STREAM (stream)->colorimetry.transfer =
11128 gst_video_transfer_function_from_iso (transfer_function);
11129 CUR_STREAM (stream)->colorimetry.matrix =
11130 gst_video_color_matrix_from_iso (matrix);
11131 CUR_STREAM (stream)->colorimetry.range =
11132 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11133 GST_VIDEO_COLOR_RANGE_16_235;
11135 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11138 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11143 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11144 stream->stream_tags);
11151 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11152 const guint8 *avc_data = stsd_entry_data + 0x56;
11155 while (len >= 0x8) {
11158 if (QT_UINT32 (avc_data) <= len)
11159 size = QT_UINT32 (avc_data) - 0x8;
11164 /* No real data, so break out */
11167 switch (QT_FOURCC (avc_data + 0x4)) {
11170 /* parse, if found */
11173 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11175 /* First 4 bytes are the length of the atom, the next 4 bytes
11176 * are the fourcc, the next 1 byte is the version, and the
11177 * subsequent bytes are profile_tier_level structure like data. */
11178 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11179 avc_data + 8 + 1, size - 1);
11180 buf = gst_buffer_new_and_alloc (size);
11181 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11182 gst_caps_set_simple (entry->caps,
11183 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11184 gst_buffer_unref (buf);
11192 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11194 /* First 4 bytes are the length of the atom, the next 4 bytes
11195 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11196 * next 1 byte is the version, and the
11197 * subsequent bytes are sequence parameter set like data. */
11199 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11201 gst_codec_utils_h264_caps_set_level_and_profile
11202 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11204 buf = gst_buffer_new_and_alloc (size);
11205 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11206 gst_caps_set_simple (entry->caps,
11207 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11208 gst_buffer_unref (buf);
11214 guint avg_bitrate, max_bitrate;
11216 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11220 max_bitrate = QT_UINT32 (avc_data + 0xc);
11221 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11223 if (!max_bitrate && !avg_bitrate)
11226 /* Some muxers seem to swap the average and maximum bitrates
11227 * (I'm looking at you, YouTube), so we swap for sanity. */
11228 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11229 guint temp = avg_bitrate;
11231 avg_bitrate = max_bitrate;
11232 max_bitrate = temp;
11235 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11236 gst_tag_list_add (stream->stream_tags,
11237 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11238 max_bitrate, NULL);
11240 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11241 gst_tag_list_add (stream->stream_tags,
11242 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11254 avc_data += size + 8;
11265 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11266 const guint8 *hevc_data = stsd_entry_data + 0x56;
11269 while (len >= 0x8) {
11272 if (QT_UINT32 (hevc_data) <= len)
11273 size = QT_UINT32 (hevc_data) - 0x8;
11278 /* No real data, so break out */
11281 switch (QT_FOURCC (hevc_data + 0x4)) {
11284 /* parse, if found */
11287 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11289 /* First 4 bytes are the length of the atom, the next 4 bytes
11290 * are the fourcc, the next 1 byte is the version, and the
11291 * subsequent bytes are sequence parameter set like data. */
11292 gst_codec_utils_h265_caps_set_level_tier_and_profile
11293 (entry->caps, hevc_data + 8 + 1, size - 1);
11295 buf = gst_buffer_new_and_alloc (size);
11296 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11297 gst_caps_set_simple (entry->caps,
11298 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11299 gst_buffer_unref (buf);
11306 hevc_data += size + 8;
11319 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11320 GST_FOURCC_ARGS (fourcc));
11322 /* codec data might be in glbl extension atom */
11324 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11330 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11332 len = QT_UINT32 (data);
11335 buf = gst_buffer_new_and_alloc (len);
11336 gst_buffer_fill (buf, 0, data + 8, len);
11337 gst_caps_set_simple (entry->caps,
11338 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11339 gst_buffer_unref (buf);
11346 /* see annex I of the jpeg2000 spec */
11347 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11348 const guint8 *data;
11349 const gchar *colorspace = NULL;
11351 guint32 ncomp_map = 0;
11352 gint32 *comp_map = NULL;
11353 guint32 nchan_def = 0;
11354 gint32 *chan_def = NULL;
11356 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11357 /* some required atoms */
11358 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11361 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11365 /* number of components; redundant with info in codestream, but useful
11367 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11368 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11370 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11372 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11375 GST_DEBUG_OBJECT (qtdemux, "found colr");
11376 /* extract colour space info */
11377 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11378 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11380 colorspace = "sRGB";
11383 colorspace = "GRAY";
11386 colorspace = "sYUV";
11394 /* colr is required, and only values 16, 17, and 18 are specified,
11395 so error if we have no colorspace */
11398 /* extract component mapping */
11399 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11401 guint32 cmap_len = 0;
11403 cmap_len = QT_UINT32 (cmap->data);
11404 if (cmap_len >= 8) {
11405 /* normal box, subtract off header */
11407 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11408 if (cmap_len % 4 == 0) {
11409 ncomp_map = (cmap_len / 4);
11410 comp_map = g_new0 (gint32, ncomp_map);
11411 for (i = 0; i < ncomp_map; i++) {
11414 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11415 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11416 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11417 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11422 /* extract channel definitions */
11423 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11425 guint32 cdef_len = 0;
11427 cdef_len = QT_UINT32 (cdef->data);
11428 if (cdef_len >= 10) {
11429 /* normal box, subtract off header and len */
11431 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11432 if (cdef_len % 6 == 0) {
11433 nchan_def = (cdef_len / 6);
11434 chan_def = g_new0 (gint32, nchan_def);
11435 for (i = 0; i < nchan_def; i++)
11437 for (i = 0; i < nchan_def; i++) {
11438 guint16 cn, typ, asoc;
11439 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11440 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11441 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11442 if (cn < nchan_def) {
11445 chan_def[cn] = asoc;
11448 chan_def[cn] = 0; /* alpha */
11451 chan_def[cn] = -typ;
11459 gst_caps_set_simple (entry->caps,
11460 "num-components", G_TYPE_INT, ncomp, NULL);
11461 gst_caps_set_simple (entry->caps,
11462 "colorspace", G_TYPE_STRING, colorspace, NULL);
11465 GValue arr = { 0, };
11466 GValue elt = { 0, };
11468 g_value_init (&arr, GST_TYPE_ARRAY);
11469 g_value_init (&elt, G_TYPE_INT);
11470 for (i = 0; i < ncomp_map; i++) {
11471 g_value_set_int (&elt, comp_map[i]);
11472 gst_value_array_append_value (&arr, &elt);
11474 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11475 "component-map", &arr);
11476 g_value_unset (&elt);
11477 g_value_unset (&arr);
11482 GValue arr = { 0, };
11483 GValue elt = { 0, };
11485 g_value_init (&arr, GST_TYPE_ARRAY);
11486 g_value_init (&elt, G_TYPE_INT);
11487 for (i = 0; i < nchan_def; i++) {
11488 g_value_set_int (&elt, chan_def[i]);
11489 gst_value_array_append_value (&arr, &elt);
11491 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11492 "channel-definitions", &arr);
11493 g_value_unset (&elt);
11494 g_value_unset (&arr);
11498 /* some optional atoms */
11499 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11500 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11502 /* indicate possible fields in caps */
11504 data = (guint8 *) field->data + 8;
11506 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11507 (gint) * data, NULL);
11509 /* add codec_data if provided */
11514 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11515 data = prefix->data;
11516 len = QT_UINT32 (data);
11519 buf = gst_buffer_new_and_alloc (len);
11520 gst_buffer_fill (buf, 0, data + 8, len);
11521 gst_caps_set_simple (entry->caps,
11522 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11523 gst_buffer_unref (buf);
11532 GstBuffer *seqh = NULL;
11533 const guint8 *gamma_data = NULL;
11534 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11536 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11539 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11540 QT_FP32 (gamma_data), NULL);
11543 /* sorry for the bad name, but we don't know what this is, other
11544 * than its own fourcc */
11545 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11547 gst_buffer_unref (seqh);
11550 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11551 buf = gst_buffer_new_and_alloc (len);
11552 gst_buffer_fill (buf, 0, stsd_data, len);
11553 gst_caps_set_simple (entry->caps,
11554 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11555 gst_buffer_unref (buf);
11560 /* https://developer.apple.com/standards/qtff-2001.pdf,
11561 * page 92, "Video Sample Description", under table 3.1 */
11564 const gint compressor_offset =
11565 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11566 const gint min_size = compressor_offset + 32 + 2 + 2;
11569 guint16 color_table_id = 0;
11572 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11574 /* recover information on interlaced/progressive */
11575 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11579 len = QT_UINT32 (jpeg->data);
11580 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11582 if (len >= min_size) {
11583 gst_byte_reader_init (&br, jpeg->data, len);
11585 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11586 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11587 if (color_table_id != 0) {
11588 /* the spec says there can be concatenated chunks in the data, and we want
11589 * to find one called field. Walk through them. */
11590 gint offset = min_size;
11591 while (offset + 8 < len) {
11592 guint32 size = 0, tag;
11593 ok = gst_byte_reader_get_uint32_le (&br, &size);
11594 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11595 if (!ok || size < 8) {
11596 GST_WARNING_OBJECT (qtdemux,
11597 "Failed to walk optional chunk list");
11600 GST_DEBUG_OBJECT (qtdemux,
11601 "Found optional %4.4s chunk, size %u",
11602 (const char *) &tag, size);
11603 if (tag == FOURCC_fiel) {
11604 guint8 n_fields = 0, ordering = 0;
11605 gst_byte_reader_get_uint8 (&br, &n_fields);
11606 gst_byte_reader_get_uint8 (&br, &ordering);
11607 if (n_fields == 1 || n_fields == 2) {
11608 GST_DEBUG_OBJECT (qtdemux,
11609 "Found fiel tag with %u fields, ordering %u",
11610 n_fields, ordering);
11612 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11613 "interlace-mode", G_TYPE_STRING, "interleaved",
11616 GST_WARNING_OBJECT (qtdemux,
11617 "Found fiel tag with invalid fields (%u)", n_fields);
11623 GST_DEBUG_OBJECT (qtdemux,
11624 "Color table ID is 0, not trying to get interlacedness");
11627 GST_WARNING_OBJECT (qtdemux,
11628 "Length of jpeg chunk is too small, not trying to get interlacedness");
11636 gst_caps_set_simple (entry->caps,
11637 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11643 GNode *xith, *xdxt;
11645 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11646 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11650 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11654 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11655 /* collect the headers and store them in a stream list so that we can
11656 * send them out first */
11657 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11667 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11668 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11671 ovc1_data = ovc1->data;
11672 ovc1_len = QT_UINT32 (ovc1_data);
11673 if (ovc1_len <= 198) {
11674 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11677 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11678 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11679 gst_caps_set_simple (entry->caps,
11680 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11681 gst_buffer_unref (buf);
11686 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11687 const guint8 *vc1_data = stsd_entry_data + 0x56;
11693 if (QT_UINT32 (vc1_data) <= len)
11694 size = QT_UINT32 (vc1_data) - 8;
11699 /* No real data, so break out */
11702 switch (QT_FOURCC (vc1_data + 0x4)) {
11703 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11707 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11708 buf = gst_buffer_new_and_alloc (size);
11709 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11710 gst_caps_set_simple (entry->caps,
11711 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11712 gst_buffer_unref (buf);
11719 vc1_data += size + 8;
11725 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11726 const guint8 *av1_data = stsd_entry_data + 0x56;
11729 while (len >= 0x8) {
11732 if (QT_UINT32 (av1_data) <= len)
11733 size = QT_UINT32 (av1_data) - 0x8;
11738 /* No real data, so break out */
11741 switch (QT_FOURCC (av1_data + 0x4)) {
11744 /* parse, if found */
11746 guint8 pres_delay_field;
11748 GST_DEBUG_OBJECT (qtdemux,
11749 "found av1C codec_data in stsd of size %d", size);
11751 /* not enough data, just ignore and hope for the best */
11756 * 4 bytes: atom length
11761 * 1 bits: initial_presentation_delay_present
11762 * 4 bits: initial_presentation_delay (if present else reserved
11766 if (av1_data[9] != 0) {
11767 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11771 /* We skip initial_presentation_delay* for now */
11772 pres_delay_field = *(av1_data + 12);
11773 if (pres_delay_field & (1 << 5)) {
11774 gst_caps_set_simple (entry->caps,
11775 "presentation-delay", G_TYPE_INT,
11776 (gint) (pres_delay_field & 0x0F) + 1, NULL);
11779 buf = gst_buffer_new_and_alloc (size - 5);
11780 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11781 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
11782 gst_caps_set_simple (entry->caps,
11783 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11784 gst_buffer_unref (buf);
11793 av1_data += size + 8;
11799 /* TODO: Need to parse vpcC for VP8 codec too.
11800 * Note that VPCodecConfigurationBox (vpcC) is defined for
11801 * vp08, vp09, and vp10 fourcc. */
11804 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11805 const guint8 *vpcc_data = stsd_entry_data + 0x56;
11808 while (len >= 0x8) {
11811 if (QT_UINT32 (vpcc_data) <= len)
11812 size = QT_UINT32 (vpcc_data) - 0x8;
11817 /* No real data, so break out */
11820 switch (QT_FOURCC (vpcc_data + 0x4)) {
11823 const gchar *profile_str = NULL;
11824 const gchar *chroma_format_str = NULL;
11827 guint8 chroma_format;
11828 GstVideoColorimetry cinfo;
11830 /* parse, if found */
11831 GST_DEBUG_OBJECT (qtdemux,
11832 "found vp codec_data in stsd of size %d", size);
11834 /* the meaning of "size" is length of the atom body, excluding
11835 * atom length and fourcc fields */
11840 * 4 bytes: atom length
11847 * 3 bits: chromaSubsampling
11848 * 1 bit: videoFullRangeFlag
11849 * 1 byte: colourPrimaries
11850 * 1 byte: transferCharacteristics
11851 * 1 byte: matrixCoefficients
11852 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
11853 * rest: codecIntializationData (not used for vp8 and vp9)
11856 if (vpcc_data[8] != 1) {
11857 GST_WARNING_OBJECT (qtdemux,
11858 "unknown vpcC version %d", vpcc_data[8]);
11862 profile = vpcc_data[12];
11881 gst_caps_set_simple (entry->caps,
11882 "profile", G_TYPE_STRING, profile_str, NULL);
11885 /* skip level, the VP9 spec v0.6 defines only one level atm,
11886 * but webm spec define various ones. Add level to caps
11887 * if we really need it then */
11889 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
11890 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
11891 gst_caps_set_simple (entry->caps,
11892 "bit-depth-luma", G_TYPE_UINT, bitdepth,
11893 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
11896 chroma_format = (vpcc_data[14] & 0xe) >> 1;
11897 switch (chroma_format) {
11900 chroma_format_str = "4:2:0";
11903 chroma_format_str = "4:2:2";
11906 chroma_format_str = "4:4:4";
11912 if (chroma_format_str) {
11913 gst_caps_set_simple (entry->caps,
11914 "chroma-format", G_TYPE_STRING, chroma_format_str,
11918 if ((vpcc_data[14] & 0x1) != 0)
11919 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
11921 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
11923 gst_video_color_primaries_from_iso (vpcc_data[15]);
11925 gst_video_transfer_function_from_iso (vpcc_data[16]);
11927 gst_video_color_matrix_from_iso (vpcc_data[17]);
11929 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
11930 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
11931 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
11932 /* set this only if all values are known, otherwise this
11933 * might overwrite valid ones parsed from other color box */
11934 CUR_STREAM (stream)->colorimetry = cinfo;
11943 vpcc_data += size + 8;
11953 GST_INFO_OBJECT (qtdemux,
11954 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11955 GST_FOURCC_ARGS (fourcc), entry->caps);
11957 } else if (stream->subtype == FOURCC_soun) {
11959 int version, samplesize;
11960 guint16 compression_id;
11961 gboolean amrwb = FALSE;
11964 /* sample description entry (16) + sound sample description v0 (20) */
11968 version = QT_UINT32 (stsd_entry_data + offset);
11969 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11970 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11971 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11972 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11974 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
11975 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
11976 QT_UINT32 (stsd_entry_data + offset + 4));
11977 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11978 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
11979 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
11980 GST_LOG_OBJECT (qtdemux, "packet size: %d",
11981 QT_UINT16 (stsd_entry_data + offset + 14));
11982 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11984 if (compression_id == 0xfffe)
11985 entry->sampled = TRUE;
11987 /* first assume uncompressed audio */
11988 entry->bytes_per_sample = samplesize / 8;
11989 entry->samples_per_frame = entry->n_channels;
11990 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
11991 entry->samples_per_packet = entry->samples_per_frame;
11992 entry->bytes_per_packet = entry->bytes_per_sample;
11996 if (version == 0x00010000) {
11997 /* sample description entry (16) + sound sample description v1 (20+16) */
12001 /* take information from here over the normal sample description */
12002 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12003 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12004 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12005 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12007 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12008 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12009 entry->samples_per_packet);
12010 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12011 entry->bytes_per_packet);
12012 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12013 entry->bytes_per_frame);
12014 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12015 entry->bytes_per_sample);
12017 if (!entry->sampled && entry->bytes_per_packet) {
12018 entry->samples_per_frame = (entry->bytes_per_frame /
12019 entry->bytes_per_packet) * entry->samples_per_packet;
12020 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12021 entry->samples_per_frame);
12023 } else if (version == 0x00020000) {
12024 /* sample description entry (16) + sound sample description v2 (56) */
12028 /* take information from here over the normal sample description */
12029 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12030 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12031 entry->samples_per_frame = entry->n_channels;
12032 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12033 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12034 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12035 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12037 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12038 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12039 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12040 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12041 entry->bytes_per_sample * 8);
12042 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12043 QT_UINT32 (stsd_entry_data + offset + 24));
12044 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12045 entry->bytes_per_packet);
12046 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12047 entry->samples_per_packet);
12048 } else if (version != 0x00000) {
12049 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12054 /* Yes, these have to be hard-coded */
12057 entry->samples_per_packet = 6;
12058 entry->bytes_per_packet = 1;
12059 entry->bytes_per_frame = 1 * entry->n_channels;
12060 entry->bytes_per_sample = 1;
12061 entry->samples_per_frame = 6 * entry->n_channels;
12066 entry->samples_per_packet = 3;
12067 entry->bytes_per_packet = 1;
12068 entry->bytes_per_frame = 1 * entry->n_channels;
12069 entry->bytes_per_sample = 1;
12070 entry->samples_per_frame = 3 * entry->n_channels;
12075 entry->samples_per_packet = 64;
12076 entry->bytes_per_packet = 34;
12077 entry->bytes_per_frame = 34 * entry->n_channels;
12078 entry->bytes_per_sample = 2;
12079 entry->samples_per_frame = 64 * entry->n_channels;
12085 entry->samples_per_packet = 1;
12086 entry->bytes_per_packet = 1;
12087 entry->bytes_per_frame = 1 * entry->n_channels;
12088 entry->bytes_per_sample = 1;
12089 entry->samples_per_frame = 1 * entry->n_channels;
12094 entry->samples_per_packet = 160;
12095 entry->bytes_per_packet = 33;
12096 entry->bytes_per_frame = 33 * entry->n_channels;
12097 entry->bytes_per_sample = 2;
12098 entry->samples_per_frame = 160 * entry->n_channels;
12101 /* fix up any invalid header information from above */
12106 /* Sometimes these are set to 0 in the sound sample descriptions so
12107 * let's try to infer useful values from the other information we
12108 * have available */
12109 if (entry->bytes_per_sample == 0)
12110 entry->bytes_per_sample =
12111 entry->bytes_per_frame / entry->n_channels;
12112 if (entry->bytes_per_sample == 0)
12113 entry->bytes_per_sample = samplesize / 8;
12115 if (entry->bytes_per_frame == 0)
12116 entry->bytes_per_frame =
12117 entry->bytes_per_sample * entry->n_channels;
12119 if (entry->bytes_per_packet == 0)
12120 entry->bytes_per_packet = entry->bytes_per_sample;
12122 if (entry->samples_per_frame == 0)
12123 entry->samples_per_frame = entry->n_channels;
12125 if (entry->samples_per_packet == 0)
12126 entry->samples_per_packet = entry->samples_per_frame;
12136 entry->bytes_per_sample = 3;
12140 entry->bytes_per_sample = 4;
12143 entry->bytes_per_sample = 8;
12146 entry->bytes_per_sample = 2;
12149 g_assert_not_reached ();
12152 entry->samples_per_frame = entry->n_channels;
12153 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12154 entry->samples_per_packet = entry->samples_per_frame;
12155 entry->bytes_per_packet = entry->bytes_per_sample;
12163 gst_caps_unref (entry->caps);
12165 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12166 stsd_entry_data + 32, len - 16, &codec);
12177 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12179 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12181 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12183 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12186 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12187 const gchar *format_str;
12191 format_str = (enda_value) ? "S24LE" : "S24BE";
12194 format_str = (enda_value) ? "S32LE" : "S32BE";
12197 format_str = (enda_value) ? "F32LE" : "F32BE";
12200 format_str = (enda_value) ? "F64LE" : "F64BE";
12203 g_assert_not_reached ();
12206 gst_caps_set_simple (entry->caps,
12207 "format", G_TYPE_STRING, format_str, NULL);
12213 const guint8 *owma_data;
12214 const gchar *codec_name = NULL;
12218 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12219 /* FIXME this should also be gst_riff_strf_auds,
12220 * but the latter one is actually missing bits-per-sample :( */
12225 gint32 nSamplesPerSec;
12226 gint32 nAvgBytesPerSec;
12227 gint16 nBlockAlign;
12228 gint16 wBitsPerSample;
12231 WAVEFORMATEX *wfex;
12233 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12234 owma_data = stsd_entry_data;
12235 owma_len = QT_UINT32 (owma_data);
12236 if (owma_len <= 54) {
12237 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12240 wfex = (WAVEFORMATEX *) (owma_data + 36);
12241 buf = gst_buffer_new_and_alloc (owma_len - 54);
12242 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12243 if (wfex->wFormatTag == 0x0161) {
12244 codec_name = "Windows Media Audio";
12246 } else if (wfex->wFormatTag == 0x0162) {
12247 codec_name = "Windows Media Audio 9 Pro";
12249 } else if (wfex->wFormatTag == 0x0163) {
12250 codec_name = "Windows Media Audio 9 Lossless";
12251 /* is that correct? gstffmpegcodecmap.c is missing it, but
12252 * fluendo codec seems to support it */
12256 gst_caps_set_simple (entry->caps,
12257 "codec_data", GST_TYPE_BUFFER, buf,
12258 "wmaversion", G_TYPE_INT, version,
12259 "block_align", G_TYPE_INT,
12260 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12261 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12262 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12263 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12264 gst_buffer_unref (buf);
12268 codec = g_strdup (codec_name);
12274 gint len = QT_UINT32 (stsd_entry_data) - offset;
12275 const guint8 *wfex_data = stsd_entry_data + offset;
12276 const gchar *codec_name = NULL;
12278 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12279 /* FIXME this should also be gst_riff_strf_auds,
12280 * but the latter one is actually missing bits-per-sample :( */
12285 gint32 nSamplesPerSec;
12286 gint32 nAvgBytesPerSec;
12287 gint16 nBlockAlign;
12288 gint16 wBitsPerSample;
12293 /* FIXME: unify with similar wavformatex parsing code above */
12294 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12300 if (QT_UINT32 (wfex_data) <= len)
12301 size = QT_UINT32 (wfex_data) - 8;
12306 /* No real data, so break out */
12309 switch (QT_FOURCC (wfex_data + 4)) {
12310 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12312 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12317 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12318 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12319 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12320 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12321 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12322 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12323 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12325 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12326 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12327 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12328 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12329 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12330 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12332 if (wfex.wFormatTag == 0x0161) {
12333 codec_name = "Windows Media Audio";
12335 } else if (wfex.wFormatTag == 0x0162) {
12336 codec_name = "Windows Media Audio 9 Pro";
12338 } else if (wfex.wFormatTag == 0x0163) {
12339 codec_name = "Windows Media Audio 9 Lossless";
12340 /* is that correct? gstffmpegcodecmap.c is missing it, but
12341 * fluendo codec seems to support it */
12345 gst_caps_set_simple (entry->caps,
12346 "wmaversion", G_TYPE_INT, version,
12347 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12348 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12349 "width", G_TYPE_INT, wfex.wBitsPerSample,
12350 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12352 if (size > wfex.cbSize) {
12355 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12356 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12357 size - wfex.cbSize);
12358 gst_caps_set_simple (entry->caps,
12359 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12360 gst_buffer_unref (buf);
12362 GST_WARNING_OBJECT (qtdemux, "no codec data");
12367 codec = g_strdup (codec_name);
12375 wfex_data += size + 8;
12381 const guint8 *opus_data;
12382 guint8 *channel_mapping = NULL;
12385 guint8 channel_mapping_family;
12386 guint8 stream_count;
12387 guint8 coupled_count;
12390 opus_data = stsd_entry_data;
12392 channels = GST_READ_UINT8 (opus_data + 45);
12393 rate = GST_READ_UINT32_LE (opus_data + 48);
12394 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
12395 stream_count = GST_READ_UINT8 (opus_data + 55);
12396 coupled_count = GST_READ_UINT8 (opus_data + 56);
12398 if (channels > 0) {
12399 channel_mapping = g_malloc (channels * sizeof (guint8));
12400 for (i = 0; i < channels; i++)
12401 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
12404 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12405 channel_mapping_family, stream_count, coupled_count,
12417 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12418 GST_TAG_AUDIO_CODEC, codec, NULL);
12422 /* some bitrate info may have ended up in caps */
12423 s = gst_caps_get_structure (entry->caps, 0);
12424 gst_structure_get_int (s, "bitrate", &bitrate);
12426 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12427 GST_TAG_BITRATE, bitrate, NULL);
12431 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12432 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12433 if (stream->protected) {
12434 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12435 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12437 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12447 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12449 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12451 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12455 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12456 16 bits is a byte-swapped wave-style codec identifier,
12457 and we can find a WAVE header internally to a 'wave' atom here.
12458 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12459 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12462 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12463 if (len < offset + 20) {
12464 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12466 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12467 const guint8 *data = stsd_entry_data + offset + 16;
12469 GNode *waveheadernode;
12471 wavenode = g_node_new ((guint8 *) data);
12472 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12473 const guint8 *waveheader;
12476 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12477 if (waveheadernode) {
12478 waveheader = (const guint8 *) waveheadernode->data;
12479 headerlen = QT_UINT32 (waveheader);
12481 if (headerlen > 8) {
12482 gst_riff_strf_auds *header = NULL;
12483 GstBuffer *headerbuf;
12489 headerbuf = gst_buffer_new_and_alloc (headerlen);
12490 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12492 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12493 headerbuf, &header, &extra)) {
12494 gst_caps_unref (entry->caps);
12495 /* FIXME: Need to do something with the channel reorder map */
12497 gst_riff_create_audio_caps (header->format, NULL, header,
12498 extra, NULL, NULL, NULL);
12501 gst_buffer_unref (extra);
12506 GST_DEBUG ("Didn't find waveheadernode for this codec");
12508 g_node_destroy (wavenode);
12511 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12512 stream->stream_tags);
12516 /* FIXME: what is in the chunk? */
12519 gint len = QT_UINT32 (stsd_data);
12521 /* seems to be always = 116 = 0x74 */
12527 gint len = QT_UINT32 (stsd_entry_data);
12530 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12532 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12533 gst_caps_set_simple (entry->caps,
12534 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12535 gst_buffer_unref (buf);
12537 gst_caps_set_simple (entry->caps,
12538 "samplesize", G_TYPE_INT, samplesize, NULL);
12543 GNode *alac, *wave = NULL;
12545 /* apparently, m4a has this atom appended directly in the stsd entry,
12546 * while mov has it in a wave atom */
12547 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12549 /* alac now refers to stsd entry atom */
12550 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12552 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12554 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12557 const guint8 *alac_data = alac->data;
12558 gint len = QT_UINT32 (alac->data);
12562 GST_DEBUG_OBJECT (qtdemux,
12563 "discarding alac atom with unexpected len %d", len);
12565 /* codec-data contains alac atom size and prefix,
12566 * ffmpeg likes it that way, not quite gst-ish though ...*/
12567 buf = gst_buffer_new_and_alloc (len);
12568 gst_buffer_fill (buf, 0, alac->data, len);
12569 gst_caps_set_simple (entry->caps,
12570 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12571 gst_buffer_unref (buf);
12573 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12574 entry->n_channels = QT_UINT8 (alac_data + 21);
12575 entry->rate = QT_UINT32 (alac_data + 32);
12576 samplesize = QT_UINT8 (alac_data + 16 + 1);
12579 gst_caps_set_simple (entry->caps,
12580 "samplesize", G_TYPE_INT, samplesize, NULL);
12585 /* The codingname of the sample entry is 'fLaC' */
12586 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12589 /* The 'dfLa' box is added to the sample entry to convey
12590 initializing information for the decoder. */
12591 const GNode *dfla =
12592 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12595 const guint32 len = QT_UINT32 (dfla->data);
12597 /* Must contain at least dfLa box header (12),
12598 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12600 GST_DEBUG_OBJECT (qtdemux,
12601 "discarding dfla atom with unexpected len %d", len);
12603 /* skip dfLa header to get the METADATA_BLOCKs */
12604 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12605 const guint32 metadata_blocks_len = len - 12;
12607 gchar *stream_marker = g_strdup ("fLaC");
12608 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12609 strlen (stream_marker));
12612 guint32 remainder = 0;
12613 guint32 block_size = 0;
12614 gboolean is_last = FALSE;
12616 GValue array = G_VALUE_INIT;
12617 GValue value = G_VALUE_INIT;
12619 g_value_init (&array, GST_TYPE_ARRAY);
12620 g_value_init (&value, GST_TYPE_BUFFER);
12622 gst_value_set_buffer (&value, block);
12623 gst_value_array_append_value (&array, &value);
12624 g_value_reset (&value);
12626 gst_buffer_unref (block);
12628 /* check there's at least one METADATA_BLOCK_HEADER's worth
12629 * of data, and we haven't already finished parsing */
12630 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12631 remainder = metadata_blocks_len - index;
12633 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12635 (metadata_blocks[index + 1] << 16) +
12636 (metadata_blocks[index + 2] << 8) +
12637 metadata_blocks[index + 3];
12639 /* be careful not to read off end of box */
12640 if (block_size > remainder) {
12644 is_last = metadata_blocks[index] >> 7;
12646 block = gst_buffer_new_and_alloc (block_size);
12648 gst_buffer_fill (block, 0, &metadata_blocks[index],
12651 gst_value_set_buffer (&value, block);
12652 gst_value_array_append_value (&array, &value);
12653 g_value_reset (&value);
12655 gst_buffer_unref (block);
12657 index += block_size;
12660 /* only append the metadata if we successfully read all of it */
12662 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12663 (stream)->caps, 0), "streamheader", &array);
12665 GST_WARNING_OBJECT (qtdemux,
12666 "discarding all METADATA_BLOCKs due to invalid "
12667 "block_size %d at idx %d, rem %d", block_size, index,
12671 g_value_unset (&value);
12672 g_value_unset (&array);
12674 /* The sample rate obtained from the stsd may not be accurate
12675 * since it cannot represent rates greater than 65535Hz, so
12676 * override that value with the sample rate from the
12677 * METADATA_BLOCK_STREAMINFO block */
12678 CUR_STREAM (stream)->rate =
12679 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12690 gint len = QT_UINT32 (stsd_entry_data);
12693 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12696 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12698 /* If we have enough data, let's try to get the 'damr' atom. See
12699 * the 3GPP container spec (26.244) for more details. */
12700 if ((len - 0x34) > 8 &&
12701 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12702 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12703 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12706 gst_caps_set_simple (entry->caps,
12707 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12708 gst_buffer_unref (buf);
12714 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12715 gint len = QT_UINT32 (stsd_entry_data);
12718 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
12720 if (sound_version == 1) {
12721 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
12722 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
12723 guint8 codec_data[2];
12725 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
12727 gint sample_rate_index =
12728 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12730 /* build AAC codec data */
12731 codec_data[0] = profile << 3;
12732 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12733 codec_data[1] = (sample_rate_index & 0x01) << 7;
12734 codec_data[1] |= (channels & 0xF) << 3;
12736 buf = gst_buffer_new_and_alloc (2);
12737 gst_buffer_fill (buf, 0, codec_data, 2);
12738 gst_caps_set_simple (entry->caps,
12739 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12740 gst_buffer_unref (buf);
12751 /* Fully handled elsewhere */
12754 GST_INFO_OBJECT (qtdemux,
12755 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12759 GST_INFO_OBJECT (qtdemux,
12760 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12761 GST_FOURCC_ARGS (fourcc), entry->caps);
12763 } else if (stream->subtype == FOURCC_strm) {
12764 if (fourcc == FOURCC_rtsp) {
12765 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12767 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12768 GST_FOURCC_ARGS (fourcc));
12769 goto unknown_stream;
12771 entry->sampled = TRUE;
12772 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12773 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12774 || stream->subtype == FOURCC_clcp) {
12776 entry->sampled = TRUE;
12777 entry->sparse = TRUE;
12780 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12783 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12784 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12789 /* hunt for sort-of codec data */
12793 GNode *mp4s = NULL;
12794 GNode *esds = NULL;
12796 /* look for palette in a stsd->mp4s->esds sub-atom */
12797 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12799 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12800 if (esds == NULL) {
12802 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12806 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12807 stream->stream_tags);
12811 GST_INFO_OBJECT (qtdemux,
12812 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12815 GST_INFO_OBJECT (qtdemux,
12816 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12817 GST_FOURCC_ARGS (fourcc), entry->caps);
12819 /* everything in 1 sample */
12820 entry->sampled = TRUE;
12823 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12826 if (entry->caps == NULL)
12827 goto unknown_stream;
12830 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12831 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12837 /* promote to sampled format */
12838 if (entry->fourcc == FOURCC_samr) {
12839 /* force mono 8000 Hz for AMR */
12840 entry->sampled = TRUE;
12841 entry->n_channels = 1;
12842 entry->rate = 8000;
12843 } else if (entry->fourcc == FOURCC_sawb) {
12844 /* force mono 16000 Hz for AMR-WB */
12845 entry->sampled = TRUE;
12846 entry->n_channels = 1;
12847 entry->rate = 16000;
12848 } else if (entry->fourcc == FOURCC_mp4a) {
12849 entry->sampled = TRUE;
12853 stsd_entry_data += len;
12854 remaining_stsd_len -= len;
12858 /* collect sample information */
12859 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12860 goto samples_failed;
12862 if (qtdemux->fragmented) {
12865 /* need all moov samples as basis; probably not many if any at all */
12866 /* prevent moof parsing taking of at this time */
12867 offset = qtdemux->moof_offset;
12868 qtdemux->moof_offset = 0;
12869 if (stream->n_samples &&
12870 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12871 qtdemux->moof_offset = offset;
12872 goto samples_failed;
12874 qtdemux->moof_offset = offset;
12875 /* movie duration more reliable in this case (e.g. mehd) */
12876 if (qtdemux->segment.duration &&
12877 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12879 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12882 /* configure segments */
12883 if (!qtdemux_parse_segments (qtdemux, stream, trak))
12884 goto segments_failed;
12886 /* add some language tag, if useful */
12887 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12888 strcmp (stream->lang_id, "und")) {
12889 const gchar *lang_code;
12891 /* convert ISO 639-2 code to ISO 639-1 */
12892 lang_code = gst_tag_get_language_code (stream->lang_id);
12893 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12894 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12897 /* Check for UDTA tags */
12898 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12899 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12902 /* Insert and sort new stream in track-id order.
12903 * This will help in comparing old/new streams during stream update check */
12904 g_ptr_array_add (qtdemux->active_streams, stream);
12905 g_ptr_array_sort (qtdemux->active_streams,
12906 (GCompareFunc) qtdemux_track_id_compare_func);
12907 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
12908 QTDEMUX_N_STREAMS (qtdemux));
12915 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12916 (_("This file is corrupt and cannot be played.")), (NULL));
12918 gst_qtdemux_stream_unref (stream);
12923 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12924 gst_qtdemux_stream_unref (stream);
12930 /* we posted an error already */
12931 /* free stbl sub-atoms */
12932 gst_qtdemux_stbl_free (stream);
12933 gst_qtdemux_stream_unref (stream);
12938 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
12944 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
12945 GST_FOURCC_ARGS (stream->subtype));
12946 gst_qtdemux_stream_unref (stream);
12951 /* If we can estimate the overall bitrate, and don't have information about the
12952 * stream bitrate for exactly one stream, this guesses the stream bitrate as
12953 * the overall bitrate minus the sum of the bitrates of all other streams. This
12954 * should be useful for the common case where we have one audio and one video
12955 * stream and can estimate the bitrate of one, but not the other. */
12957 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
12959 QtDemuxStream *stream = NULL;
12960 gint64 size, sys_bitrate, sum_bitrate = 0;
12961 GstClockTime duration;
12965 if (qtdemux->fragmented)
12968 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
12970 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
12972 GST_DEBUG_OBJECT (qtdemux,
12973 "Size in bytes of the stream not known - bailing");
12977 /* Subtract the header size */
12978 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
12979 size, qtdemux->header_size);
12981 if (size < qtdemux->header_size)
12984 size = size - qtdemux->header_size;
12986 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
12987 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
12991 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12992 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
12993 switch (str->subtype) {
12996 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
12997 CUR_STREAM (str)->caps);
12998 /* retrieve bitrate, prefer avg then max */
13000 if (str->stream_tags) {
13001 if (gst_tag_list_get_uint (str->stream_tags,
13002 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13003 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13004 if (gst_tag_list_get_uint (str->stream_tags,
13005 GST_TAG_NOMINAL_BITRATE, &bitrate))
13006 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13007 if (gst_tag_list_get_uint (str->stream_tags,
13008 GST_TAG_BITRATE, &bitrate))
13009 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13012 sum_bitrate += bitrate;
13015 GST_DEBUG_OBJECT (qtdemux,
13016 ">1 stream with unknown bitrate - bailing");
13023 /* For other subtypes, we assume no significant impact on bitrate */
13029 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13033 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13035 if (sys_bitrate < sum_bitrate) {
13036 /* This can happen, since sum_bitrate might be derived from maximum
13037 * bitrates and not average bitrates */
13038 GST_DEBUG_OBJECT (qtdemux,
13039 "System bitrate less than sum bitrate - bailing");
13043 bitrate = sys_bitrate - sum_bitrate;
13044 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13045 ", Stream bitrate = %u", sys_bitrate, bitrate);
13047 if (!stream->stream_tags)
13048 stream->stream_tags = gst_tag_list_new_empty ();
13050 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13052 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13053 GST_TAG_BITRATE, bitrate, NULL);
13056 static GstFlowReturn
13057 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13059 GstFlowReturn ret = GST_FLOW_OK;
13062 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13064 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13065 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13066 guint32 sample_num = 0;
13068 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13069 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13071 if (qtdemux->fragmented && qtdemux->pullbased) {
13072 /* need all moov samples first */
13073 GST_OBJECT_LOCK (qtdemux);
13074 while (stream->n_samples == 0)
13075 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13077 GST_OBJECT_UNLOCK (qtdemux);
13079 /* discard any stray moof */
13080 qtdemux->moof_offset = 0;
13083 /* prepare braking */
13084 if (ret != GST_FLOW_ERROR)
13087 /* in pull mode, we should have parsed some sample info by now;
13088 * and quite some code will not handle no samples.
13089 * in push mode, we'll just have to deal with it */
13090 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13091 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13092 g_ptr_array_remove_index (qtdemux->active_streams, i);
13095 } else if (stream->track_id == qtdemux->chapters_track_id &&
13096 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13097 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13098 so that it doesn't look like a subtitle track */
13099 g_ptr_array_remove_index (qtdemux->active_streams, i);
13104 /* parse the initial sample for use in setting the frame rate cap */
13105 while (sample_num == 0 && sample_num < stream->n_samples) {
13106 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13116 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13118 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13122 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13126 /* Different length, updated */
13127 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13130 /* streams in list are sorted in track-id order */
13131 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13132 /* Different stream-id, updated */
13133 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13134 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13142 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13143 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13145 /* Connect old stream's srcpad to new stream */
13146 newstream->pad = oldstream->pad;
13147 oldstream->pad = NULL;
13149 /* unset new_stream to prevent stream-start event */
13150 newstream->new_stream = FALSE;
13152 return gst_qtdemux_configure_stream (qtdemux, newstream);
13156 qtdemux_update_streams (GstQTDemux * qtdemux)
13159 g_assert (qtdemux->streams_aware);
13161 /* At below, figure out which stream in active_streams has identical stream-id
13162 * with that of in old_streams. If there is matching stream-id,
13163 * corresponding newstream will not be exposed again,
13164 * but demux will reuse srcpad of matched old stream
13166 * active_streams : newly created streams from the latest moov
13167 * old_streams : existing streams (belong to previous moov)
13170 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13171 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13172 QtDemuxStream *oldstream = NULL;
13175 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13176 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13178 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13179 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13180 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13182 /* null pad stream cannot be reused */
13183 if (oldstream->pad == NULL)
13188 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13190 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13193 /* we don't need to preserve order of old streams */
13194 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13198 /* now we have all info and can expose */
13199 list = stream->stream_tags;
13200 stream->stream_tags = NULL;
13201 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13209 /* Must be called with expose lock */
13210 static GstFlowReturn
13211 qtdemux_expose_streams (GstQTDemux * qtdemux)
13215 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13217 if (!qtdemux_is_streams_update (qtdemux)) {
13218 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13219 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13220 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13221 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13222 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13223 return GST_FLOW_ERROR;
13226 g_ptr_array_set_size (qtdemux->old_streams, 0);
13227 qtdemux->need_segment = TRUE;
13229 return GST_FLOW_OK;
13232 if (qtdemux->streams_aware) {
13233 if (!qtdemux_update_streams (qtdemux))
13234 return GST_FLOW_ERROR;
13236 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13237 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13240 /* now we have all info and can expose */
13241 list = stream->stream_tags;
13242 stream->stream_tags = NULL;
13243 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13244 return GST_FLOW_ERROR;
13249 gst_qtdemux_guess_bitrate (qtdemux);
13251 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13253 /* If we have still old_streams, it's no more used stream */
13254 for (i = 0; i < qtdemux->old_streams->len; i++) {
13255 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13260 event = gst_event_new_eos ();
13261 if (qtdemux->segment_seqnum)
13262 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13264 gst_pad_push_event (stream->pad, event);
13268 g_ptr_array_set_size (qtdemux->old_streams, 0);
13270 /* check if we should post a redirect in case there is a single trak
13271 * and it is a redirecting trak */
13272 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13273 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13276 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13277 "an external content");
13278 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13279 gst_structure_new ("redirect",
13280 "new-location", G_TYPE_STRING,
13281 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13282 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13283 g_free (qtdemux->redirect_location);
13284 qtdemux->redirect_location =
13285 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13288 g_ptr_array_foreach (qtdemux->active_streams,
13289 (GFunc) qtdemux_do_allocation, qtdemux);
13291 qtdemux->need_segment = TRUE;
13293 qtdemux->exposed = TRUE;
13294 return GST_FLOW_OK;
13299 GstStructure *structure; /* helper for sort function */
13301 guint min_req_bitrate;
13302 guint min_req_qt_version;
13306 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13308 GstQtReference *ref_a = (GstQtReference *) a;
13309 GstQtReference *ref_b = (GstQtReference *) b;
13311 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13312 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13314 /* known bitrates go before unknown; higher bitrates go first */
13315 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13318 /* sort the redirects and post a message for the application.
13321 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13323 GstQtReference *best;
13326 GValue list_val = { 0, };
13329 g_assert (references != NULL);
13331 references = g_list_sort (references, qtdemux_redirects_sort_func);
13333 best = (GstQtReference *) references->data;
13335 g_value_init (&list_val, GST_TYPE_LIST);
13337 for (l = references; l != NULL; l = l->next) {
13338 GstQtReference *ref = (GstQtReference *) l->data;
13339 GValue struct_val = { 0, };
13341 ref->structure = gst_structure_new ("redirect",
13342 "new-location", G_TYPE_STRING, ref->location, NULL);
13344 if (ref->min_req_bitrate > 0) {
13345 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13346 ref->min_req_bitrate, NULL);
13349 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13350 g_value_set_boxed (&struct_val, ref->structure);
13351 gst_value_list_append_value (&list_val, &struct_val);
13352 g_value_unset (&struct_val);
13353 /* don't free anything here yet, since we need best->structure below */
13356 g_assert (best != NULL);
13357 s = gst_structure_copy (best->structure);
13359 if (g_list_length (references) > 1) {
13360 gst_structure_set_value (s, "locations", &list_val);
13363 g_value_unset (&list_val);
13365 for (l = references; l != NULL; l = l->next) {
13366 GstQtReference *ref = (GstQtReference *) l->data;
13368 gst_structure_free (ref->structure);
13369 g_free (ref->location);
13372 g_list_free (references);
13374 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13375 g_free (qtdemux->redirect_location);
13376 qtdemux->redirect_location =
13377 g_strdup (gst_structure_get_string (s, "new-location"));
13378 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13379 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13382 /* look for redirect nodes, collect all redirect information and
13386 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13388 GNode *rmra, *rmda, *rdrf;
13390 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13392 GList *redirects = NULL;
13394 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13396 GstQtReference ref = { NULL, NULL, 0, 0 };
13397 GNode *rmdr, *rmvc;
13399 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13400 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13401 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13402 ref.min_req_bitrate);
13405 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13406 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13407 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13409 #ifndef GST_DISABLE_GST_DEBUG
13410 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13412 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13414 GST_LOG_OBJECT (qtdemux,
13415 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13416 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13417 bitmask, check_type);
13418 if (package == FOURCC_qtim && check_type == 0) {
13419 ref.min_req_qt_version = version;
13423 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13429 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13430 if (ref_len > 20) {
13431 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13432 ref_data = (guint8 *) rdrf->data + 20;
13433 if (ref_type == FOURCC_alis) {
13434 guint record_len, record_version, fn_len;
13436 if (ref_len > 70) {
13437 /* MacOSX alias record, google for alias-layout.txt */
13438 record_len = QT_UINT16 (ref_data + 4);
13439 record_version = QT_UINT16 (ref_data + 4 + 2);
13440 fn_len = QT_UINT8 (ref_data + 50);
13441 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13442 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13445 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13448 } else if (ref_type == FOURCC_url_) {
13449 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13451 GST_DEBUG_OBJECT (qtdemux,
13452 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13453 GST_FOURCC_ARGS (ref_type));
13455 if (ref.location != NULL) {
13456 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13458 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13460 GST_WARNING_OBJECT (qtdemux,
13461 "Failed to extract redirect location from rdrf atom");
13464 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13468 /* look for others */
13469 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13472 if (redirects != NULL) {
13473 qtdemux_process_redirects (qtdemux, redirects);
13479 static GstTagList *
13480 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13484 if (tags == NULL) {
13485 tags = gst_tag_list_new_empty ();
13486 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13489 if (qtdemux->major_brand == FOURCC_mjp2)
13490 fmt = "Motion JPEG 2000";
13491 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13493 else if (qtdemux->major_brand == FOURCC_qt__)
13495 else if (qtdemux->fragmented)
13498 fmt = "ISO MP4/M4A";
13500 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13501 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13503 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13509 /* we have read the complete moov node now.
13510 * This function parses all of the relevant info, creates the traks and
13511 * prepares all data structures for playback
13514 qtdemux_parse_tree (GstQTDemux * qtdemux)
13521 guint64 creation_time;
13522 GstDateTime *datetime = NULL;
13525 /* make sure we have a usable taglist */
13526 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13528 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13529 if (mvhd == NULL) {
13530 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13531 return qtdemux_parse_redirects (qtdemux);
13534 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13535 if (version == 1) {
13536 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13537 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13538 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13539 } else if (version == 0) {
13540 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13541 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13542 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13544 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13548 /* Moving qt creation time (secs since 1904) to unix time */
13549 if (creation_time != 0) {
13550 /* Try to use epoch first as it should be faster and more commonly found */
13551 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13554 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13555 /* some data cleansing sanity */
13556 now_s = g_get_real_time () / G_USEC_PER_SEC;
13557 if (now_s + 24 * 3600 < creation_time) {
13558 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13560 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13563 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13564 GDateTime *dt, *dt_local;
13566 dt = g_date_time_add_seconds (base_dt, creation_time);
13567 dt_local = g_date_time_to_local (dt);
13568 datetime = gst_date_time_new_from_g_date_time (dt_local);
13570 g_date_time_unref (base_dt);
13571 g_date_time_unref (dt);
13575 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13576 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13578 gst_date_time_unref (datetime);
13581 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13582 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13584 /* check for fragmented file and get some (default) data */
13585 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13588 GstByteReader mehd_data;
13590 /* let track parsing or anyone know weird stuff might happen ... */
13591 qtdemux->fragmented = TRUE;
13593 /* compensate for total duration */
13594 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13596 qtdemux_parse_mehd (qtdemux, &mehd_data);
13599 /* Update the movie segment duration, unless it was directly given to us
13600 * by upstream. Otherwise let it as is, as we don't want to mangle the
13601 * duration provided by upstream that may come e.g. from a MPD file. */
13602 if (!qtdemux->upstream_format_is_time) {
13603 GstClockTime duration;
13604 /* set duration in the segment info */
13605 gst_qtdemux_get_duration (qtdemux, &duration);
13606 qtdemux->segment.duration = duration;
13607 /* also do not exceed duration; stop is set that way post seek anyway,
13608 * and segment activation falls back to duration,
13609 * whereas loop only checks stop, so let's align this here as well */
13610 qtdemux->segment.stop = duration;
13613 /* parse all traks */
13614 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13616 qtdemux_parse_trak (qtdemux, trak);
13617 /* iterate all siblings */
13618 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13621 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13624 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13626 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13628 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13631 /* maybe also some tags in meta box */
13632 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13634 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13635 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13637 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13640 /* parse any protection system info */
13641 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13643 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13644 qtdemux_parse_pssh (qtdemux, pssh);
13645 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13648 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13653 /* taken from ffmpeg */
13655 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13667 len = (len << 7) | (c & 0x7f);
13676 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13677 gsize codec_data_size)
13679 GList *list = NULL;
13680 guint8 *p = codec_data;
13681 gint i, offset, num_packets;
13682 guint *length, last;
13684 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13686 if (codec_data == NULL || codec_data_size == 0)
13689 /* start of the stream and vorbis audio or theora video, need to
13690 * send the codec_priv data as first three packets */
13691 num_packets = p[0] + 1;
13692 GST_DEBUG_OBJECT (qtdemux,
13693 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13694 (guint) num_packets, codec_data_size);
13696 /* Let's put some limits, Don't think there even is a xiph codec
13697 * with more than 3-4 headers */
13698 if (G_UNLIKELY (num_packets > 16)) {
13699 GST_WARNING_OBJECT (qtdemux,
13700 "Unlikely number of xiph headers, most likely not valid");
13704 length = g_alloca (num_packets * sizeof (guint));
13708 /* first packets, read length values */
13709 for (i = 0; i < num_packets - 1; i++) {
13711 while (offset < codec_data_size) {
13712 length[i] += p[offset];
13713 if (p[offset++] != 0xff)
13718 if (offset + last > codec_data_size)
13721 /* last packet is the remaining size */
13722 length[i] = codec_data_size - offset - last;
13724 for (i = 0; i < num_packets; i++) {
13727 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
13729 if (offset + length[i] > codec_data_size)
13732 hdr = gst_buffer_new_memdup (p + offset, length[i]);
13733 list = g_list_append (list, hdr);
13735 offset += length[i];
13744 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
13750 /* this can change the codec originally present in @list */
13752 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13753 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13755 int len = QT_UINT32 (esds->data);
13756 guint8 *ptr = esds->data;
13757 guint8 *end = ptr + len;
13759 guint8 *data_ptr = NULL;
13761 guint8 object_type_id = 0;
13762 guint8 stream_type = 0;
13763 const char *codec_name = NULL;
13764 GstCaps *caps = NULL;
13766 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13768 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13770 while (ptr + 1 < end) {
13771 tag = QT_UINT8 (ptr);
13772 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13774 len = read_descr_size (ptr, end, &ptr);
13775 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13777 /* Check the stated amount of data is available for reading */
13778 if (len < 0 || ptr + len > end)
13782 case ES_DESCRIPTOR_TAG:
13783 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
13784 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
13787 case DECODER_CONFIG_DESC_TAG:{
13788 guint max_bitrate, avg_bitrate;
13790 object_type_id = QT_UINT8 (ptr);
13791 stream_type = QT_UINT8 (ptr + 1) >> 2;
13792 max_bitrate = QT_UINT32 (ptr + 5);
13793 avg_bitrate = QT_UINT32 (ptr + 9);
13794 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13795 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
13796 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13797 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13798 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13799 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13800 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13801 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13803 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13804 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13805 avg_bitrate, NULL);
13810 case DECODER_SPECIFIC_INFO_TAG:
13811 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13812 if (object_type_id == 0xe0 && len == 0x40) {
13818 GST_DEBUG_OBJECT (qtdemux,
13819 "Have VOBSUB palette. Creating palette event");
13820 /* move to decConfigDescr data and read palette */
13822 for (i = 0; i < 16; i++) {
13823 clut[i] = QT_UINT32 (data);
13827 s = gst_structure_new ("application/x-gst-dvd", "event",
13828 G_TYPE_STRING, "dvd-spu-clut-change",
13829 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13830 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13831 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13832 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13833 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13834 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13835 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13836 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13839 /* store event and trigger custom processing */
13840 stream->pending_event =
13841 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13843 /* Generic codec_data handler puts it on the caps */
13850 case SL_CONFIG_DESC_TAG:
13851 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13855 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13857 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13863 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13864 * in use, and should also be used to override some other parameters for some
13866 switch (object_type_id) {
13867 case 0x20: /* MPEG-4 */
13868 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13869 * profile_and_level_indication */
13870 if (data_ptr != NULL && data_len >= 5 &&
13871 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13872 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13873 data_ptr + 4, data_len - 4);
13875 break; /* Nothing special needed here */
13876 case 0x21: /* H.264 */
13877 codec_name = "H.264 / AVC";
13878 caps = gst_caps_new_simple ("video/x-h264",
13879 "stream-format", G_TYPE_STRING, "avc",
13880 "alignment", G_TYPE_STRING, "au", NULL);
13882 case 0x40: /* AAC (any) */
13883 case 0x66: /* AAC Main */
13884 case 0x67: /* AAC LC */
13885 case 0x68: /* AAC SSR */
13886 /* Override channels and rate based on the codec_data, as it's often
13888 /* Only do so for basic setup without HE-AAC extension */
13889 if (data_ptr && data_len == 2) {
13890 guint channels, rate;
13892 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13894 entry->n_channels = channels;
13896 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13898 entry->rate = rate;
13901 /* Set level and profile if possible */
13902 if (data_ptr != NULL && data_len >= 2) {
13903 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13904 data_ptr, data_len);
13906 const gchar *profile_str = NULL;
13909 guint8 *codec_data;
13910 gint rate_idx, profile;
13912 /* No codec_data, let's invent something.
13913 * FIXME: This is wrong for SBR! */
13915 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13917 buffer = gst_buffer_new_and_alloc (2);
13918 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13919 codec_data = map.data;
13922 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13925 switch (object_type_id) {
13927 profile_str = "main";
13931 profile_str = "lc";
13935 profile_str = "ssr";
13943 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13945 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13947 gst_buffer_unmap (buffer, &map);
13948 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13949 GST_TYPE_BUFFER, buffer, NULL);
13950 gst_buffer_unref (buffer);
13953 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13954 G_TYPE_STRING, profile_str, NULL);
13958 case 0x60: /* MPEG-2, various profiles */
13964 codec_name = "MPEG-2 video";
13965 caps = gst_caps_new_simple ("video/mpeg",
13966 "mpegversion", G_TYPE_INT, 2,
13967 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13969 case 0x69: /* MPEG-2 BC audio */
13970 case 0x6B: /* MPEG-1 audio */
13971 caps = gst_caps_new_simple ("audio/mpeg",
13972 "mpegversion", G_TYPE_INT, 1, NULL);
13973 codec_name = "MPEG-1 audio";
13975 case 0x6A: /* MPEG-1 */
13976 codec_name = "MPEG-1 video";
13977 caps = gst_caps_new_simple ("video/mpeg",
13978 "mpegversion", G_TYPE_INT, 1,
13979 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13981 case 0x6C: /* MJPEG */
13983 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13985 codec_name = "Motion-JPEG";
13987 case 0x6D: /* PNG */
13989 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13991 codec_name = "PNG still images";
13993 case 0x6E: /* JPEG2000 */
13994 codec_name = "JPEG-2000";
13995 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13997 case 0xA4: /* Dirac */
13998 codec_name = "Dirac";
13999 caps = gst_caps_new_empty_simple ("video/x-dirac");
14001 case 0xA5: /* AC3 */
14002 codec_name = "AC-3 audio";
14003 caps = gst_caps_new_simple ("audio/x-ac3",
14004 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14006 case 0xA9: /* AC3 */
14007 codec_name = "DTS audio";
14008 caps = gst_caps_new_simple ("audio/x-dts",
14009 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14012 if (stream_type == 0x05 && data_ptr) {
14014 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14017 GValue arr_val = G_VALUE_INIT;
14018 GValue buf_val = G_VALUE_INIT;
14021 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14022 codec_name = "Vorbis";
14023 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14024 g_value_init (&arr_val, GST_TYPE_ARRAY);
14025 g_value_init (&buf_val, GST_TYPE_BUFFER);
14026 for (tmp = headers; tmp; tmp = tmp->next) {
14027 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14028 gst_value_array_append_value (&arr_val, &buf_val);
14030 s = gst_caps_get_structure (caps, 0);
14031 gst_structure_take_value (s, "streamheader", &arr_val);
14032 g_value_unset (&buf_val);
14033 g_list_free (headers);
14040 case 0xE1: /* QCELP */
14041 /* QCELP, the codec_data is a riff tag (little endian) with
14042 * 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). */
14043 caps = gst_caps_new_empty_simple ("audio/qcelp");
14044 codec_name = "QCELP";
14050 /* If we have a replacement caps, then change our caps for this stream */
14052 gst_caps_unref (entry->caps);
14053 entry->caps = caps;
14056 if (codec_name && list)
14057 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14058 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14060 /* Add the codec_data attribute to caps, if we have it */
14064 buffer = gst_buffer_new_and_alloc (data_len);
14065 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14067 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14068 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14070 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14072 gst_buffer_unref (buffer);
14077 static inline GstCaps *
14078 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14082 char *s, fourstr[5];
14084 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14085 for (i = 0; i < 4; i++) {
14086 if (!g_ascii_isalnum (fourstr[i]))
14089 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14090 caps = gst_caps_new_empty_simple (s);
14095 #define _codec(name) \
14097 if (codec_name) { \
14098 *codec_name = g_strdup (name); \
14103 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14104 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14105 const guint8 * stsd_entry_data, gchar ** codec_name)
14107 GstCaps *caps = NULL;
14108 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14112 _codec ("PNG still images");
14113 caps = gst_caps_new_empty_simple ("image/png");
14116 _codec ("JPEG still images");
14118 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14121 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14122 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14123 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14124 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14125 _codec ("Motion-JPEG");
14127 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14130 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14131 _codec ("Motion-JPEG format B");
14132 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14135 _codec ("JPEG-2000");
14136 /* override to what it should be according to spec, avoid palette_data */
14137 entry->bits_per_sample = 24;
14138 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14141 _codec ("Sorensen video v.3");
14142 caps = gst_caps_new_simple ("video/x-svq",
14143 "svqversion", G_TYPE_INT, 3, NULL);
14145 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14146 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14147 _codec ("Sorensen video v.1");
14148 caps = gst_caps_new_simple ("video/x-svq",
14149 "svqversion", G_TYPE_INT, 1, NULL);
14151 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14152 caps = gst_caps_new_empty_simple ("video/x-raw");
14153 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14154 _codec ("Windows Raw RGB");
14155 stream->alignment = 32;
14161 bps = QT_UINT16 (stsd_entry_data + 82);
14164 format = GST_VIDEO_FORMAT_RGB15;
14167 format = GST_VIDEO_FORMAT_RGB16;
14170 format = GST_VIDEO_FORMAT_RGB;
14173 format = GST_VIDEO_FORMAT_ARGB;
14181 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14182 format = GST_VIDEO_FORMAT_I420;
14184 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14185 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14186 format = GST_VIDEO_FORMAT_I420;
14189 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14190 format = GST_VIDEO_FORMAT_UYVY;
14192 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14193 format = GST_VIDEO_FORMAT_v308;
14195 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14196 format = GST_VIDEO_FORMAT_v216;
14199 format = GST_VIDEO_FORMAT_v210;
14201 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14202 format = GST_VIDEO_FORMAT_r210;
14204 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14205 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14206 format = GST_VIDEO_FORMAT_v410;
14209 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14210 * but different order than AYUV
14211 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14212 format = GST_VIDEO_FORMAT_v408;
14215 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14216 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14217 _codec ("MPEG-1 video");
14218 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14219 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14221 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14222 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14223 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14224 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14225 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14226 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14227 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14228 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14229 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14230 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14231 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14232 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14233 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14234 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14235 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14236 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14237 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14238 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14239 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14240 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14241 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14242 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14243 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14244 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14245 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14246 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14247 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14248 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14249 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14250 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14251 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14252 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14253 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14254 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14255 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14256 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14257 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14258 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14259 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14260 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14261 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14262 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14263 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14264 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14265 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14266 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14267 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14268 _codec ("MPEG-2 video");
14269 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14270 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14272 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14273 _codec ("GIF still images");
14274 caps = gst_caps_new_empty_simple ("image/gif");
14277 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14279 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14281 /* ffmpeg uses the height/width props, don't know why */
14282 caps = gst_caps_new_simple ("video/x-h263",
14283 "variant", G_TYPE_STRING, "itu", NULL);
14287 _codec ("MPEG-4 video");
14288 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14289 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14291 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14292 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14293 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14294 caps = gst_caps_new_simple ("video/x-msmpeg",
14295 "msmpegversion", G_TYPE_INT, 43, NULL);
14297 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14299 caps = gst_caps_new_simple ("video/x-divx",
14300 "divxversion", G_TYPE_INT, 3, NULL);
14302 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14303 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14305 caps = gst_caps_new_simple ("video/x-divx",
14306 "divxversion", G_TYPE_INT, 4, NULL);
14308 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14310 caps = gst_caps_new_simple ("video/x-divx",
14311 "divxversion", G_TYPE_INT, 5, NULL);
14314 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14316 caps = gst_caps_new_simple ("video/x-ffv",
14317 "ffvversion", G_TYPE_INT, 1, NULL);
14320 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14321 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14326 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14327 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14328 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14332 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14333 _codec ("Cinepak");
14334 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14336 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14337 _codec ("Apple QuickDraw");
14338 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14340 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14341 _codec ("Apple video");
14342 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14347 _codec ("H.264 / AVC");
14348 caps = gst_caps_new_simple ("video/x-h264",
14349 "stream-format", G_TYPE_STRING, "avc",
14350 "alignment", G_TYPE_STRING, "au", NULL);
14354 _codec ("H.264 / AVC");
14355 caps = gst_caps_new_simple ("video/x-h264",
14356 "stream-format", G_TYPE_STRING, "avc3",
14357 "alignment", G_TYPE_STRING, "au", NULL);
14362 _codec ("H.265 / HEVC");
14363 caps = gst_caps_new_simple ("video/x-h265",
14364 "stream-format", G_TYPE_STRING, "hvc1",
14365 "alignment", G_TYPE_STRING, "au", NULL);
14369 _codec ("H.265 / HEVC");
14370 caps = gst_caps_new_simple ("video/x-h265",
14371 "stream-format", G_TYPE_STRING, "hev1",
14372 "alignment", G_TYPE_STRING, "au", NULL);
14375 _codec ("Run-length encoding");
14376 caps = gst_caps_new_simple ("video/x-rle",
14377 "layout", G_TYPE_STRING, "quicktime", NULL);
14380 _codec ("Run-length encoding");
14381 caps = gst_caps_new_simple ("video/x-rle",
14382 "layout", G_TYPE_STRING, "microsoft", NULL);
14384 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14385 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14386 _codec ("Indeo Video 3");
14387 caps = gst_caps_new_simple ("video/x-indeo",
14388 "indeoversion", G_TYPE_INT, 3, NULL);
14390 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14391 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14392 _codec ("Intel Video 4");
14393 caps = gst_caps_new_simple ("video/x-indeo",
14394 "indeoversion", G_TYPE_INT, 4, NULL);
14398 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14399 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14400 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14401 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14402 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14403 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14404 _codec ("DV Video");
14405 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14406 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14408 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14409 case FOURCC_dv5p: /* DVCPRO50 PAL */
14410 _codec ("DVCPro50 Video");
14411 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14412 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14414 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14415 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14416 _codec ("DVCProHD Video");
14417 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14418 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14420 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14421 _codec ("Apple Graphics (SMC)");
14422 caps = gst_caps_new_empty_simple ("video/x-smc");
14424 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14426 caps = gst_caps_new_empty_simple ("video/x-vp3");
14428 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14429 _codec ("VP6 Flash");
14430 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14434 caps = gst_caps_new_empty_simple ("video/x-theora");
14435 /* theora uses one byte of padding in the data stream because it does not
14436 * allow 0 sized packets while theora does */
14437 entry->padding = 1;
14441 caps = gst_caps_new_empty_simple ("video/x-dirac");
14443 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14444 _codec ("TIFF still images");
14445 caps = gst_caps_new_empty_simple ("image/tiff");
14447 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14448 _codec ("Apple Intermediate Codec");
14449 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14451 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14452 _codec ("AVID DNxHD");
14453 caps = gst_caps_from_string ("video/x-dnxhd");
14457 _codec ("On2 VP8");
14458 caps = gst_caps_from_string ("video/x-vp8");
14461 _codec ("Google VP9");
14462 caps = gst_caps_from_string ("video/x-vp9");
14465 _codec ("Apple ProRes LT");
14467 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14471 _codec ("Apple ProRes HQ");
14473 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14477 _codec ("Apple ProRes");
14479 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14483 _codec ("Apple ProRes Proxy");
14485 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14489 _codec ("Apple ProRes 4444");
14491 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14495 _codec ("Apple ProRes 4444 XQ");
14497 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14501 _codec ("GoPro CineForm");
14502 caps = gst_caps_from_string ("video/x-cineform");
14507 caps = gst_caps_new_simple ("video/x-wmv",
14508 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14512 caps = gst_caps_new_empty_simple ("video/x-av1");
14514 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14517 caps = _get_unknown_codec_name ("video", fourcc);
14522 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14525 gst_video_info_init (&info);
14526 gst_video_info_set_format (&info, format, entry->width, entry->height);
14528 caps = gst_video_info_to_caps (&info);
14529 *codec_name = gst_pb_utils_get_codec_description (caps);
14531 /* enable clipping for raw video streams */
14532 stream->need_clip = TRUE;
14533 stream->alignment = 32;
14540 round_up_pow2 (guint n)
14552 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14553 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14554 int len, gchar ** codec_name)
14557 const GstStructure *s;
14560 GstAudioFormat format = 0;
14563 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14565 depth = entry->bytes_per_packet * 8;
14568 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14570 /* 8-bit audio is unsigned */
14572 format = GST_AUDIO_FORMAT_U8;
14573 /* otherwise it's signed and big-endian just like 'twos' */
14575 endian = G_BIG_ENDIAN;
14582 endian = G_LITTLE_ENDIAN;
14585 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14587 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14591 caps = gst_caps_new_simple ("audio/x-raw",
14592 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14593 "layout", G_TYPE_STRING, "interleaved", NULL);
14594 stream->alignment = GST_ROUND_UP_8 (depth);
14595 stream->alignment = round_up_pow2 (stream->alignment);
14599 _codec ("Raw 64-bit floating-point audio");
14600 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14602 caps = gst_caps_new_simple ("audio/x-raw",
14603 "format", G_TYPE_STRING, "F64BE",
14604 "layout", G_TYPE_STRING, "interleaved", NULL);
14605 stream->alignment = 8;
14608 _codec ("Raw 32-bit floating-point audio");
14609 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14611 caps = gst_caps_new_simple ("audio/x-raw",
14612 "format", G_TYPE_STRING, "F32BE",
14613 "layout", G_TYPE_STRING, "interleaved", NULL);
14614 stream->alignment = 4;
14617 _codec ("Raw 24-bit PCM audio");
14618 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14620 caps = gst_caps_new_simple ("audio/x-raw",
14621 "format", G_TYPE_STRING, "S24BE",
14622 "layout", G_TYPE_STRING, "interleaved", NULL);
14623 stream->alignment = 4;
14626 _codec ("Raw 32-bit PCM audio");
14627 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14629 caps = gst_caps_new_simple ("audio/x-raw",
14630 "format", G_TYPE_STRING, "S32BE",
14631 "layout", G_TYPE_STRING, "interleaved", NULL);
14632 stream->alignment = 4;
14635 _codec ("Raw 16-bit PCM audio");
14636 caps = gst_caps_new_simple ("audio/x-raw",
14637 "format", G_TYPE_STRING, "S16LE",
14638 "layout", G_TYPE_STRING, "interleaved", NULL);
14639 stream->alignment = 2;
14642 _codec ("Mu-law audio");
14643 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14646 _codec ("A-law audio");
14647 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14651 _codec ("Microsoft ADPCM");
14652 /* Microsoft ADPCM-ACM code 2 */
14653 caps = gst_caps_new_simple ("audio/x-adpcm",
14654 "layout", G_TYPE_STRING, "microsoft", NULL);
14658 _codec ("DVI/IMA ADPCM");
14659 caps = gst_caps_new_simple ("audio/x-adpcm",
14660 "layout", G_TYPE_STRING, "dvi", NULL);
14664 _codec ("DVI/Intel IMA ADPCM");
14665 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14666 caps = gst_caps_new_simple ("audio/x-adpcm",
14667 "layout", G_TYPE_STRING, "quicktime", NULL);
14671 /* MPEG layer 3, CBR only (pre QT4.1) */
14674 _codec ("MPEG-1 layer 3");
14675 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14676 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14677 "mpegversion", G_TYPE_INT, 1, NULL);
14679 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14680 _codec ("MPEG-1 layer 2");
14682 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14683 "mpegversion", G_TYPE_INT, 1, NULL);
14686 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14687 _codec ("EAC-3 audio");
14688 caps = gst_caps_new_simple ("audio/x-eac3",
14689 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14690 entry->sampled = TRUE;
14692 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14694 _codec ("AC-3 audio");
14695 caps = gst_caps_new_simple ("audio/x-ac3",
14696 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14697 entry->sampled = TRUE;
14699 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14700 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14701 _codec ("DTS audio");
14702 caps = gst_caps_new_simple ("audio/x-dts",
14703 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14704 entry->sampled = TRUE;
14706 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14707 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14708 _codec ("DTS-HD audio");
14709 caps = gst_caps_new_simple ("audio/x-dts",
14710 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14711 entry->sampled = TRUE;
14715 caps = gst_caps_new_simple ("audio/x-mace",
14716 "maceversion", G_TYPE_INT, 3, NULL);
14720 caps = gst_caps_new_simple ("audio/x-mace",
14721 "maceversion", G_TYPE_INT, 6, NULL);
14723 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14725 caps = gst_caps_new_empty_simple ("application/ogg");
14727 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14728 _codec ("DV audio");
14729 caps = gst_caps_new_empty_simple ("audio/x-dv");
14732 _codec ("MPEG-4 AAC audio");
14733 caps = gst_caps_new_simple ("audio/mpeg",
14734 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14735 "stream-format", G_TYPE_STRING, "raw", NULL);
14737 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14738 _codec ("QDesign Music");
14739 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14742 _codec ("QDesign Music v.2");
14743 /* FIXME: QDesign music version 2 (no constant) */
14744 if (FALSE && data) {
14745 caps = gst_caps_new_simple ("audio/x-qdm2",
14746 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14747 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14748 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14750 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14754 _codec ("GSM audio");
14755 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14758 _codec ("AMR audio");
14759 caps = gst_caps_new_empty_simple ("audio/AMR");
14762 _codec ("AMR-WB audio");
14763 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14766 _codec ("Quicktime IMA ADPCM");
14767 caps = gst_caps_new_simple ("audio/x-adpcm",
14768 "layout", G_TYPE_STRING, "quicktime", NULL);
14771 _codec ("Apple lossless audio");
14772 caps = gst_caps_new_empty_simple ("audio/x-alac");
14775 _codec ("Free Lossless Audio Codec");
14776 caps = gst_caps_new_simple ("audio/x-flac",
14777 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14779 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14780 _codec ("QualComm PureVoice");
14781 caps = gst_caps_from_string ("audio/qcelp");
14786 caps = gst_caps_new_empty_simple ("audio/x-wma");
14790 caps = gst_caps_new_empty_simple ("audio/x-opus");
14797 GstAudioFormat format;
14800 FLAG_IS_FLOAT = 0x1,
14801 FLAG_IS_BIG_ENDIAN = 0x2,
14802 FLAG_IS_SIGNED = 0x4,
14803 FLAG_IS_PACKED = 0x8,
14804 FLAG_IS_ALIGNED_HIGH = 0x10,
14805 FLAG_IS_NON_INTERLEAVED = 0x20
14807 _codec ("Raw LPCM audio");
14809 if (data && len >= 36) {
14810 depth = QT_UINT32 (data + 24);
14811 flags = QT_UINT32 (data + 28);
14812 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
14814 if ((flags & FLAG_IS_FLOAT) == 0) {
14819 if ((flags & FLAG_IS_ALIGNED_HIGH))
14822 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14823 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14824 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14825 caps = gst_caps_new_simple ("audio/x-raw",
14826 "format", G_TYPE_STRING,
14828 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
14829 "UNKNOWN", "layout", G_TYPE_STRING,
14830 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
14831 "interleaved", NULL);
14832 stream->alignment = GST_ROUND_UP_8 (depth);
14833 stream->alignment = round_up_pow2 (stream->alignment);
14838 if (flags & FLAG_IS_BIG_ENDIAN)
14839 format = GST_AUDIO_FORMAT_F64BE;
14841 format = GST_AUDIO_FORMAT_F64LE;
14843 if (flags & FLAG_IS_BIG_ENDIAN)
14844 format = GST_AUDIO_FORMAT_F32BE;
14846 format = GST_AUDIO_FORMAT_F32LE;
14848 caps = gst_caps_new_simple ("audio/x-raw",
14849 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14850 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14851 "non-interleaved" : "interleaved", NULL);
14852 stream->alignment = width / 8;
14856 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
14859 caps = gst_caps_new_empty_simple ("audio/x-ac4");
14862 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14866 caps = _get_unknown_codec_name ("audio", fourcc);
14872 GstCaps *templ_caps =
14873 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14874 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14875 gst_caps_unref (caps);
14876 gst_caps_unref (templ_caps);
14877 caps = intersection;
14880 /* enable clipping for raw audio streams */
14881 s = gst_caps_get_structure (caps, 0);
14882 name = gst_structure_get_name (s);
14883 if (g_str_has_prefix (name, "audio/x-raw")) {
14884 stream->need_clip = TRUE;
14885 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
14886 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14887 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
14888 stream->max_buffer_size);
14894 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14895 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14896 const guint8 * stsd_entry_data, gchar ** codec_name)
14900 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14904 _codec ("DVD subtitle");
14905 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14906 stream->need_process = TRUE;
14909 _codec ("Quicktime timed text");
14912 _codec ("3GPP timed text");
14914 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14916 /* actual text piece needs to be extracted */
14917 stream->need_process = TRUE;
14920 _codec ("XML subtitles");
14921 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14924 _codec ("CEA 608 Closed Caption");
14926 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
14927 G_TYPE_STRING, "s334-1a", NULL);
14928 stream->need_process = TRUE;
14929 stream->need_split = TRUE;
14932 _codec ("CEA 708 Closed Caption");
14934 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
14935 G_TYPE_STRING, "cdp", NULL);
14936 stream->need_process = TRUE;
14941 caps = _get_unknown_codec_name ("text", fourcc);
14949 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14950 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14951 const guint8 * stsd_entry_data, gchar ** codec_name)
14957 _codec ("MPEG 1 video");
14958 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14959 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14969 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14970 const gchar * system_id)
14974 if (!qtdemux->protection_system_ids)
14975 qtdemux->protection_system_ids =
14976 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14977 /* Check whether we already have an entry for this system ID. */
14978 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14979 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14980 if (g_ascii_strcasecmp (system_id, id) == 0) {
14984 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14985 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,