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 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
721 if (fmt == GST_FORMAT_BYTES) {
722 /* We always refuse BYTES seeks from downstream */
726 /* try upstream first */
727 res = gst_pad_query_default (pad, parent, query);
730 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
731 if (fmt == GST_FORMAT_TIME) {
732 GstClockTime duration;
734 gst_qtdemux_get_duration (qtdemux, &duration);
736 if (!qtdemux->pullbased) {
739 /* we might be able with help from upstream */
741 q = gst_query_new_seeking (GST_FORMAT_BYTES);
742 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
743 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
744 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
748 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
754 case GST_QUERY_SEGMENT:
759 format = qtdemux->segment.format;
762 gst_segment_to_stream_time (&qtdemux->segment, format,
763 qtdemux->segment.start);
764 if ((stop = qtdemux->segment.stop) == -1)
765 stop = qtdemux->segment.duration;
767 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
769 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
774 res = gst_pad_query_default (pad, parent, query);
782 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
784 if (G_LIKELY (stream->pad)) {
785 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
786 GST_DEBUG_PAD_NAME (stream->pad));
788 if (!gst_tag_list_is_empty (stream->stream_tags)) {
789 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
790 stream->stream_tags);
791 gst_pad_push_event (stream->pad,
792 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
795 if (G_UNLIKELY (stream->send_global_tags)) {
796 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
798 gst_pad_push_event (stream->pad,
799 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
800 stream->send_global_tags = FALSE;
805 /* push event on all source pads; takes ownership of the event */
807 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
809 gboolean has_valid_stream = FALSE;
810 GstEventType etype = GST_EVENT_TYPE (event);
813 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
814 GST_EVENT_TYPE_NAME (event));
816 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
818 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
819 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
821 if ((pad = stream->pad)) {
822 has_valid_stream = TRUE;
824 if (etype == GST_EVENT_EOS) {
825 /* let's not send twice */
826 if (stream->sent_eos)
828 stream->sent_eos = TRUE;
831 gst_pad_push_event (pad, gst_event_ref (event));
835 gst_event_unref (event);
837 /* if it is EOS and there are no pads, post an error */
838 if (!has_valid_stream && etype == GST_EVENT_EOS) {
839 gst_qtdemux_post_no_playable_stream_error (qtdemux);
849 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
851 if ((gint64) s1->timestamp > *media_time)
853 if ((gint64) s1->timestamp == *media_time)
859 /* find the index of the sample that includes the data for @media_time using a
860 * binary search. Only to be called in optimized cases of linear search below.
862 * Returns the index of the sample with the corresponding *DTS*.
865 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
868 QtDemuxSample *result;
871 /* convert media_time to mov format */
873 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
875 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
876 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
877 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
879 if (G_LIKELY (result))
880 index = result - str->samples;
889 /* find the index of the sample that includes the data for @media_offset using a
892 * Returns the index of the sample.
895 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
896 QtDemuxStream * str, gint64 media_offset)
898 QtDemuxSample *result = str->samples;
901 if (result == NULL || str->n_samples == 0)
904 if (media_offset == result->offset)
908 while (index < str->n_samples - 1) {
909 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
912 if (media_offset < result->offset)
923 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
928 /* find the index of the sample that includes the data for @media_time using a
929 * linear search, and keeping in mind that not all samples may have been parsed
930 * yet. If possible, it will delegate to binary search.
932 * Returns the index of the sample.
935 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
936 GstClockTime media_time)
940 QtDemuxSample *sample;
942 /* convert media_time to mov format */
944 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
946 sample = str->samples;
947 if (mov_time == sample->timestamp + sample->pts_offset)
950 /* use faster search if requested time in already parsed range */
951 sample = str->samples + str->stbl_index;
952 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
953 index = gst_qtdemux_find_index (qtdemux, str, media_time);
954 sample = str->samples + index;
956 while (index < str->n_samples - 1) {
957 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
960 sample = str->samples + index + 1;
961 if (mov_time < sample->timestamp) {
962 sample = str->samples + index;
970 /* sample->timestamp is now <= media_time, need to find the corresponding
971 * PTS now by looking backwards */
972 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
974 sample = str->samples + index;
982 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
987 /* find the index of the keyframe needed to decode the sample at @index
988 * of stream @str, or of a subsequent keyframe (depending on @next)
990 * Returns the index of the keyframe.
993 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
994 guint32 index, gboolean next)
996 guint32 new_index = index;
998 if (index >= str->n_samples) {
999 new_index = str->n_samples;
1003 /* all keyframes, return index */
1004 if (str->all_keyframe) {
1009 /* else search until we have a keyframe */
1010 while (new_index < str->n_samples) {
1011 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1014 if (str->samples[new_index].keyframe)
1026 if (new_index == str->n_samples) {
1027 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1032 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1033 "gave %u", next ? "after" : "before", index, new_index);
1040 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1045 /* find the segment for @time_position for @stream
1047 * Returns the index of the segment containing @time_position.
1048 * Returns the last segment and sets the @eos variable to TRUE
1049 * if the time is beyond the end. @eos may be NULL
1052 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1053 GstClockTime time_position)
1058 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1059 GST_TIME_ARGS (time_position));
1062 for (i = 0; i < stream->n_segments; i++) {
1063 QtDemuxSegment *segment = &stream->segments[i];
1065 GST_LOG_OBJECT (stream->pad,
1066 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1067 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1069 /* For the last segment we include stop_time in the last segment */
1070 if (i < stream->n_segments - 1) {
1071 if (segment->time <= time_position && time_position < segment->stop_time) {
1072 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1077 /* Last segment always matches */
1085 /* move the stream @str to the sample position @index.
1087 * Updates @str->sample_index and marks discontinuity if needed.
1090 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1093 /* no change needed */
1094 if (index == str->sample_index)
1097 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1100 /* position changed, we have a discont */
1101 str->sample_index = index;
1102 str->offset_in_sample = 0;
1103 /* Each time we move in the stream we store the position where we are
1105 str->from_sample = index;
1106 str->discont = TRUE;
1110 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1111 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1114 gint64 min_byte_offset = -1;
1117 min_offset = desired_time;
1119 /* for each stream, find the index of the sample in the segment
1120 * and move back to the previous keyframe. */
1121 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1123 guint32 index, kindex;
1125 GstClockTime media_start;
1126 GstClockTime media_time;
1127 GstClockTime seg_time;
1128 QtDemuxSegment *seg;
1129 gboolean empty_segment = FALSE;
1131 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1133 if (CUR_STREAM (str)->sparse && !use_sparse)
1136 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1137 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1139 /* get segment and time in the segment */
1140 seg = &str->segments[seg_idx];
1141 seg_time = (desired_time - seg->time) * seg->rate;
1143 while (QTSEGMENT_IS_EMPTY (seg)) {
1145 empty_segment = TRUE;
1146 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1149 if (seg_idx == str->n_segments)
1151 seg = &str->segments[seg_idx];
1154 if (seg_idx == str->n_segments) {
1155 /* FIXME track shouldn't have the last segment as empty, but if it
1156 * happens we better handle it */
1160 /* get the media time in the segment */
1161 media_start = seg->media_start + seg_time;
1163 /* get the index of the sample with media time */
1164 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1165 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1166 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1167 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1170 /* shift to next frame if we are looking for next keyframe */
1171 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1172 && index < str->stbl_index)
1175 if (!empty_segment) {
1176 /* find previous keyframe */
1177 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1179 /* we will settle for one before if none found after */
1180 if (next && kindex == -1)
1181 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1183 /* Update the requested time whenever a keyframe was found, to make it
1184 * accurate and avoid having the first buffer fall outside of the segment
1189 /* get timestamp of keyframe */
1190 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1191 GST_DEBUG_OBJECT (qtdemux,
1192 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1193 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1194 str->samples[kindex].offset);
1196 /* keyframes in the segment get a chance to change the
1197 * desired_offset. keyframes out of the segment are
1199 if (media_time >= seg->media_start) {
1200 GstClockTime seg_time;
1202 /* this keyframe is inside the segment, convert back to
1204 seg_time = (media_time - seg->media_start) + seg->time;
1205 if ((!next && (seg_time < min_offset)) ||
1206 (next && (seg_time > min_offset)))
1207 min_offset = seg_time;
1212 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1213 min_byte_offset = str->samples[index].offset;
1217 *key_time = min_offset;
1219 *key_offset = min_byte_offset;
1223 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1224 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1228 g_return_val_if_fail (format != NULL, FALSE);
1229 g_return_val_if_fail (cur != NULL, FALSE);
1230 g_return_val_if_fail (stop != NULL, FALSE);
1232 if (*format == GST_FORMAT_TIME)
1236 if (cur_type != GST_SEEK_TYPE_NONE)
1237 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1238 if (res && stop_type != GST_SEEK_TYPE_NONE)
1239 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1242 *format = GST_FORMAT_TIME;
1247 /* perform seek in push based mode:
1248 find BYTE position to move to based on time and delegate to upstream
1251 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1256 GstSeekType cur_type, stop_type;
1257 gint64 cur, stop, key_cur;
1260 gint64 original_stop;
1263 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1265 gst_event_parse_seek (event, &rate, &format, &flags,
1266 &cur_type, &cur, &stop_type, &stop);
1267 seqnum = gst_event_get_seqnum (event);
1269 /* Directly send the instant-rate-change event here before taking the
1270 * stream-lock so that it can be applied as soon as possible */
1271 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1274 /* instant rate change only supported if direction does not change. All
1275 * other requirements are already checked before creating the seek event
1276 * but let's double-check here to be sure */
1277 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1278 (qtdemux->segment.rate < 0 && rate > 0) ||
1279 cur_type != GST_SEEK_TYPE_NONE ||
1280 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1281 GST_ERROR_OBJECT (qtdemux,
1282 "Instant rate change seeks only supported in the "
1283 "same direction, without flushing and position change");
1287 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1288 (GstSegmentFlags) flags);
1289 gst_event_set_seqnum (ev, seqnum);
1290 gst_qtdemux_push_event (qtdemux, ev);
1294 /* only forward streaming and seeking is possible */
1296 goto unsupported_seek;
1298 /* convert to TIME if needed and possible */
1299 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1303 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1304 * the original stop position to use when upstream pushes the new segment
1306 original_stop = stop;
1309 /* find reasonable corresponding BYTE position,
1310 * also try to mind about keyframes, since we can not go back a bit for them
1312 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1313 * mostly just work, but let's not yet boldly go there ... */
1314 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1319 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1320 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1323 GST_OBJECT_LOCK (qtdemux);
1324 qtdemux->seek_offset = byte_cur;
1325 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1326 qtdemux->push_seek_start = cur;
1328 qtdemux->push_seek_start = key_cur;
1331 if (stop_type == GST_SEEK_TYPE_NONE) {
1332 qtdemux->push_seek_stop = qtdemux->segment.stop;
1334 qtdemux->push_seek_stop = original_stop;
1336 GST_OBJECT_UNLOCK (qtdemux);
1338 qtdemux->segment_seqnum = seqnum;
1339 /* BYTE seek event */
1340 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1342 gst_event_set_seqnum (event, seqnum);
1343 res = gst_pad_push_event (qtdemux->sinkpad, event);
1350 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1356 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1361 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1366 /* perform the seek.
1368 * We set all segment_indexes in the streams to unknown and
1369 * adjust the time_position to the desired position. this is enough
1370 * to trigger a segment switch in the streaming thread to start
1371 * streaming from the desired position.
1373 * Keyframe seeking is a little more complicated when dealing with
1374 * segments. Ideally we want to move to the previous keyframe in
1375 * the segment but there might not be a keyframe in the segment. In
1376 * fact, none of the segments could contain a keyframe. We take a
1377 * practical approach: seek to the previous keyframe in the segment,
1378 * if there is none, seek to the beginning of the segment.
1380 * Called with STREAM_LOCK
1383 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1384 guint32 seqnum, GstSeekFlags flags)
1386 gint64 desired_offset;
1389 desired_offset = segment->position;
1391 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1392 GST_TIME_ARGS (desired_offset));
1394 /* may not have enough fragmented info to do this adjustment,
1395 * and we can't scan (and probably should not) at this time with
1396 * possibly flushing upstream */
1397 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1399 gboolean next, before, after;
1401 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1402 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1403 next = after && !before;
1404 if (segment->rate < 0)
1407 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1409 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1410 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1411 desired_offset = min_offset;
1414 /* and set all streams to the final position */
1415 GST_OBJECT_LOCK (qtdemux);
1416 gst_flow_combiner_reset (qtdemux->flowcombiner);
1417 GST_OBJECT_UNLOCK (qtdemux);
1418 qtdemux->segment_seqnum = seqnum;
1419 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1420 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1422 stream->time_position = desired_offset;
1423 stream->accumulated_base = 0;
1424 stream->sample_index = -1;
1425 stream->offset_in_sample = 0;
1426 stream->segment_index = -1;
1427 stream->sent_eos = FALSE;
1428 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1430 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1431 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1433 segment->position = desired_offset;
1434 if (segment->rate >= 0) {
1435 segment->start = desired_offset;
1436 /* We need to update time as we update start in that direction */
1437 segment->time = desired_offset;
1439 /* we stop at the end */
1440 if (segment->stop == -1)
1441 segment->stop = segment->duration;
1443 segment->stop = desired_offset;
1446 if (qtdemux->fragmented)
1447 qtdemux->fragmented_seek_pending = TRUE;
1452 /* do a seek in pull based mode */
1454 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1459 GstSeekType cur_type, stop_type;
1461 gboolean flush, instant_rate_change;
1463 GstSegment seeksegment;
1464 guint32 seqnum = GST_SEQNUM_INVALID;
1465 GstEvent *flush_event;
1468 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1470 gst_event_parse_seek (event, &rate, &format, &flags,
1471 &cur_type, &cur, &stop_type, &stop);
1472 seqnum = gst_event_get_seqnum (event);
1474 /* we have to have a format as the segment format. Try to convert
1476 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1480 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1482 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1483 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1485 /* Directly send the instant-rate-change event here before taking the
1486 * stream-lock so that it can be applied as soon as possible */
1487 if (instant_rate_change) {
1490 /* instant rate change only supported if direction does not change. All
1491 * other requirements are already checked before creating the seek event
1492 * but let's double-check here to be sure */
1493 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1494 (qtdemux->segment.rate < 0 && rate > 0) ||
1495 cur_type != GST_SEEK_TYPE_NONE ||
1496 stop_type != GST_SEEK_TYPE_NONE || flush) {
1497 GST_ERROR_OBJECT (qtdemux,
1498 "Instant rate change seeks only supported in the "
1499 "same direction, without flushing and position change");
1503 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1504 (GstSegmentFlags) flags);
1505 gst_event_set_seqnum (ev, seqnum);
1506 gst_qtdemux_push_event (qtdemux, ev);
1510 /* stop streaming, either by flushing or by pausing the task */
1512 flush_event = gst_event_new_flush_start ();
1513 if (seqnum != GST_SEQNUM_INVALID)
1514 gst_event_set_seqnum (flush_event, seqnum);
1515 /* unlock upstream pull_range */
1516 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1517 /* make sure out loop function exits */
1518 gst_qtdemux_push_event (qtdemux, flush_event);
1520 /* non flushing seek, pause the task */
1521 gst_pad_pause_task (qtdemux->sinkpad);
1524 /* wait for streaming to finish */
1525 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1527 /* copy segment, we need this because we still need the old
1528 * segment when we close the current segment. */
1529 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1531 /* configure the segment with the seek variables */
1532 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1533 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1534 cur_type, cur, stop_type, stop, &update)) {
1536 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1538 /* now do the seek */
1539 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1542 /* prepare for streaming again */
1544 flush_event = gst_event_new_flush_stop (TRUE);
1545 if (seqnum != GST_SEQNUM_INVALID)
1546 gst_event_set_seqnum (flush_event, seqnum);
1548 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1549 gst_qtdemux_push_event (qtdemux, flush_event);
1552 /* commit the new segment */
1553 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1555 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1556 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1557 qtdemux->segment.format, qtdemux->segment.position);
1558 if (seqnum != GST_SEQNUM_INVALID)
1559 gst_message_set_seqnum (msg, seqnum);
1560 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1563 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1564 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1565 qtdemux->sinkpad, NULL);
1567 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1574 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1580 qtdemux_ensure_index (GstQTDemux * qtdemux)
1584 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1586 /* Build complete index */
1587 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1588 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1590 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1591 GST_LOG_OBJECT (qtdemux,
1592 "Building complete index of track-id %u for seeking failed!",
1602 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1605 gboolean res = TRUE;
1606 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1608 switch (GST_EVENT_TYPE (event)) {
1609 case GST_EVENT_RECONFIGURE:
1610 GST_OBJECT_LOCK (qtdemux);
1611 gst_flow_combiner_reset (qtdemux->flowcombiner);
1612 GST_OBJECT_UNLOCK (qtdemux);
1613 res = gst_pad_event_default (pad, parent, event);
1615 case GST_EVENT_SEEK:
1617 GstSeekFlags flags = 0;
1618 GstFormat seek_format;
1619 gboolean instant_rate_change;
1621 #ifndef GST_DISABLE_GST_DEBUG
1622 GstClockTime ts = gst_util_get_timestamp ();
1624 guint32 seqnum = gst_event_get_seqnum (event);
1626 qtdemux->received_seek = TRUE;
1628 gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1630 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1632 if (seqnum == qtdemux->segment_seqnum) {
1633 GST_LOG_OBJECT (pad,
1634 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1635 gst_event_unref (event);
1639 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1640 /* seek should be handled by upstream, we might need to re-download fragments */
1641 GST_DEBUG_OBJECT (qtdemux,
1642 "let upstream handle seek for fragmented playback");
1646 if (seek_format == GST_FORMAT_BYTES) {
1647 GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1648 gst_event_unref (event);
1652 gst_event_parse_seek_trickmode_interval (event,
1653 &qtdemux->trickmode_interval);
1655 /* Build complete index for seeking;
1656 * if not a fragmented file at least and we're really doing a seek,
1657 * not just an instant-rate-change */
1658 if (!qtdemux->fragmented && !instant_rate_change) {
1659 if (!qtdemux_ensure_index (qtdemux))
1662 #ifndef GST_DISABLE_GST_DEBUG
1663 ts = gst_util_get_timestamp () - ts;
1664 GST_INFO_OBJECT (qtdemux,
1665 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1667 if (qtdemux->pullbased) {
1668 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1669 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1670 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1672 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1673 && QTDEMUX_N_STREAMS (qtdemux)
1674 && !qtdemux->fragmented) {
1675 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1677 GST_DEBUG_OBJECT (qtdemux,
1678 "ignoring seek in push mode in current state");
1681 gst_event_unref (event);
1686 res = gst_pad_event_default (pad, parent, event);
1696 GST_ERROR_OBJECT (qtdemux, "Index failed");
1697 gst_event_unref (event);
1703 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1705 * If @fw is false, the coding order is explored backwards.
1707 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1708 * sample is found for that track.
1710 * The stream and sample index of the sample with the minimum offset in the direction explored
1711 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1713 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1714 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1715 * @_stream and @_index. */
1717 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1718 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1721 gint64 time, min_time;
1722 QtDemuxStream *stream;
1729 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1732 gboolean set_sample;
1734 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1741 i = str->n_samples - 1;
1745 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1746 if (str->samples[i].size == 0)
1749 if (fw && (str->samples[i].offset < byte_pos))
1752 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1755 /* move stream to first available sample */
1757 gst_qtdemux_move_stream (qtdemux, str, i);
1761 /* avoid index from sparse streams since they might be far away */
1762 if (!CUR_STREAM (str)->sparse) {
1763 /* determine min/max time */
1764 time = QTSAMPLE_PTS (str, &str->samples[i]);
1765 if (min_time == -1 || (!fw && time > min_time) ||
1766 (fw && time < min_time)) {
1770 /* determine stream with leading sample, to get its position */
1772 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1773 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1781 /* no sample for this stream, mark eos */
1783 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1794 /* Copied from mpegtsbase code */
1795 /* FIXME: replace this function when we add new util function for stream-id creation */
1797 _get_upstream_id (GstQTDemux * demux)
1799 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1802 /* Try to create one from the upstream URI, else use a randome number */
1806 /* Try to generate one from the URI query and
1807 * if it fails take a random number instead */
1808 query = gst_query_new_uri ();
1809 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1810 gst_query_parse_uri (query, &uri);
1816 /* And then generate an SHA256 sum of the URI */
1817 cs = g_checksum_new (G_CHECKSUM_SHA256);
1818 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1820 upstream_id = g_strdup (g_checksum_get_string (cs));
1821 g_checksum_free (cs);
1823 /* Just get some random number if the URI query fails */
1824 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1825 "implementing a deterministic way of creating a stream-id");
1827 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1828 g_random_int (), g_random_int ());
1831 gst_query_unref (query);
1836 static QtDemuxStream *
1837 _create_stream (GstQTDemux * demux, guint32 track_id)
1839 QtDemuxStream *stream;
1842 stream = g_new0 (QtDemuxStream, 1);
1843 stream->demux = demux;
1844 stream->track_id = track_id;
1845 upstream_id = _get_upstream_id (demux);
1846 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1847 g_free (upstream_id);
1848 /* new streams always need a discont */
1849 stream->discont = TRUE;
1850 /* we enable clipping for raw audio/video streams */
1851 stream->need_clip = FALSE;
1852 stream->process_func = NULL;
1853 stream->segment_index = -1;
1854 stream->time_position = 0;
1855 stream->sample_index = -1;
1856 stream->offset_in_sample = 0;
1857 stream->new_stream = TRUE;
1858 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1859 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1860 stream->protected = FALSE;
1861 stream->protection_scheme_type = 0;
1862 stream->protection_scheme_version = 0;
1863 stream->protection_scheme_info = NULL;
1864 stream->n_samples_moof = 0;
1865 stream->duration_moof = 0;
1866 stream->duration_last_moof = 0;
1867 stream->alignment = 1;
1868 stream->stream_tags = gst_tag_list_new_empty ();
1869 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1870 g_queue_init (&stream->protection_scheme_event_queue);
1871 stream->ref_count = 1;
1872 /* consistent default for push based mode */
1873 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1878 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1880 GstStructure *structure;
1881 const gchar *variant;
1882 const GstCaps *mediacaps = NULL;
1884 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1886 structure = gst_caps_get_structure (caps, 0);
1887 variant = gst_structure_get_string (structure, "variant");
1889 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1890 QtDemuxStream *stream;
1891 const GValue *value;
1893 demux->fragmented = TRUE;
1894 demux->mss_mode = TRUE;
1896 if (QTDEMUX_N_STREAMS (demux) > 1) {
1897 /* can't do this, we can only renegotiate for another mss format */
1901 value = gst_structure_get_value (structure, "media-caps");
1904 const GValue *timescale_v;
1906 /* TODO update when stream changes during playback */
1908 if (QTDEMUX_N_STREAMS (demux) == 0) {
1909 stream = _create_stream (demux, 1);
1910 g_ptr_array_add (demux->active_streams, stream);
1911 /* mss has no stsd/stsd entry, use id 0 as default */
1912 stream->stsd_entries_length = 1;
1913 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1914 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1916 stream = QTDEMUX_NTH_STREAM (demux, 0);
1919 timescale_v = gst_structure_get_value (structure, "timescale");
1921 stream->timescale = g_value_get_uint64 (timescale_v);
1923 /* default mss timescale */
1924 stream->timescale = 10000000;
1926 demux->timescale = stream->timescale;
1928 mediacaps = gst_value_get_caps (value);
1929 if (!CUR_STREAM (stream)->caps
1930 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1931 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1933 stream->new_caps = TRUE;
1935 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1936 structure = gst_caps_get_structure (mediacaps, 0);
1937 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1938 stream->subtype = FOURCC_vide;
1940 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1941 gst_structure_get_int (structure, "height",
1942 &CUR_STREAM (stream)->height);
1943 gst_structure_get_fraction (structure, "framerate",
1944 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1945 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1947 stream->subtype = FOURCC_soun;
1948 gst_structure_get_int (structure, "channels",
1949 &CUR_STREAM (stream)->n_channels);
1950 gst_structure_get_int (structure, "rate", &rate);
1951 CUR_STREAM (stream)->rate = rate;
1952 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1953 if (gst_structure_has_field (structure, "original-media-type")) {
1954 const gchar *media_type =
1955 gst_structure_get_string (structure, "original-media-type");
1956 if (g_str_has_prefix (media_type, "video")) {
1957 stream->subtype = FOURCC_vide;
1958 } else if (g_str_has_prefix (media_type, "audio")) {
1959 stream->subtype = FOURCC_soun;
1964 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1966 demux->mss_mode = FALSE;
1973 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1977 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1978 gst_pad_stop_task (qtdemux->sinkpad);
1980 if (hard || qtdemux->upstream_format_is_time) {
1981 qtdemux->state = QTDEMUX_STATE_INITIAL;
1982 qtdemux->neededbytes = 16;
1983 qtdemux->todrop = 0;
1984 qtdemux->pullbased = FALSE;
1985 g_clear_pointer (&qtdemux->redirect_location, g_free);
1986 qtdemux->first_mdat = -1;
1987 qtdemux->header_size = 0;
1988 qtdemux->mdatoffset = -1;
1989 qtdemux->restoredata_offset = -1;
1990 if (qtdemux->mdatbuffer)
1991 gst_buffer_unref (qtdemux->mdatbuffer);
1992 if (qtdemux->restoredata_buffer)
1993 gst_buffer_unref (qtdemux->restoredata_buffer);
1994 qtdemux->mdatbuffer = NULL;
1995 qtdemux->restoredata_buffer = NULL;
1996 qtdemux->mdatleft = 0;
1997 qtdemux->mdatsize = 0;
1998 if (qtdemux->comp_brands)
1999 gst_buffer_unref (qtdemux->comp_brands);
2000 qtdemux->comp_brands = NULL;
2001 qtdemux->last_moov_offset = -1;
2002 if (qtdemux->moov_node_compressed) {
2003 g_node_destroy (qtdemux->moov_node_compressed);
2004 if (qtdemux->moov_node)
2005 g_free (qtdemux->moov_node->data);
2007 qtdemux->moov_node_compressed = NULL;
2008 if (qtdemux->moov_node)
2009 g_node_destroy (qtdemux->moov_node);
2010 qtdemux->moov_node = NULL;
2011 if (qtdemux->tag_list)
2012 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2013 qtdemux->tag_list = gst_tag_list_new_empty ();
2014 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2016 if (qtdemux->element_index)
2017 gst_object_unref (qtdemux->element_index);
2018 qtdemux->element_index = NULL;
2020 qtdemux->major_brand = 0;
2021 qtdemux->upstream_format_is_time = FALSE;
2022 qtdemux->upstream_seekable = FALSE;
2023 qtdemux->upstream_size = 0;
2025 qtdemux->fragment_start = -1;
2026 qtdemux->fragment_start_offset = -1;
2027 qtdemux->duration = 0;
2028 qtdemux->moof_offset = 0;
2029 qtdemux->chapters_track_id = 0;
2030 qtdemux->have_group_id = FALSE;
2031 qtdemux->group_id = G_MAXUINT;
2033 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2035 g_queue_clear (&qtdemux->protection_event_queue);
2037 qtdemux->received_seek = FALSE;
2038 qtdemux->first_moof_already_parsed = FALSE;
2040 qtdemux->offset = 0;
2041 gst_adapter_clear (qtdemux->adapter);
2042 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2043 qtdemux->need_segment = TRUE;
2046 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2047 qtdemux->trickmode_interval = 0;
2048 g_ptr_array_set_size (qtdemux->active_streams, 0);
2049 g_ptr_array_set_size (qtdemux->old_streams, 0);
2050 qtdemux->n_video_streams = 0;
2051 qtdemux->n_audio_streams = 0;
2052 qtdemux->n_sub_streams = 0;
2053 qtdemux->exposed = FALSE;
2054 qtdemux->fragmented = FALSE;
2055 qtdemux->mss_mode = FALSE;
2056 gst_caps_replace (&qtdemux->media_caps, NULL);
2057 qtdemux->timescale = 0;
2058 qtdemux->got_moov = FALSE;
2059 qtdemux->cenc_aux_info_offset = 0;
2060 qtdemux->cenc_aux_info_sizes = NULL;
2061 qtdemux->cenc_aux_sample_count = 0;
2062 if (qtdemux->protection_system_ids) {
2063 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2064 qtdemux->protection_system_ids = NULL;
2066 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2067 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2068 GST_BIN_FLAG_STREAMS_AWARE);
2070 if (qtdemux->preferred_protection_system_id) {
2071 g_free (qtdemux->preferred_protection_system_id);
2072 qtdemux->preferred_protection_system_id = NULL;
2074 } else if (qtdemux->mss_mode) {
2075 gst_flow_combiner_reset (qtdemux->flowcombiner);
2076 g_ptr_array_foreach (qtdemux->active_streams,
2077 (GFunc) gst_qtdemux_stream_clear, NULL);
2079 gst_flow_combiner_reset (qtdemux->flowcombiner);
2080 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2081 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2082 stream->sent_eos = FALSE;
2083 stream->time_position = 0;
2084 stream->accumulated_base = 0;
2085 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2091 /* Maps the @segment to the qt edts internal segments and pushes
2092 * the corresponding segment event.
2094 * If it ends up being at a empty segment, a gap will be pushed and the next
2095 * edts segment will be activated in sequence.
2097 * To be used in push-mode only */
2099 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2103 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2104 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2106 stream->time_position = segment->start;
2108 /* in push mode we should be guaranteed that we will have empty segments
2109 * at the beginning and then one segment after, other scenarios are not
2110 * supported and are discarded when parsing the edts */
2111 for (i = 0; i < stream->n_segments; i++) {
2112 if (stream->segments[i].stop_time > segment->start) {
2113 /* push the empty segment and move to the next one */
2114 gst_qtdemux_activate_segment (qtdemux, stream, i,
2115 stream->time_position);
2116 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2117 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2118 stream->time_position);
2120 /* accumulate previous segments */
2121 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2122 stream->accumulated_base +=
2123 (stream->segment.stop -
2124 stream->segment.start) / ABS (stream->segment.rate);
2128 g_assert (i == stream->n_segments - 1);
2135 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2146 for (i = 0; i < len; i++) {
2147 QtDemuxStream *stream = g_ptr_array_index (src, i);
2149 #ifndef GST_DISABLE_GST_DEBUG
2150 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2151 stream, GST_STR_NULL (stream->stream_id), dest);
2153 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2156 g_ptr_array_set_size (src, 0);
2160 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2163 GstQTDemux *demux = GST_QTDEMUX (parent);
2164 gboolean res = TRUE;
2166 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2168 switch (GST_EVENT_TYPE (event)) {
2169 case GST_EVENT_SEGMENT:
2172 QtDemuxStream *stream;
2176 /* some debug output */
2177 gst_event_copy_segment (event, &segment);
2178 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2181 if (segment.format == GST_FORMAT_TIME) {
2182 demux->upstream_format_is_time = TRUE;
2183 demux->segment_seqnum = gst_event_get_seqnum (event);
2185 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2186 "not in time format");
2188 /* chain will send initial newsegment after pads have been added */
2189 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2190 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2195 /* check if this matches a time seek we received previously
2196 * FIXME for backwards compatibility reasons we use the
2197 * seek_offset here to compare. In the future we might want to
2198 * change this to use the seqnum as it uniquely should identify
2199 * the segment that corresponds to the seek. */
2200 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2201 ", received segment offset %" G_GINT64_FORMAT,
2202 demux->seek_offset, segment.start);
2203 if (segment.format == GST_FORMAT_BYTES
2204 && demux->seek_offset == segment.start) {
2205 GST_OBJECT_LOCK (demux);
2206 offset = segment.start;
2208 segment.format = GST_FORMAT_TIME;
2209 segment.start = demux->push_seek_start;
2210 segment.stop = demux->push_seek_stop;
2211 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2212 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2213 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2214 GST_OBJECT_UNLOCK (demux);
2217 /* we only expect a BYTE segment, e.g. following a seek */
2218 if (segment.format == GST_FORMAT_BYTES) {
2219 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2220 offset = segment.start;
2222 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2223 NULL, (gint64 *) & segment.start);
2224 if ((gint64) segment.start < 0)
2227 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2228 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2229 NULL, (gint64 *) & segment.stop);
2230 /* keyframe seeking should already arrange for start >= stop,
2231 * but make sure in other rare cases */
2232 segment.stop = MAX (segment.stop, segment.start);
2234 } else if (segment.format == GST_FORMAT_TIME) {
2235 /* push all data on the adapter before starting this
2237 gst_qtdemux_process_adapter (demux, TRUE);
2239 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2243 /* We shouldn't modify upstream driven TIME FORMAT segment */
2244 if (!demux->upstream_format_is_time) {
2245 /* accept upstream's notion of segment and distribute along */
2246 segment.format = GST_FORMAT_TIME;
2247 segment.position = segment.time = segment.start;
2248 segment.duration = demux->segment.duration;
2249 segment.base = gst_segment_to_running_time (&demux->segment,
2250 GST_FORMAT_TIME, demux->segment.position);
2253 gst_segment_copy_into (&segment, &demux->segment);
2254 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2256 /* map segment to internal qt segments and push on each stream */
2257 if (QTDEMUX_N_STREAMS (demux)) {
2258 demux->need_segment = TRUE;
2259 gst_qtdemux_check_send_pending_segment (demux);
2262 /* clear leftover in current segment, if any */
2263 gst_adapter_clear (demux->adapter);
2265 /* set up streaming thread */
2266 demux->offset = offset;
2267 if (demux->upstream_format_is_time) {
2268 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2269 "set values to restart reading from a new atom");
2270 demux->neededbytes = 16;
2273 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2276 demux->todrop = stream->samples[idx].offset - offset;
2277 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2279 /* set up for EOS */
2280 demux->neededbytes = -1;
2285 gst_event_unref (event);
2289 case GST_EVENT_FLUSH_START:
2291 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2292 gst_event_unref (event);
2295 QTDEMUX_EXPOSE_LOCK (demux);
2296 res = gst_pad_event_default (demux->sinkpad, parent, event);
2297 QTDEMUX_EXPOSE_UNLOCK (demux);
2300 case GST_EVENT_FLUSH_STOP:
2304 dur = demux->segment.duration;
2305 gst_qtdemux_reset (demux, FALSE);
2306 demux->segment.duration = dur;
2308 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2309 gst_event_unref (event);
2315 /* If we are in push mode, and get an EOS before we've seen any streams,
2316 * then error out - we have nowhere to send the EOS */
2317 if (!demux->pullbased) {
2319 gboolean has_valid_stream = FALSE;
2320 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2321 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2322 has_valid_stream = TRUE;
2326 if (!has_valid_stream)
2327 gst_qtdemux_post_no_playable_stream_error (demux);
2329 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2330 (guint) gst_adapter_available (demux->adapter));
2331 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2337 case GST_EVENT_CAPS:{
2338 GstCaps *caps = NULL;
2340 gst_event_parse_caps (event, &caps);
2341 gst_qtdemux_setcaps (demux, caps);
2343 gst_event_unref (event);
2346 case GST_EVENT_PROTECTION:
2348 const gchar *system_id = NULL;
2350 gst_event_parse_protection (event, &system_id, NULL, NULL);
2351 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2353 gst_qtdemux_append_protection_system_id (demux, system_id);
2354 /* save the event for later, for source pads that have not been created */
2355 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2356 /* send it to all pads that already exist */
2357 gst_qtdemux_push_event (demux, event);
2361 case GST_EVENT_STREAM_START:
2364 gst_event_unref (event);
2366 /* Drain all the buffers */
2367 gst_qtdemux_process_adapter (demux, TRUE);
2368 gst_qtdemux_reset (demux, FALSE);
2369 /* We expect new moov box after new stream-start event */
2370 if (demux->exposed) {
2371 gst_qtdemux_stream_concat (demux,
2372 demux->old_streams, demux->active_streams);
2381 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2388 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2391 GstQTDemux *demux = GST_QTDEMUX (parent);
2392 gboolean res = FALSE;
2394 switch (GST_QUERY_TYPE (query)) {
2395 case GST_QUERY_BITRATE:
2397 GstClockTime duration;
2399 /* populate demux->upstream_size if not done yet */
2400 gst_qtdemux_check_seekability (demux);
2402 if (demux->upstream_size != -1
2403 && gst_qtdemux_get_duration (demux, &duration)) {
2405 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2408 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2409 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2410 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2412 /* TODO: better results based on ranges/index tables */
2413 gst_query_set_bitrate (query, bitrate);
2419 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2429 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2431 GstQTDemux *demux = GST_QTDEMUX (element);
2433 GST_OBJECT_LOCK (demux);
2434 if (demux->element_index)
2435 gst_object_unref (demux->element_index);
2437 demux->element_index = gst_object_ref (index);
2439 demux->element_index = NULL;
2441 GST_OBJECT_UNLOCK (demux);
2442 /* object lock might be taken again */
2444 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2445 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2446 demux->element_index, demux->index_id);
2450 gst_qtdemux_get_index (GstElement * element)
2452 GstIndex *result = NULL;
2453 GstQTDemux *demux = GST_QTDEMUX (element);
2455 GST_OBJECT_LOCK (demux);
2456 if (demux->element_index)
2457 result = gst_object_ref (demux->element_index);
2458 GST_OBJECT_UNLOCK (demux);
2460 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2467 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2469 g_free ((gpointer) stream->stco.data);
2470 stream->stco.data = NULL;
2471 g_free ((gpointer) stream->stsz.data);
2472 stream->stsz.data = NULL;
2473 g_free ((gpointer) stream->stsc.data);
2474 stream->stsc.data = NULL;
2475 g_free ((gpointer) stream->stts.data);
2476 stream->stts.data = NULL;
2477 g_free ((gpointer) stream->stss.data);
2478 stream->stss.data = NULL;
2479 g_free ((gpointer) stream->stps.data);
2480 stream->stps.data = NULL;
2481 g_free ((gpointer) stream->ctts.data);
2482 stream->ctts.data = NULL;
2486 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2488 g_free (stream->segments);
2489 stream->segments = NULL;
2490 stream->segment_index = -1;
2491 stream->accumulated_base = 0;
2495 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2497 g_free (stream->samples);
2498 stream->samples = NULL;
2499 gst_qtdemux_stbl_free (stream);
2502 g_free (stream->ra_entries);
2503 stream->ra_entries = NULL;
2504 stream->n_ra_entries = 0;
2506 stream->sample_index = -1;
2507 stream->stbl_index = -1;
2508 stream->n_samples = 0;
2509 stream->time_position = 0;
2511 stream->n_samples_moof = 0;
2512 stream->duration_moof = 0;
2513 stream->duration_last_moof = 0;
2517 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2520 if (stream->allocator)
2521 gst_object_unref (stream->allocator);
2522 while (stream->buffers) {
2523 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2524 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2526 for (i = 0; i < stream->stsd_entries_length; i++) {
2527 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2528 if (entry->rgb8_palette) {
2529 gst_memory_unref (entry->rgb8_palette);
2530 entry->rgb8_palette = NULL;
2532 entry->sparse = FALSE;
2535 if (stream->stream_tags)
2536 gst_tag_list_unref (stream->stream_tags);
2538 stream->stream_tags = gst_tag_list_new_empty ();
2539 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2540 g_free (stream->redirect_uri);
2541 stream->redirect_uri = NULL;
2542 stream->sent_eos = FALSE;
2543 stream->protected = FALSE;
2544 if (stream->protection_scheme_info) {
2545 if (stream->protection_scheme_type == FOURCC_cenc
2546 || stream->protection_scheme_type == FOURCC_cbcs) {
2547 QtDemuxCencSampleSetInfo *info =
2548 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2549 if (info->default_properties)
2550 gst_structure_free (info->default_properties);
2551 if (info->crypto_info)
2552 g_ptr_array_free (info->crypto_info, TRUE);
2554 if (stream->protection_scheme_type == FOURCC_aavd) {
2555 QtDemuxAavdEncryptionInfo *info =
2556 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2557 if (info->default_properties)
2558 gst_structure_free (info->default_properties);
2560 g_free (stream->protection_scheme_info);
2561 stream->protection_scheme_info = NULL;
2563 stream->protection_scheme_type = 0;
2564 stream->protection_scheme_version = 0;
2565 g_queue_foreach (&stream->protection_scheme_event_queue,
2566 (GFunc) gst_event_unref, NULL);
2567 g_queue_clear (&stream->protection_scheme_event_queue);
2568 gst_qtdemux_stream_flush_segments_data (stream);
2569 gst_qtdemux_stream_flush_samples_data (stream);
2573 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2576 gst_qtdemux_stream_clear (stream);
2577 for (i = 0; i < stream->stsd_entries_length; i++) {
2578 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2580 gst_caps_unref (entry->caps);
2584 g_free (stream->stsd_entries);
2585 stream->stsd_entries = NULL;
2586 stream->stsd_entries_length = 0;
2589 static QtDemuxStream *
2590 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2592 g_atomic_int_add (&stream->ref_count, 1);
2598 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2600 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2601 gst_qtdemux_stream_reset (stream);
2602 gst_tag_list_unref (stream->stream_tags);
2604 GstQTDemux *demux = stream->demux;
2605 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2606 GST_OBJECT_LOCK (demux);
2607 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2608 GST_OBJECT_UNLOCK (demux);
2610 g_free (stream->stream_id);
2615 static GstStateChangeReturn
2616 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2618 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2619 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2621 switch (transition) {
2622 case GST_STATE_CHANGE_READY_TO_PAUSED:
2623 gst_qtdemux_reset (qtdemux, TRUE);
2629 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2631 switch (transition) {
2632 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2633 gst_qtdemux_reset (qtdemux, TRUE);
2644 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2646 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2648 g_return_if_fail (GST_IS_CONTEXT (context));
2650 if (gst_context_has_context_type (context,
2651 "drm-preferred-decryption-system-id")) {
2652 const GstStructure *s;
2654 s = gst_context_get_structure (context);
2655 g_free (qtdemux->preferred_protection_system_id);
2656 qtdemux->preferred_protection_system_id =
2657 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2658 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2659 qtdemux->preferred_protection_system_id);
2662 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2666 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2668 /* counts as header data */
2669 qtdemux->header_size += length;
2671 /* only consider at least a sufficiently complete ftyp atom */
2675 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2676 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2677 GST_FOURCC_ARGS (qtdemux->major_brand));
2678 if (qtdemux->comp_brands)
2679 gst_buffer_unref (qtdemux->comp_brands);
2680 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2681 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2686 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2687 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2688 guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2689 guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2690 const guint8 * constant_iv)
2692 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2693 gst_buffer_fill (kid_buf, 0, kid, 16);
2694 if (info->default_properties)
2695 gst_structure_free (info->default_properties);
2696 info->default_properties =
2697 gst_structure_new ("application/x-cenc",
2698 "iv_size", G_TYPE_UINT, iv_size,
2699 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2700 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2701 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2702 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2703 gst_buffer_unref (kid_buf);
2704 if (protection_scheme_type == FOURCC_cbcs) {
2705 if (crypt_byte_block != 0 || skip_byte_block != 0) {
2706 gst_structure_set (info->default_properties, "crypt_byte_block",
2707 G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2708 skip_byte_block, NULL);
2710 if (constant_iv != NULL) {
2711 GstBuffer *constant_iv_buf =
2712 gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2713 gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2714 gst_structure_set (info->default_properties, "constant_iv_size",
2715 G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2717 gst_buffer_unref (constant_iv_buf);
2719 gst_structure_set (info->default_properties, "cipher-mode",
2720 G_TYPE_STRING, "cbcs", NULL);
2722 gst_structure_set (info->default_properties, "cipher-mode",
2723 G_TYPE_STRING, "cenc", NULL);
2728 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2729 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2731 guint32 algorithm_id = 0;
2733 gboolean is_encrypted = TRUE;
2736 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2737 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2742 if (algorithm_id == 0) {
2743 is_encrypted = FALSE;
2744 } else if (algorithm_id == 1) {
2745 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2746 } else if (algorithm_id == 2) {
2747 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2750 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2753 if (!gst_byte_reader_get_data (br, 16, &kid))
2756 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2757 is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2758 gst_structure_set (info->default_properties, "piff_algorithm_id",
2759 G_TYPE_UINT, algorithm_id, NULL);
2765 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2773 QtDemuxStream *stream;
2774 GstStructure *structure;
2775 QtDemuxCencSampleSetInfo *ss_info = NULL;
2776 const gchar *system_id;
2777 gboolean uses_sub_sample_encryption = FALSE;
2778 guint32 sample_count;
2780 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2783 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2785 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2786 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2787 GST_WARNING_OBJECT (qtdemux,
2788 "Attempting PIFF box parsing on an unencrypted stream.");
2792 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2793 G_TYPE_STRING, &system_id, NULL);
2794 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2796 stream->protected = TRUE;
2797 stream->protection_scheme_type = FOURCC_cenc;
2799 if (!stream->protection_scheme_info)
2800 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2802 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2803 if (!ss_info->default_properties) {
2804 ss_info->default_properties =
2805 gst_structure_new ("application/x-cenc",
2806 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2811 if (ss_info->crypto_info) {
2812 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2813 g_ptr_array_free (ss_info->crypto_info, TRUE);
2814 ss_info->crypto_info = NULL;
2818 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2820 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2821 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2825 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2826 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2830 if ((flags & 0x000001)) {
2831 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2834 } else if ((flags & 0x000002)) {
2835 uses_sub_sample_encryption = TRUE;
2838 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2840 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2844 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2845 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2849 ss_info->crypto_info =
2850 g_ptr_array_new_full (sample_count,
2851 (GDestroyNotify) qtdemux_gst_structure_free);
2853 for (i = 0; i < sample_count; ++i) {
2854 GstStructure *properties;
2858 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2859 if (properties == NULL) {
2860 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2861 qtdemux->cenc_aux_sample_count = i;
2865 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2866 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2867 gst_structure_free (properties);
2868 qtdemux->cenc_aux_sample_count = i;
2871 buf = gst_buffer_new_wrapped (data, iv_size);
2872 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2873 gst_buffer_unref (buf);
2875 if (uses_sub_sample_encryption) {
2876 guint16 n_subsamples;
2877 const GValue *kid_buf_value;
2879 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2880 || n_subsamples == 0) {
2881 GST_ERROR_OBJECT (qtdemux,
2882 "failed to get subsample count for sample %u", i);
2883 gst_structure_free (properties);
2884 qtdemux->cenc_aux_sample_count = i;
2887 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2888 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2889 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2891 gst_structure_free (properties);
2892 qtdemux->cenc_aux_sample_count = i;
2895 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2898 gst_structure_get_value (ss_info->default_properties, "kid");
2900 gst_structure_set (properties,
2901 "subsample_count", G_TYPE_UINT, n_subsamples,
2902 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2903 gst_structure_set_value (properties, "kid", kid_buf_value);
2904 gst_buffer_unref (buf);
2906 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2909 g_ptr_array_add (ss_info->crypto_info, properties);
2912 qtdemux->cenc_aux_sample_count = sample_count;
2916 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2918 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2919 0x97, 0xA9, 0x42, 0xE8,
2920 0x9C, 0x71, 0x99, 0x94,
2921 0x91, 0xE3, 0xAF, 0xAC
2923 static const guint8 playready_uuid[] = {
2924 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2925 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2928 static const guint8 piff_sample_encryption_uuid[] = {
2929 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2930 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2935 /* counts as header data */
2936 qtdemux->header_size += length;
2938 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2940 if (length <= offset + 16) {
2941 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2945 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2947 GstTagList *taglist;
2949 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2950 length - offset - 16, NULL);
2951 taglist = gst_tag_list_from_xmp_buffer (buf);
2952 gst_buffer_unref (buf);
2954 /* make sure we have a usable taglist */
2955 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2957 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2959 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2961 const gunichar2 *s_utf16;
2964 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2965 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2966 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2967 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2971 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2972 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2974 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2975 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2977 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2978 GST_READ_UINT32_LE (buffer + offset),
2979 GST_READ_UINT32_LE (buffer + offset + 4),
2980 GST_READ_UINT32_LE (buffer + offset + 8),
2981 GST_READ_UINT32_LE (buffer + offset + 12));
2986 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2988 GstSidxParser sidx_parser;
2989 GstIsoffParserResult res;
2992 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2995 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2997 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2998 if (res == GST_ISOFF_QT_PARSER_DONE) {
2999 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3001 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3004 /* caller verifies at least 8 bytes in buf */
3006 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3007 guint64 * plength, guint32 * pfourcc)
3012 length = QT_UINT32 (data);
3013 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3014 fourcc = QT_FOURCC (data + 4);
3015 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3018 length = G_MAXUINT64;
3019 } else if (length == 1 && size >= 16) {
3020 /* this means we have an extended size, which is the 64 bit value of
3021 * the next 8 bytes */
3022 length = QT_UINT64 (data + 8);
3023 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3033 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3035 guint32 version = 0;
3036 GstClockTime duration = 0;
3038 if (!gst_byte_reader_get_uint32_be (br, &version))
3043 if (!gst_byte_reader_get_uint64_be (br, &duration))
3048 if (!gst_byte_reader_get_uint32_be (br, &dur))
3053 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3054 qtdemux->duration = duration;
3060 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3066 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3067 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3069 if (!stream->parsed_trex && qtdemux->moov_node) {
3071 GstByteReader trex_data;
3073 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3075 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3078 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3080 /* skip version/flags */
3081 if (!gst_byte_reader_skip (&trex_data, 4))
3083 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3085 if (id != stream->track_id)
3087 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3089 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3091 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3093 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3096 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3097 "duration %d, size %d, flags 0x%x", stream->track_id,
3100 stream->parsed_trex = TRUE;
3101 stream->def_sample_description_index = sdi;
3102 stream->def_sample_duration = dur;
3103 stream->def_sample_size = size;
3104 stream->def_sample_flags = flags;
3107 /* iterate all siblings */
3108 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3114 *ds_duration = stream->def_sample_duration;
3115 *ds_size = stream->def_sample_size;
3116 *ds_flags = stream->def_sample_flags;
3118 /* even then, above values are better than random ... */
3119 if (G_UNLIKELY (!stream->parsed_trex)) {
3120 GST_WARNING_OBJECT (qtdemux,
3121 "failed to find fragment defaults for stream %d", stream->track_id);
3128 /* This method should be called whenever a more accurate duration might
3129 * have been found. It will update all relevant variables if/where needed
3132 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3136 GstClockTime prevdur;
3138 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3140 if (movdur > qtdemux->duration) {
3141 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3142 GST_DEBUG_OBJECT (qtdemux,
3143 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3144 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3145 qtdemux->duration = movdur;
3146 GST_DEBUG_OBJECT (qtdemux,
3147 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3148 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3149 GST_TIME_ARGS (qtdemux->segment.stop));
3150 if (qtdemux->segment.duration == prevdur) {
3151 /* If the current segment has duration/stop identical to previous duration
3152 * update them also (because they were set at that point in time with
3153 * the wrong duration */
3154 /* We convert the value *from* the timescale version to avoid rounding errors */
3155 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3156 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3157 qtdemux->segment.duration = fixeddur;
3158 qtdemux->segment.stop = fixeddur;
3162 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3163 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3165 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3166 if (movdur > stream->duration) {
3167 GST_DEBUG_OBJECT (qtdemux,
3168 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3169 GST_TIME_ARGS (duration));
3170 stream->duration = movdur;
3171 /* internal duration tracking state has been updated above, so */
3172 /* preserve an open-ended dummy segment rather than repeatedly updating
3173 * it and spamming downstream accordingly with segment events */
3174 /* also mangle the edit list end time when fragmented with a single edit
3175 * list that may only cover any non-fragmented data */
3176 if ((stream->dummy_segment ||
3177 (qtdemux->fragmented && stream->n_segments == 1)) &&
3178 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3179 /* Update all dummy values to new duration */
3180 stream->segments[0].stop_time = duration;
3181 stream->segments[0].duration = duration;
3182 stream->segments[0].media_stop = duration;
3184 /* let downstream know we possibly have a new stop time */
3185 if (stream->segment_index != -1) {
3188 if (qtdemux->segment.rate >= 0) {
3189 pos = stream->segment.start;
3191 pos = stream->segment.stop;
3194 gst_qtdemux_stream_update_segment (qtdemux, stream,
3195 stream->segment_index, pos, NULL, NULL);
3203 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3204 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3205 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3206 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3209 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3211 gint32 data_offset = 0;
3212 guint32 flags = 0, first_flags = 0, samples_count = 0;
3215 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3216 QtDemuxSample *sample;
3217 gboolean ismv = FALSE;
3218 gint64 initial_offset;
3220 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3221 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3222 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3223 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3225 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3226 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3230 /* presence of stss or not can't really tell us much,
3231 * and flags and so on tend to be marginally reliable in these files */
3232 if (stream->subtype == FOURCC_soun) {
3233 GST_DEBUG_OBJECT (qtdemux,
3234 "sound track in fragmented file; marking all keyframes");
3235 stream->all_keyframe = TRUE;
3238 if (!gst_byte_reader_skip (trun, 1) ||
3239 !gst_byte_reader_get_uint24_be (trun, &flags))
3242 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3245 if (flags & TR_DATA_OFFSET) {
3246 /* note this is really signed */
3247 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3249 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3250 /* default base offset = first byte of moof */
3251 if (*base_offset == -1) {
3252 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3253 *base_offset = moof_offset;
3255 *running_offset = *base_offset + data_offset;
3257 /* if no offset at all, that would mean data starts at moof start,
3258 * which is a bit wrong and is ismv crappy way, so compensate
3259 * assuming data is in mdat following moof */
3260 if (*base_offset == -1) {
3261 *base_offset = moof_offset + moof_length + 8;
3262 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3265 if (*running_offset == -1)
3266 *running_offset = *base_offset;
3269 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3271 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3272 data_offset, flags, samples_count);
3274 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3275 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3276 GST_DEBUG_OBJECT (qtdemux,
3277 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3278 flags ^= TR_FIRST_SAMPLE_FLAGS;
3280 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3282 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3286 /* FIXME ? spec says other bits should also be checked to determine
3287 * entry size (and prefix size for that matter) */
3289 dur_offset = size_offset = 0;
3290 if (flags & TR_SAMPLE_DURATION) {
3291 GST_LOG_OBJECT (qtdemux, "entry duration present");
3292 dur_offset = entry_size;
3295 if (flags & TR_SAMPLE_SIZE) {
3296 GST_LOG_OBJECT (qtdemux, "entry size present");
3297 size_offset = entry_size;
3300 if (flags & TR_SAMPLE_FLAGS) {
3301 GST_LOG_OBJECT (qtdemux, "entry flags present");
3302 flags_offset = entry_size;
3305 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3306 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3307 ct_offset = entry_size;
3311 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3313 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3315 if (stream->n_samples + samples_count >=
3316 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3319 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3320 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3321 (stream->n_samples + samples_count) *
3322 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3324 /* create a new array of samples if it's the first sample parsed */
3325 if (stream->n_samples == 0) {
3326 g_assert (stream->samples == NULL);
3327 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3328 /* or try to reallocate it with space enough to insert the new samples */
3330 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3331 stream->n_samples + samples_count);
3332 if (stream->samples == NULL)
3335 if (qtdemux->fragment_start != -1) {
3336 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3337 qtdemux->fragment_start = -1;
3339 if (stream->n_samples == 0) {
3340 if (decode_ts > 0) {
3341 timestamp = decode_ts;
3342 } else if (stream->pending_seek != NULL) {
3343 /* if we don't have a timestamp from a tfdt box, we'll use the one
3344 * from the mfra seek table */
3345 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3346 GST_TIME_ARGS (stream->pending_seek->ts));
3348 /* FIXME: this is not fully correct, the timestamp refers to the random
3349 * access sample refered to in the tfra entry, which may not necessarily
3350 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3351 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3356 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3357 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3358 GST_TIME_ARGS (gst_ts));
3360 /* subsequent fragments extend stream */
3362 stream->samples[stream->n_samples - 1].timestamp +
3363 stream->samples[stream->n_samples - 1].duration;
3365 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3366 * difference (1 sec.) between decode_ts and timestamp, prefer the
3368 if (has_tfdt && !qtdemux->upstream_format_is_time
3369 && ABSDIFF (decode_ts, timestamp) >
3370 MAX (stream->duration_last_moof / 2,
3371 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3372 GST_INFO_OBJECT (qtdemux,
3373 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3374 ") are significantly different (more than %" GST_TIME_FORMAT
3375 "), using decode_ts",
3376 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3377 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3378 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3379 MAX (stream->duration_last_moof / 2,
3380 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3381 timestamp = decode_ts;
3384 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3385 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3386 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3390 initial_offset = *running_offset;
3392 sample = stream->samples + stream->n_samples;
3393 for (i = 0; i < samples_count; i++) {
3394 guint32 dur, size, sflags, ct;
3396 /* first read sample data */
3397 if (flags & TR_SAMPLE_DURATION) {
3398 dur = QT_UINT32 (data + dur_offset);
3400 dur = d_sample_duration;
3402 if (flags & TR_SAMPLE_SIZE) {
3403 size = QT_UINT32 (data + size_offset);
3405 size = d_sample_size;
3407 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3409 sflags = first_flags;
3411 sflags = d_sample_flags;
3413 } else if (flags & TR_SAMPLE_FLAGS) {
3414 sflags = QT_UINT32 (data + flags_offset);
3416 sflags = d_sample_flags;
3418 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3419 ct = QT_UINT32 (data + ct_offset);
3425 /* fill the sample information */
3426 sample->offset = *running_offset;
3427 sample->pts_offset = ct;
3428 sample->size = size;
3429 sample->timestamp = timestamp;
3430 sample->duration = dur;
3431 /* sample-is-difference-sample */
3432 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3433 * now idea how it relates to bitfield other than massive LE/BE confusion */
3434 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3435 *running_offset += size;
3437 stream->duration_moof += dur;
3441 /* Update total duration if needed */
3442 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3444 /* Pre-emptively figure out size of mdat based on trun information.
3445 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3446 * size, else we will still be able to use this when dealing with gap'ed
3448 qtdemux->mdatleft = *running_offset - initial_offset;
3449 qtdemux->mdatoffset = initial_offset;
3450 qtdemux->mdatsize = qtdemux->mdatleft;
3452 stream->n_samples += samples_count;
3453 stream->n_samples_moof += samples_count;
3455 if (stream->pending_seek != NULL)
3456 stream->pending_seek = NULL;
3462 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3467 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3473 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3474 "be larger than %uMB (broken file?)", stream->n_samples,
3475 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3480 /* find stream with @id */
3481 static inline QtDemuxStream *
3482 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3484 QtDemuxStream *stream;
3488 if (G_UNLIKELY (!id)) {
3489 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3493 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3494 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3495 if (stream->track_id == id)
3498 if (qtdemux->mss_mode) {
3499 /* mss should have only 1 stream anyway */
3500 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3507 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3508 guint32 * fragment_number)
3510 if (!gst_byte_reader_skip (mfhd, 4))
3512 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3517 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3523 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3524 QtDemuxStream ** stream, guint32 * default_sample_duration,
3525 guint32 * default_sample_size, guint32 * default_sample_flags,
3526 gint64 * base_offset)
3529 guint32 track_id = 0;
3531 if (!gst_byte_reader_skip (tfhd, 1) ||
3532 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3535 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3538 *stream = qtdemux_find_stream (qtdemux, track_id);
3539 if (G_UNLIKELY (!*stream))
3540 goto unknown_stream;
3542 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3543 *base_offset = qtdemux->moof_offset;
3545 if (flags & TF_BASE_DATA_OFFSET)
3546 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3549 /* obtain stream defaults */
3550 qtdemux_parse_trex (qtdemux, *stream,
3551 default_sample_duration, default_sample_size, default_sample_flags);
3553 (*stream)->stsd_sample_description_id =
3554 (*stream)->def_sample_description_index - 1;
3556 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3557 guint32 sample_description_index;
3558 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3560 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3563 if (qtdemux->mss_mode) {
3564 /* mss has no stsd entry */
3565 (*stream)->stsd_sample_description_id = 0;
3568 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3569 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3572 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3573 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3576 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3577 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3584 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3589 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3595 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3596 guint64 * decode_time)
3598 guint32 version = 0;
3600 if (!gst_byte_reader_get_uint32_be (br, &version))
3605 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3608 guint32 dec_time = 0;
3609 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3611 *decode_time = dec_time;
3614 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3621 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3626 /* Returns a pointer to a GstStructure containing the properties of
3627 * the stream sample identified by @sample_index. The caller must unref
3628 * the returned object after use. Returns NULL if unsuccessful. */
3629 static GstStructure *
3630 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3631 QtDemuxStream * stream, guint sample_index)
3633 QtDemuxCencSampleSetInfo *info = NULL;
3635 g_return_val_if_fail (stream != NULL, NULL);
3636 g_return_val_if_fail (stream->protected, NULL);
3637 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3639 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3641 /* Currently, cenc properties for groups of samples are not supported, so
3642 * simply return a copy of the default sample properties */
3643 return gst_structure_copy (info->default_properties);
3646 /* Parses the sizes of sample auxiliary information contained within a stream,
3647 * as given in a saiz box. Returns array of sample_count guint8 size values,
3648 * or NULL on failure */
3650 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3651 GstByteReader * br, guint32 * sample_count)
3655 guint8 default_info_size;
3657 g_return_val_if_fail (qtdemux != NULL, NULL);
3658 g_return_val_if_fail (stream != NULL, NULL);
3659 g_return_val_if_fail (br != NULL, NULL);
3660 g_return_val_if_fail (sample_count != NULL, NULL);
3662 if (!gst_byte_reader_get_uint32_be (br, &flags))
3666 /* aux_info_type and aux_info_type_parameter are ignored */
3667 if (!gst_byte_reader_skip (br, 8))
3671 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3673 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3675 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3677 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3680 if (default_info_size == 0) {
3681 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3685 info_sizes = g_new (guint8, *sample_count);
3686 memset (info_sizes, default_info_size, *sample_count);
3692 /* Parses the offset of sample auxiliary information contained within a stream,
3693 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3695 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3696 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3701 guint32 aux_info_type = 0;
3702 guint32 aux_info_type_parameter = 0;
3703 guint32 entry_count;
3706 const guint8 *aux_info_type_data = NULL;
3708 g_return_val_if_fail (qtdemux != NULL, FALSE);
3709 g_return_val_if_fail (stream != NULL, FALSE);
3710 g_return_val_if_fail (br != NULL, FALSE);
3711 g_return_val_if_fail (offset != NULL, FALSE);
3713 if (!gst_byte_reader_get_uint8 (br, &version))
3716 if (!gst_byte_reader_get_uint24_be (br, &flags))
3721 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3723 aux_info_type = QT_FOURCC (aux_info_type_data);
3725 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3727 } else if (stream->protected) {
3728 aux_info_type = stream->protection_scheme_type;
3730 aux_info_type = CUR_STREAM (stream)->fourcc;
3734 *info_type = aux_info_type;
3735 if (info_type_parameter)
3736 *info_type_parameter = aux_info_type_parameter;
3738 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3739 "aux_info_type_parameter: %#06x",
3740 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3742 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3745 if (entry_count != 1) {
3746 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3751 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3753 *offset = (guint64) off_32;
3755 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3760 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3765 qtdemux_gst_structure_free (GstStructure * gststructure)
3768 gst_structure_free (gststructure);
3772 /* Parses auxiliary information relating to samples protected using
3773 * Common Encryption (cenc); the format of this information
3774 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3777 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3778 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3780 QtDemuxCencSampleSetInfo *ss_info = NULL;
3783 GPtrArray *old_crypto_info = NULL;
3784 guint old_entries = 0;
3786 g_return_val_if_fail (qtdemux != NULL, FALSE);
3787 g_return_val_if_fail (stream != NULL, FALSE);
3788 g_return_val_if_fail (br != NULL, FALSE);
3789 g_return_val_if_fail (stream->protected, FALSE);
3790 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3792 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3794 if (ss_info->crypto_info) {
3795 old_crypto_info = ss_info->crypto_info;
3796 /* Count number of non-null entries remaining at the tail end */
3797 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3798 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3804 ss_info->crypto_info =
3805 g_ptr_array_new_full (sample_count + old_entries,
3806 (GDestroyNotify) qtdemux_gst_structure_free);
3808 /* We preserve old entries because we parse the next moof in advance
3809 * of consuming all samples from the previous moof, and otherwise
3810 * we'd discard the corresponding crypto info for the samples
3811 * from the previous fragment. */
3813 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3815 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3816 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3818 g_ptr_array_index (old_crypto_info, i) = NULL;
3822 if (old_crypto_info) {
3823 /* Everything now belongs to the new array */
3824 g_ptr_array_free (old_crypto_info, TRUE);
3827 for (i = 0; i < sample_count; ++i) {
3828 GstStructure *properties;
3829 guint16 n_subsamples = 0;
3833 gboolean could_read_iv;
3835 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3836 if (properties == NULL) {
3837 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3840 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3841 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3842 gst_structure_free (properties);
3846 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3847 if (could_read_iv) {
3848 buf = gst_buffer_new_wrapped (data, iv_size);
3849 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3850 gst_buffer_unref (buf);
3851 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3852 const GValue *constant_iv_size_value =
3853 gst_structure_get_value (properties, "constant_iv_size");
3854 const GValue *constant_iv_value =
3855 gst_structure_get_value (properties, "iv");
3856 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3857 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3858 gst_structure_free (properties);
3861 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3862 gst_structure_remove_field (properties, "constant_iv_size");
3863 } else if (stream->protection_scheme_type == FOURCC_cenc) {
3864 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3865 gst_structure_free (properties);
3868 size = info_sizes[i];
3869 if (size > iv_size) {
3870 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3871 || !(n_subsamples > 0)) {
3872 gst_structure_free (properties);
3873 GST_ERROR_OBJECT (qtdemux,
3874 "failed to get subsample count for sample %u", i);
3877 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3878 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3879 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3881 gst_structure_free (properties);
3884 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3886 gst_structure_free (properties);
3889 gst_structure_set (properties,
3890 "subsample_count", G_TYPE_UINT, n_subsamples,
3891 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3892 gst_buffer_unref (buf);
3894 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3896 g_ptr_array_add (ss_info->crypto_info, properties);
3901 /* Converts a UUID in raw byte form to a string representation, as defined in
3902 * RFC 4122. The caller takes ownership of the returned string and is
3903 * responsible for freeing it after use. */
3905 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3907 const guint8 *uuid = (const guint8 *) uuid_bytes;
3909 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3910 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3911 uuid[0], uuid[1], uuid[2], uuid[3],
3912 uuid[4], uuid[5], uuid[6], uuid[7],
3913 uuid[8], uuid[9], uuid[10], uuid[11],
3914 uuid[12], uuid[13], uuid[14], uuid[15]);
3917 /* Parses a Protection System Specific Header box (pssh), as defined in the
3918 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3919 * information needed by a specific content protection system in order to
3920 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3923 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3925 gchar *sysid_string;
3926 guint32 pssh_size = QT_UINT32 (node->data);
3927 GstBuffer *pssh = NULL;
3928 GstEvent *event = NULL;
3929 guint32 parent_box_type;
3932 if (G_UNLIKELY (pssh_size < 32U)) {
3933 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3938 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3940 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3942 pssh = gst_buffer_new_memdup (node->data, pssh_size);
3943 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3944 gst_buffer_get_size (pssh));
3946 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3948 /* Push an event containing the pssh box onto the queues of all streams. */
3949 event = gst_event_new_protection (sysid_string, pssh,
3950 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3951 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3952 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3953 GST_TRACE_OBJECT (qtdemux,
3954 "adding protection event for stream %s and system %s",
3955 stream->stream_id, sysid_string);
3956 g_queue_push_tail (&stream->protection_scheme_event_queue,
3957 gst_event_ref (event));
3959 g_free (sysid_string);
3960 gst_event_unref (event);
3961 gst_buffer_unref (pssh);
3966 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3967 guint64 moof_offset, QtDemuxStream * stream)
3969 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3971 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3972 GNode *saiz_node, *saio_node, *pssh_node;
3973 GstByteReader saiz_data, saio_data;
3974 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3975 gint64 base_offset, running_offset;
3977 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
3979 /* NOTE @stream ignored */
3981 moof_node = g_node_new ((guint8 *) buffer);
3982 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3983 qtdemux_node_dump (qtdemux, moof_node);
3985 /* Get fragment number from mfhd and check it's valid */
3987 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3988 if (mfhd_node == NULL)
3990 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3992 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3994 /* unknown base_offset to start with */
3995 base_offset = running_offset = -1;
3996 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3998 guint64 decode_time = 0;
4000 /* Fragment Header node */
4002 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4006 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4007 &ds_size, &ds_flags, &base_offset))
4010 /* The following code assumes at most a single set of sample auxiliary
4011 * data in the fragment (consisting of a saiz box and a corresponding saio
4012 * box); in theory, however, there could be multiple sets of sample
4013 * auxiliary data in a fragment. */
4015 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4018 guint32 info_type = 0;
4020 guint32 info_type_parameter = 0;
4022 g_free (qtdemux->cenc_aux_info_sizes);
4024 qtdemux->cenc_aux_info_sizes =
4025 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4026 &qtdemux->cenc_aux_sample_count);
4027 if (qtdemux->cenc_aux_info_sizes == NULL) {
4028 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4032 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4035 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4036 g_free (qtdemux->cenc_aux_info_sizes);
4037 qtdemux->cenc_aux_info_sizes = NULL;
4041 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4042 &info_type, &info_type_parameter, &offset))) {
4043 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4044 g_free (qtdemux->cenc_aux_info_sizes);
4045 qtdemux->cenc_aux_info_sizes = NULL;
4048 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4049 offset += (guint64) (base_offset - qtdemux->moof_offset);
4050 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4051 && info_type_parameter == 0U) {
4053 if (offset > length) {
4054 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4055 qtdemux->cenc_aux_info_offset = offset;
4057 gst_byte_reader_init (&br, buffer + offset, length - offset);
4058 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4059 qtdemux->cenc_aux_info_sizes,
4060 qtdemux->cenc_aux_sample_count)) {
4061 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4062 g_free (qtdemux->cenc_aux_info_sizes);
4063 qtdemux->cenc_aux_info_sizes = NULL;
4071 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4074 /* We'll use decode_time to interpolate timestamps
4075 * in case the input timestamps are missing */
4076 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4078 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4079 " (%" GST_TIME_FORMAT ")", decode_time,
4080 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4081 decode_time) : GST_CLOCK_TIME_NONE));
4083 /* Discard the fragment buffer timestamp info to avoid using it.
4084 * Rely on tfdt instead as it is more accurate than the timestamp
4085 * that is fetched from a manifest/playlist and is usually
4087 qtdemux->fragment_start = -1;
4090 if (G_UNLIKELY (!stream)) {
4091 /* we lost track of offset, we'll need to regain it,
4092 * but can delay complaining until later or avoid doing so altogether */
4096 if (G_UNLIKELY (base_offset < -1))
4099 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4101 if (!qtdemux->pullbased) {
4102 /* Sample tables can grow enough to be problematic if the system memory
4103 * is very low (e.g. embedded devices) and the videos very long
4104 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4105 * Fortunately, we can easily discard them for each new fragment when
4106 * we know qtdemux will not receive seeks outside of the current fragment.
4107 * adaptivedemux honors this assumption.
4108 * This optimization is also useful for applications that use qtdemux as
4109 * a push-based simple demuxer, like Media Source Extensions. */
4110 gst_qtdemux_stream_flush_samples_data (stream);
4113 /* initialise moof sample data */
4114 stream->n_samples_moof = 0;
4115 stream->duration_last_moof = stream->duration_moof;
4116 stream->duration_moof = 0;
4118 /* Track Run node */
4120 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4123 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4124 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4125 &running_offset, decode_time, (tfdt_node != NULL));
4126 /* iterate all siblings */
4127 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4131 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4133 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4134 guint32 box_length = QT_UINT32 (uuid_buffer);
4136 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4139 /* if no new base_offset provided for next traf,
4140 * base is end of current traf */
4141 base_offset = running_offset;
4142 running_offset = -1;
4144 if (stream->n_samples_moof && stream->duration_moof)
4145 stream->new_caps = TRUE;
4148 /* iterate all siblings */
4149 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4152 /* parse any protection system info */
4153 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4155 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4156 qtdemux_parse_pssh (qtdemux, pssh_node);
4157 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4160 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4161 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4163 /* Unless the user has explicitly requested another seek, perform an
4164 * internal seek to the time specified in the tfdt.
4166 * This way if the user opens a file where the first tfdt is 1 hour
4167 * into the presentation, they will not have to wait 1 hour for run
4168 * time to catch up and actual playback to start. */
4171 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4172 "performing an internal seek to %" GST_TIME_FORMAT,
4173 GST_TIME_ARGS (min_dts));
4175 qtdemux->segment.start = min_dts;
4176 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4178 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4179 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4180 stream->time_position = min_dts;
4183 /* Before this code was run a segment was already sent when the moov was
4184 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4185 * be emitted after a moov, and we can emit a second segment anyway for
4186 * special cases like this. */
4187 qtdemux->need_segment = TRUE;
4190 qtdemux->first_moof_already_parsed = TRUE;
4192 g_node_destroy (moof_node);
4197 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4202 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4207 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4212 g_node_destroy (moof_node);
4213 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4214 (_("This file is corrupt and cannot be played.")), (NULL));
4220 /* might be used if some day we actually use mfra & co
4221 * for random access to fragments,
4222 * but that will require quite some modifications and much less relying
4223 * on a sample array */
4227 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4229 QtDemuxStream *stream;
4230 guint32 ver_flags, track_id, len, num_entries, i;
4231 guint value_size, traf_size, trun_size, sample_size;
4232 guint64 time = 0, moof_offset = 0;
4234 GstBuffer *buf = NULL;
4239 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4241 if (!gst_byte_reader_skip (&tfra, 8))
4244 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4247 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4248 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4249 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4252 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4254 stream = qtdemux_find_stream (qtdemux, track_id);
4256 goto unknown_trackid;
4258 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4259 sample_size = (len & 3) + 1;
4260 trun_size = ((len & 12) >> 2) + 1;
4261 traf_size = ((len & 48) >> 4) + 1;
4263 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4264 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4266 if (num_entries == 0)
4269 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4270 value_size + value_size + traf_size + trun_size + sample_size))
4273 g_free (stream->ra_entries);
4274 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4275 stream->n_ra_entries = num_entries;
4277 for (i = 0; i < num_entries; i++) {
4278 qt_atom_parser_get_offset (&tfra, value_size, &time);
4279 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4280 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4281 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4282 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4284 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4286 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4287 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4289 stream->ra_entries[i].ts = time;
4290 stream->ra_entries[i].moof_offset = moof_offset;
4292 /* don't want to go through the entire file and read all moofs at startup */
4294 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4295 if (ret != GST_FLOW_OK)
4297 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4298 moof_offset, stream);
4299 gst_buffer_unref (buf);
4303 check_update_duration (qtdemux, time);
4310 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4315 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4320 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4326 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4328 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4329 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4330 GstBuffer *mfro = NULL, *mfra = NULL;
4332 gboolean ret = FALSE;
4333 GNode *mfra_node, *tfra_node;
4334 guint64 mfra_offset = 0;
4335 guint32 fourcc, mfra_size;
4338 /* query upstream size in bytes */
4339 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4340 goto size_query_failed;
4342 /* mfro box should be at the very end of the file */
4343 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4344 if (flow != GST_FLOW_OK)
4347 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4349 fourcc = QT_FOURCC (mfro_map.data + 4);
4350 if (fourcc != FOURCC_mfro)
4353 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4354 if (mfro_map.size < 16)
4355 goto invalid_mfro_size;
4357 mfra_size = QT_UINT32 (mfro_map.data + 12);
4358 if (mfra_size >= len)
4359 goto invalid_mfra_size;
4361 mfra_offset = len - mfra_size;
4363 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4364 mfra_offset, mfra_size);
4366 /* now get and parse mfra box */
4367 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4368 if (flow != GST_FLOW_OK)
4371 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4373 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4374 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4376 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4379 qtdemux_parse_tfra (qtdemux, tfra_node);
4380 /* iterate all siblings */
4381 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4383 g_node_destroy (mfra_node);
4385 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4391 if (mfro_map.memory != NULL)
4392 gst_buffer_unmap (mfro, &mfro_map);
4393 gst_buffer_unref (mfro);
4396 if (mfra_map.memory != NULL)
4397 gst_buffer_unmap (mfra, &mfra_map);
4398 gst_buffer_unref (mfra);
4405 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4410 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4415 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4420 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4426 add_offset (guint64 offset, guint64 advance)
4428 /* Avoid 64-bit overflow by clamping */
4429 if (offset > G_MAXUINT64 - advance)
4431 return offset + advance;
4434 static GstFlowReturn
4435 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4439 GstBuffer *buf = NULL;
4440 GstFlowReturn ret = GST_FLOW_OK;
4441 guint64 cur_offset = qtdemux->offset;
4444 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4445 if (G_UNLIKELY (ret != GST_FLOW_OK))
4447 gst_buffer_map (buf, &map, GST_MAP_READ);
4448 if (G_LIKELY (map.size >= 8))
4449 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4450 gst_buffer_unmap (buf, &map);
4451 gst_buffer_unref (buf);
4453 /* maybe we already got most we needed, so only consider this eof */
4454 if (G_UNLIKELY (length == 0)) {
4455 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4456 (_("Invalid atom size.")),
4457 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4458 GST_FOURCC_ARGS (fourcc)));
4465 /* record for later parsing when needed */
4466 if (!qtdemux->moof_offset) {
4467 qtdemux->moof_offset = qtdemux->offset;
4469 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4472 qtdemux->offset += length; /* skip moof and keep going */
4474 if (qtdemux->got_moov) {
4475 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4487 GST_LOG_OBJECT (qtdemux,
4488 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4489 GST_FOURCC_ARGS (fourcc), cur_offset);
4490 qtdemux->offset = add_offset (qtdemux->offset, length);
4495 GstBuffer *moov = NULL;
4497 if (qtdemux->got_moov) {
4498 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4499 qtdemux->offset = add_offset (qtdemux->offset, length);
4503 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4504 if (ret != GST_FLOW_OK)
4506 gst_buffer_map (moov, &map, GST_MAP_READ);
4508 if (length != map.size) {
4509 /* Some files have a 'moov' atom at the end of the file which contains
4510 * a terminal 'free' atom where the body of the atom is missing.
4511 * Check for, and permit, this special case.
4513 if (map.size >= 8) {
4514 guint8 *final_data = map.data + (map.size - 8);
4515 guint32 final_length = QT_UINT32 (final_data);
4516 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4518 if (final_fourcc == FOURCC_free
4519 && map.size + final_length - 8 == length) {
4520 /* Ok, we've found that special case. Allocate a new buffer with
4521 * that free atom actually present. */
4522 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4523 gst_buffer_fill (newmoov, 0, map.data, map.size);
4524 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4525 gst_buffer_unmap (moov, &map);
4526 gst_buffer_unref (moov);
4528 gst_buffer_map (moov, &map, GST_MAP_READ);
4533 if (length != map.size) {
4534 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4535 (_("This file is incomplete and cannot be played.")),
4536 ("We got less than expected (received %" G_GSIZE_FORMAT
4537 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4538 (guint) length, cur_offset));
4539 gst_buffer_unmap (moov, &map);
4540 gst_buffer_unref (moov);
4541 ret = GST_FLOW_ERROR;
4544 qtdemux->offset += length;
4546 qtdemux_parse_moov (qtdemux, map.data, length);
4547 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4549 qtdemux_parse_tree (qtdemux);
4550 if (qtdemux->moov_node_compressed) {
4551 g_node_destroy (qtdemux->moov_node_compressed);
4552 g_free (qtdemux->moov_node->data);
4554 qtdemux->moov_node_compressed = NULL;
4555 g_node_destroy (qtdemux->moov_node);
4556 qtdemux->moov_node = NULL;
4557 gst_buffer_unmap (moov, &map);
4558 gst_buffer_unref (moov);
4559 qtdemux->got_moov = TRUE;
4565 GstBuffer *ftyp = NULL;
4567 /* extract major brand; might come in handy for ISO vs QT issues */
4568 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4569 if (ret != GST_FLOW_OK)
4571 qtdemux->offset += length;
4572 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4573 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4574 gst_buffer_unmap (ftyp, &map);
4575 gst_buffer_unref (ftyp);
4580 GstBuffer *uuid = NULL;
4582 /* uuid are extension atoms */
4583 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4584 if (ret != GST_FLOW_OK)
4586 qtdemux->offset += length;
4587 gst_buffer_map (uuid, &map, GST_MAP_READ);
4588 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4589 gst_buffer_unmap (uuid, &map);
4590 gst_buffer_unref (uuid);
4595 GstBuffer *sidx = NULL;
4596 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4597 if (ret != GST_FLOW_OK)
4599 qtdemux->offset += length;
4600 gst_buffer_map (sidx, &map, GST_MAP_READ);
4601 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4602 gst_buffer_unmap (sidx, &map);
4603 gst_buffer_unref (sidx);
4608 GstBuffer *unknown = NULL;
4610 GST_LOG_OBJECT (qtdemux,
4611 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4612 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4614 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4615 if (ret != GST_FLOW_OK)
4617 gst_buffer_map (unknown, &map, GST_MAP_READ);
4618 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4619 gst_buffer_unmap (unknown, &map);
4620 gst_buffer_unref (unknown);
4621 qtdemux->offset += length;
4627 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4628 /* digested all data, show what we have */
4629 qtdemux_prepare_streams (qtdemux);
4630 QTDEMUX_EXPOSE_LOCK (qtdemux);
4631 ret = qtdemux_expose_streams (qtdemux);
4632 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4634 qtdemux->state = QTDEMUX_STATE_MOVIE;
4635 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4642 /* Seeks to the previous keyframe of the indexed stream and
4643 * aligns other streams with respect to the keyframe timestamp
4644 * of indexed stream. Only called in case of Reverse Playback
4646 static GstFlowReturn
4647 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4649 guint32 seg_idx = 0, k_index = 0;
4650 guint32 ref_seg_idx, ref_k_index;
4651 GstClockTime k_pos = 0, last_stop = 0;
4652 QtDemuxSegment *seg = NULL;
4653 QtDemuxStream *ref_str = NULL;
4654 guint64 seg_media_start_mov; /* segment media start time in mov format */
4658 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4659 * and finally align all the other streams on that timestamp with their
4660 * respective keyframes */
4661 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4662 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4664 /* No candidate yet, take the first stream */
4670 /* So that stream has a segment, we prefer video streams */
4671 if (str->subtype == FOURCC_vide) {
4677 if (G_UNLIKELY (!ref_str)) {
4678 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4682 if (G_UNLIKELY (!ref_str->from_sample)) {
4683 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4687 /* So that stream has been playing from from_sample to to_sample. We will
4688 * get the timestamp of the previous sample and search for a keyframe before
4689 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4690 if (ref_str->subtype == FOURCC_vide) {
4691 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4692 ref_str->from_sample - 1, FALSE);
4694 if (ref_str->from_sample >= 10)
4695 k_index = ref_str->from_sample - 10;
4701 ref_str->samples[k_index].timestamp +
4702 ref_str->samples[k_index].pts_offset;
4704 /* get current segment for that stream */
4705 seg = &ref_str->segments[ref_str->segment_index];
4706 /* Use segment start in original timescale for comparisons */
4707 seg_media_start_mov = seg->trak_media_start;
4709 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4710 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4711 k_index, target_ts, seg_media_start_mov,
4712 GST_TIME_ARGS (seg->media_start));
4714 /* Crawl back through segments to find the one containing this I frame */
4715 while (target_ts < seg_media_start_mov) {
4716 GST_DEBUG_OBJECT (qtdemux,
4717 "keyframe position (sample %u) is out of segment %u " " target %"
4718 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4719 ref_str->segment_index, target_ts, seg_media_start_mov);
4721 if (G_UNLIKELY (!ref_str->segment_index)) {
4722 /* Reached first segment, let's consider it's EOS */
4725 ref_str->segment_index--;
4726 seg = &ref_str->segments[ref_str->segment_index];
4727 /* Use segment start in original timescale for comparisons */
4728 seg_media_start_mov = seg->trak_media_start;
4730 /* Calculate time position of the keyframe and where we should stop */
4732 QTSTREAMTIME_TO_GSTTIME (ref_str,
4733 target_ts - seg->trak_media_start) + seg->time;
4735 QTSTREAMTIME_TO_GSTTIME (ref_str,
4736 ref_str->samples[ref_str->from_sample].timestamp -
4737 seg->trak_media_start) + seg->time;
4739 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4740 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4741 k_index, GST_TIME_ARGS (k_pos));
4743 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4744 qtdemux->segment.position = last_stop;
4745 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4746 GST_TIME_ARGS (last_stop));
4748 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4749 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4753 ref_seg_idx = ref_str->segment_index;
4754 ref_k_index = k_index;
4756 /* Align them all on this */
4757 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4759 GstClockTime seg_time = 0;
4760 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4762 /* aligning reference stream again might lead to backing up to yet another
4763 * keyframe (due to timestamp rounding issues),
4764 * potentially putting more load on downstream; so let's try to avoid */
4765 if (str == ref_str) {
4766 seg_idx = ref_seg_idx;
4767 seg = &str->segments[seg_idx];
4768 k_index = ref_k_index;
4769 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4770 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4772 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4773 GST_DEBUG_OBJECT (qtdemux,
4774 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4775 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4777 /* get segment and time in the segment */
4778 seg = &str->segments[seg_idx];
4779 seg_time = k_pos - seg->time;
4781 /* get the media time in the segment.
4782 * No adjustment for empty "filler" segments */
4783 if (seg->media_start != GST_CLOCK_TIME_NONE)
4784 seg_time += seg->media_start;
4786 /* get the index of the sample with media time */
4787 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4788 GST_DEBUG_OBJECT (qtdemux,
4789 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4790 GST_TIME_ARGS (seg_time), index);
4792 /* find previous keyframe */
4793 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4796 /* Remember until where we want to go */
4797 str->to_sample = str->from_sample - 1;
4798 /* Define our time position */
4800 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4801 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4802 if (seg->media_start != GST_CLOCK_TIME_NONE)
4803 str->time_position -= seg->media_start;
4805 /* Now seek back in time */
4806 gst_qtdemux_move_stream (qtdemux, str, k_index);
4807 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4808 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4809 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4815 return GST_FLOW_EOS;
4819 * Gets the current qt segment start, stop and position for the
4820 * given time offset. This is used in update_segment()
4823 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4824 QtDemuxStream * stream, GstClockTime offset,
4825 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4827 GstClockTime seg_time;
4828 GstClockTime start, stop, time;
4829 QtDemuxSegment *segment;
4831 segment = &stream->segments[stream->segment_index];
4833 /* get time in this segment */
4834 seg_time = (offset - segment->time) * segment->rate;
4836 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4837 GST_TIME_ARGS (seg_time));
4839 if (G_UNLIKELY (seg_time > segment->duration)) {
4840 GST_LOG_OBJECT (stream->pad,
4841 "seg_time > segment->duration %" GST_TIME_FORMAT,
4842 GST_TIME_ARGS (segment->duration));
4843 seg_time = segment->duration;
4846 /* qtdemux->segment.stop is in outside-time-realm, whereas
4847 * segment->media_stop is in track-time-realm.
4849 * In order to compare the two, we need to bring segment.stop
4850 * into the track-time-realm
4852 * FIXME - does this comment still hold? Don't see any conversion here */
4854 stop = qtdemux->segment.stop;
4855 if (stop == GST_CLOCK_TIME_NONE)
4856 stop = qtdemux->segment.duration;
4857 if (stop == GST_CLOCK_TIME_NONE)
4858 stop = segment->media_stop;
4861 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4863 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4864 start = segment->time + seg_time;
4866 stop = start - seg_time + segment->duration;
4867 } else if (qtdemux->segment.rate >= 0) {
4868 start = MIN (segment->media_start + seg_time, stop);
4871 if (segment->media_start >= qtdemux->segment.start) {
4872 time = segment->time;
4874 time = segment->time + (qtdemux->segment.start - segment->media_start);
4877 start = MAX (segment->media_start, qtdemux->segment.start);
4878 stop = MIN (segment->media_start + seg_time, stop);
4887 * Updates the qt segment used for the stream and pushes a new segment event
4888 * downstream on this stream's pad.
4891 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4892 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4893 GstClockTime * _stop)
4895 QtDemuxSegment *segment;
4896 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4900 /* update the current segment */
4901 stream->segment_index = seg_idx;
4903 /* get the segment */
4904 segment = &stream->segments[seg_idx];
4906 if (G_UNLIKELY (offset < segment->time)) {
4907 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4908 GST_TIME_ARGS (segment->time));
4912 /* segment lies beyond total indicated duration */
4913 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4914 segment->time > qtdemux->segment.duration)) {
4915 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4916 " < segment->time %" GST_TIME_FORMAT,
4917 GST_TIME_ARGS (qtdemux->segment.duration),
4918 GST_TIME_ARGS (segment->time));
4922 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4923 &start, &stop, &time);
4925 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4926 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4927 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4929 /* combine global rate with that of the segment */
4930 rate = segment->rate * qtdemux->segment.rate;
4932 /* Copy flags from main segment */
4933 stream->segment.flags = qtdemux->segment.flags;
4935 /* update the segment values used for clipping */
4936 stream->segment.offset = qtdemux->segment.offset;
4937 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4938 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4939 stream->segment.rate = rate;
4940 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4941 stream->cslg_shift);
4942 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4943 stream->cslg_shift);
4944 stream->segment.time = time;
4945 stream->segment.position = stream->segment.start;
4947 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4950 /* now prepare and send the segment */
4952 event = gst_event_new_segment (&stream->segment);
4953 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4954 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4956 gst_pad_push_event (stream->pad, event);
4957 /* assume we can send more data now */
4958 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4959 /* clear to send tags on this pad now */
4960 gst_qtdemux_push_tags (qtdemux, stream);
4971 /* activate the given segment number @seg_idx of @stream at time @offset.
4972 * @offset is an absolute global position over all the segments.
4974 * This will push out a NEWSEGMENT event with the right values and
4975 * position the stream index to the first decodable sample before
4979 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4980 guint32 seg_idx, GstClockTime offset)
4982 QtDemuxSegment *segment;
4983 guint32 index, kf_index;
4984 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4986 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4987 seg_idx, GST_TIME_ARGS (offset));
4989 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4993 segment = &stream->segments[stream->segment_index];
4995 /* in the fragmented case, we pick a fragment that starts before our
4996 * desired position and rely on downstream to wait for a keyframe
4997 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4998 * tfra entries tells us which trun/sample the key unit is in, but we don't
4999 * make use of this additional information at the moment) */
5000 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5001 stream->to_sample = G_MAXUINT32;
5004 /* well, it will be taken care of below */
5005 qtdemux->fragmented_seek_pending = FALSE;
5006 /* FIXME ideally the do_fragmented_seek can be done right here,
5007 * rather than at loop level
5008 * (which might even allow handling edit lists in a fragmented file) */
5011 /* We don't need to look for a sample in push-based */
5012 if (!qtdemux->pullbased)
5015 /* and move to the keyframe before the indicated media time of the
5017 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5018 if (qtdemux->segment.rate >= 0) {
5019 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5020 stream->to_sample = G_MAXUINT32;
5021 GST_DEBUG_OBJECT (stream->pad,
5022 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5023 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5024 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5026 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5027 stream->to_sample = index;
5028 GST_DEBUG_OBJECT (stream->pad,
5029 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5030 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5031 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5034 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5035 "this is an empty segment");
5039 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5040 * encountered an error and printed a message so we return appropriately */
5044 /* we're at the right spot */
5045 if (index == stream->sample_index) {
5046 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5050 /* find keyframe of the target index */
5051 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5053 /* go back two frames to provide lead-in for non-raw audio decoders */
5054 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5055 guint32 lead_in = 2;
5056 guint32 old_index = kf_index;
5057 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5059 if (gst_structure_has_name (s, "audio/mpeg")) {
5061 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5062 && mpegversion == 1) {
5063 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5068 kf_index = MAX (kf_index, lead_in) - lead_in;
5069 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5070 GST_DEBUG_OBJECT (stream->pad,
5071 "Moving backwards %u frames to ensure sufficient sound lead-in",
5072 old_index - kf_index);
5074 kf_index = old_index;
5078 /* if we move forwards, we don't have to go back to the previous
5079 * keyframe since we already sent that. We can also just jump to
5080 * the keyframe right before the target index if there is one. */
5081 if (index > stream->sample_index) {
5082 /* moving forwards check if we move past a keyframe */
5083 if (kf_index > stream->sample_index) {
5084 GST_DEBUG_OBJECT (stream->pad,
5085 "moving forwards to keyframe at %u "
5086 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5088 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5089 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5090 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5092 GST_DEBUG_OBJECT (stream->pad,
5093 "moving forwards, keyframe at %u "
5094 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5096 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5097 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5100 GST_DEBUG_OBJECT (stream->pad,
5101 "moving backwards to %sframe at %u "
5102 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5103 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5104 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5105 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5106 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5112 /* prepare to get the current sample of @stream, getting essential values.
5114 * This function will also prepare and send the segment when needed.
5116 * Return FALSE if the stream is EOS.
5121 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5122 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5123 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5124 gboolean * keyframe)
5126 QtDemuxSample *sample;
5127 GstClockTime time_position;
5130 g_return_val_if_fail (stream != NULL, FALSE);
5132 time_position = stream->time_position;
5133 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5136 seg_idx = stream->segment_index;
5137 if (G_UNLIKELY (seg_idx == -1)) {
5138 /* find segment corresponding to time_position if we are looking
5140 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5143 /* different segment, activate it, sample_index will be set. */
5144 if (G_UNLIKELY (stream->segment_index != seg_idx))
5145 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5147 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5148 segments[stream->segment_index]))) {
5149 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5151 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5152 " prepare empty sample");
5155 *pts = *dts = time_position;
5156 *duration = seg->duration - (time_position - seg->time);
5163 if (stream->sample_index == -1)
5164 stream->sample_index = 0;
5166 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5167 stream->sample_index, stream->n_samples);
5169 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5170 if (!qtdemux->fragmented)
5173 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5177 GST_OBJECT_LOCK (qtdemux);
5178 flow = qtdemux_add_fragmented_samples (qtdemux);
5179 GST_OBJECT_UNLOCK (qtdemux);
5181 if (flow != GST_FLOW_OK)
5184 while (stream->sample_index >= stream->n_samples);
5187 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5188 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5189 stream->sample_index);
5193 /* now get the info for the sample we're at */
5194 sample = &stream->samples[stream->sample_index];
5196 *dts = QTSAMPLE_DTS (stream, sample);
5197 *pts = QTSAMPLE_PTS (stream, sample);
5198 *offset = sample->offset;
5199 *size = sample->size;
5200 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5201 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5208 stream->time_position = GST_CLOCK_TIME_NONE;
5213 /* move to the next sample in @stream.
5215 * Moves to the next segment when needed.
5218 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5220 QtDemuxSample *sample;
5221 QtDemuxSegment *segment;
5223 /* get current segment */
5224 segment = &stream->segments[stream->segment_index];
5226 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5227 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5231 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5232 /* Mark the stream as EOS */
5233 GST_DEBUG_OBJECT (qtdemux,
5234 "reached max allowed sample %u, mark EOS", stream->to_sample);
5235 stream->time_position = GST_CLOCK_TIME_NONE;
5239 /* move to next sample */
5240 stream->sample_index++;
5241 stream->offset_in_sample = 0;
5243 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5246 /* reached the last sample, we need the next segment */
5247 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5250 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5251 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5252 stream->sample_index);
5256 /* get next sample */
5257 sample = &stream->samples[stream->sample_index];
5259 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5260 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5261 GST_TIME_ARGS (segment->media_stop));
5263 /* see if we are past the segment */
5264 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5267 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5268 /* inside the segment, update time_position, looks very familiar to
5269 * GStreamer segments, doesn't it? */
5270 stream->time_position =
5271 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5273 /* not yet in segment, time does not yet increment. This means
5274 * that we are still prerolling keyframes to the decoder so it can
5275 * decode the first sample of the segment. */
5276 stream->time_position = segment->time;
5280 /* move to the next segment */
5283 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5285 if (stream->segment_index == stream->n_segments - 1) {
5286 /* are we at the end of the last segment, we're EOS */
5287 stream->time_position = GST_CLOCK_TIME_NONE;
5289 /* else we're only at the end of the current segment */
5290 stream->time_position = segment->stop_time;
5292 /* make sure we select a new segment */
5294 /* accumulate previous segments */
5295 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5296 stream->accumulated_base +=
5297 (stream->segment.stop -
5298 stream->segment.start) / ABS (stream->segment.rate);
5300 stream->segment_index = -1;
5305 gst_qtdemux_sync_streams (GstQTDemux * demux)
5309 if (QTDEMUX_N_STREAMS (demux) <= 1)
5312 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5313 QtDemuxStream *stream;
5314 GstClockTime end_time;
5316 stream = QTDEMUX_NTH_STREAM (demux, i);
5321 /* TODO advance time on subtitle streams here, if any some day */
5323 /* some clips/trailers may have unbalanced streams at the end,
5324 * so send EOS on shorter stream to prevent stalling others */
5326 /* do not mess with EOS if SEGMENT seeking */
5327 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5330 if (demux->pullbased) {
5331 /* loop mode is sample time based */
5332 if (!STREAM_IS_EOS (stream))
5335 /* push mode is byte position based */
5336 if (stream->n_samples &&
5337 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5341 if (stream->sent_eos)
5344 /* only act if some gap */
5345 end_time = stream->segments[stream->n_segments - 1].stop_time;
5346 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5347 ", stream end: %" GST_TIME_FORMAT,
5348 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5349 if (GST_CLOCK_TIME_IS_VALID (end_time)
5350 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5353 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5354 GST_PAD_NAME (stream->pad));
5355 stream->sent_eos = TRUE;
5356 event = gst_event_new_eos ();
5357 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5358 gst_event_set_seqnum (event, demux->segment_seqnum);
5359 gst_pad_push_event (stream->pad, event);
5364 /* EOS and NOT_LINKED need to be combined. This means that we return:
5366 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5367 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5369 static GstFlowReturn
5370 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5373 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5376 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5379 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5381 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5385 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5386 * completely clipped
5388 * Should be used only with raw buffers */
5390 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5393 guint64 start, stop, cstart, cstop, diff;
5394 GstClockTime pts, duration;
5396 gint num_rate, denom_rate;
5401 osize = size = gst_buffer_get_size (buf);
5404 /* depending on the type, setup the clip parameters */
5405 if (stream->subtype == FOURCC_soun) {
5406 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5407 num_rate = GST_SECOND;
5408 denom_rate = (gint) CUR_STREAM (stream)->rate;
5410 } else if (stream->subtype == FOURCC_vide) {
5412 num_rate = CUR_STREAM (stream)->fps_n;
5413 denom_rate = CUR_STREAM (stream)->fps_d;
5418 if (frame_size <= 0)
5419 goto bad_frame_size;
5421 /* we can only clip if we have a valid pts */
5422 pts = GST_BUFFER_PTS (buf);
5423 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5426 duration = GST_BUFFER_DURATION (buf);
5428 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5430 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5434 stop = start + duration;
5436 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5437 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5440 /* see if some clipping happened */
5441 diff = cstart - start;
5447 /* bring clipped time to samples and to bytes */
5448 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5451 GST_DEBUG_OBJECT (qtdemux,
5452 "clipping start to %" GST_TIME_FORMAT " %"
5453 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5459 diff = stop - cstop;
5464 /* bring clipped time to samples and then to bytes */
5465 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5467 GST_DEBUG_OBJECT (qtdemux,
5468 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5469 " bytes", GST_TIME_ARGS (cstop), diff);
5474 if (offset != 0 || size != osize)
5475 gst_buffer_resize (buf, offset, size);
5477 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5478 GST_BUFFER_PTS (buf) = pts;
5479 GST_BUFFER_DURATION (buf) = duration;
5483 /* dropped buffer */
5486 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5491 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5496 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5501 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5502 gst_buffer_unref (buf);
5508 gst_qtdemux_align_buffer (GstQTDemux * demux,
5509 GstBuffer * buffer, gsize alignment)
5513 gst_buffer_map (buffer, &map, GST_MAP_READ);
5515 if (map.size < sizeof (guintptr)) {
5516 gst_buffer_unmap (buffer, &map);
5520 if (((guintptr) map.data) & (alignment - 1)) {
5521 GstBuffer *new_buffer;
5522 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5524 new_buffer = gst_buffer_new_allocate (NULL,
5525 gst_buffer_get_size (buffer), ¶ms);
5527 /* Copy data "by hand", so ensure alignment is kept: */
5528 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5530 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5531 GST_DEBUG_OBJECT (demux,
5532 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5535 gst_buffer_unmap (buffer, &map);
5536 gst_buffer_unref (buffer);
5541 gst_buffer_unmap (buffer, &map);
5546 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5552 /* We are converting from pairs to triplets */
5553 *res = ccpair_size / 2 * 3;
5554 storage = g_malloc (*res);
5555 for (i = 0; i * 2 < ccpair_size; i += 1) {
5556 /* FIXME: Use line offset 0 as we simply can't know here */
5558 storage[i * 3] = 0x80 | 0x00;
5560 storage[i * 3] = 0x00 | 0x00;
5561 storage[i * 3 + 1] = ccpair[i * 2];
5562 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5569 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5573 guint32 atom_length, fourcc;
5574 QtDemuxStreamStsdEntry *stsd_entry;
5576 GST_MEMDUMP ("caption atom", data, size);
5578 /* There might be multiple atoms */
5583 atom_length = QT_UINT32 (data);
5584 fourcc = QT_FOURCC (data + 4);
5585 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5588 GST_DEBUG_OBJECT (stream->pad, "here");
5590 /* Check if we have something compatible */
5591 stsd_entry = CUR_STREAM (stream);
5592 switch (stsd_entry->fourcc) {
5594 guint8 *cdat = NULL, *cdt2 = NULL;
5595 gsize cdat_size = 0, cdt2_size = 0;
5596 /* Should be cdat or cdt2 */
5597 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5598 GST_WARNING_OBJECT (stream->pad,
5599 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5600 GST_FOURCC_ARGS (fourcc));
5604 /* Convert to S334-1 Annex A byte triplet */
5605 if (fourcc == FOURCC_cdat)
5606 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5608 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5609 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5612 /* Check for another atom ? */
5613 if (size > atom_length + 8) {
5614 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5615 if (size >= atom_length + new_atom_length) {
5616 fourcc = QT_FOURCC (data + atom_length + 4);
5617 if (fourcc == FOURCC_cdat) {
5620 convert_to_s334_1a (data + atom_length + 8,
5621 new_atom_length - 8, 1, &cdat_size);
5623 GST_WARNING_OBJECT (stream->pad,
5624 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5628 convert_to_s334_1a (data + atom_length + 8,
5629 new_atom_length - 8, 2, &cdt2_size);
5631 GST_WARNING_OBJECT (stream->pad,
5632 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5637 *cclen = cdat_size + cdt2_size;
5638 res = g_malloc (*cclen);
5640 memcpy (res, cdat, cdat_size);
5642 memcpy (res + cdat_size, cdt2, cdt2_size);
5648 if (fourcc != FOURCC_ccdp) {
5649 GST_WARNING_OBJECT (stream->pad,
5650 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5651 GST_FOURCC_ARGS (fourcc));
5654 *cclen = atom_length - 8;
5655 res = g_memdup2 (data + 8, *cclen);
5658 /* Keep this here in case other closed caption formats are added */
5659 g_assert_not_reached ();
5663 GST_MEMDUMP ("Output", res, *cclen);
5668 GST_WARNING ("[cdat] atom is too small or invalid");
5672 /* Handle Closed Caption sample buffers.
5673 * The input buffer metadata must be writable,
5674 * but time/duration etc not yet set and need not be preserved */
5676 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5683 gst_buffer_map (buf, &map, GST_MAP_READ);
5685 /* empty buffer is sent to terminate previous subtitle */
5686 if (map.size <= 2) {
5687 gst_buffer_unmap (buf, &map);
5688 gst_buffer_unref (buf);
5692 /* For closed caption, we need to extract the information from the
5693 * [cdat],[cdt2] or [ccdp] atom */
5694 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5695 gst_buffer_unmap (buf, &map);
5696 gst_buffer_unref (buf);
5698 buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5700 /* Conversion failed or there's nothing */
5706 /* DVD subpicture specific sample handling.
5707 * the input buffer metadata must be writable,
5708 * but time/duration etc not yet set and need not be preserved */
5710 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5713 /* send a one time dvd clut event */
5714 if (stream->pending_event && stream->pad)
5715 gst_pad_push_event (stream->pad, stream->pending_event);
5716 stream->pending_event = NULL;
5718 /* empty buffer is sent to terminate previous subtitle */
5719 if (gst_buffer_get_size (buf) <= 2) {
5720 gst_buffer_unref (buf);
5724 /* That's all the processing needed for subpictures */
5728 /* Timed text formats
5729 * the input buffer metadata must be writable,
5730 * but time/duration etc not yet set and need not be preserved */
5732 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5739 /* not many cases for now */
5740 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5741 stream->subtype != FOURCC_sbtl)) {
5745 gst_buffer_map (buf, &map, GST_MAP_READ);
5747 /* empty buffer is sent to terminate previous subtitle */
5748 if (map.size <= 2) {
5749 gst_buffer_unmap (buf, &map);
5750 gst_buffer_unref (buf);
5754 nsize = GST_READ_UINT16_BE (map.data);
5755 nsize = MIN (nsize, map.size - 2);
5757 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5760 /* takes care of UTF-8 validation or UTF-16 recognition,
5761 * no other encoding expected */
5762 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5763 gst_buffer_unmap (buf, &map);
5765 gst_buffer_unref (buf);
5766 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5768 /* this should not really happen unless the subtitle is corrupted */
5769 gst_buffer_unref (buf);
5773 /* FIXME ? convert optional subsequent style info to markup */
5778 static GstFlowReturn
5779 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5782 GstFlowReturn ret = GST_FLOW_OK;
5783 GstClockTime pts, duration;
5785 if (stream->need_clip)
5786 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5788 if (G_UNLIKELY (buf == NULL))
5791 if (G_UNLIKELY (stream->discont)) {
5792 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5793 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5794 stream->discont = FALSE;
5796 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5799 GST_LOG_OBJECT (qtdemux,
5800 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5801 ", duration %" GST_TIME_FORMAT " on pad %s",
5802 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5803 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5804 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5806 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5807 GstStructure *crypto_info;
5808 QtDemuxAavdEncryptionInfo *info =
5809 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5811 crypto_info = gst_structure_copy (info->default_properties);
5812 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5813 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5816 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
5817 || stream->protection_scheme_type == FOURCC_cbcs)) {
5818 GstStructure *crypto_info;
5819 QtDemuxCencSampleSetInfo *info =
5820 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5824 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5825 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5826 GST_PTR_FORMAT, event);
5827 gst_pad_push_event (stream->pad, event);
5830 if (info->crypto_info == NULL) {
5831 if (stream->protection_scheme_type == FOURCC_cbcs) {
5832 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
5833 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
5834 GST_ERROR_OBJECT (qtdemux,
5835 "failed to attach cbcs metadata to buffer");
5836 qtdemux_gst_structure_free (crypto_info);
5838 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
5841 GST_DEBUG_OBJECT (qtdemux,
5842 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5845 /* The end of the crypto_info array matches our n_samples position,
5846 * so count backward from there */
5847 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5848 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5849 /* steal structure from array */
5850 crypto_info = g_ptr_array_index (info->crypto_info, index);
5851 g_ptr_array_index (info->crypto_info, index) = NULL;
5852 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5853 info->crypto_info->len);
5854 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5855 GST_ERROR_OBJECT (qtdemux,
5856 "failed to attach cenc metadata to buffer");
5858 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5859 index, stream->sample_index);
5864 if (stream->alignment > 1)
5865 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5867 pts = GST_BUFFER_PTS (buf);
5868 duration = GST_BUFFER_DURATION (buf);
5870 ret = gst_pad_push (stream->pad, buf);
5872 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5873 /* mark position in stream, we'll need this to know when to send GAP event */
5874 stream->segment.position = pts + duration;
5882 static GstFlowReturn
5883 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5886 GstFlowReturn ret = GST_FLOW_OK;
5888 if (stream->subtype == FOURCC_clcp
5889 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
5891 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
5892 guint n_triplets, i;
5893 guint field1_off = 0, field2_off = 0;
5895 /* We have to split CEA608 buffers so that each outgoing buffer contains
5896 * one byte pair per field according to the framerate of the video track.
5898 * If there is only a single byte pair per field we don't have to do
5902 gst_buffer_map (buf, &map, GST_MAP_READ);
5904 n_triplets = map.size / 3;
5905 for (i = 0; i < n_triplets; i++) {
5906 if (map.data[3 * i] & 0x80)
5912 g_assert (n_field1 || n_field2);
5914 /* If there's more than 1 frame we have to split, otherwise we can just
5916 if (n_field1 > 1 || n_field2 > 1) {
5918 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
5919 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
5921 for (i = 0; i < n_output_buffers; i++) {
5923 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
5927 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
5928 outptr = outmap.data;
5931 gboolean found = FALSE;
5933 while (map.data + field1_off < map.data + map.size) {
5934 if (map.data[field1_off] & 0x80) {
5935 memcpy (outptr, &map.data[field1_off], 3);
5944 const guint8 empty[] = { 0x80, 0x80, 0x80 };
5946 memcpy (outptr, empty, 3);
5953 gboolean found = FALSE;
5955 while (map.data + field2_off < map.data + map.size) {
5956 if ((map.data[field2_off] & 0x80) == 0) {
5957 memcpy (outptr, &map.data[field2_off], 3);
5966 const guint8 empty[] = { 0x00, 0x80, 0x80 };
5968 memcpy (outptr, empty, 3);
5974 gst_buffer_unmap (outbuf, &outmap);
5976 GST_BUFFER_PTS (outbuf) =
5977 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
5978 GST_SECOND * CUR_STREAM (stream)->fps_d,
5979 CUR_STREAM (stream)->fps_n);
5980 GST_BUFFER_DURATION (outbuf) =
5981 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
5982 CUR_STREAM (stream)->fps_n);
5983 GST_BUFFER_OFFSET (outbuf) = -1;
5984 GST_BUFFER_OFFSET_END (outbuf) = -1;
5986 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
5988 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
5991 gst_buffer_unmap (buf, &map);
5992 gst_buffer_unref (buf);
5994 gst_buffer_unmap (buf, &map);
5995 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
5998 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6004 /* Sets a buffer's attributes properly and pushes it downstream.
6005 * Also checks for additional actions and custom processing that may
6006 * need to be done first.
6008 static GstFlowReturn
6009 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6010 QtDemuxStream * stream, GstBuffer * buf,
6011 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6012 gboolean keyframe, GstClockTime position, guint64 byte_position)
6014 GstFlowReturn ret = GST_FLOW_OK;
6016 /* offset the timestamps according to the edit list */
6018 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6022 gst_buffer_map (buf, &map, GST_MAP_READ);
6023 url = g_strndup ((gchar *) map.data, map.size);
6024 gst_buffer_unmap (buf, &map);
6025 if (url != NULL && strlen (url) != 0) {
6026 /* we have RTSP redirect now */
6027 g_free (qtdemux->redirect_location);
6028 qtdemux->redirect_location = g_strdup (url);
6029 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6030 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6031 gst_structure_new ("redirect",
6032 "new-location", G_TYPE_STRING, url, NULL)));
6034 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6040 /* position reporting */
6041 if (qtdemux->segment.rate >= 0) {
6042 qtdemux->segment.position = position;
6043 gst_qtdemux_sync_streams (qtdemux);
6046 if (G_UNLIKELY (!stream->pad)) {
6047 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6048 gst_buffer_unref (buf);
6052 /* send out pending buffers */
6053 while (stream->buffers) {
6054 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6056 if (G_UNLIKELY (stream->discont)) {
6057 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6058 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6059 stream->discont = FALSE;
6061 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6064 if (stream->alignment > 1)
6065 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6066 gst_pad_push (stream->pad, buffer);
6068 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6071 /* we're going to modify the metadata */
6072 buf = gst_buffer_make_writable (buf);
6074 if (G_UNLIKELY (stream->process_func))
6075 buf = stream->process_func (qtdemux, stream, buf);
6081 GST_BUFFER_DTS (buf) = dts;
6082 GST_BUFFER_PTS (buf) = pts;
6083 GST_BUFFER_DURATION (buf) = duration;
6084 GST_BUFFER_OFFSET (buf) = -1;
6085 GST_BUFFER_OFFSET_END (buf) = -1;
6088 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6089 stream->on_keyframe = FALSE;
6091 stream->on_keyframe = TRUE;
6094 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6095 gst_buffer_append_memory (buf,
6096 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6098 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6099 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6102 if (G_UNLIKELY (qtdemux->element_index)) {
6103 GstClockTime stream_time;
6106 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6108 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6109 GST_LOG_OBJECT (qtdemux,
6110 "adding association %" GST_TIME_FORMAT "-> %"
6111 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6112 gst_index_add_association (qtdemux->element_index,
6114 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6115 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6116 GST_FORMAT_BYTES, byte_position, NULL);
6121 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6127 static const QtDemuxRandomAccessEntry *
6128 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6129 GstClockTime pos, gboolean after)
6131 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6132 guint n_entries = stream->n_ra_entries;
6135 /* we assume the table is sorted */
6136 for (i = 0; i < n_entries; ++i) {
6137 if (entries[i].ts > pos)
6141 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6142 * probably okay to assume that the index lists the very first fragment */
6149 return &entries[i - 1];
6153 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6155 const QtDemuxRandomAccessEntry *best_entry = NULL;
6158 GST_OBJECT_LOCK (qtdemux);
6160 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6162 /* first see if we can determine where to go to using mfra,
6163 * before we start clearing things */
6164 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6165 const QtDemuxRandomAccessEntry *entry;
6166 QtDemuxStream *stream;
6167 gboolean is_audio_or_video;
6169 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6171 if (stream->ra_entries == NULL)
6174 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6175 is_audio_or_video = TRUE;
6177 is_audio_or_video = FALSE;
6180 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6181 stream->time_position, !is_audio_or_video);
6183 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6184 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6186 stream->pending_seek = entry;
6188 /* decide position to jump to just based on audio/video tracks, not subs */
6189 if (!is_audio_or_video)
6192 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6196 /* no luck, will handle seek otherwise */
6197 if (best_entry == NULL) {
6198 GST_OBJECT_UNLOCK (qtdemux);
6202 /* ok, now we can prepare for processing as of located moof */
6203 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6204 QtDemuxStream *stream;
6206 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6208 g_free (stream->samples);
6209 stream->samples = NULL;
6210 stream->n_samples = 0;
6211 stream->stbl_index = -1; /* no samples have yet been parsed */
6212 stream->sample_index = -1;
6214 if (stream->protection_scheme_info) {
6215 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6216 if (stream->protection_scheme_type == FOURCC_cenc
6217 || stream->protection_scheme_type == FOURCC_cbcs) {
6218 QtDemuxCencSampleSetInfo *info =
6219 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6220 if (info->crypto_info) {
6221 g_ptr_array_free (info->crypto_info, TRUE);
6222 info->crypto_info = NULL;
6228 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6229 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6230 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6231 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6233 qtdemux->moof_offset = best_entry->moof_offset;
6235 qtdemux_add_fragmented_samples (qtdemux);
6237 GST_OBJECT_UNLOCK (qtdemux);
6241 static GstFlowReturn
6242 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6244 GstFlowReturn ret = GST_FLOW_OK;
6245 GstBuffer *buf = NULL;
6246 QtDemuxStream *stream, *target_stream = NULL;
6247 GstClockTime min_time;
6249 GstClockTime dts = GST_CLOCK_TIME_NONE;
6250 GstClockTime pts = GST_CLOCK_TIME_NONE;
6251 GstClockTime duration = 0;
6252 gboolean keyframe = FALSE;
6253 guint sample_size = 0;
6254 guint num_samples = 1;
6259 if (qtdemux->fragmented_seek_pending) {
6260 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6261 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6262 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6263 qtdemux->fragmented_seek_pending = FALSE;
6265 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6269 /* Figure out the next stream sample to output, min_time is expressed in
6270 * global time and runs over the edit list segments. */
6271 min_time = G_MAXUINT64;
6272 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6273 GstClockTime position;
6275 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6276 position = stream->time_position;
6278 if (!GST_CLOCK_TIME_IS_VALID (position))
6281 if (stream->segment_index != -1) {
6282 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6283 position += segment->media_start;
6286 /* position of -1 is EOS */
6287 if (position < min_time) {
6288 min_time = position;
6289 target_stream = stream;
6293 if (G_UNLIKELY (target_stream == NULL)) {
6294 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6298 /* check for segment end */
6299 if (G_UNLIKELY (qtdemux->segment.stop != -1
6300 && qtdemux->segment.rate >= 0
6301 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6302 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6303 target_stream->time_position = GST_CLOCK_TIME_NONE;
6307 /* gap events for subtitle streams */
6308 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6309 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6311 GstClockTime gap_threshold;
6313 /* Only send gap events on non-subtitle streams if lagging way behind. */
6314 if (stream->subtype == FOURCC_subp
6315 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)
6316 gap_threshold = 1 * GST_SECOND;
6318 gap_threshold = 3 * GST_SECOND;
6320 /* send gap events until the stream catches up */
6321 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6322 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6323 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6324 stream->segment.position + gap_threshold < min_time) {
6326 gst_event_new_gap (stream->segment.position, gap_threshold);
6327 gst_pad_push_event (stream->pad, gap);
6328 stream->segment.position += gap_threshold;
6333 stream = target_stream;
6334 /* fetch info for the current sample of this stream */
6335 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6336 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6339 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6340 if (stream->new_caps) {
6341 gst_qtdemux_configure_stream (qtdemux, stream);
6342 qtdemux_do_allocation (stream, qtdemux);
6345 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6346 if (G_UNLIKELY (qtdemux->segment.
6347 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6348 if (stream->subtype == FOURCC_vide) {
6350 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6353 } else if (qtdemux->trickmode_interval > 0) {
6354 GstClockTimeDiff interval;
6356 if (qtdemux->segment.rate > 0)
6357 interval = stream->time_position - stream->last_keyframe_dts;
6359 interval = stream->last_keyframe_dts - stream->time_position;
6361 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6362 && interval < qtdemux->trickmode_interval) {
6363 GST_LOG_OBJECT (qtdemux,
6364 "Skipping keyframe within interval on track-id %u",
6368 stream->last_keyframe_dts = stream->time_position;
6374 GST_DEBUG_OBJECT (qtdemux,
6375 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6376 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6377 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6378 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6379 GST_TIME_ARGS (duration));
6381 if (G_UNLIKELY (empty)) {
6382 /* empty segment, push a gap if there's a second or more
6383 * difference and move to the next one */
6384 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6385 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6386 stream->segment.position = pts + duration;
6390 /* hmm, empty sample, skip and move to next sample */
6391 if (G_UNLIKELY (sample_size <= 0))
6394 /* last pushed sample was out of boundary, goto next sample */
6395 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6398 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6399 GST_DEBUG_OBJECT (qtdemux,
6400 "size %d larger than stream max_buffer_size %d, trimming",
6401 sample_size, stream->max_buffer_size);
6403 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6404 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6405 && sample_size < stream->min_buffer_size) {
6406 guint start_sample_index = stream->sample_index;
6407 guint accumulated_size = sample_size;
6408 guint64 expected_next_offset = offset + sample_size;
6410 GST_DEBUG_OBJECT (qtdemux,
6411 "size %d smaller than stream min_buffer_size %d, combining with the next",
6412 sample_size, stream->min_buffer_size);
6414 while (stream->sample_index < stream->to_sample
6415 && stream->sample_index + 1 < stream->n_samples) {
6416 const QtDemuxSample *next_sample;
6418 /* Increment temporarily */
6419 stream->sample_index++;
6421 /* Failed to parse sample so let's go back to the previous one that was
6422 * still successful */
6423 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6424 stream->sample_index--;
6428 next_sample = &stream->samples[stream->sample_index];
6430 /* Not contiguous with the previous sample so let's go back to the
6431 * previous one that was still successful */
6432 if (next_sample->offset != expected_next_offset) {
6433 stream->sample_index--;
6437 accumulated_size += next_sample->size;
6438 expected_next_offset += next_sample->size;
6439 if (accumulated_size >= stream->min_buffer_size)
6443 num_samples = stream->sample_index + 1 - start_sample_index;
6444 stream->sample_index = start_sample_index;
6445 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6446 num_samples, accumulated_size);
6447 size = accumulated_size;
6452 if (qtdemux->cenc_aux_info_offset > 0) {
6455 GstBuffer *aux_info = NULL;
6457 /* pull the data stored before the sample */
6459 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6460 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6461 if (G_UNLIKELY (ret != GST_FLOW_OK))
6463 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6464 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6465 gst_byte_reader_init (&br, map.data + 8, map.size);
6466 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6467 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6468 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6469 gst_buffer_unmap (aux_info, &map);
6470 gst_buffer_unref (aux_info);
6471 ret = GST_FLOW_ERROR;
6474 gst_buffer_unmap (aux_info, &map);
6475 gst_buffer_unref (aux_info);
6478 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6481 if (stream->use_allocator) {
6482 /* if we have a per-stream allocator, use it */
6483 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6486 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6488 if (G_UNLIKELY (ret != GST_FLOW_OK))
6491 /* Update for both splitting and combining of samples */
6492 if (size != sample_size) {
6493 pts += gst_util_uint64_scale_int (GST_SECOND,
6494 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6497 gst_util_uint64_scale_int (GST_SECOND,
6498 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6501 gst_util_uint64_scale_int (GST_SECOND,
6502 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6505 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6506 dts, pts, duration, keyframe, min_time, offset);
6508 if (size < sample_size) {
6509 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6510 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6512 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6514 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6515 if (time_position >= segment->media_start) {
6516 /* inside the segment, update time_position, looks very familiar to
6517 * GStreamer segments, doesn't it? */
6518 stream->time_position = (time_position - segment->media_start) +
6521 /* not yet in segment, time does not yet increment. This means
6522 * that we are still prerolling keyframes to the decoder so it can
6523 * decode the first sample of the segment. */
6524 stream->time_position = segment->time;
6526 } else if (size > sample_size) {
6527 /* Increase to the last sample we already pulled so that advancing
6528 * below brings us to the next sample we need to pull */
6529 stream->sample_index += num_samples - 1;
6533 GST_OBJECT_LOCK (qtdemux);
6534 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6535 GST_OBJECT_UNLOCK (qtdemux);
6536 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6537 * we have no more data for the pad to push */
6538 if (ret == GST_FLOW_EOS)
6541 stream->offset_in_sample += size;
6542 if (stream->offset_in_sample >= sample_size) {
6543 gst_qtdemux_advance_sample (qtdemux, stream);
6548 gst_qtdemux_advance_sample (qtdemux, stream);
6556 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6562 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6563 /* EOS will be raised if all are EOS */
6570 gst_qtdemux_loop (GstPad * pad)
6572 GstQTDemux *qtdemux;
6576 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6578 cur_offset = qtdemux->offset;
6579 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6580 cur_offset, qt_demux_state_string (qtdemux->state));
6582 switch (qtdemux->state) {
6583 case QTDEMUX_STATE_INITIAL:
6584 case QTDEMUX_STATE_HEADER:
6585 ret = gst_qtdemux_loop_state_header (qtdemux);
6587 case QTDEMUX_STATE_MOVIE:
6588 ret = gst_qtdemux_loop_state_movie (qtdemux);
6589 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6590 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6598 /* if something went wrong, pause */
6599 if (ret != GST_FLOW_OK)
6603 gst_object_unref (qtdemux);
6609 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6610 (NULL), ("streaming stopped, invalid state"));
6611 gst_pad_pause_task (pad);
6612 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6617 const gchar *reason = gst_flow_get_name (ret);
6619 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6621 gst_pad_pause_task (pad);
6623 /* fatal errors need special actions */
6625 if (ret == GST_FLOW_EOS) {
6626 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6627 /* we have no streams, post an error */
6628 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6630 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6633 if ((stop = qtdemux->segment.stop) == -1)
6634 stop = qtdemux->segment.duration;
6636 if (qtdemux->segment.rate >= 0) {
6637 GstMessage *message;
6640 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6641 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6642 GST_FORMAT_TIME, stop);
6643 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6644 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6645 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6646 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6648 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6649 gst_qtdemux_push_event (qtdemux, event);
6651 GstMessage *message;
6654 /* For Reverse Playback */
6655 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6656 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6657 GST_FORMAT_TIME, qtdemux->segment.start);
6658 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6659 qtdemux->segment.start);
6660 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6661 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6662 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6664 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6665 gst_qtdemux_push_event (qtdemux, event);
6670 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6671 event = gst_event_new_eos ();
6672 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6673 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6674 gst_qtdemux_push_event (qtdemux, event);
6676 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6677 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6678 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6687 * Returns if there are samples to be played.
6690 has_next_entry (GstQTDemux * demux)
6692 QtDemuxStream *stream;
6695 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6697 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6698 stream = QTDEMUX_NTH_STREAM (demux, i);
6700 if (stream->sample_index == -1) {
6701 stream->sample_index = 0;
6702 stream->offset_in_sample = 0;
6705 if (stream->sample_index >= stream->n_samples) {
6706 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6709 GST_DEBUG_OBJECT (demux, "Found a sample");
6713 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6720 * Returns the size of the first entry at the current offset.
6721 * If -1, there are none (which means EOS or empty file).
6724 next_entry_size (GstQTDemux * demux)
6726 QtDemuxStream *stream, *target_stream = NULL;
6727 guint64 smalloffs = (guint64) - 1;
6728 QtDemuxSample *sample;
6731 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6734 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6735 stream = QTDEMUX_NTH_STREAM (demux, i);
6737 if (stream->sample_index == -1) {
6738 stream->sample_index = 0;
6739 stream->offset_in_sample = 0;
6742 if (stream->sample_index >= stream->n_samples) {
6743 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6747 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6748 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6749 stream->sample_index);
6753 sample = &stream->samples[stream->sample_index];
6755 GST_LOG_OBJECT (demux,
6756 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6757 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6758 stream->sample_index, sample->offset, sample->size);
6760 if (((smalloffs == -1)
6761 || (sample->offset < smalloffs)) && (sample->size)) {
6762 smalloffs = sample->offset;
6763 target_stream = stream;
6770 GST_LOG_OBJECT (demux,
6771 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6772 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6774 stream = target_stream;
6775 sample = &stream->samples[stream->sample_index];
6777 if (sample->offset >= demux->offset) {
6778 demux->todrop = sample->offset - demux->offset;
6779 return sample->size + demux->todrop;
6782 GST_DEBUG_OBJECT (demux,
6783 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6788 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6790 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6792 gst_element_post_message (GST_ELEMENT_CAST (demux),
6793 gst_message_new_element (GST_OBJECT_CAST (demux),
6794 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6798 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6803 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6806 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6807 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6808 GST_SEEK_TYPE_NONE, -1);
6810 /* store seqnum to drop flush events, they don't need to reach downstream */
6811 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6812 res = gst_pad_push_event (demux->sinkpad, event);
6813 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6818 /* check for seekable upstream, above and beyond a mere query */
6820 gst_qtdemux_check_seekability (GstQTDemux * demux)
6823 gboolean seekable = FALSE;
6824 gint64 start = -1, stop = -1;
6826 if (demux->upstream_size)
6829 if (demux->upstream_format_is_time)
6832 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6833 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6834 GST_DEBUG_OBJECT (demux, "seeking query failed");
6838 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6840 /* try harder to query upstream size if we didn't get it the first time */
6841 if (seekable && stop == -1) {
6842 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6843 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6846 /* if upstream doesn't know the size, it's likely that it's not seekable in
6847 * practice even if it technically may be seekable */
6848 if (seekable && (start != 0 || stop <= start)) {
6849 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6854 gst_query_unref (query);
6856 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6857 G_GUINT64_FORMAT ")", seekable, start, stop);
6858 demux->upstream_seekable = seekable;
6859 demux->upstream_size = seekable ? stop : -1;
6863 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6865 g_return_if_fail (bytes <= demux->todrop);
6867 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6868 gst_adapter_flush (demux->adapter, bytes);
6869 demux->neededbytes -= bytes;
6870 demux->offset += bytes;
6871 demux->todrop -= bytes;
6874 /* PUSH-MODE only: Send a segment, if not done already. */
6876 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6878 if (G_UNLIKELY (demux->need_segment)) {
6881 if (!demux->upstream_format_is_time) {
6882 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6884 GstEvent *segment_event;
6885 segment_event = gst_event_new_segment (&demux->segment);
6886 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6887 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6888 gst_qtdemux_push_event (demux, segment_event);
6891 demux->need_segment = FALSE;
6893 /* clear to send tags on all streams */
6894 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6895 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6896 gst_qtdemux_push_tags (demux, stream);
6897 if (CUR_STREAM (stream)->sparse) {
6898 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6899 gst_pad_push_event (stream->pad,
6900 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6906 /* Used for push mode only. */
6908 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6909 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6911 GstClockTime ts, dur;
6915 stream->segments[segment_index].duration - (pos -
6916 stream->segments[segment_index].time);
6917 stream->time_position += dur;
6919 /* Only gaps with a duration of at least one second are propagated.
6920 * Same workaround as in pull mode.
6921 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6922 if (dur >= GST_SECOND) {
6924 gap = gst_event_new_gap (ts, dur);
6926 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6927 "segment: %" GST_PTR_FORMAT, gap);
6928 gst_pad_push_event (stream->pad, gap);
6932 static GstFlowReturn
6933 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6937 demux = GST_QTDEMUX (parent);
6939 GST_DEBUG_OBJECT (demux,
6940 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6941 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6942 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6943 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6944 gst_buffer_get_size (inbuf), demux->offset);
6946 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6947 gboolean is_gap_input = FALSE;
6950 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6952 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6953 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
6956 /* Check if we can land back on our feet in the case where upstream is
6957 * handling the seeking/pushing of samples with gaps in between (like
6958 * in the case of trick-mode DASH for example) */
6959 if (demux->upstream_format_is_time
6960 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6961 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6963 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6964 GST_LOG_OBJECT (demux,
6965 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
6966 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
6968 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6969 stream, GST_BUFFER_OFFSET (inbuf));
6971 QtDemuxSample *sample = &stream->samples[res];
6972 GST_LOG_OBJECT (demux,
6973 "Checking if sample %d from track-id %u is valid (offset:%"
6974 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
6975 stream->track_id, sample->offset, sample->size);
6976 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6977 GST_LOG_OBJECT (demux,
6978 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6980 is_gap_input = TRUE;
6981 /* We can go back to standard playback mode */
6982 demux->state = QTDEMUX_STATE_MOVIE;
6983 /* Remember which sample this stream is at */
6984 stream->sample_index = res;
6985 /* Finally update all push-based values to the expected values */
6986 demux->neededbytes = stream->samples[res].size;
6987 demux->offset = GST_BUFFER_OFFSET (inbuf);
6989 demux->mdatsize - demux->offset + demux->mdatoffset;
6994 if (!is_gap_input) {
6995 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6996 /* Reset state if it's a real discont */
6997 demux->neededbytes = 16;
6998 demux->state = QTDEMUX_STATE_INITIAL;
6999 demux->offset = GST_BUFFER_OFFSET (inbuf);
7000 gst_adapter_clear (demux->adapter);
7003 /* Reverse fragmented playback, need to flush all we have before
7004 * consuming a new fragment.
7005 * The samples array have the timestamps calculated by accumulating the
7006 * durations but this won't work for reverse playback of fragments as
7007 * the timestamps of a subsequent fragment should be smaller than the
7008 * previously received one. */
7009 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7010 gst_qtdemux_process_adapter (demux, TRUE);
7011 g_ptr_array_foreach (demux->active_streams,
7012 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7016 gst_adapter_push (demux->adapter, inbuf);
7018 GST_DEBUG_OBJECT (demux,
7019 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7020 demux->neededbytes, gst_adapter_available (demux->adapter));
7022 return gst_qtdemux_process_adapter (demux, FALSE);
7025 static GstFlowReturn
7026 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7028 GstFlowReturn ret = GST_FLOW_OK;
7030 /* we never really mean to buffer that much */
7031 if (demux->neededbytes == -1) {
7035 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7036 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7038 #ifndef GST_DISABLE_GST_DEBUG
7040 guint64 discont_offset, distance_from_discont;
7042 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7043 distance_from_discont =
7044 gst_adapter_distance_from_discont (demux->adapter);
7046 GST_DEBUG_OBJECT (demux,
7047 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7048 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7049 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7050 demux->offset, discont_offset, distance_from_discont);
7054 switch (demux->state) {
7055 case QTDEMUX_STATE_INITIAL:{
7060 gst_qtdemux_check_seekability (demux);
7062 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7064 /* get fourcc/length, set neededbytes */
7065 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7067 gst_adapter_unmap (demux->adapter);
7069 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7070 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7072 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7073 (_("This file is invalid and cannot be played.")),
7074 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7075 GST_FOURCC_ARGS (fourcc)));
7076 ret = GST_FLOW_ERROR;
7079 if (fourcc == FOURCC_mdat) {
7080 gint next_entry = next_entry_size (demux);
7081 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7082 || !demux->fragmented)) {
7083 /* we have the headers, start playback */
7084 demux->state = QTDEMUX_STATE_MOVIE;
7085 demux->neededbytes = next_entry;
7086 demux->mdatleft = size;
7087 demux->mdatsize = demux->mdatleft;
7089 /* no headers yet, try to get them */
7092 guint64 old, target;
7095 old = demux->offset;
7096 target = old + size;
7098 /* try to jump over the atom with a seek */
7099 /* only bother if it seems worth doing so,
7100 * and avoids possible upstream/server problems */
7101 if (demux->upstream_seekable &&
7102 demux->upstream_size > 4 * (1 << 20)) {
7103 res = qtdemux_seek_offset (demux, target);
7105 GST_DEBUG_OBJECT (demux, "skipping seek");
7110 GST_DEBUG_OBJECT (demux, "seek success");
7111 /* remember the offset fo the first mdat so we can seek back to it
7112 * after we have the headers */
7113 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7114 demux->first_mdat = old;
7115 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7118 /* seek worked, continue reading */
7119 demux->offset = target;
7120 demux->neededbytes = 16;
7121 demux->state = QTDEMUX_STATE_INITIAL;
7123 /* seek failed, need to buffer */
7124 demux->offset = old;
7125 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7126 /* there may be multiple mdat (or alike) buffers */
7128 if (demux->mdatbuffer)
7129 bs = gst_buffer_get_size (demux->mdatbuffer);
7132 if (size + bs > 10 * (1 << 20))
7134 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7135 demux->neededbytes = size;
7136 if (!demux->mdatbuffer)
7137 demux->mdatoffset = demux->offset;
7140 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7141 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7142 (_("This file is invalid and cannot be played.")),
7143 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7144 GST_FOURCC_ARGS (fourcc), size));
7145 ret = GST_FLOW_ERROR;
7148 /* this means we already started buffering and still no moov header,
7149 * let's continue buffering everything till we get moov */
7150 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7151 || fourcc == FOURCC_moof))
7153 demux->neededbytes = size;
7154 demux->state = QTDEMUX_STATE_HEADER;
7158 case QTDEMUX_STATE_HEADER:{
7162 GST_DEBUG_OBJECT (demux, "In header");
7164 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7166 /* parse the header */
7167 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7169 if (fourcc == FOURCC_moov) {
7170 /* in usual fragmented setup we could try to scan for more
7171 * and end up at the the moov (after mdat) again */
7172 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7174 || demux->last_moov_offset == demux->offset)) {
7175 GST_DEBUG_OBJECT (demux,
7176 "Skipping moov atom as we have (this) one already");
7178 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7180 if (demux->got_moov && demux->fragmented) {
7181 GST_DEBUG_OBJECT (demux,
7182 "Got a second moov, clean up data from old one");
7183 if (demux->moov_node_compressed) {
7184 g_node_destroy (demux->moov_node_compressed);
7185 if (demux->moov_node)
7186 g_free (demux->moov_node->data);
7188 demux->moov_node_compressed = NULL;
7189 if (demux->moov_node)
7190 g_node_destroy (demux->moov_node);
7191 demux->moov_node = NULL;
7194 demux->last_moov_offset = demux->offset;
7196 /* Update streams with new moov */
7197 gst_qtdemux_stream_concat (demux,
7198 demux->old_streams, demux->active_streams);
7200 qtdemux_parse_moov (demux, data, demux->neededbytes);
7201 qtdemux_node_dump (demux, demux->moov_node);
7202 qtdemux_parse_tree (demux);
7203 qtdemux_prepare_streams (demux);
7204 QTDEMUX_EXPOSE_LOCK (demux);
7205 qtdemux_expose_streams (demux);
7206 QTDEMUX_EXPOSE_UNLOCK (demux);
7208 demux->got_moov = TRUE;
7210 gst_qtdemux_check_send_pending_segment (demux);
7212 if (demux->moov_node_compressed) {
7213 g_node_destroy (demux->moov_node_compressed);
7214 g_free (demux->moov_node->data);
7216 demux->moov_node_compressed = NULL;
7217 g_node_destroy (demux->moov_node);
7218 demux->moov_node = NULL;
7219 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7221 } else if (fourcc == FOURCC_moof) {
7222 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7224 GstClockTime prev_pts;
7225 guint64 prev_offset;
7226 guint64 adapter_discont_offset, adapter_discont_dist;
7228 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7231 * The timestamp of the moof buffer is relevant as some scenarios
7232 * won't have the initial timestamp in the atoms. Whenever a new
7233 * buffer has started, we get that buffer's PTS and use it as a base
7234 * timestamp for the trun entries.
7236 * To keep track of the current buffer timestamp and starting point
7237 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7238 * from the beginning of the buffer, with the distance and demux->offset
7239 * we know if it is still the same buffer or not.
7241 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7242 prev_offset = demux->offset - dist;
7243 if (demux->fragment_start_offset == -1
7244 || prev_offset > demux->fragment_start_offset) {
7245 demux->fragment_start_offset = prev_offset;
7246 demux->fragment_start = prev_pts;
7247 GST_DEBUG_OBJECT (demux,
7248 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7249 GST_TIME_FORMAT, demux->fragment_start_offset,
7250 GST_TIME_ARGS (demux->fragment_start));
7253 /* We can't use prev_offset() here because this would require
7254 * upstream to set consistent and correct offsets on all buffers
7255 * since the discont. Nothing ever did that in the past and we
7256 * would break backwards compatibility here then.
7257 * Instead take the offset we had at the last discont and count
7258 * the bytes from there. This works with old code as there would
7259 * be no discont between moov and moof, and also works with
7260 * adaptivedemux which correctly sets offset and will set the
7261 * DISCONT flag accordingly when needed.
7263 * We also only do this for upstream TIME segments as otherwise
7264 * there are potential backwards compatibility problems with
7265 * seeking in PUSH mode and upstream providing inconsistent
7267 adapter_discont_offset =
7268 gst_adapter_offset_at_discont (demux->adapter);
7269 adapter_discont_dist =
7270 gst_adapter_distance_from_discont (demux->adapter);
7272 GST_DEBUG_OBJECT (demux,
7273 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7274 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7275 demux->offset, adapter_discont_offset, adapter_discont_dist);
7277 if (demux->upstream_format_is_time) {
7278 demux->moof_offset = adapter_discont_offset;
7279 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7280 demux->moof_offset += adapter_discont_dist;
7281 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7282 demux->moof_offset = demux->offset;
7284 demux->moof_offset = demux->offset;
7287 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7288 demux->moof_offset, NULL)) {
7289 gst_adapter_unmap (demux->adapter);
7290 ret = GST_FLOW_ERROR;
7294 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7295 if (demux->mss_mode && !demux->exposed) {
7296 QTDEMUX_EXPOSE_LOCK (demux);
7297 qtdemux_expose_streams (demux);
7298 QTDEMUX_EXPOSE_UNLOCK (demux);
7301 gst_qtdemux_check_send_pending_segment (demux);
7303 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7305 } else if (fourcc == FOURCC_ftyp) {
7306 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7307 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7308 } else if (fourcc == FOURCC_uuid) {
7309 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7310 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7311 } else if (fourcc == FOURCC_sidx) {
7312 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7313 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7317 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7321 /* [free] and [skip] are padding atoms */
7322 GST_DEBUG_OBJECT (demux,
7323 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7324 GST_FOURCC_ARGS (fourcc));
7327 GST_WARNING_OBJECT (demux,
7328 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7329 GST_FOURCC_ARGS (fourcc));
7330 /* Let's jump that one and go back to initial state */
7334 gst_adapter_unmap (demux->adapter);
7337 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7338 gsize remaining_data_size = 0;
7340 /* the mdat was before the header */
7341 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7342 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7343 /* restore our adapter/offset view of things with upstream;
7344 * put preceding buffered data ahead of current moov data.
7345 * This should also handle evil mdat, moov, mdat cases and alike */
7346 gst_adapter_flush (demux->adapter, demux->neededbytes);
7348 /* Store any remaining data after the mdat for later usage */
7349 remaining_data_size = gst_adapter_available (demux->adapter);
7350 if (remaining_data_size > 0) {
7351 g_assert (demux->restoredata_buffer == NULL);
7352 demux->restoredata_buffer =
7353 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7354 demux->restoredata_offset = demux->offset + demux->neededbytes;
7355 GST_DEBUG_OBJECT (demux,
7356 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7357 G_GUINT64_FORMAT, remaining_data_size,
7358 demux->restoredata_offset);
7361 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7362 demux->mdatbuffer = NULL;
7363 demux->offset = demux->mdatoffset;
7364 demux->neededbytes = next_entry_size (demux);
7365 demux->state = QTDEMUX_STATE_MOVIE;
7366 demux->mdatleft = gst_adapter_available (demux->adapter);
7367 demux->mdatsize = demux->mdatleft;
7369 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7370 gst_adapter_flush (demux->adapter, demux->neededbytes);
7372 /* only go back to the mdat if there are samples to play */
7373 if (demux->got_moov && demux->first_mdat != -1
7374 && has_next_entry (demux)) {
7377 /* we need to seek back */
7378 res = qtdemux_seek_offset (demux, demux->first_mdat);
7380 demux->offset = demux->first_mdat;
7382 GST_DEBUG_OBJECT (demux, "Seek back failed");
7385 demux->offset += demux->neededbytes;
7387 demux->neededbytes = 16;
7388 demux->state = QTDEMUX_STATE_INITIAL;
7393 case QTDEMUX_STATE_BUFFER_MDAT:{
7397 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7399 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7400 gst_buffer_extract (buf, 0, fourcc, 4);
7401 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7402 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7403 if (demux->mdatbuffer)
7404 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7406 demux->mdatbuffer = buf;
7407 demux->offset += demux->neededbytes;
7408 demux->neededbytes = 16;
7409 demux->state = QTDEMUX_STATE_INITIAL;
7410 gst_qtdemux_post_progress (demux, 1, 1);
7414 case QTDEMUX_STATE_MOVIE:{
7415 QtDemuxStream *stream = NULL;
7416 QtDemuxSample *sample;
7417 GstClockTime dts, pts, duration;
7421 GST_DEBUG_OBJECT (demux,
7422 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7424 if (demux->fragmented) {
7425 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7427 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7428 /* if needed data starts within this atom,
7429 * then it should not exceed this atom */
7430 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7431 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7432 (_("This file is invalid and cannot be played.")),
7433 ("sample data crosses atom boundary"));
7434 ret = GST_FLOW_ERROR;
7437 demux->mdatleft -= demux->neededbytes;
7439 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7440 /* so we are dropping more than left in this atom */
7441 gst_qtdemux_drop_data (demux, demux->mdatleft);
7442 demux->mdatleft = 0;
7444 /* need to resume atom parsing so we do not miss any other pieces */
7445 demux->state = QTDEMUX_STATE_INITIAL;
7446 demux->neededbytes = 16;
7448 /* check if there was any stored post mdat data from previous buffers */
7449 if (demux->restoredata_buffer) {
7450 g_assert (gst_adapter_available (demux->adapter) == 0);
7452 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7453 demux->restoredata_buffer = NULL;
7454 demux->offset = demux->restoredata_offset;
7461 if (demux->todrop) {
7462 if (demux->cenc_aux_info_offset > 0) {
7466 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7467 data = gst_adapter_map (demux->adapter, demux->todrop);
7468 gst_byte_reader_init (&br, data + 8, demux->todrop);
7469 if (!qtdemux_parse_cenc_aux_info (demux,
7470 QTDEMUX_NTH_STREAM (demux, 0), &br,
7471 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7472 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7473 ret = GST_FLOW_ERROR;
7474 gst_adapter_unmap (demux->adapter);
7475 g_free (demux->cenc_aux_info_sizes);
7476 demux->cenc_aux_info_sizes = NULL;
7479 demux->cenc_aux_info_offset = 0;
7480 g_free (demux->cenc_aux_info_sizes);
7481 demux->cenc_aux_info_sizes = NULL;
7482 gst_adapter_unmap (demux->adapter);
7484 gst_qtdemux_drop_data (demux, demux->todrop);
7488 /* initial newsegment sent here after having added pads,
7489 * possible others in sink_event */
7490 gst_qtdemux_check_send_pending_segment (demux);
7492 /* Figure out which stream this packet belongs to */
7493 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7494 stream = QTDEMUX_NTH_STREAM (demux, i);
7495 if (stream->sample_index >= stream->n_samples) {
7496 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7500 GST_LOG_OBJECT (demux,
7501 "Checking track-id %u (sample_index:%d / offset:%"
7502 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7503 stream->sample_index,
7504 stream->samples[stream->sample_index].offset,
7505 stream->samples[stream->sample_index].size);
7507 if (stream->samples[stream->sample_index].offset == demux->offset)
7511 if (G_UNLIKELY (stream == NULL))
7512 goto unknown_stream;
7514 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7516 if (stream->new_caps) {
7517 gst_qtdemux_configure_stream (demux, stream);
7520 /* Put data in a buffer, set timestamps, caps, ... */
7521 sample = &stream->samples[stream->sample_index];
7523 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7524 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7525 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7527 dts = QTSAMPLE_DTS (stream, sample);
7528 pts = QTSAMPLE_PTS (stream, sample);
7529 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7530 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7532 /* check for segment end */
7533 if (G_UNLIKELY (demux->segment.stop != -1
7534 && demux->segment.stop <= pts && stream->on_keyframe)
7535 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7536 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7537 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7539 /* skip this data, stream is EOS */
7540 gst_adapter_flush (demux->adapter, demux->neededbytes);
7541 demux->offset += demux->neededbytes;
7543 /* check if all streams are eos */
7545 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7546 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7555 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7557 /* FIXME: should either be an assert or a plain check */
7558 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7560 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7561 dts, pts, duration, keyframe, dts, demux->offset);
7565 GST_OBJECT_LOCK (demux);
7566 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7567 GST_OBJECT_UNLOCK (demux);
7569 /* skip this data, stream is EOS */
7570 gst_adapter_flush (demux->adapter, demux->neededbytes);
7573 stream->sample_index++;
7574 stream->offset_in_sample = 0;
7576 /* update current offset and figure out size of next buffer */
7577 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7578 demux->offset, demux->neededbytes);
7579 demux->offset += demux->neededbytes;
7580 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7584 if (ret == GST_FLOW_EOS) {
7585 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7586 demux->neededbytes = -1;
7590 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7591 if (demux->fragmented) {
7592 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7593 /* there may be more to follow, only finish this atom */
7594 demux->todrop = demux->mdatleft;
7595 demux->neededbytes = demux->todrop;
7600 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7601 goto non_ok_unlinked_flow;
7610 /* when buffering movie data, at least show user something is happening */
7611 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7612 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7613 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7614 demux->neededbytes);
7621 non_ok_unlinked_flow:
7623 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7624 gst_flow_get_name (ret));
7629 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7630 ret = GST_FLOW_ERROR;
7635 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7641 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7642 (NULL), ("qtdemuxer invalid state %d", demux->state));
7643 ret = GST_FLOW_ERROR;
7648 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7649 (NULL), ("no 'moov' atom within the first 10 MB"));
7650 ret = GST_FLOW_ERROR;
7656 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7661 query = gst_query_new_scheduling ();
7663 if (!gst_pad_peer_query (sinkpad, query)) {
7664 gst_query_unref (query);
7668 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7669 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7670 gst_query_unref (query);
7675 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7676 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7680 GST_DEBUG_OBJECT (sinkpad, "activating push");
7681 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7686 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7687 GstPadMode mode, gboolean active)
7690 GstQTDemux *demux = GST_QTDEMUX (parent);
7693 case GST_PAD_MODE_PUSH:
7694 demux->pullbased = FALSE;
7697 case GST_PAD_MODE_PULL:
7699 demux->pullbased = TRUE;
7700 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7703 res = gst_pad_stop_task (sinkpad);
7715 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7721 memset (&z, 0, sizeof (z));
7726 if ((ret = inflateInit (&z)) != Z_OK) {
7727 GST_ERROR ("inflateInit() returned %d", ret);
7731 z.next_in = z_buffer;
7732 z.avail_in = z_length;
7734 buffer = (guint8 *) g_malloc (*length);
7735 z.avail_out = *length;
7736 z.next_out = (Bytef *) buffer;
7738 ret = inflate (&z, Z_NO_FLUSH);
7739 if (ret == Z_STREAM_END) {
7741 } else if (ret != Z_OK) {
7742 GST_WARNING ("inflate() returned %d", ret);
7747 buffer = (guint8 *) g_realloc (buffer, *length);
7748 z.next_out = (Bytef *) (buffer + z.total_out);
7749 z.avail_out += 4096;
7750 } while (z.avail_in > 0);
7752 if (ret != Z_STREAM_END) {
7757 *length = z.total_out;
7764 #endif /* HAVE_ZLIB */
7767 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7771 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7773 /* counts as header data */
7774 qtdemux->header_size += length;
7776 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7777 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7779 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7786 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7787 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7788 if (dcom == NULL || cmvd == NULL)
7789 goto invalid_compression;
7791 dcom_len = QT_UINT32 (dcom->data);
7793 goto invalid_compression;
7795 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7799 guint uncompressed_length;
7800 guint compressed_length;
7804 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7806 goto invalid_compression;
7808 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7809 compressed_length = cmvd_len - 12;
7810 GST_LOG ("length = %u", uncompressed_length);
7813 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7814 compressed_length, &uncompressed_length);
7817 qtdemux->moov_node_compressed = qtdemux->moov_node;
7818 qtdemux->moov_node = g_node_new (buf);
7820 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7821 uncompressed_length);
7825 #endif /* HAVE_ZLIB */
7827 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7828 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7835 invalid_compression:
7837 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7843 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7846 while (G_UNLIKELY (buf < end)) {
7850 if (G_UNLIKELY (buf + 4 > end)) {
7851 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7854 len = QT_UINT32 (buf);
7855 if (G_UNLIKELY (len == 0)) {
7856 GST_LOG_OBJECT (qtdemux, "empty container");
7859 if (G_UNLIKELY (len < 8)) {
7860 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7863 if (G_UNLIKELY (len > (end - buf))) {
7864 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7865 (gint) (end - buf));
7869 child = g_node_new ((guint8 *) buf);
7870 g_node_append (node, child);
7871 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7872 qtdemux_parse_node (qtdemux, child, buf, len);
7880 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7883 int len = QT_UINT32 (xdxt->data);
7884 guint8 *buf = xdxt->data;
7885 guint8 *end = buf + len;
7888 /* skip size and type */
7896 size = QT_UINT32 (buf);
7897 type = QT_FOURCC (buf + 4);
7899 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7901 if (buf + size > end || size <= 0)
7907 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7908 GST_FOURCC_ARGS (type));
7912 buffer = gst_buffer_new_and_alloc (size);
7913 gst_buffer_fill (buffer, 0, buf, size);
7914 stream->buffers = g_slist_append (stream->buffers, buffer);
7915 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7918 buffer = gst_buffer_new_and_alloc (size);
7919 gst_buffer_fill (buffer, 0, buf, size);
7920 stream->buffers = g_slist_append (stream->buffers, buffer);
7921 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7924 buffer = gst_buffer_new_and_alloc (size);
7925 gst_buffer_fill (buffer, 0, buf, size);
7926 stream->buffers = g_slist_append (stream->buffers, buffer);
7927 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7930 GST_WARNING_OBJECT (qtdemux,
7931 "unknown theora cookie %" GST_FOURCC_FORMAT,
7932 GST_FOURCC_ARGS (type));
7941 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7945 guint32 node_length = 0;
7946 const QtNodeType *type;
7949 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7951 if (G_UNLIKELY (length < 8))
7952 goto not_enough_data;
7954 node_length = QT_UINT32 (buffer);
7955 fourcc = QT_FOURCC (buffer + 4);
7957 /* ignore empty nodes */
7958 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7961 type = qtdemux_type_get (fourcc);
7963 end = buffer + length;
7965 GST_LOG_OBJECT (qtdemux,
7966 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7967 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7969 if (node_length > length)
7970 goto broken_atom_size;
7972 if (type->flags & QT_FLAG_CONTAINER) {
7973 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7978 if (node_length < 20) {
7979 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7982 GST_DEBUG_OBJECT (qtdemux,
7983 "parsing stsd (sample table, sample description) atom");
7984 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7985 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7997 /* also read alac (or whatever) in stead of mp4a in the following,
7998 * since a similar layout is used in other cases as well */
7999 if (fourcc == FOURCC_mp4a)
8001 else if (fourcc == FOURCC_fLaC)
8006 /* There are two things we might encounter here: a true mp4a atom, and
8007 an mp4a entry in an stsd atom. The latter is what we're interested
8008 in, and it looks like an atom, but isn't really one. The true mp4a
8009 atom is short, so we detect it based on length here. */
8010 if (length < min_size) {
8011 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8012 GST_FOURCC_ARGS (fourcc));
8016 /* 'version' here is the sound sample description version. Types 0 and
8017 1 are documented in the QTFF reference, but type 2 is not: it's
8018 described in Apple header files instead (struct SoundDescriptionV2
8020 version = QT_UINT16 (buffer + 16);
8022 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8023 GST_FOURCC_ARGS (fourcc), version);
8025 /* parse any esds descriptors */
8037 GST_WARNING_OBJECT (qtdemux,
8038 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8039 GST_FOURCC_ARGS (fourcc), version);
8044 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8072 /* codec_data is contained inside these atoms, which all have
8073 * the same format. */
8074 /* video sample description size is 86 bytes without extension.
8075 * node_length have to be bigger than 86 bytes because video sample
8076 * description can include extensions such as esds, fiel, glbl, etc. */
8077 if (node_length < 86) {
8078 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8079 " sample description length too short (%u < 86)",
8080 GST_FOURCC_ARGS (fourcc), node_length);
8084 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8085 GST_FOURCC_ARGS (fourcc));
8087 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8089 * revision level (2 bytes) : must be set to 0. */
8090 version = QT_UINT32 (buffer + 16);
8091 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8093 /* compressor name : PASCAL string and informative purposes
8094 * first byte : the number of bytes to be displayed.
8095 * it has to be less than 32 because it is reserved
8096 * space of 32 bytes total including itself. */
8097 str_len = QT_UINT8 (buffer + 50);
8099 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8100 (char *) buffer + 51);
8102 GST_WARNING_OBJECT (qtdemux,
8103 "compressorname length too big (%u > 31)", str_len);
8105 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8107 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8112 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8114 /* You are reading this correctly. QTFF specifies that the
8115 * metadata atom is a short atom, whereas ISO BMFF specifies
8116 * it's a full atom. But since so many people are doing things
8117 * differently, we actually peek into the atom to see which
8120 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8121 GST_FOURCC_ARGS (fourcc));
8124 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8125 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8126 * starts with a 'hdlr' atom */
8127 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8128 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8129 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8130 * with version/flags both set to zero */
8131 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8133 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8138 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8139 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8140 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8149 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8150 GST_FOURCC_ARGS (fourcc));
8154 version = QT_UINT32 (buffer + 12);
8155 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8162 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8167 if (length < offset) {
8168 GST_WARNING_OBJECT (qtdemux,
8169 "skipping too small %" GST_FOURCC_FORMAT " box",
8170 GST_FOURCC_ARGS (fourcc));
8173 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8179 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8184 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8189 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8193 if (!strcmp (type->name, "unknown"))
8194 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8198 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8199 GST_FOURCC_ARGS (fourcc));
8205 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8206 (_("This file is corrupt and cannot be played.")),
8207 ("Not enough data for an atom header, got only %u bytes", length));
8212 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8213 (_("This file is corrupt and cannot be played.")),
8214 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8215 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8222 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8224 /* FIXME: This can only reliably work if demuxers have a
8225 * separate streaming thread per srcpad. This should be
8226 * done in a demuxer base class, which integrates parts
8229 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8234 query = gst_query_new_allocation (stream->caps, FALSE);
8236 if (!gst_pad_peer_query (stream->pad, query)) {
8237 /* not a problem, just debug a little */
8238 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8241 if (stream->allocator)
8242 gst_object_unref (stream->allocator);
8244 if (gst_query_get_n_allocation_params (query) > 0) {
8245 /* try the allocator */
8246 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8248 stream->use_allocator = TRUE;
8250 stream->allocator = NULL;
8251 gst_allocation_params_init (&stream->params);
8252 stream->use_allocator = FALSE;
8254 gst_query_unref (query);
8259 pad_query (const GValue * item, GValue * value, gpointer user_data)
8261 GstPad *pad = g_value_get_object (item);
8262 GstQuery *query = user_data;
8265 res = gst_pad_peer_query (pad, query);
8268 g_value_set_boolean (value, TRUE);
8272 GST_INFO_OBJECT (pad, "pad peer query failed");
8277 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8278 GstPadDirection direction)
8281 GstIteratorFoldFunction func = pad_query;
8282 GValue res = { 0, };
8284 g_value_init (&res, G_TYPE_BOOLEAN);
8285 g_value_set_boolean (&res, FALSE);
8288 if (direction == GST_PAD_SRC)
8289 it = gst_element_iterate_src_pads (element);
8291 it = gst_element_iterate_sink_pads (element);
8293 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8294 gst_iterator_resync (it);
8296 gst_iterator_free (it);
8298 return g_value_get_boolean (&res);
8302 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8303 QtDemuxStream * stream)
8307 GstElement *element = GST_ELEMENT (qtdemux);
8309 gchar **filtered_sys_ids;
8310 GValue event_list = G_VALUE_INIT;
8313 /* 1. Check if we already have the context. */
8314 if (qtdemux->preferred_protection_system_id != NULL) {
8315 GST_LOG_OBJECT (element,
8316 "already have the protection context, no need to request it again");
8320 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8321 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8322 (const gchar **) qtdemux->protection_system_ids->pdata);
8324 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8325 qtdemux->protection_system_ids->len - 1);
8326 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8327 "decryptors for %u of them, running context request",
8328 qtdemux->protection_system_ids->len,
8329 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8332 if (stream->protection_scheme_event_queue.length) {
8333 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8334 stream->protection_scheme_event_queue.length);
8335 walk = stream->protection_scheme_event_queue.tail;
8337 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8338 qtdemux->protection_event_queue.length);
8339 walk = qtdemux->protection_event_queue.tail;
8342 g_value_init (&event_list, GST_TYPE_LIST);
8343 for (; walk; walk = g_list_previous (walk)) {
8344 GValue *event_value = g_new0 (GValue, 1);
8345 g_value_init (event_value, GST_TYPE_EVENT);
8346 g_value_set_boxed (event_value, walk->data);
8347 gst_value_list_append_and_take_value (&event_list, event_value);
8350 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8351 * check if downstream already has a context of the specific type
8352 * 2b) Query upstream as above.
8354 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8355 st = gst_query_writable_structure (query);
8356 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8357 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8359 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8360 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8361 gst_query_parse_context (query, &ctxt);
8362 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8363 gst_element_set_context (element, ctxt);
8364 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8365 gst_query_parse_context (query, &ctxt);
8366 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8367 gst_element_set_context (element, ctxt);
8369 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8370 * the required context type and afterwards check if a
8371 * usable context was set now as in 1). The message could
8372 * be handled by the parent bins of the element and the
8377 GST_INFO_OBJECT (element, "posting need context message");
8378 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8379 "drm-preferred-decryption-system-id");
8380 st = (GstStructure *) gst_message_get_structure (msg);
8381 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8382 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8385 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8386 gst_element_post_message (element, msg);
8389 g_strfreev (filtered_sys_ids);
8390 g_value_unset (&event_list);
8391 gst_query_unref (query);
8395 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8396 QtDemuxStream * stream)
8399 const gchar *selected_system = NULL;
8401 g_return_val_if_fail (qtdemux != NULL, FALSE);
8402 g_return_val_if_fail (stream != NULL, FALSE);
8403 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8406 if (stream->protection_scheme_type == FOURCC_aavd) {
8407 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8408 if (!gst_structure_has_name (s, "application/x-aavd")) {
8409 gst_structure_set (s,
8410 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8412 gst_structure_set_name (s, "application/x-aavd");
8417 if (stream->protection_scheme_type != FOURCC_cenc
8418 && stream->protection_scheme_type != FOURCC_cbcs) {
8419 GST_ERROR_OBJECT (qtdemux,
8420 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8421 GST_FOURCC_ARGS (stream->protection_scheme_type));
8425 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8426 if (!gst_structure_has_name (s, "application/x-cenc")) {
8427 gst_structure_set (s,
8428 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8429 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8430 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8432 gst_structure_set_name (s, "application/x-cenc");
8435 if (qtdemux->protection_system_ids == NULL) {
8436 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8437 "cenc protection system information has been found, not setting a "
8438 "protection system UUID");
8442 gst_qtdemux_request_protection_context (qtdemux, stream);
8443 if (qtdemux->preferred_protection_system_id != NULL) {
8444 const gchar *preferred_system_array[] =
8445 { qtdemux->preferred_protection_system_id, NULL };
8447 selected_system = gst_protection_select_system (preferred_system_array);
8449 if (selected_system) {
8450 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8451 qtdemux->preferred_protection_system_id);
8453 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8454 "because there is no available decryptor",
8455 qtdemux->preferred_protection_system_id);
8459 if (!selected_system) {
8460 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8461 selected_system = gst_protection_select_system ((const gchar **)
8462 qtdemux->protection_system_ids->pdata);
8463 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8464 qtdemux->protection_system_ids->len - 1);
8467 if (!selected_system) {
8468 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8469 "suitable decryptor element has been found");
8473 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8476 gst_structure_set (s,
8477 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8484 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8486 /* fps is calculated base on the duration of the average framerate since
8487 * qt does not have a fixed framerate. */
8488 gboolean fps_available = TRUE;
8489 guint32 first_duration = 0;
8491 if (stream->n_samples > 0)
8492 first_duration = stream->samples[0].duration;
8494 if ((stream->n_samples == 1 && first_duration == 0)
8495 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8497 CUR_STREAM (stream)->fps_n = 0;
8498 CUR_STREAM (stream)->fps_d = 1;
8500 if (stream->duration == 0 || stream->n_samples < 2) {
8501 CUR_STREAM (stream)->fps_n = stream->timescale;
8502 CUR_STREAM (stream)->fps_d = 1;
8503 fps_available = FALSE;
8505 GstClockTime avg_duration;
8509 /* duration and n_samples can be updated for fragmented format
8510 * so, framerate of fragmented format is calculated using data in a moof */
8511 if (qtdemux->fragmented && stream->n_samples_moof > 0
8512 && stream->duration_moof > 0) {
8513 n_samples = stream->n_samples_moof;
8514 duration = stream->duration_moof;
8516 n_samples = stream->n_samples;
8517 duration = stream->duration;
8520 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8521 /* stream->duration is guint64, timescale, n_samples are guint32 */
8523 gst_util_uint64_scale_round (duration -
8524 first_duration, GST_SECOND,
8525 (guint64) (stream->timescale) * (n_samples - 1));
8527 GST_LOG_OBJECT (qtdemux,
8528 "Calculating avg sample duration based on stream (or moof) duration %"
8530 " minus first sample %u, leaving %d samples gives %"
8531 GST_TIME_FORMAT, duration, first_duration,
8532 n_samples - 1, GST_TIME_ARGS (avg_duration));
8535 gst_video_guess_framerate (avg_duration,
8536 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8538 GST_DEBUG_OBJECT (qtdemux,
8539 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8540 stream->timescale, CUR_STREAM (stream)->fps_n,
8541 CUR_STREAM (stream)->fps_d);
8545 return fps_available;
8549 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8551 if (stream->subtype == FOURCC_vide) {
8552 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8554 if (CUR_STREAM (stream)->caps) {
8555 CUR_STREAM (stream)->caps =
8556 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8558 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8559 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8560 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8561 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8563 /* set framerate if calculated framerate is reliable */
8564 if (fps_available) {
8565 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8566 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8567 CUR_STREAM (stream)->fps_d, NULL);
8570 /* calculate pixel-aspect-ratio using display width and height */
8571 GST_DEBUG_OBJECT (qtdemux,
8572 "video size %dx%d, target display size %dx%d",
8573 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8574 stream->display_width, stream->display_height);
8575 /* qt file might have pasp atom */
8576 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8577 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8578 CUR_STREAM (stream)->par_h);
8579 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8580 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8581 CUR_STREAM (stream)->par_h, NULL);
8582 } else if (stream->display_width > 0 && stream->display_height > 0
8583 && CUR_STREAM (stream)->width > 0
8584 && CUR_STREAM (stream)->height > 0) {
8587 /* calculate the pixel aspect ratio using the display and pixel w/h */
8588 n = stream->display_width * CUR_STREAM (stream)->height;
8589 d = stream->display_height * CUR_STREAM (stream)->width;
8592 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8593 CUR_STREAM (stream)->par_w = n;
8594 CUR_STREAM (stream)->par_h = d;
8595 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8596 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8597 CUR_STREAM (stream)->par_h, NULL);
8600 if (CUR_STREAM (stream)->interlace_mode > 0) {
8601 if (CUR_STREAM (stream)->interlace_mode == 1) {
8602 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8603 G_TYPE_STRING, "progressive", NULL);
8604 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8605 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8606 G_TYPE_STRING, "interleaved", NULL);
8607 if (CUR_STREAM (stream)->field_order == 9) {
8608 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8609 G_TYPE_STRING, "top-field-first", NULL);
8610 } else if (CUR_STREAM (stream)->field_order == 14) {
8611 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8612 G_TYPE_STRING, "bottom-field-first", NULL);
8617 /* Create incomplete colorimetry here if needed */
8618 if (CUR_STREAM (stream)->colorimetry.range ||
8619 CUR_STREAM (stream)->colorimetry.matrix ||
8620 CUR_STREAM (stream)->colorimetry.transfer
8621 || CUR_STREAM (stream)->colorimetry.primaries) {
8622 gchar *colorimetry =
8623 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8624 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8625 G_TYPE_STRING, colorimetry, NULL);
8626 g_free (colorimetry);
8629 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8630 guint par_w = 1, par_h = 1;
8632 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8633 par_w = CUR_STREAM (stream)->par_w;
8634 par_h = CUR_STREAM (stream)->par_h;
8637 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8638 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8640 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8643 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8644 "multiview-mode", G_TYPE_STRING,
8645 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8646 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8647 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8652 else if (stream->subtype == FOURCC_soun) {
8653 if (CUR_STREAM (stream)->caps) {
8654 CUR_STREAM (stream)->caps =
8655 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8656 if (CUR_STREAM (stream)->rate > 0)
8657 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8658 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8659 if (CUR_STREAM (stream)->n_channels > 0)
8660 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8661 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8662 if (CUR_STREAM (stream)->n_channels > 2) {
8663 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8664 * correctly; this is just the minimum we can do - assume
8665 * we don't actually have any channel positions. */
8666 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8667 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8672 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8673 const GstStructure *s;
8674 QtDemuxStream *fps_stream = NULL;
8675 gboolean fps_available = FALSE;
8677 /* CEA608 closed caption tracks are a bit special in that each sample
8678 * can contain CCs for multiple frames, and CCs can be omitted and have to
8679 * be inferred from the duration of the sample then.
8681 * As such we take the framerate from the (first) video track here for
8682 * CEA608 as there must be one CC byte pair for every video frame
8683 * according to the spec.
8685 * For CEA708 all is fine and there is one sample per frame.
8688 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8689 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8692 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8693 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8695 if (tmp->subtype == FOURCC_vide) {
8702 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8703 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8704 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8707 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8708 fps_stream = stream;
8711 CUR_STREAM (stream)->caps =
8712 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8714 /* set framerate if calculated framerate is reliable */
8715 if (fps_available) {
8716 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8717 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8718 CUR_STREAM (stream)->fps_d, NULL);
8723 GstCaps *prev_caps = NULL;
8725 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8726 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8727 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8728 gst_pad_set_active (stream->pad, TRUE);
8730 gst_pad_use_fixed_caps (stream->pad);
8732 if (stream->protected) {
8733 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8734 GST_ERROR_OBJECT (qtdemux,
8735 "Failed to configure protected stream caps.");
8740 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8741 CUR_STREAM (stream)->caps);
8742 if (stream->new_stream) {
8744 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8747 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8750 gst_event_parse_stream_flags (event, &stream_flags);
8751 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8752 qtdemux->have_group_id = TRUE;
8754 qtdemux->have_group_id = FALSE;
8755 gst_event_unref (event);
8756 } else if (!qtdemux->have_group_id) {
8757 qtdemux->have_group_id = TRUE;
8758 qtdemux->group_id = gst_util_group_id_next ();
8761 stream->new_stream = FALSE;
8762 event = gst_event_new_stream_start (stream->stream_id);
8763 if (qtdemux->have_group_id)
8764 gst_event_set_group_id (event, qtdemux->group_id);
8765 if (stream->disabled)
8766 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8767 if (CUR_STREAM (stream)->sparse) {
8768 stream_flags |= GST_STREAM_FLAG_SPARSE;
8770 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8772 gst_event_set_stream_flags (event, stream_flags);
8773 gst_pad_push_event (stream->pad, event);
8776 prev_caps = gst_pad_get_current_caps (stream->pad);
8778 if (CUR_STREAM (stream)->caps) {
8780 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8781 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8782 CUR_STREAM (stream)->caps);
8783 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8785 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8788 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8792 gst_caps_unref (prev_caps);
8793 stream->new_caps = FALSE;
8799 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8800 QtDemuxStream * stream)
8802 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8805 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8806 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8807 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8808 stream->stsd_entries_length)) {
8809 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8810 (_("This file is invalid and cannot be played.")),
8811 ("New sample description id is out of bounds (%d >= %d)",
8812 stream->stsd_sample_description_id, stream->stsd_entries_length));
8814 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8815 stream->new_caps = TRUE;
8820 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8821 QtDemuxStream * stream, GstTagList * list)
8823 gboolean ret = TRUE;
8825 if (stream->subtype == FOURCC_vide) {
8826 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8829 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);
8839 qtdemux->n_video_streams++;
8840 } else if (stream->subtype == FOURCC_soun) {
8841 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8844 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8846 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8847 gst_object_unref (stream->pad);
8852 qtdemux->n_audio_streams++;
8853 } else if (stream->subtype == FOURCC_strm) {
8854 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8855 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8856 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8857 || stream->subtype == FOURCC_clcp) {
8858 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8861 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8863 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8864 gst_object_unref (stream->pad);
8869 qtdemux->n_sub_streams++;
8870 } else if (CUR_STREAM (stream)->caps) {
8871 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8874 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8876 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8877 gst_object_unref (stream->pad);
8882 qtdemux->n_video_streams++;
8884 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8891 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8892 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8893 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8894 GST_OBJECT_LOCK (qtdemux);
8895 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8896 GST_OBJECT_UNLOCK (qtdemux);
8898 if (stream->stream_tags)
8899 gst_tag_list_unref (stream->stream_tags);
8900 stream->stream_tags = list;
8902 /* global tags go on each pad anyway */
8903 stream->send_global_tags = TRUE;
8904 /* send upstream GST_EVENT_PROTECTION events that were received before
8905 this source pad was created */
8906 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8907 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8911 gst_tag_list_unref (list);
8915 /* find next atom with @fourcc starting at @offset */
8916 static GstFlowReturn
8917 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8918 guint64 * length, guint32 fourcc)
8924 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8925 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8931 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8932 if (G_UNLIKELY (ret != GST_FLOW_OK))
8934 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8937 gst_buffer_unref (buf);
8940 gst_buffer_map (buf, &map, GST_MAP_READ);
8941 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8942 gst_buffer_unmap (buf, &map);
8943 gst_buffer_unref (buf);
8945 if (G_UNLIKELY (*length == 0)) {
8946 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8947 ret = GST_FLOW_ERROR;
8951 if (lfourcc == fourcc) {
8952 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
8953 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8956 GST_LOG_OBJECT (qtdemux,
8957 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8958 GST_FOURCC_ARGS (lfourcc), *offset);
8959 if (*offset == G_MAXUINT64)
8969 /* might simply have had last one */
8970 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8975 /* should only do something in pull mode */
8976 /* call with OBJECT lock */
8977 static GstFlowReturn
8978 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8980 guint64 length, offset;
8981 GstBuffer *buf = NULL;
8982 GstFlowReturn ret = GST_FLOW_OK;
8983 GstFlowReturn res = GST_FLOW_OK;
8986 offset = qtdemux->moof_offset;
8987 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8990 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8991 return GST_FLOW_EOS;
8994 /* best not do pull etc with lock held */
8995 GST_OBJECT_UNLOCK (qtdemux);
8997 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8998 if (ret != GST_FLOW_OK)
9001 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9002 if (G_UNLIKELY (ret != GST_FLOW_OK))
9004 gst_buffer_map (buf, &map, GST_MAP_READ);
9005 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9006 gst_buffer_unmap (buf, &map);
9007 gst_buffer_unref (buf);
9012 gst_buffer_unmap (buf, &map);
9013 gst_buffer_unref (buf);
9017 /* look for next moof */
9018 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9019 if (G_UNLIKELY (ret != GST_FLOW_OK))
9023 GST_OBJECT_LOCK (qtdemux);
9025 qtdemux->moof_offset = offset;
9031 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9033 res = GST_FLOW_ERROR;
9038 /* maybe upstream temporarily flushing */
9039 if (ret != GST_FLOW_FLUSHING) {
9040 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9043 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9044 /* resume at current position next time */
9052 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9056 gint32 stts_duration;
9057 GstByteWriter stsc, stts, stsz;
9059 /* Each sample has a different size, which we don't support for merging */
9060 if (stream->sample_size == 0) {
9061 GST_DEBUG_OBJECT (qtdemux,
9062 "Not all samples have the same size, not merging");
9066 /* The stream has a ctts table, we don't support that */
9067 if (stream->ctts_present) {
9068 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9072 /* If there's a sync sample table also ignore this stream */
9073 if (stream->stps_present || stream->stss_present) {
9074 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9078 /* If chunks are considered samples already ignore this stream */
9079 if (stream->chunks_are_samples) {
9080 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9084 /* Require that all samples have the same duration */
9085 if (stream->n_sample_times > 1) {
9086 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9090 /* Parse the stts to get the sample duration and number of samples */
9091 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9092 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9094 /* Parse the number of chunks from the stco manually because the
9095 * reader is already behind that */
9096 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9098 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9101 /* Now parse stsc, convert chunks into single samples and generate a
9102 * new stsc, stts and stsz from this information */
9103 gst_byte_writer_init (&stsc);
9104 gst_byte_writer_init (&stts);
9105 gst_byte_writer_init (&stsz);
9107 /* Note: we skip fourccs, size, version, flags and other fields of the new
9108 * atoms as the byte readers with them are already behind that position
9109 * anyway and only update the values of those inside the stream directly.
9111 stream->n_sample_times = 0;
9112 stream->n_samples = 0;
9113 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9115 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9117 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9118 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9119 sample_description_id =
9120 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9122 if (i == stream->n_samples_per_chunk - 1) {
9123 /* +1 because first_chunk is 1-based */
9124 last_chunk = num_chunks + 1;
9126 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9129 GST_DEBUG_OBJECT (qtdemux,
9130 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9131 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9133 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9134 /* One sample in this chunk */
9135 gst_byte_writer_put_uint32_be (&stsc, 1);
9136 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9138 /* For each chunk write a stts and stsz entry now */
9139 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9140 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9141 for (j = first_chunk; j < last_chunk; j++) {
9142 gst_byte_writer_put_uint32_be (&stsz,
9143 stream->sample_size * samples_per_chunk);
9146 stream->n_sample_times += 1;
9147 stream->n_samples += last_chunk - first_chunk;
9150 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9152 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9153 stream->n_samples, stream->n_sample_times);
9155 /* We don't have a fixed sample size anymore */
9156 stream->sample_size = 0;
9158 /* Free old data for the atoms */
9159 g_free ((gpointer) stream->stsz.data);
9160 stream->stsz.data = NULL;
9161 g_free ((gpointer) stream->stsc.data);
9162 stream->stsc.data = NULL;
9163 g_free ((gpointer) stream->stts.data);
9164 stream->stts.data = NULL;
9166 /* Store new data and replace byte readers */
9167 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9168 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9169 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9170 stream->stts.size = gst_byte_writer_get_size (&stts);
9171 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9172 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9173 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9174 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9175 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9178 /* initialise bytereaders for stbl sub-atoms */
9180 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9182 stream->stbl_index = -1; /* no samples have yet been parsed */
9183 stream->sample_index = -1;
9185 /* time-to-sample atom */
9186 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9189 /* copy atom data into a new buffer for later use */
9190 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9192 /* skip version + flags */
9193 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9194 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9196 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9198 /* make sure there's enough data */
9199 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9200 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9201 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9202 stream->n_sample_times);
9203 if (!stream->n_sample_times)
9207 /* sync sample atom */
9208 stream->stps_present = FALSE;
9209 if ((stream->stss_present =
9210 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9211 &stream->stss) ? TRUE : FALSE) == TRUE) {
9212 /* copy atom data into a new buffer for later use */
9213 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9215 /* skip version + flags */
9216 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9217 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9220 if (stream->n_sample_syncs) {
9221 /* make sure there's enough data */
9222 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9226 /* partial sync sample atom */
9227 if ((stream->stps_present =
9228 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9229 &stream->stps) ? TRUE : FALSE) == TRUE) {
9230 /* copy atom data into a new buffer for later use */
9231 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9233 /* skip version + flags */
9234 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9235 !gst_byte_reader_get_uint32_be (&stream->stps,
9236 &stream->n_sample_partial_syncs))
9239 /* if there are no entries, the stss table contains the real
9241 if (stream->n_sample_partial_syncs) {
9242 /* make sure there's enough data */
9243 if (!qt_atom_parser_has_chunks (&stream->stps,
9244 stream->n_sample_partial_syncs, 4))
9251 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9254 /* copy atom data into a new buffer for later use */
9255 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9257 /* skip version + flags */
9258 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9259 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9262 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9265 if (!stream->n_samples)
9268 /* sample-to-chunk atom */
9269 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9272 /* copy atom data into a new buffer for later use */
9273 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9275 /* skip version + flags */
9276 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9277 !gst_byte_reader_get_uint32_be (&stream->stsc,
9278 &stream->n_samples_per_chunk))
9281 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9282 stream->n_samples_per_chunk);
9284 /* make sure there's enough data */
9285 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9291 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9292 stream->co_size = sizeof (guint32);
9293 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9295 stream->co_size = sizeof (guint64);
9299 /* copy atom data into a new buffer for later use */
9300 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9302 /* skip version + flags */
9303 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9306 /* chunks_are_samples == TRUE means treat chunks as samples */
9307 stream->chunks_are_samples = stream->sample_size
9308 && !CUR_STREAM (stream)->sampled;
9309 if (stream->chunks_are_samples) {
9310 /* treat chunks as samples */
9311 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9314 /* skip number of entries */
9315 if (!gst_byte_reader_skip (&stream->stco, 4))
9318 /* make sure there are enough data in the stsz atom */
9319 if (!stream->sample_size) {
9320 /* different sizes for each sample */
9321 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9326 /* composition time-to-sample */
9327 if ((stream->ctts_present =
9328 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9329 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9330 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9332 /* copy atom data into a new buffer for later use */
9333 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9335 /* skip version + flags */
9336 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
9337 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9338 &stream->n_composition_times))
9341 /* make sure there's enough data */
9342 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9346 /* This is optional, if missing we iterate the ctts */
9347 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9348 if (!gst_byte_reader_skip (&cslg, 1 + 3)
9349 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
9350 g_free ((gpointer) cslg.data);
9354 gint32 cslg_least = 0;
9355 guint num_entries, pos;
9358 pos = gst_byte_reader_get_pos (&stream->ctts);
9359 num_entries = stream->n_composition_times;
9361 stream->cslg_shift = 0;
9363 for (i = 0; i < num_entries; i++) {
9366 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9367 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9368 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9369 * slightly inaccurate PTS could be more usable than corrupted one */
9370 if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
9371 GST_WARNING_OBJECT (qtdemux,
9372 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9373 " larger than duration %" G_GUINT64_FORMAT,
9374 offset, stream->duration);
9376 stream->cslg_shift = 0;
9377 stream->ctts_present = FALSE;
9381 if (offset < cslg_least)
9382 cslg_least = offset;
9386 stream->cslg_shift = ABS (cslg_least);
9388 stream->cslg_shift = 0;
9390 /* reset the reader so we can generate sample table */
9391 gst_byte_reader_set_pos (&stream->ctts, pos);
9394 /* Ensure the cslg_shift value is consistent so we can use it
9395 * unconditionally to produce TS and Segment */
9396 stream->cslg_shift = 0;
9399 /* For raw audio streams especially we might want to merge the samples
9400 * to not output one audio sample per buffer. We're doing this here
9401 * before allocating the sample tables so that from this point onwards
9402 * the number of container samples are static */
9403 if (stream->min_buffer_size > 0) {
9404 qtdemux_merge_sample_table (qtdemux, stream);
9408 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9409 stream->n_samples, (guint) sizeof (QtDemuxSample),
9410 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9412 if (stream->n_samples >=
9413 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9414 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9415 "be larger than %uMB (broken file?)", stream->n_samples,
9416 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9420 g_assert (stream->samples == NULL);
9421 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9422 if (!stream->samples) {
9423 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9432 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9433 (_("This file is corrupt and cannot be played.")), (NULL));
9438 gst_qtdemux_stbl_free (stream);
9439 if (!qtdemux->fragmented) {
9440 /* not quite good */
9441 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9444 /* may pick up samples elsewhere */
9450 /* collect samples from the next sample to be parsed up to sample @n for @stream
9451 * by reading the info from @stbl
9453 * This code can be executed from both the streaming thread and the seeking
9454 * thread so it takes the object lock to protect itself
9457 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9460 QtDemuxSample *samples, *first, *cur, *last;
9461 guint32 n_samples_per_chunk;
9464 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9465 GST_FOURCC_FORMAT ", pad %s",
9466 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9467 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9469 n_samples = stream->n_samples;
9472 goto out_of_samples;
9474 GST_OBJECT_LOCK (qtdemux);
9475 if (n <= stream->stbl_index)
9476 goto already_parsed;
9478 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9480 if (!stream->stsz.data) {
9481 /* so we already parsed and passed all the moov samples;
9482 * onto fragmented ones */
9483 g_assert (qtdemux->fragmented);
9487 /* pointer to the sample table */
9488 samples = stream->samples;
9490 /* starts from -1, moves to the next sample index to parse */
9491 stream->stbl_index++;
9493 /* keep track of the first and last sample to fill */
9494 first = &samples[stream->stbl_index];
9497 if (!stream->chunks_are_samples) {
9498 /* set the sample sizes */
9499 if (stream->sample_size == 0) {
9500 /* different sizes for each sample */
9501 for (cur = first; cur <= last; cur++) {
9502 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9503 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9504 (guint) (cur - samples), cur->size);
9507 /* samples have the same size */
9508 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9509 for (cur = first; cur <= last; cur++)
9510 cur->size = stream->sample_size;
9514 n_samples_per_chunk = stream->n_samples_per_chunk;
9517 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9520 if (stream->stsc_chunk_index >= stream->last_chunk
9521 || stream->stsc_chunk_index < stream->first_chunk) {
9522 stream->first_chunk =
9523 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9524 stream->samples_per_chunk =
9525 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9527 stream->stsd_sample_description_id =
9528 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9530 /* chunk numbers are counted from 1 it seems */
9531 if (G_UNLIKELY (stream->first_chunk == 0))
9534 --stream->first_chunk;
9536 /* the last chunk of each entry is calculated by taking the first chunk
9537 * of the next entry; except if there is no next, where we fake it with
9539 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9540 stream->last_chunk = G_MAXUINT32;
9542 stream->last_chunk =
9543 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9544 if (G_UNLIKELY (stream->last_chunk == 0))
9547 --stream->last_chunk;
9550 GST_LOG_OBJECT (qtdemux,
9551 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9552 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9553 stream->samples_per_chunk, stream->stsd_sample_description_id);
9555 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9558 if (stream->last_chunk != G_MAXUINT32) {
9559 if (!qt_atom_parser_peek_sub (&stream->stco,
9560 stream->first_chunk * stream->co_size,
9561 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9566 stream->co_chunk = stream->stco;
9567 if (!gst_byte_reader_skip (&stream->co_chunk,
9568 stream->first_chunk * stream->co_size))
9572 stream->stsc_chunk_index = stream->first_chunk;
9575 last_chunk = stream->last_chunk;
9577 if (stream->chunks_are_samples) {
9578 cur = &samples[stream->stsc_chunk_index];
9580 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9583 stream->stsc_chunk_index = j;
9588 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9591 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9592 "%" G_GUINT64_FORMAT, j, cur->offset);
9594 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9595 CUR_STREAM (stream)->bytes_per_frame > 0) {
9597 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9598 CUR_STREAM (stream)->samples_per_frame *
9599 CUR_STREAM (stream)->bytes_per_frame;
9601 cur->size = stream->samples_per_chunk;
9604 GST_DEBUG_OBJECT (qtdemux,
9605 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9606 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9607 stream->stco_sample_index)), cur->size);
9609 cur->timestamp = stream->stco_sample_index;
9610 cur->duration = stream->samples_per_chunk;
9611 cur->keyframe = TRUE;
9614 stream->stco_sample_index += stream->samples_per_chunk;
9616 stream->stsc_chunk_index = j;
9618 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9619 guint32 samples_per_chunk;
9620 guint64 chunk_offset;
9622 if (!stream->stsc_sample_index
9623 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9624 &stream->chunk_offset))
9627 samples_per_chunk = stream->samples_per_chunk;
9628 chunk_offset = stream->chunk_offset;
9630 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9631 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9632 G_GUINT64_FORMAT " and size %d",
9633 (guint) (cur - samples), chunk_offset, cur->size);
9635 cur->offset = chunk_offset;
9636 chunk_offset += cur->size;
9639 if (G_UNLIKELY (cur > last)) {
9641 stream->stsc_sample_index = k + 1;
9642 stream->chunk_offset = chunk_offset;
9643 stream->stsc_chunk_index = j;
9647 stream->stsc_sample_index = 0;
9649 stream->stsc_chunk_index = j;
9651 stream->stsc_index++;
9654 if (stream->chunks_are_samples)
9658 guint32 n_sample_times;
9660 n_sample_times = stream->n_sample_times;
9663 for (i = stream->stts_index; i < n_sample_times; i++) {
9664 guint32 stts_samples;
9665 gint32 stts_duration;
9668 if (stream->stts_sample_index >= stream->stts_samples
9669 || !stream->stts_sample_index) {
9671 stream->stts_samples =
9672 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9673 stream->stts_duration =
9674 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9676 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9677 i, stream->stts_samples, stream->stts_duration);
9679 stream->stts_sample_index = 0;
9682 stts_samples = stream->stts_samples;
9683 stts_duration = stream->stts_duration;
9684 stts_time = stream->stts_time;
9686 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9687 GST_DEBUG_OBJECT (qtdemux,
9688 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9689 (guint) (cur - samples), j,
9690 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9692 cur->timestamp = stts_time;
9693 cur->duration = stts_duration;
9695 /* avoid 32-bit wrap-around,
9696 * but still mind possible 'negative' duration */
9697 stts_time += (gint64) stts_duration;
9700 if (G_UNLIKELY (cur > last)) {
9702 stream->stts_time = stts_time;
9703 stream->stts_sample_index = j + 1;
9704 if (stream->stts_sample_index >= stream->stts_samples)
9705 stream->stts_index++;
9709 stream->stts_sample_index = 0;
9710 stream->stts_time = stts_time;
9711 stream->stts_index++;
9713 /* fill up empty timestamps with the last timestamp, this can happen when
9714 * the last samples do not decode and so we don't have timestamps for them.
9715 * We however look at the last timestamp to estimate the track length so we
9716 * need something in here. */
9717 for (; cur < last; cur++) {
9718 GST_DEBUG_OBJECT (qtdemux,
9719 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9720 (guint) (cur - samples),
9721 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9722 cur->timestamp = stream->stts_time;
9728 /* sample sync, can be NULL */
9729 if (stream->stss_present == TRUE) {
9730 guint32 n_sample_syncs;
9732 n_sample_syncs = stream->n_sample_syncs;
9734 if (!n_sample_syncs) {
9735 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9736 stream->all_keyframe = TRUE;
9738 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9739 /* note that the first sample is index 1, not 0 */
9742 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9744 if (G_LIKELY (index > 0 && index <= n_samples)) {
9746 samples[index].keyframe = TRUE;
9747 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9748 /* and exit if we have enough samples */
9749 if (G_UNLIKELY (index >= n)) {
9756 stream->stss_index = i;
9759 /* stps marks partial sync frames like open GOP I-Frames */
9760 if (stream->stps_present == TRUE) {
9761 guint32 n_sample_partial_syncs;
9763 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9765 /* if there are no entries, the stss table contains the real
9767 if (n_sample_partial_syncs) {
9768 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9769 /* note that the first sample is index 1, not 0 */
9772 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9774 if (G_LIKELY (index > 0 && index <= n_samples)) {
9776 samples[index].keyframe = TRUE;
9777 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9778 /* and exit if we have enough samples */
9779 if (G_UNLIKELY (index >= n)) {
9786 stream->stps_index = i;
9790 /* no stss, all samples are keyframes */
9791 stream->all_keyframe = TRUE;
9792 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9797 /* composition time to sample */
9798 if (stream->ctts_present == TRUE) {
9799 guint32 n_composition_times;
9801 gint32 ctts_soffset;
9803 /* Fill in the pts_offsets */
9805 n_composition_times = stream->n_composition_times;
9807 for (i = stream->ctts_index; i < n_composition_times; i++) {
9808 if (stream->ctts_sample_index >= stream->ctts_count
9809 || !stream->ctts_sample_index) {
9810 stream->ctts_count =
9811 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9812 stream->ctts_soffset =
9813 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9814 stream->ctts_sample_index = 0;
9817 ctts_count = stream->ctts_count;
9818 ctts_soffset = stream->ctts_soffset;
9820 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9821 cur->pts_offset = ctts_soffset;
9824 if (G_UNLIKELY (cur > last)) {
9826 stream->ctts_sample_index = j + 1;
9830 stream->ctts_sample_index = 0;
9831 stream->ctts_index++;
9835 stream->stbl_index = n;
9836 /* if index has been completely parsed, free data that is no-longer needed */
9837 if (n + 1 == stream->n_samples) {
9838 gst_qtdemux_stbl_free (stream);
9839 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9840 if (qtdemux->pullbased) {
9841 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9842 while (n + 1 == stream->n_samples)
9843 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9847 GST_OBJECT_UNLOCK (qtdemux);
9854 GST_LOG_OBJECT (qtdemux,
9855 "Tried to parse up to sample %u but this sample has already been parsed",
9857 /* if fragmented, there may be more */
9858 if (qtdemux->fragmented && n == stream->stbl_index)
9860 GST_OBJECT_UNLOCK (qtdemux);
9866 GST_LOG_OBJECT (qtdemux,
9867 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9869 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9870 (_("This file is corrupt and cannot be played.")), (NULL));
9875 GST_OBJECT_UNLOCK (qtdemux);
9876 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9877 (_("This file is corrupt and cannot be played.")), (NULL));
9882 /* collect all segment info for @stream.
9885 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9889 /* accept edts if they contain gaps at start and there is only
9890 * one media segment */
9891 gboolean allow_pushbased_edts = TRUE;
9892 gint media_segments_count = 0;
9894 /* parse and prepare segment info from the edit list */
9895 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9896 stream->n_segments = 0;
9897 stream->segments = NULL;
9898 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9901 gint segment_number, entry_size;
9904 const guint8 *buffer;
9908 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9909 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9912 buffer = elst->data;
9914 size = QT_UINT32 (buffer);
9915 /* version, flags, n_segments */
9917 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9920 version = QT_UINT8 (buffer + 8);
9921 entry_size = (version == 1) ? 20 : 12;
9923 n_segments = QT_UINT32 (buffer + 12);
9925 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9926 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9930 /* we might allocate a bit too much, at least allocate 1 segment */
9931 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9933 /* segments always start from 0 */
9937 for (segment_number = 0; segment_number < n_segments; segment_number++) {
9940 gboolean empty_edit = FALSE;
9941 QtDemuxSegment *segment;
9943 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9946 media_time = QT_UINT64 (buffer + 8);
9947 duration = QT_UINT64 (buffer);
9948 if (media_time == G_MAXUINT64)
9951 media_time = QT_UINT32 (buffer + 4);
9952 duration = QT_UINT32 (buffer);
9953 if (media_time == G_MAXUINT32)
9958 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9960 segment = &stream->segments[segment_number];
9962 /* time and duration expressed in global timescale */
9963 segment->time = stime;
9964 if (duration != 0 || empty_edit) {
9965 /* edge case: empty edits with duration=zero are treated here.
9966 * (files should not have these anyway). */
9968 /* add non scaled values so we don't cause roundoff errors */
9970 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9971 segment->duration = stime - segment->time;
9973 /* zero duration does not imply media_start == media_stop
9974 * but, only specify media_start. The edit ends with the track. */
9975 stime = segment->duration = GST_CLOCK_TIME_NONE;
9976 /* Don't allow more edits after this one. */
9977 n_segments = segment_number + 1;
9979 segment->stop_time = stime;
9981 segment->trak_media_start = media_time;
9982 /* media_time expressed in stream timescale */
9984 segment->media_start = media_start;
9985 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
9986 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
9987 media_segments_count++;
9989 segment->media_start = GST_CLOCK_TIME_NONE;
9990 segment->media_stop = GST_CLOCK_TIME_NONE;
9992 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9994 if (rate_int <= 1) {
9995 /* 0 is not allowed, some programs write 1 instead of the floating point
9997 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10001 segment->rate = rate_int / 65536.0;
10004 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10005 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10006 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10007 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10008 segment_number, GST_TIME_ARGS (segment->time),
10009 GST_TIME_ARGS (segment->duration),
10010 GST_TIME_ARGS (segment->media_start), media_time,
10011 GST_TIME_ARGS (segment->media_stop),
10012 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10013 stream->timescale);
10014 if (segment->stop_time > qtdemux->segment.stop &&
10015 !qtdemux->upstream_format_is_time) {
10016 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10017 " extends to %" GST_TIME_FORMAT
10018 " past the end of the declared movie duration %" GST_TIME_FORMAT
10019 " movie segment will be extended", segment_number,
10020 GST_TIME_ARGS (segment->stop_time),
10021 GST_TIME_ARGS (qtdemux->segment.stop));
10022 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10025 buffer += entry_size;
10027 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10028 stream->n_segments = n_segments;
10029 if (media_segments_count != 1)
10030 allow_pushbased_edts = FALSE;
10034 /* push based does not handle segments, so act accordingly here,
10035 * and warn if applicable */
10036 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10037 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10038 /* remove and use default one below, we stream like it anyway */
10039 g_free (stream->segments);
10040 stream->segments = NULL;
10041 stream->n_segments = 0;
10044 /* no segments, create one to play the complete trak */
10045 if (stream->n_segments == 0) {
10046 GstClockTime stream_duration =
10047 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10049 if (stream->segments == NULL)
10050 stream->segments = g_new (QtDemuxSegment, 1);
10052 /* represent unknown our way */
10053 if (stream_duration == 0)
10054 stream_duration = GST_CLOCK_TIME_NONE;
10056 stream->segments[0].time = 0;
10057 stream->segments[0].stop_time = stream_duration;
10058 stream->segments[0].duration = stream_duration;
10059 stream->segments[0].media_start = 0;
10060 stream->segments[0].media_stop = stream_duration;
10061 stream->segments[0].rate = 1.0;
10062 stream->segments[0].trak_media_start = 0;
10064 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10065 GST_TIME_ARGS (stream_duration));
10066 stream->n_segments = 1;
10067 stream->dummy_segment = TRUE;
10069 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10075 * Parses the stsd atom of a svq3 trak looking for
10076 * the SMI and gama atoms.
10079 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10080 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10082 const guint8 *_gamma = NULL;
10083 GstBuffer *_seqh = NULL;
10084 const guint8 *stsd_data = stsd_entry_data;
10085 guint32 length = QT_UINT32 (stsd_data);
10089 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10095 version = QT_UINT16 (stsd_data);
10096 if (version == 3) {
10097 if (length >= 70) {
10100 while (length > 8) {
10101 guint32 fourcc, size;
10102 const guint8 *data;
10103 size = QT_UINT32 (stsd_data);
10104 fourcc = QT_FOURCC (stsd_data + 4);
10105 data = stsd_data + 8;
10108 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10109 "svq3 atom parsing");
10118 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10119 " for gama atom, expected 12", size);
10124 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10126 if (_seqh != NULL) {
10127 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10128 " found, ignoring");
10130 seqh_size = QT_UINT32 (data + 4);
10131 if (seqh_size > 0) {
10132 _seqh = gst_buffer_new_and_alloc (seqh_size);
10133 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10140 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10141 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10145 if (size <= length) {
10151 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10154 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10155 G_GUINT16_FORMAT, version);
10165 } else if (_seqh) {
10166 gst_buffer_unref (_seqh);
10171 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10174 GstByteReader dref;
10178 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10179 * atom that might contain a 'data' atom with the rtsp uri.
10180 * This case was reported in bug #597497, some info about
10181 * the hndl atom can be found in TN1195
10183 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10184 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10187 guint32 dref_num_entries = 0;
10188 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10189 gst_byte_reader_skip (&dref, 4) &&
10190 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10193 /* search dref entries for hndl atom */
10194 for (i = 0; i < dref_num_entries; i++) {
10195 guint32 size = 0, type;
10196 guint8 string_len = 0;
10197 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10198 qt_atom_parser_get_fourcc (&dref, &type)) {
10199 if (type == FOURCC_hndl) {
10200 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10202 /* skip data reference handle bytes and the
10203 * following pascal string and some extra 4
10204 * bytes I have no idea what are */
10205 if (!gst_byte_reader_skip (&dref, 4) ||
10206 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10207 !gst_byte_reader_skip (&dref, string_len + 4)) {
10208 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10212 /* iterate over the atoms to find the data atom */
10213 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10217 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10218 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10219 if (atom_type == FOURCC_data) {
10220 const guint8 *uri_aux = NULL;
10222 /* found the data atom that might contain the rtsp uri */
10223 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10224 "hndl atom, interpreting it as an URI");
10225 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10227 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10228 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10230 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10231 "didn't contain a rtsp address");
10233 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10238 /* skipping to the next entry */
10239 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10242 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10249 /* skip to the next entry */
10250 if (!gst_byte_reader_skip (&dref, size - 8))
10253 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10256 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10262 #define AMR_NB_ALL_MODES 0x81ff
10263 #define AMR_WB_ALL_MODES 0x83ff
10265 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10267 /* The 'damr' atom is of the form:
10269 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10270 * 32 b 8 b 16 b 8 b 8 b
10272 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10273 * represents the highest mode used in the stream (and thus the maximum
10274 * bitrate), with a couple of special cases as seen below.
10277 /* Map of frame type ID -> bitrate */
10278 static const guint nb_bitrates[] = {
10279 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10281 static const guint wb_bitrates[] = {
10282 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10288 gst_buffer_map (buf, &map, GST_MAP_READ);
10290 if (map.size != 0x11) {
10291 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10295 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10296 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10297 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10301 mode_set = QT_UINT16 (map.data + 13);
10303 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10304 max_mode = 7 + (wb ? 1 : 0);
10306 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10307 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10309 if (max_mode == -1) {
10310 GST_DEBUG ("No mode indication was found (mode set) = %x",
10315 gst_buffer_unmap (buf, &map);
10316 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10319 gst_buffer_unmap (buf, &map);
10324 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10325 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10328 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10334 if (gst_byte_reader_get_remaining (reader) < 36)
10337 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10338 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10339 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10340 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10341 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10342 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10343 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10344 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10345 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10347 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10348 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10349 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10351 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10352 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10354 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10355 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10362 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10363 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10370 * This macro will only compare value abdegh, it expects cfi to have already
10373 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10374 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10376 /* only handle the cases where the last column has standard values */
10377 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10378 const gchar *rotation_tag = NULL;
10380 /* no rotation needed */
10381 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10383 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10384 rotation_tag = "rotate-90";
10385 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10386 rotation_tag = "rotate-180";
10387 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10388 rotation_tag = "rotate-270";
10390 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10393 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10394 GST_STR_NULL (rotation_tag));
10395 if (rotation_tag != NULL) {
10396 if (*taglist == NULL)
10397 *taglist = gst_tag_list_new_empty ();
10398 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10399 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10402 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10407 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10408 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10412 GstBuffer *adrm_buf = NULL;
10413 QtDemuxAavdEncryptionInfo *info;
10415 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10416 if (G_UNLIKELY (!adrm)) {
10417 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10420 adrm_size = QT_UINT32 (adrm->data);
10421 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10423 stream->protection_scheme_type = FOURCC_aavd;
10425 if (!stream->protection_scheme_info)
10426 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10428 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10430 if (info->default_properties)
10431 gst_structure_free (info->default_properties);
10432 info->default_properties = gst_structure_new ("application/x-aavd",
10433 "encrypted", G_TYPE_BOOLEAN, TRUE,
10434 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10435 gst_buffer_unref (adrm_buf);
10437 *original_fmt = FOURCC_mp4a;
10441 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10442 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10443 * Common Encryption (cenc), the function will also parse the tenc box (defined
10444 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10445 * (typically an enc[v|a|t|s] sample entry); the function will set
10446 * @original_fmt to the fourcc of the original unencrypted stream format.
10447 * Returns TRUE if successful; FALSE otherwise. */
10449 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10450 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10456 QtDemuxCencSampleSetInfo *info;
10458 const guint8 *tenc_data;
10460 g_return_val_if_fail (qtdemux != NULL, FALSE);
10461 g_return_val_if_fail (stream != NULL, FALSE);
10462 g_return_val_if_fail (container != NULL, FALSE);
10463 g_return_val_if_fail (original_fmt != NULL, FALSE);
10465 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10466 if (G_UNLIKELY (!sinf)) {
10467 if (stream->protection_scheme_type == FOURCC_cenc
10468 || stream->protection_scheme_type == FOURCC_cbcs) {
10469 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10470 "mandatory for Common Encryption");
10476 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10477 if (G_UNLIKELY (!frma)) {
10478 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10482 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10483 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10484 GST_FOURCC_ARGS (*original_fmt));
10486 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10488 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10491 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10492 stream->protection_scheme_version =
10493 QT_UINT32 ((const guint8 *) schm->data + 16);
10495 GST_DEBUG_OBJECT (qtdemux,
10496 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10497 "protection_scheme_version: %#010x",
10498 GST_FOURCC_ARGS (stream->protection_scheme_type),
10499 stream->protection_scheme_version);
10501 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10503 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10506 if (stream->protection_scheme_type != FOURCC_cenc &&
10507 stream->protection_scheme_type != FOURCC_piff &&
10508 stream->protection_scheme_type != FOURCC_cbcs) {
10509 GST_ERROR_OBJECT (qtdemux,
10510 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10511 GST_FOURCC_ARGS (stream->protection_scheme_type));
10515 if (G_UNLIKELY (!stream->protection_scheme_info))
10516 stream->protection_scheme_info =
10517 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10519 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10521 if (stream->protection_scheme_type == FOURCC_cenc
10522 || stream->protection_scheme_type == FOURCC_cbcs) {
10523 guint8 is_encrypted;
10525 guint8 constant_iv_size = 0;
10526 const guint8 *default_kid;
10527 guint8 crypt_byte_block = 0;
10528 guint8 skip_byte_block = 0;
10529 const guint8 *constant_iv = NULL;
10531 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10533 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10534 "which is mandatory for Common Encryption");
10537 tenc_data = (const guint8 *) tenc->data + 12;
10538 is_encrypted = QT_UINT8 (tenc_data + 2);
10539 iv_size = QT_UINT8 (tenc_data + 3);
10540 default_kid = (tenc_data + 4);
10541 if (stream->protection_scheme_type == FOURCC_cbcs) {
10542 guint8 possible_pattern_info;
10543 if (iv_size == 0) {
10544 constant_iv_size = QT_UINT8 (tenc_data + 20);
10545 if (constant_iv_size != 8 && constant_iv_size != 16) {
10546 GST_ERROR_OBJECT (qtdemux,
10547 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10550 constant_iv = (tenc_data + 21);
10552 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10553 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10554 skip_byte_block = possible_pattern_info & 0x0f;
10556 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10557 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10558 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10559 } else if (stream->protection_scheme_type == FOURCC_piff) {
10561 static const guint8 piff_track_encryption_uuid[] = {
10562 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10563 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10566 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10568 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10569 "which is mandatory for Common Encryption");
10573 tenc_data = (const guint8 *) tenc->data + 8;
10574 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10575 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10576 GST_ERROR_OBJECT (qtdemux,
10577 "Unsupported track encryption box with uuid: %s", box_uuid);
10581 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10582 gst_byte_reader_init (&br, tenc_data, 20);
10583 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10584 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10587 stream->protection_scheme_type = FOURCC_cenc;
10594 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10595 QtDemuxStream ** stream2)
10597 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10601 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10606 /*parse svmi header if existing */
10607 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10609 guint len = QT_UINT32 ((guint8 *) svmi->data);
10610 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10612 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10613 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10614 guint8 frame_type, frame_layout;
10615 guint32 stereo_mono_change_count;
10620 /* MPEG-A stereo video */
10621 if (qtdemux->major_brand == FOURCC_ss02)
10622 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10624 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10625 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10626 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10628 switch (frame_type) {
10630 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10633 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10636 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10639 /* mode 3 is primary/secondary view sequence, ie
10640 * left/right views in separate tracks. See section 7.2
10641 * of ISO/IEC 23000-11:2009 */
10642 /* In the future this might be supported using related
10643 * streams, like an enhancement track - if files like this
10645 GST_FIXME_OBJECT (qtdemux,
10646 "Implement stereo video in separate streams");
10649 if ((frame_layout & 0x1) == 0)
10650 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10652 GST_LOG_OBJECT (qtdemux,
10653 "StereoVideo: composition type: %u, is_left_first: %u",
10654 frame_type, frame_layout);
10656 if (stereo_mono_change_count > 1) {
10657 GST_FIXME_OBJECT (qtdemux,
10658 "Mixed-mono flags are not yet supported in qtdemux.");
10661 stream->multiview_mode = mode;
10662 stream->multiview_flags = flags;
10669 /* parse the traks.
10670 * With each track we associate a new QtDemuxStream that contains all the info
10672 * traks that do not decode to something (like strm traks) will not have a pad.
10675 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10677 GstByteReader tkhd;
10691 QtDemuxStream *stream = NULL;
10692 const guint8 *stsd_data;
10693 const guint8 *stsd_entry_data;
10694 guint remaining_stsd_len;
10695 guint stsd_entry_count;
10697 guint16 lang_code; /* quicktime lang code or packed iso code */
10699 guint32 tkhd_flags = 0;
10700 guint8 tkhd_version = 0;
10701 guint32 w = 0, h = 0;
10702 guint value_size, stsd_len, len;
10706 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10708 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10709 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10710 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10713 /* pick between 64 or 32 bits */
10714 value_size = tkhd_version == 1 ? 8 : 4;
10715 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10716 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10719 /* Check if current moov has duplicated track_id */
10720 if (qtdemux_find_stream (qtdemux, track_id))
10721 goto existing_stream;
10723 stream = _create_stream (qtdemux, track_id);
10724 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10726 /* need defaults for fragments */
10727 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10729 if ((tkhd_flags & 1) == 0)
10730 stream->disabled = TRUE;
10732 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10733 tkhd_version, tkhd_flags, stream->track_id);
10735 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10738 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10739 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10740 if (qtdemux->major_brand != FOURCC_mjp2 ||
10741 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10745 len = QT_UINT32 ((guint8 *) mdhd->data);
10746 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10747 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10748 if (version == 0x01000000) {
10751 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10752 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10753 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
10757 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10758 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10759 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10762 if (lang_code < 0x400) {
10763 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10764 } else if (lang_code == 0x7fff) {
10765 stream->lang_id[0] = 0; /* unspecified */
10767 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10768 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10769 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10770 stream->lang_id[3] = 0;
10773 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10774 stream->timescale);
10775 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10777 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10778 lang_code, stream->lang_id);
10780 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10783 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10784 /* chapters track reference */
10785 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10787 gsize length = GST_READ_UINT32_BE (chap->data);
10788 if (qtdemux->chapters_track_id)
10789 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10791 if (length >= 12) {
10792 qtdemux->chapters_track_id =
10793 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10798 /* fragmented files may have bogus duration in moov */
10799 if (!qtdemux->fragmented &&
10800 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10801 guint64 tdur1, tdur2;
10803 /* don't overflow */
10804 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10805 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10808 * some of those trailers, nowadays, have prologue images that are
10809 * themselves video tracks as well. I haven't really found a way to
10810 * identify those yet, except for just looking at their duration. */
10811 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10812 GST_WARNING_OBJECT (qtdemux,
10813 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10814 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10815 "found, assuming preview image or something; skipping track",
10816 stream->duration, stream->timescale, qtdemux->duration,
10817 qtdemux->timescale);
10818 gst_qtdemux_stream_unref (stream);
10823 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10826 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10827 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10829 len = QT_UINT32 ((guint8 *) hdlr->data);
10831 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10832 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10833 GST_FOURCC_ARGS (stream->subtype));
10835 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10838 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10841 /* Parse out svmi (and later st3d/sv3d) atoms */
10842 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
10845 /* parse rest of tkhd */
10846 if (stream->subtype == FOURCC_vide) {
10849 /* version 1 uses some 64-bit ints */
10850 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10853 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10856 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10857 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10860 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10861 &stream->stream_tags);
10865 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10867 stsd_data = (const guint8 *) stsd->data;
10869 /* stsd should at least have one entry */
10870 stsd_len = QT_UINT32 (stsd_data);
10871 if (stsd_len < 24) {
10872 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10873 if (stream->subtype == FOURCC_vivo) {
10874 gst_qtdemux_stream_unref (stream);
10881 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10882 /* each stsd entry must contain at least 8 bytes */
10883 if (stream->stsd_entries_length == 0
10884 || stream->stsd_entries_length > stsd_len / 8) {
10885 stream->stsd_entries_length = 0;
10888 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10889 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
10890 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
10892 stsd_entry_data = stsd_data + 16;
10893 remaining_stsd_len = stsd_len - 16;
10894 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10896 gchar *codec = NULL;
10897 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10899 /* and that entry should fit within stsd */
10900 len = QT_UINT32 (stsd_entry_data);
10901 if (len > remaining_stsd_len)
10904 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10905 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
10906 GST_FOURCC_ARGS (entry->fourcc));
10907 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
10909 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10910 goto error_encrypted;
10912 if (fourcc == FOURCC_aavd) {
10913 if (stream->subtype != FOURCC_soun) {
10914 GST_ERROR_OBJECT (qtdemux,
10915 "Unexpeced stsd type 'aavd' outside 'soun' track");
10917 /* encrypted audio with sound sample description v0 */
10918 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10919 stream->protected = TRUE;
10920 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
10921 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10925 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10926 /* FIXME this looks wrong, there might be multiple children
10927 * with the same type */
10928 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10929 stream->protected = TRUE;
10930 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10931 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10934 if (stream->subtype == FOURCC_vide) {
10939 gint depth, palette_size, palette_count;
10940 guint32 *palette_data = NULL;
10942 entry->sampled = TRUE;
10944 stream->display_width = w >> 16;
10945 stream->display_height = h >> 16;
10948 if (len < 86) /* TODO verify */
10951 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10952 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10953 entry->fps_n = 0; /* this is filled in later */
10954 entry->fps_d = 0; /* this is filled in later */
10955 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10956 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10958 /* if color_table_id is 0, ctab atom must follow; however some files
10959 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10960 * if color table is not present we'll correct the value */
10961 if (entry->color_table_id == 0 &&
10963 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10964 entry->color_table_id = -1;
10967 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10968 entry->width, entry->height, entry->bits_per_sample,
10969 entry->color_table_id);
10971 depth = entry->bits_per_sample;
10973 /* more than 32 bits means grayscale */
10974 gray = (depth > 32);
10975 /* low 32 bits specify the depth */
10978 /* different number of palette entries is determined by depth. */
10980 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10981 palette_count = (1 << depth);
10982 palette_size = palette_count * 4;
10984 if (entry->color_table_id) {
10985 switch (palette_count) {
10989 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
10992 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
10997 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
10999 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11004 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11007 g_memdup2 (ff_qt_default_palette_256, palette_size);
11010 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11011 (_("The video in this file might not play correctly.")),
11012 ("unsupported palette depth %d", depth));
11016 gint i, j, start, end;
11022 start = QT_UINT32 (stsd_entry_data + offset + 70);
11023 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11024 end = QT_UINT16 (stsd_entry_data + offset + 76);
11026 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11027 start, end, palette_count);
11034 if (len < 94 + (end - start) * 8)
11037 /* palette is always the same size */
11038 palette_data = g_malloc0 (256 * 4);
11039 palette_size = 256 * 4;
11041 for (j = 0, i = start; i <= end; j++, i++) {
11042 guint32 a, r, g, b;
11044 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11045 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11046 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11047 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11049 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11050 (g & 0xff00) | (b >> 8);
11055 gst_caps_unref (entry->caps);
11058 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11060 if (G_UNLIKELY (!entry->caps)) {
11061 g_free (palette_data);
11062 goto unknown_stream;
11066 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11067 GST_TAG_VIDEO_CODEC, codec, NULL);
11072 if (palette_data) {
11075 if (entry->rgb8_palette)
11076 gst_memory_unref (entry->rgb8_palette);
11077 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11078 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11080 s = gst_caps_get_structure (entry->caps, 0);
11082 /* non-raw video has a palette_data property. raw video has the palette as
11083 * an extra plane that we append to the output buffers before we push
11085 if (!gst_structure_has_name (s, "video/x-raw")) {
11086 GstBuffer *palette;
11088 palette = gst_buffer_new ();
11089 gst_buffer_append_memory (palette, entry->rgb8_palette);
11090 entry->rgb8_palette = NULL;
11092 gst_caps_set_simple (entry->caps, "palette_data",
11093 GST_TYPE_BUFFER, palette, NULL);
11094 gst_buffer_unref (palette);
11096 } else if (palette_count != 0) {
11097 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11098 (NULL), ("Unsupported palette depth %d", depth));
11101 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11102 QT_UINT16 (stsd_entry_data + offset + 32));
11108 /* pick 'the' stsd child */
11109 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11110 // We should skip parsing the stsd for non-protected streams if
11111 // the entry doesn't match the fourcc, since they don't change
11112 // format. However, for protected streams we can have partial
11113 // encryption, where parts of the stream are encrypted and parts
11114 // not. For both parts of such streams, we should ensure the
11115 // esds overrides are parsed for both from the stsd.
11116 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11117 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11119 else if (!stream->protected)
11124 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11125 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11126 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11127 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11131 const guint8 *pasp_data = (const guint8 *) pasp->data;
11132 gint len = QT_UINT32 (pasp_data);
11135 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11136 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11138 CUR_STREAM (stream)->par_w = 0;
11139 CUR_STREAM (stream)->par_h = 0;
11142 CUR_STREAM (stream)->par_w = 0;
11143 CUR_STREAM (stream)->par_h = 0;
11147 const guint8 *fiel_data = (const guint8 *) fiel->data;
11148 gint len = QT_UINT32 (fiel_data);
11151 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11152 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11157 const guint8 *colr_data = (const guint8 *) colr->data;
11158 gint len = QT_UINT32 (colr_data);
11160 if (len == 19 || len == 18) {
11161 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11163 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11164 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11165 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11166 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11167 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11169 CUR_STREAM (stream)->colorimetry.primaries =
11170 gst_video_color_primaries_from_iso (primaries);
11171 CUR_STREAM (stream)->colorimetry.transfer =
11172 gst_video_transfer_function_from_iso (transfer_function);
11173 CUR_STREAM (stream)->colorimetry.matrix =
11174 gst_video_color_matrix_from_iso (matrix);
11175 CUR_STREAM (stream)->colorimetry.range =
11176 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11177 GST_VIDEO_COLOR_RANGE_16_235;
11179 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11182 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11187 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11188 stream->stream_tags);
11195 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11196 const guint8 *avc_data = stsd_entry_data + 0x56;
11199 while (len >= 0x8) {
11202 if (QT_UINT32 (avc_data) <= len)
11203 size = QT_UINT32 (avc_data) - 0x8;
11208 /* No real data, so break out */
11211 switch (QT_FOURCC (avc_data + 0x4)) {
11214 /* parse, if found */
11217 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11219 /* First 4 bytes are the length of the atom, the next 4 bytes
11220 * are the fourcc, the next 1 byte is the version, and the
11221 * subsequent bytes are profile_tier_level structure like data. */
11222 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11223 avc_data + 8 + 1, size - 1);
11224 buf = gst_buffer_new_and_alloc (size);
11225 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11226 gst_caps_set_simple (entry->caps,
11227 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11228 gst_buffer_unref (buf);
11236 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11238 /* First 4 bytes are the length of the atom, the next 4 bytes
11239 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11240 * next 1 byte is the version, and the
11241 * subsequent bytes are sequence parameter set like data. */
11243 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11245 gst_codec_utils_h264_caps_set_level_and_profile
11246 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11248 buf = gst_buffer_new_and_alloc (size);
11249 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11250 gst_caps_set_simple (entry->caps,
11251 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11252 gst_buffer_unref (buf);
11258 guint avg_bitrate, max_bitrate;
11260 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11264 max_bitrate = QT_UINT32 (avc_data + 0xc);
11265 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11267 if (!max_bitrate && !avg_bitrate)
11270 /* Some muxers seem to swap the average and maximum bitrates
11271 * (I'm looking at you, YouTube), so we swap for sanity. */
11272 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11273 guint temp = avg_bitrate;
11275 avg_bitrate = max_bitrate;
11276 max_bitrate = temp;
11279 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11280 gst_tag_list_add (stream->stream_tags,
11281 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11282 max_bitrate, NULL);
11284 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11285 gst_tag_list_add (stream->stream_tags,
11286 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11298 avc_data += size + 8;
11309 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11310 const guint8 *hevc_data = stsd_entry_data + 0x56;
11313 while (len >= 0x8) {
11316 if (QT_UINT32 (hevc_data) <= len)
11317 size = QT_UINT32 (hevc_data) - 0x8;
11322 /* No real data, so break out */
11325 switch (QT_FOURCC (hevc_data + 0x4)) {
11328 /* parse, if found */
11331 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11333 /* First 4 bytes are the length of the atom, the next 4 bytes
11334 * are the fourcc, the next 1 byte is the version, and the
11335 * subsequent bytes are sequence parameter set like data. */
11336 gst_codec_utils_h265_caps_set_level_tier_and_profile
11337 (entry->caps, hevc_data + 8 + 1, size - 1);
11339 buf = gst_buffer_new_and_alloc (size);
11340 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11341 gst_caps_set_simple (entry->caps,
11342 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11343 gst_buffer_unref (buf);
11350 hevc_data += size + 8;
11363 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11364 GST_FOURCC_ARGS (fourcc));
11366 /* codec data might be in glbl extension atom */
11368 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11374 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11376 len = QT_UINT32 (data);
11379 buf = gst_buffer_new_and_alloc (len);
11380 gst_buffer_fill (buf, 0, data + 8, len);
11381 gst_caps_set_simple (entry->caps,
11382 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11383 gst_buffer_unref (buf);
11390 /* see annex I of the jpeg2000 spec */
11391 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11392 const guint8 *data;
11393 const gchar *colorspace = NULL;
11395 guint32 ncomp_map = 0;
11396 gint32 *comp_map = NULL;
11397 guint32 nchan_def = 0;
11398 gint32 *chan_def = NULL;
11400 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11401 /* some required atoms */
11402 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11405 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11409 /* number of components; redundant with info in codestream, but useful
11411 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11412 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11414 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11416 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11419 GST_DEBUG_OBJECT (qtdemux, "found colr");
11420 /* extract colour space info */
11421 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11422 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11424 colorspace = "sRGB";
11427 colorspace = "GRAY";
11430 colorspace = "sYUV";
11438 /* colr is required, and only values 16, 17, and 18 are specified,
11439 so error if we have no colorspace */
11442 /* extract component mapping */
11443 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11445 guint32 cmap_len = 0;
11447 cmap_len = QT_UINT32 (cmap->data);
11448 if (cmap_len >= 8) {
11449 /* normal box, subtract off header */
11451 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11452 if (cmap_len % 4 == 0) {
11453 ncomp_map = (cmap_len / 4);
11454 comp_map = g_new0 (gint32, ncomp_map);
11455 for (i = 0; i < ncomp_map; i++) {
11458 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11459 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11460 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11461 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11466 /* extract channel definitions */
11467 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11469 guint32 cdef_len = 0;
11471 cdef_len = QT_UINT32 (cdef->data);
11472 if (cdef_len >= 10) {
11473 /* normal box, subtract off header and len */
11475 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11476 if (cdef_len % 6 == 0) {
11477 nchan_def = (cdef_len / 6);
11478 chan_def = g_new0 (gint32, nchan_def);
11479 for (i = 0; i < nchan_def; i++)
11481 for (i = 0; i < nchan_def; i++) {
11482 guint16 cn, typ, asoc;
11483 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11484 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11485 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11486 if (cn < nchan_def) {
11489 chan_def[cn] = asoc;
11492 chan_def[cn] = 0; /* alpha */
11495 chan_def[cn] = -typ;
11503 gst_caps_set_simple (entry->caps,
11504 "num-components", G_TYPE_INT, ncomp, NULL);
11505 gst_caps_set_simple (entry->caps,
11506 "colorspace", G_TYPE_STRING, colorspace, NULL);
11509 GValue arr = { 0, };
11510 GValue elt = { 0, };
11512 g_value_init (&arr, GST_TYPE_ARRAY);
11513 g_value_init (&elt, G_TYPE_INT);
11514 for (i = 0; i < ncomp_map; i++) {
11515 g_value_set_int (&elt, comp_map[i]);
11516 gst_value_array_append_value (&arr, &elt);
11518 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11519 "component-map", &arr);
11520 g_value_unset (&elt);
11521 g_value_unset (&arr);
11526 GValue arr = { 0, };
11527 GValue elt = { 0, };
11529 g_value_init (&arr, GST_TYPE_ARRAY);
11530 g_value_init (&elt, G_TYPE_INT);
11531 for (i = 0; i < nchan_def; i++) {
11532 g_value_set_int (&elt, chan_def[i]);
11533 gst_value_array_append_value (&arr, &elt);
11535 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11536 "channel-definitions", &arr);
11537 g_value_unset (&elt);
11538 g_value_unset (&arr);
11542 /* some optional atoms */
11543 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11544 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11546 /* indicate possible fields in caps */
11548 data = (guint8 *) field->data + 8;
11550 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11551 (gint) * data, NULL);
11553 /* add codec_data if provided */
11558 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11559 data = prefix->data;
11560 len = QT_UINT32 (data);
11563 buf = gst_buffer_new_and_alloc (len);
11564 gst_buffer_fill (buf, 0, data + 8, len);
11565 gst_caps_set_simple (entry->caps,
11566 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11567 gst_buffer_unref (buf);
11576 GstBuffer *seqh = NULL;
11577 const guint8 *gamma_data = NULL;
11578 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11580 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11583 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11584 QT_FP32 (gamma_data), NULL);
11587 /* sorry for the bad name, but we don't know what this is, other
11588 * than its own fourcc */
11589 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11591 gst_buffer_unref (seqh);
11594 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11595 buf = gst_buffer_new_and_alloc (len);
11596 gst_buffer_fill (buf, 0, stsd_data, len);
11597 gst_caps_set_simple (entry->caps,
11598 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11599 gst_buffer_unref (buf);
11604 /* https://developer.apple.com/standards/qtff-2001.pdf,
11605 * page 92, "Video Sample Description", under table 3.1 */
11608 const gint compressor_offset =
11609 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11610 const gint min_size = compressor_offset + 32 + 2 + 2;
11613 guint16 color_table_id = 0;
11616 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11618 /* recover information on interlaced/progressive */
11619 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11623 len = QT_UINT32 (jpeg->data);
11624 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11626 if (len >= min_size) {
11627 gst_byte_reader_init (&br, jpeg->data, len);
11629 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11630 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11631 if (color_table_id != 0) {
11632 /* the spec says there can be concatenated chunks in the data, and we want
11633 * to find one called field. Walk through them. */
11634 gint offset = min_size;
11635 while (offset + 8 < len) {
11636 guint32 size = 0, tag;
11637 ok = gst_byte_reader_get_uint32_le (&br, &size);
11638 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11639 if (!ok || size < 8) {
11640 GST_WARNING_OBJECT (qtdemux,
11641 "Failed to walk optional chunk list");
11644 GST_DEBUG_OBJECT (qtdemux,
11645 "Found optional %4.4s chunk, size %u",
11646 (const char *) &tag, size);
11647 if (tag == FOURCC_fiel) {
11648 guint8 n_fields = 0, ordering = 0;
11649 gst_byte_reader_get_uint8 (&br, &n_fields);
11650 gst_byte_reader_get_uint8 (&br, &ordering);
11651 if (n_fields == 1 || n_fields == 2) {
11652 GST_DEBUG_OBJECT (qtdemux,
11653 "Found fiel tag with %u fields, ordering %u",
11654 n_fields, ordering);
11656 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11657 "interlace-mode", G_TYPE_STRING, "interleaved",
11660 GST_WARNING_OBJECT (qtdemux,
11661 "Found fiel tag with invalid fields (%u)", n_fields);
11667 GST_DEBUG_OBJECT (qtdemux,
11668 "Color table ID is 0, not trying to get interlacedness");
11671 GST_WARNING_OBJECT (qtdemux,
11672 "Length of jpeg chunk is too small, not trying to get interlacedness");
11680 gst_caps_set_simple (entry->caps,
11681 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11687 GNode *xith, *xdxt;
11689 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11690 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11694 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11698 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11699 /* collect the headers and store them in a stream list so that we can
11700 * send them out first */
11701 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11711 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11712 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11715 ovc1_data = ovc1->data;
11716 ovc1_len = QT_UINT32 (ovc1_data);
11717 if (ovc1_len <= 198) {
11718 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11721 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11722 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11723 gst_caps_set_simple (entry->caps,
11724 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11725 gst_buffer_unref (buf);
11730 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11731 const guint8 *vc1_data = stsd_entry_data + 0x56;
11737 if (QT_UINT32 (vc1_data) <= len)
11738 size = QT_UINT32 (vc1_data) - 8;
11743 /* No real data, so break out */
11746 switch (QT_FOURCC (vc1_data + 0x4)) {
11747 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11751 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11752 buf = gst_buffer_new_and_alloc (size);
11753 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11754 gst_caps_set_simple (entry->caps,
11755 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11756 gst_buffer_unref (buf);
11763 vc1_data += size + 8;
11769 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11770 const guint8 *av1_data = stsd_entry_data + 0x56;
11773 while (len >= 0x8) {
11776 if (QT_UINT32 (av1_data) <= len)
11777 size = QT_UINT32 (av1_data) - 0x8;
11782 /* No real data, so break out */
11785 switch (QT_FOURCC (av1_data + 0x4)) {
11788 /* parse, if found */
11790 guint8 pres_delay_field;
11792 GST_DEBUG_OBJECT (qtdemux,
11793 "found av1C codec_data in stsd of size %d", size);
11795 /* not enough data, just ignore and hope for the best */
11800 * 4 bytes: atom length
11805 * 1 bits: initial_presentation_delay_present
11806 * 4 bits: initial_presentation_delay (if present else reserved
11810 if (av1_data[9] != 0) {
11811 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11815 /* We skip initial_presentation_delay* for now */
11816 pres_delay_field = *(av1_data + 12);
11817 if (pres_delay_field & (1 << 5)) {
11818 gst_caps_set_simple (entry->caps,
11819 "presentation-delay", G_TYPE_INT,
11820 (gint) (pres_delay_field & 0x0F) + 1, NULL);
11823 buf = gst_buffer_new_and_alloc (size - 5);
11824 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11825 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
11826 gst_caps_set_simple (entry->caps,
11827 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11828 gst_buffer_unref (buf);
11837 av1_data += size + 8;
11843 /* TODO: Need to parse vpcC for VP8 codec too.
11844 * Note that VPCodecConfigurationBox (vpcC) is defined for
11845 * vp08, vp09, and vp10 fourcc. */
11848 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11849 const guint8 *vpcc_data = stsd_entry_data + 0x56;
11852 while (len >= 0x8) {
11855 if (QT_UINT32 (vpcc_data) <= len)
11856 size = QT_UINT32 (vpcc_data) - 0x8;
11861 /* No real data, so break out */
11864 switch (QT_FOURCC (vpcc_data + 0x4)) {
11867 const gchar *profile_str = NULL;
11868 const gchar *chroma_format_str = NULL;
11871 guint8 chroma_format;
11872 GstVideoColorimetry cinfo;
11874 /* parse, if found */
11875 GST_DEBUG_OBJECT (qtdemux,
11876 "found vp codec_data in stsd of size %d", size);
11878 /* the meaning of "size" is length of the atom body, excluding
11879 * atom length and fourcc fields */
11884 * 4 bytes: atom length
11891 * 3 bits: chromaSubsampling
11892 * 1 bit: videoFullRangeFlag
11893 * 1 byte: colourPrimaries
11894 * 1 byte: transferCharacteristics
11895 * 1 byte: matrixCoefficients
11896 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
11897 * rest: codecIntializationData (not used for vp8 and vp9)
11900 if (vpcc_data[8] != 1) {
11901 GST_WARNING_OBJECT (qtdemux,
11902 "unknown vpcC version %d", vpcc_data[8]);
11906 profile = vpcc_data[12];
11925 gst_caps_set_simple (entry->caps,
11926 "profile", G_TYPE_STRING, profile_str, NULL);
11929 /* skip level, the VP9 spec v0.6 defines only one level atm,
11930 * but webm spec define various ones. Add level to caps
11931 * if we really need it then */
11933 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
11934 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
11935 gst_caps_set_simple (entry->caps,
11936 "bit-depth-luma", G_TYPE_UINT, bitdepth,
11937 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
11940 chroma_format = (vpcc_data[14] & 0xe) >> 1;
11941 switch (chroma_format) {
11944 chroma_format_str = "4:2:0";
11947 chroma_format_str = "4:2:2";
11950 chroma_format_str = "4:4:4";
11956 if (chroma_format_str) {
11957 gst_caps_set_simple (entry->caps,
11958 "chroma-format", G_TYPE_STRING, chroma_format_str,
11962 if ((vpcc_data[14] & 0x1) != 0)
11963 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
11965 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
11967 gst_video_color_primaries_from_iso (vpcc_data[15]);
11969 gst_video_transfer_function_from_iso (vpcc_data[16]);
11971 gst_video_color_matrix_from_iso (vpcc_data[17]);
11973 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
11974 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
11975 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
11976 /* set this only if all values are known, otherwise this
11977 * might overwrite valid ones parsed from other color box */
11978 CUR_STREAM (stream)->colorimetry = cinfo;
11987 vpcc_data += size + 8;
11997 GST_INFO_OBJECT (qtdemux,
11998 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11999 GST_FOURCC_ARGS (fourcc), entry->caps);
12001 } else if (stream->subtype == FOURCC_soun) {
12003 int version, samplesize;
12004 guint16 compression_id;
12005 gboolean amrwb = FALSE;
12008 /* sample description entry (16) + sound sample description v0 (20) */
12012 version = QT_UINT32 (stsd_entry_data + offset);
12013 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12014 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12015 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12016 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12018 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12019 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12020 QT_UINT32 (stsd_entry_data + offset + 4));
12021 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12022 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12023 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12024 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12025 QT_UINT16 (stsd_entry_data + offset + 14));
12026 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12028 if (compression_id == 0xfffe)
12029 entry->sampled = TRUE;
12031 /* first assume uncompressed audio */
12032 entry->bytes_per_sample = samplesize / 8;
12033 entry->samples_per_frame = entry->n_channels;
12034 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12035 entry->samples_per_packet = entry->samples_per_frame;
12036 entry->bytes_per_packet = entry->bytes_per_sample;
12040 if (version == 0x00010000) {
12041 /* sample description entry (16) + sound sample description v1 (20+16) */
12045 /* take information from here over the normal sample description */
12046 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12047 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12048 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12049 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12051 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12052 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12053 entry->samples_per_packet);
12054 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12055 entry->bytes_per_packet);
12056 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12057 entry->bytes_per_frame);
12058 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12059 entry->bytes_per_sample);
12061 if (!entry->sampled && entry->bytes_per_packet) {
12062 entry->samples_per_frame = (entry->bytes_per_frame /
12063 entry->bytes_per_packet) * entry->samples_per_packet;
12064 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12065 entry->samples_per_frame);
12067 } else if (version == 0x00020000) {
12068 /* sample description entry (16) + sound sample description v2 (56) */
12072 /* take information from here over the normal sample description */
12073 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12074 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12075 entry->samples_per_frame = entry->n_channels;
12076 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12077 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12078 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12079 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12081 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12082 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12083 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12084 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12085 entry->bytes_per_sample * 8);
12086 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12087 QT_UINT32 (stsd_entry_data + offset + 24));
12088 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12089 entry->bytes_per_packet);
12090 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12091 entry->samples_per_packet);
12092 } else if (version != 0x00000) {
12093 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12098 /* Yes, these have to be hard-coded */
12101 entry->samples_per_packet = 6;
12102 entry->bytes_per_packet = 1;
12103 entry->bytes_per_frame = 1 * entry->n_channels;
12104 entry->bytes_per_sample = 1;
12105 entry->samples_per_frame = 6 * entry->n_channels;
12110 entry->samples_per_packet = 3;
12111 entry->bytes_per_packet = 1;
12112 entry->bytes_per_frame = 1 * entry->n_channels;
12113 entry->bytes_per_sample = 1;
12114 entry->samples_per_frame = 3 * entry->n_channels;
12119 entry->samples_per_packet = 64;
12120 entry->bytes_per_packet = 34;
12121 entry->bytes_per_frame = 34 * entry->n_channels;
12122 entry->bytes_per_sample = 2;
12123 entry->samples_per_frame = 64 * entry->n_channels;
12129 entry->samples_per_packet = 1;
12130 entry->bytes_per_packet = 1;
12131 entry->bytes_per_frame = 1 * entry->n_channels;
12132 entry->bytes_per_sample = 1;
12133 entry->samples_per_frame = 1 * entry->n_channels;
12138 entry->samples_per_packet = 160;
12139 entry->bytes_per_packet = 33;
12140 entry->bytes_per_frame = 33 * entry->n_channels;
12141 entry->bytes_per_sample = 2;
12142 entry->samples_per_frame = 160 * entry->n_channels;
12145 /* fix up any invalid header information from above */
12150 /* Sometimes these are set to 0 in the sound sample descriptions so
12151 * let's try to infer useful values from the other information we
12152 * have available */
12153 if (entry->bytes_per_sample == 0)
12154 entry->bytes_per_sample =
12155 entry->bytes_per_frame / entry->n_channels;
12156 if (entry->bytes_per_sample == 0)
12157 entry->bytes_per_sample = samplesize / 8;
12159 if (entry->bytes_per_frame == 0)
12160 entry->bytes_per_frame =
12161 entry->bytes_per_sample * entry->n_channels;
12163 if (entry->bytes_per_packet == 0)
12164 entry->bytes_per_packet = entry->bytes_per_sample;
12166 if (entry->samples_per_frame == 0)
12167 entry->samples_per_frame = entry->n_channels;
12169 if (entry->samples_per_packet == 0)
12170 entry->samples_per_packet = entry->samples_per_frame;
12180 entry->bytes_per_sample = 3;
12184 entry->bytes_per_sample = 4;
12187 entry->bytes_per_sample = 8;
12190 entry->bytes_per_sample = 2;
12193 g_assert_not_reached ();
12196 entry->samples_per_frame = entry->n_channels;
12197 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12198 entry->samples_per_packet = entry->samples_per_frame;
12199 entry->bytes_per_packet = entry->bytes_per_sample;
12207 gst_caps_unref (entry->caps);
12209 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12210 stsd_entry_data + 32, len - 16, &codec);
12221 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12223 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12225 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12227 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12230 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12231 const gchar *format_str;
12235 format_str = (enda_value) ? "S24LE" : "S24BE";
12238 format_str = (enda_value) ? "S32LE" : "S32BE";
12241 format_str = (enda_value) ? "F32LE" : "F32BE";
12244 format_str = (enda_value) ? "F64LE" : "F64BE";
12247 g_assert_not_reached ();
12250 gst_caps_set_simple (entry->caps,
12251 "format", G_TYPE_STRING, format_str, NULL);
12257 const guint8 *owma_data;
12258 const gchar *codec_name = NULL;
12262 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12263 /* FIXME this should also be gst_riff_strf_auds,
12264 * but the latter one is actually missing bits-per-sample :( */
12269 gint32 nSamplesPerSec;
12270 gint32 nAvgBytesPerSec;
12271 gint16 nBlockAlign;
12272 gint16 wBitsPerSample;
12275 WAVEFORMATEX *wfex;
12277 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12278 owma_data = stsd_entry_data;
12279 owma_len = QT_UINT32 (owma_data);
12280 if (owma_len <= 54) {
12281 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12284 wfex = (WAVEFORMATEX *) (owma_data + 36);
12285 buf = gst_buffer_new_and_alloc (owma_len - 54);
12286 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12287 if (wfex->wFormatTag == 0x0161) {
12288 codec_name = "Windows Media Audio";
12290 } else if (wfex->wFormatTag == 0x0162) {
12291 codec_name = "Windows Media Audio 9 Pro";
12293 } else if (wfex->wFormatTag == 0x0163) {
12294 codec_name = "Windows Media Audio 9 Lossless";
12295 /* is that correct? gstffmpegcodecmap.c is missing it, but
12296 * fluendo codec seems to support it */
12300 gst_caps_set_simple (entry->caps,
12301 "codec_data", GST_TYPE_BUFFER, buf,
12302 "wmaversion", G_TYPE_INT, version,
12303 "block_align", G_TYPE_INT,
12304 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12305 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12306 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12307 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12308 gst_buffer_unref (buf);
12312 codec = g_strdup (codec_name);
12318 gint len = QT_UINT32 (stsd_entry_data) - offset;
12319 const guint8 *wfex_data = stsd_entry_data + offset;
12320 const gchar *codec_name = NULL;
12322 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12323 /* FIXME this should also be gst_riff_strf_auds,
12324 * but the latter one is actually missing bits-per-sample :( */
12329 gint32 nSamplesPerSec;
12330 gint32 nAvgBytesPerSec;
12331 gint16 nBlockAlign;
12332 gint16 wBitsPerSample;
12337 /* FIXME: unify with similar wavformatex parsing code above */
12338 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12344 if (QT_UINT32 (wfex_data) <= len)
12345 size = QT_UINT32 (wfex_data) - 8;
12350 /* No real data, so break out */
12353 switch (QT_FOURCC (wfex_data + 4)) {
12354 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12356 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12361 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12362 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12363 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12364 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12365 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12366 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12367 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12369 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12370 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12371 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12372 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12373 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12374 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12376 if (wfex.wFormatTag == 0x0161) {
12377 codec_name = "Windows Media Audio";
12379 } else if (wfex.wFormatTag == 0x0162) {
12380 codec_name = "Windows Media Audio 9 Pro";
12382 } else if (wfex.wFormatTag == 0x0163) {
12383 codec_name = "Windows Media Audio 9 Lossless";
12384 /* is that correct? gstffmpegcodecmap.c is missing it, but
12385 * fluendo codec seems to support it */
12389 gst_caps_set_simple (entry->caps,
12390 "wmaversion", G_TYPE_INT, version,
12391 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12392 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12393 "width", G_TYPE_INT, wfex.wBitsPerSample,
12394 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12396 if (size > wfex.cbSize) {
12399 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12400 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12401 size - wfex.cbSize);
12402 gst_caps_set_simple (entry->caps,
12403 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12404 gst_buffer_unref (buf);
12406 GST_WARNING_OBJECT (qtdemux, "no codec data");
12411 codec = g_strdup (codec_name);
12419 wfex_data += size + 8;
12425 const guint8 *opus_data;
12426 guint8 *channel_mapping = NULL;
12429 guint8 channel_mapping_family;
12430 guint8 stream_count;
12431 guint8 coupled_count;
12434 opus_data = stsd_entry_data;
12436 channels = GST_READ_UINT8 (opus_data + 45);
12437 rate = GST_READ_UINT32_LE (opus_data + 48);
12438 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
12439 stream_count = GST_READ_UINT8 (opus_data + 55);
12440 coupled_count = GST_READ_UINT8 (opus_data + 56);
12442 if (channels > 0) {
12443 channel_mapping = g_malloc (channels * sizeof (guint8));
12444 for (i = 0; i < channels; i++)
12445 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
12448 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12449 channel_mapping_family, stream_count, coupled_count,
12461 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12462 GST_TAG_AUDIO_CODEC, codec, NULL);
12466 /* some bitrate info may have ended up in caps */
12467 s = gst_caps_get_structure (entry->caps, 0);
12468 gst_structure_get_int (s, "bitrate", &bitrate);
12470 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12471 GST_TAG_BITRATE, bitrate, NULL);
12475 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12476 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12477 if (stream->protected) {
12478 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12479 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12481 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12491 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12493 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12495 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12499 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12500 16 bits is a byte-swapped wave-style codec identifier,
12501 and we can find a WAVE header internally to a 'wave' atom here.
12502 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12503 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12506 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12507 if (len < offset + 20) {
12508 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12510 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12511 const guint8 *data = stsd_entry_data + offset + 16;
12513 GNode *waveheadernode;
12515 wavenode = g_node_new ((guint8 *) data);
12516 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12517 const guint8 *waveheader;
12520 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12521 if (waveheadernode) {
12522 waveheader = (const guint8 *) waveheadernode->data;
12523 headerlen = QT_UINT32 (waveheader);
12525 if (headerlen > 8) {
12526 gst_riff_strf_auds *header = NULL;
12527 GstBuffer *headerbuf;
12533 headerbuf = gst_buffer_new_and_alloc (headerlen);
12534 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12536 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12537 headerbuf, &header, &extra)) {
12538 gst_caps_unref (entry->caps);
12539 /* FIXME: Need to do something with the channel reorder map */
12541 gst_riff_create_audio_caps (header->format, NULL, header,
12542 extra, NULL, NULL, NULL);
12545 gst_buffer_unref (extra);
12550 GST_DEBUG ("Didn't find waveheadernode for this codec");
12552 g_node_destroy (wavenode);
12555 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12556 stream->stream_tags);
12560 /* FIXME: what is in the chunk? */
12563 gint len = QT_UINT32 (stsd_data);
12565 /* seems to be always = 116 = 0x74 */
12571 gint len = QT_UINT32 (stsd_entry_data);
12574 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12576 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12577 gst_caps_set_simple (entry->caps,
12578 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12579 gst_buffer_unref (buf);
12581 gst_caps_set_simple (entry->caps,
12582 "samplesize", G_TYPE_INT, samplesize, NULL);
12587 GNode *alac, *wave = NULL;
12589 /* apparently, m4a has this atom appended directly in the stsd entry,
12590 * while mov has it in a wave atom */
12591 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12593 /* alac now refers to stsd entry atom */
12594 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12596 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12598 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12601 const guint8 *alac_data = alac->data;
12602 gint len = QT_UINT32 (alac->data);
12606 GST_DEBUG_OBJECT (qtdemux,
12607 "discarding alac atom with unexpected len %d", len);
12609 /* codec-data contains alac atom size and prefix,
12610 * ffmpeg likes it that way, not quite gst-ish though ...*/
12611 buf = gst_buffer_new_and_alloc (len);
12612 gst_buffer_fill (buf, 0, alac->data, len);
12613 gst_caps_set_simple (entry->caps,
12614 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12615 gst_buffer_unref (buf);
12617 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12618 entry->n_channels = QT_UINT8 (alac_data + 21);
12619 entry->rate = QT_UINT32 (alac_data + 32);
12620 samplesize = QT_UINT8 (alac_data + 16 + 1);
12623 gst_caps_set_simple (entry->caps,
12624 "samplesize", G_TYPE_INT, samplesize, NULL);
12629 /* The codingname of the sample entry is 'fLaC' */
12630 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12633 /* The 'dfLa' box is added to the sample entry to convey
12634 initializing information for the decoder. */
12635 const GNode *dfla =
12636 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12639 const guint32 len = QT_UINT32 (dfla->data);
12641 /* Must contain at least dfLa box header (12),
12642 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12644 GST_DEBUG_OBJECT (qtdemux,
12645 "discarding dfla atom with unexpected len %d", len);
12647 /* skip dfLa header to get the METADATA_BLOCKs */
12648 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12649 const guint32 metadata_blocks_len = len - 12;
12651 gchar *stream_marker = g_strdup ("fLaC");
12652 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12653 strlen (stream_marker));
12656 guint32 remainder = 0;
12657 guint32 block_size = 0;
12658 gboolean is_last = FALSE;
12660 GValue array = G_VALUE_INIT;
12661 GValue value = G_VALUE_INIT;
12663 g_value_init (&array, GST_TYPE_ARRAY);
12664 g_value_init (&value, GST_TYPE_BUFFER);
12666 gst_value_set_buffer (&value, block);
12667 gst_value_array_append_value (&array, &value);
12668 g_value_reset (&value);
12670 gst_buffer_unref (block);
12672 /* check there's at least one METADATA_BLOCK_HEADER's worth
12673 * of data, and we haven't already finished parsing */
12674 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12675 remainder = metadata_blocks_len - index;
12677 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12679 (metadata_blocks[index + 1] << 16) +
12680 (metadata_blocks[index + 2] << 8) +
12681 metadata_blocks[index + 3];
12683 /* be careful not to read off end of box */
12684 if (block_size > remainder) {
12688 is_last = metadata_blocks[index] >> 7;
12690 block = gst_buffer_new_and_alloc (block_size);
12692 gst_buffer_fill (block, 0, &metadata_blocks[index],
12695 gst_value_set_buffer (&value, block);
12696 gst_value_array_append_value (&array, &value);
12697 g_value_reset (&value);
12699 gst_buffer_unref (block);
12701 index += block_size;
12704 /* only append the metadata if we successfully read all of it */
12706 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12707 (stream)->caps, 0), "streamheader", &array);
12709 GST_WARNING_OBJECT (qtdemux,
12710 "discarding all METADATA_BLOCKs due to invalid "
12711 "block_size %d at idx %d, rem %d", block_size, index,
12715 g_value_unset (&value);
12716 g_value_unset (&array);
12718 /* The sample rate obtained from the stsd may not be accurate
12719 * since it cannot represent rates greater than 65535Hz, so
12720 * override that value with the sample rate from the
12721 * METADATA_BLOCK_STREAMINFO block */
12722 CUR_STREAM (stream)->rate =
12723 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12734 gint len = QT_UINT32 (stsd_entry_data);
12737 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12740 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12742 /* If we have enough data, let's try to get the 'damr' atom. See
12743 * the 3GPP container spec (26.244) for more details. */
12744 if ((len - 0x34) > 8 &&
12745 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12746 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12747 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12750 gst_caps_set_simple (entry->caps,
12751 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12752 gst_buffer_unref (buf);
12758 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12759 gint len = QT_UINT32 (stsd_entry_data);
12760 guint16 sound_version = 0;
12761 /* FIXME: Can this be determined somehow? There doesn't seem to be
12762 * anything in mp4a atom that specifis compression */
12764 guint16 channels = entry->n_channels;
12765 guint32 time_scale = (guint32) entry->rate;
12766 gint sample_rate_index = -1;
12769 sound_version = QT_UINT16 (stsd_entry_data + 16);
12771 if (sound_version == 1) {
12772 channels = QT_UINT16 (stsd_entry_data + 24);
12773 time_scale = QT_UINT32 (stsd_entry_data + 30);
12775 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
12779 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
12783 sample_rate_index =
12784 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12785 if (sample_rate_index >= 0 && channels > 0) {
12786 guint8 codec_data[2];
12789 /* build AAC codec data */
12790 codec_data[0] = profile << 3;
12791 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12792 codec_data[1] = (sample_rate_index & 0x01) << 7;
12793 codec_data[1] |= (channels & 0xF) << 3;
12795 buf = gst_buffer_new_and_alloc (2);
12796 gst_buffer_fill (buf, 0, codec_data, 2);
12797 gst_caps_set_simple (entry->caps,
12798 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12799 gst_buffer_unref (buf);
12809 /* Fully handled elsewhere */
12812 GST_INFO_OBJECT (qtdemux,
12813 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12817 GST_INFO_OBJECT (qtdemux,
12818 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12819 GST_FOURCC_ARGS (fourcc), entry->caps);
12821 } else if (stream->subtype == FOURCC_strm) {
12822 if (fourcc == FOURCC_rtsp) {
12823 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12825 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12826 GST_FOURCC_ARGS (fourcc));
12827 goto unknown_stream;
12829 entry->sampled = TRUE;
12830 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12831 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12832 || stream->subtype == FOURCC_clcp) {
12834 entry->sampled = TRUE;
12835 entry->sparse = TRUE;
12838 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12841 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12842 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12847 /* hunt for sort-of codec data */
12851 GNode *mp4s = NULL;
12852 GNode *esds = NULL;
12854 /* look for palette in a stsd->mp4s->esds sub-atom */
12855 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12857 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12858 if (esds == NULL) {
12860 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12864 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12865 stream->stream_tags);
12869 GST_INFO_OBJECT (qtdemux,
12870 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12873 GST_INFO_OBJECT (qtdemux,
12874 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12875 GST_FOURCC_ARGS (fourcc), entry->caps);
12877 /* everything in 1 sample */
12878 entry->sampled = TRUE;
12881 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12884 if (entry->caps == NULL)
12885 goto unknown_stream;
12888 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12889 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12895 /* promote to sampled format */
12896 if (entry->fourcc == FOURCC_samr) {
12897 /* force mono 8000 Hz for AMR */
12898 entry->sampled = TRUE;
12899 entry->n_channels = 1;
12900 entry->rate = 8000;
12901 } else if (entry->fourcc == FOURCC_sawb) {
12902 /* force mono 16000 Hz for AMR-WB */
12903 entry->sampled = TRUE;
12904 entry->n_channels = 1;
12905 entry->rate = 16000;
12906 } else if (entry->fourcc == FOURCC_mp4a) {
12907 entry->sampled = TRUE;
12911 stsd_entry_data += len;
12912 remaining_stsd_len -= len;
12916 /* collect sample information */
12917 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12918 goto samples_failed;
12920 if (qtdemux->fragmented) {
12923 /* need all moov samples as basis; probably not many if any at all */
12924 /* prevent moof parsing taking of at this time */
12925 offset = qtdemux->moof_offset;
12926 qtdemux->moof_offset = 0;
12927 if (stream->n_samples &&
12928 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12929 qtdemux->moof_offset = offset;
12930 goto samples_failed;
12932 qtdemux->moof_offset = offset;
12933 /* movie duration more reliable in this case (e.g. mehd) */
12934 if (qtdemux->segment.duration &&
12935 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12937 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12940 /* configure segments */
12941 if (!qtdemux_parse_segments (qtdemux, stream, trak))
12942 goto segments_failed;
12944 /* add some language tag, if useful */
12945 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12946 strcmp (stream->lang_id, "und")) {
12947 const gchar *lang_code;
12949 /* convert ISO 639-2 code to ISO 639-1 */
12950 lang_code = gst_tag_get_language_code (stream->lang_id);
12951 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12952 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12955 /* Check for UDTA tags */
12956 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12957 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12960 /* Insert and sort new stream in track-id order.
12961 * This will help in comparing old/new streams during stream update check */
12962 g_ptr_array_add (qtdemux->active_streams, stream);
12963 g_ptr_array_sort (qtdemux->active_streams,
12964 (GCompareFunc) qtdemux_track_id_compare_func);
12965 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
12966 QTDEMUX_N_STREAMS (qtdemux));
12973 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12974 (_("This file is corrupt and cannot be played.")), (NULL));
12976 gst_qtdemux_stream_unref (stream);
12981 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12982 gst_qtdemux_stream_unref (stream);
12988 /* we posted an error already */
12989 /* free stbl sub-atoms */
12990 gst_qtdemux_stbl_free (stream);
12991 gst_qtdemux_stream_unref (stream);
12996 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13002 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13003 GST_FOURCC_ARGS (stream->subtype));
13004 gst_qtdemux_stream_unref (stream);
13009 /* If we can estimate the overall bitrate, and don't have information about the
13010 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13011 * the overall bitrate minus the sum of the bitrates of all other streams. This
13012 * should be useful for the common case where we have one audio and one video
13013 * stream and can estimate the bitrate of one, but not the other. */
13015 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13017 QtDemuxStream *stream = NULL;
13018 gint64 size, sys_bitrate, sum_bitrate = 0;
13019 GstClockTime duration;
13023 if (qtdemux->fragmented)
13026 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13028 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13030 GST_DEBUG_OBJECT (qtdemux,
13031 "Size in bytes of the stream not known - bailing");
13035 /* Subtract the header size */
13036 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13037 size, qtdemux->header_size);
13039 if (size < qtdemux->header_size)
13042 size = size - qtdemux->header_size;
13044 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13045 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13049 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13050 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13051 switch (str->subtype) {
13054 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13055 CUR_STREAM (str)->caps);
13056 /* retrieve bitrate, prefer avg then max */
13058 if (str->stream_tags) {
13059 if (gst_tag_list_get_uint (str->stream_tags,
13060 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13061 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13062 if (gst_tag_list_get_uint (str->stream_tags,
13063 GST_TAG_NOMINAL_BITRATE, &bitrate))
13064 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13065 if (gst_tag_list_get_uint (str->stream_tags,
13066 GST_TAG_BITRATE, &bitrate))
13067 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13070 sum_bitrate += bitrate;
13073 GST_DEBUG_OBJECT (qtdemux,
13074 ">1 stream with unknown bitrate - bailing");
13081 /* For other subtypes, we assume no significant impact on bitrate */
13087 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13091 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13093 if (sys_bitrate < sum_bitrate) {
13094 /* This can happen, since sum_bitrate might be derived from maximum
13095 * bitrates and not average bitrates */
13096 GST_DEBUG_OBJECT (qtdemux,
13097 "System bitrate less than sum bitrate - bailing");
13101 bitrate = sys_bitrate - sum_bitrate;
13102 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13103 ", Stream bitrate = %u", sys_bitrate, bitrate);
13105 if (!stream->stream_tags)
13106 stream->stream_tags = gst_tag_list_new_empty ();
13108 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13110 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13111 GST_TAG_BITRATE, bitrate, NULL);
13114 static GstFlowReturn
13115 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13117 GstFlowReturn ret = GST_FLOW_OK;
13120 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13122 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13123 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13124 guint32 sample_num = 0;
13126 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13127 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13129 if (qtdemux->fragmented && qtdemux->pullbased) {
13130 /* need all moov samples first */
13131 GST_OBJECT_LOCK (qtdemux);
13132 while (stream->n_samples == 0)
13133 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13135 GST_OBJECT_UNLOCK (qtdemux);
13137 /* discard any stray moof */
13138 qtdemux->moof_offset = 0;
13141 /* prepare braking */
13142 if (ret != GST_FLOW_ERROR)
13145 /* in pull mode, we should have parsed some sample info by now;
13146 * and quite some code will not handle no samples.
13147 * in push mode, we'll just have to deal with it */
13148 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13149 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13150 g_ptr_array_remove_index (qtdemux->active_streams, i);
13153 } else if (stream->track_id == qtdemux->chapters_track_id &&
13154 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13155 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13156 so that it doesn't look like a subtitle track */
13157 g_ptr_array_remove_index (qtdemux->active_streams, i);
13162 /* parse the initial sample for use in setting the frame rate cap */
13163 while (sample_num == 0 && sample_num < stream->n_samples) {
13164 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13174 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13176 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13180 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13184 /* Different length, updated */
13185 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13188 /* streams in list are sorted in track-id order */
13189 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13190 /* Different stream-id, updated */
13191 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13192 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13200 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13201 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13203 /* Connect old stream's srcpad to new stream */
13204 newstream->pad = oldstream->pad;
13205 oldstream->pad = NULL;
13207 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13208 * case we need to force one through */
13209 newstream->new_stream = GST_PAD_IS_EOS (newstream->pad);
13211 return gst_qtdemux_configure_stream (qtdemux, newstream);
13215 qtdemux_update_streams (GstQTDemux * qtdemux)
13218 g_assert (qtdemux->streams_aware);
13220 /* At below, figure out which stream in active_streams has identical stream-id
13221 * with that of in old_streams. If there is matching stream-id,
13222 * corresponding newstream will not be exposed again,
13223 * but demux will reuse srcpad of matched old stream
13225 * active_streams : newly created streams from the latest moov
13226 * old_streams : existing streams (belong to previous moov)
13229 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13230 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13231 QtDemuxStream *oldstream = NULL;
13234 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13235 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13237 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13238 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13239 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13241 /* null pad stream cannot be reused */
13242 if (oldstream->pad == NULL)
13247 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13249 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13252 /* we don't need to preserve order of old streams */
13253 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13257 /* now we have all info and can expose */
13258 list = stream->stream_tags;
13259 stream->stream_tags = NULL;
13260 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13268 /* Must be called with expose lock */
13269 static GstFlowReturn
13270 qtdemux_expose_streams (GstQTDemux * qtdemux)
13274 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13276 if (!qtdemux_is_streams_update (qtdemux)) {
13277 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13278 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13279 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13280 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13281 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13282 return GST_FLOW_ERROR;
13285 g_ptr_array_set_size (qtdemux->old_streams, 0);
13286 qtdemux->need_segment = TRUE;
13288 return GST_FLOW_OK;
13291 if (qtdemux->streams_aware) {
13292 if (!qtdemux_update_streams (qtdemux))
13293 return GST_FLOW_ERROR;
13295 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13296 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13299 /* now we have all info and can expose */
13300 list = stream->stream_tags;
13301 stream->stream_tags = NULL;
13302 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13303 return GST_FLOW_ERROR;
13308 gst_qtdemux_guess_bitrate (qtdemux);
13310 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13312 /* If we have still old_streams, it's no more used stream */
13313 for (i = 0; i < qtdemux->old_streams->len; i++) {
13314 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13319 event = gst_event_new_eos ();
13320 if (qtdemux->segment_seqnum)
13321 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13323 gst_pad_push_event (stream->pad, event);
13327 g_ptr_array_set_size (qtdemux->old_streams, 0);
13329 /* check if we should post a redirect in case there is a single trak
13330 * and it is a redirecting trak */
13331 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13332 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13335 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13336 "an external content");
13337 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13338 gst_structure_new ("redirect",
13339 "new-location", G_TYPE_STRING,
13340 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13341 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13342 g_free (qtdemux->redirect_location);
13343 qtdemux->redirect_location =
13344 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13347 g_ptr_array_foreach (qtdemux->active_streams,
13348 (GFunc) qtdemux_do_allocation, qtdemux);
13350 qtdemux->need_segment = TRUE;
13352 qtdemux->exposed = TRUE;
13353 return GST_FLOW_OK;
13358 GstStructure *structure; /* helper for sort function */
13360 guint min_req_bitrate;
13361 guint min_req_qt_version;
13365 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13367 GstQtReference *ref_a = (GstQtReference *) a;
13368 GstQtReference *ref_b = (GstQtReference *) b;
13370 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13371 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13373 /* known bitrates go before unknown; higher bitrates go first */
13374 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13377 /* sort the redirects and post a message for the application.
13380 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13382 GstQtReference *best;
13385 GValue list_val = { 0, };
13388 g_assert (references != NULL);
13390 references = g_list_sort (references, qtdemux_redirects_sort_func);
13392 best = (GstQtReference *) references->data;
13394 g_value_init (&list_val, GST_TYPE_LIST);
13396 for (l = references; l != NULL; l = l->next) {
13397 GstQtReference *ref = (GstQtReference *) l->data;
13398 GValue struct_val = { 0, };
13400 ref->structure = gst_structure_new ("redirect",
13401 "new-location", G_TYPE_STRING, ref->location, NULL);
13403 if (ref->min_req_bitrate > 0) {
13404 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13405 ref->min_req_bitrate, NULL);
13408 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13409 g_value_set_boxed (&struct_val, ref->structure);
13410 gst_value_list_append_value (&list_val, &struct_val);
13411 g_value_unset (&struct_val);
13412 /* don't free anything here yet, since we need best->structure below */
13415 g_assert (best != NULL);
13416 s = gst_structure_copy (best->structure);
13418 if (g_list_length (references) > 1) {
13419 gst_structure_set_value (s, "locations", &list_val);
13422 g_value_unset (&list_val);
13424 for (l = references; l != NULL; l = l->next) {
13425 GstQtReference *ref = (GstQtReference *) l->data;
13427 gst_structure_free (ref->structure);
13428 g_free (ref->location);
13431 g_list_free (references);
13433 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13434 g_free (qtdemux->redirect_location);
13435 qtdemux->redirect_location =
13436 g_strdup (gst_structure_get_string (s, "new-location"));
13437 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13438 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13441 /* look for redirect nodes, collect all redirect information and
13445 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13447 GNode *rmra, *rmda, *rdrf;
13449 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13451 GList *redirects = NULL;
13453 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13455 GstQtReference ref = { NULL, NULL, 0, 0 };
13456 GNode *rmdr, *rmvc;
13458 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13459 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13460 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13461 ref.min_req_bitrate);
13464 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13465 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13466 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13468 #ifndef GST_DISABLE_GST_DEBUG
13469 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13471 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13473 GST_LOG_OBJECT (qtdemux,
13474 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13475 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13476 bitmask, check_type);
13477 if (package == FOURCC_qtim && check_type == 0) {
13478 ref.min_req_qt_version = version;
13482 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13488 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13489 if (ref_len > 20) {
13490 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13491 ref_data = (guint8 *) rdrf->data + 20;
13492 if (ref_type == FOURCC_alis) {
13493 guint record_len, record_version, fn_len;
13495 if (ref_len > 70) {
13496 /* MacOSX alias record, google for alias-layout.txt */
13497 record_len = QT_UINT16 (ref_data + 4);
13498 record_version = QT_UINT16 (ref_data + 4 + 2);
13499 fn_len = QT_UINT8 (ref_data + 50);
13500 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13501 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13504 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13507 } else if (ref_type == FOURCC_url_) {
13508 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13510 GST_DEBUG_OBJECT (qtdemux,
13511 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13512 GST_FOURCC_ARGS (ref_type));
13514 if (ref.location != NULL) {
13515 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13517 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13519 GST_WARNING_OBJECT (qtdemux,
13520 "Failed to extract redirect location from rdrf atom");
13523 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13527 /* look for others */
13528 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13531 if (redirects != NULL) {
13532 qtdemux_process_redirects (qtdemux, redirects);
13538 static GstTagList *
13539 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13543 if (tags == NULL) {
13544 tags = gst_tag_list_new_empty ();
13545 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13548 if (qtdemux->major_brand == FOURCC_mjp2)
13549 fmt = "Motion JPEG 2000";
13550 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13552 else if (qtdemux->major_brand == FOURCC_qt__)
13554 else if (qtdemux->fragmented)
13557 fmt = "ISO MP4/M4A";
13559 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13560 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13562 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13568 /* we have read the complete moov node now.
13569 * This function parses all of the relevant info, creates the traks and
13570 * prepares all data structures for playback
13573 qtdemux_parse_tree (GstQTDemux * qtdemux)
13580 guint64 creation_time;
13581 GstDateTime *datetime = NULL;
13584 /* make sure we have a usable taglist */
13585 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13587 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13588 if (mvhd == NULL) {
13589 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13590 return qtdemux_parse_redirects (qtdemux);
13593 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13594 if (version == 1) {
13595 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13596 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13597 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13598 } else if (version == 0) {
13599 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13600 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13601 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13603 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13607 /* Moving qt creation time (secs since 1904) to unix time */
13608 if (creation_time != 0) {
13609 /* Try to use epoch first as it should be faster and more commonly found */
13610 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13613 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13614 /* some data cleansing sanity */
13615 now_s = g_get_real_time () / G_USEC_PER_SEC;
13616 if (now_s + 24 * 3600 < creation_time) {
13617 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13619 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13622 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13623 GDateTime *dt, *dt_local;
13625 dt = g_date_time_add_seconds (base_dt, creation_time);
13626 dt_local = g_date_time_to_local (dt);
13627 datetime = gst_date_time_new_from_g_date_time (dt_local);
13629 g_date_time_unref (base_dt);
13630 g_date_time_unref (dt);
13634 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13635 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13637 gst_date_time_unref (datetime);
13640 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13641 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13643 /* check for fragmented file and get some (default) data */
13644 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13647 GstByteReader mehd_data;
13649 /* let track parsing or anyone know weird stuff might happen ... */
13650 qtdemux->fragmented = TRUE;
13652 /* compensate for total duration */
13653 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13655 qtdemux_parse_mehd (qtdemux, &mehd_data);
13658 /* Update the movie segment duration, unless it was directly given to us
13659 * by upstream. Otherwise let it as is, as we don't want to mangle the
13660 * duration provided by upstream that may come e.g. from a MPD file. */
13661 if (!qtdemux->upstream_format_is_time) {
13662 GstClockTime duration;
13663 /* set duration in the segment info */
13664 gst_qtdemux_get_duration (qtdemux, &duration);
13665 qtdemux->segment.duration = duration;
13666 /* also do not exceed duration; stop is set that way post seek anyway,
13667 * and segment activation falls back to duration,
13668 * whereas loop only checks stop, so let's align this here as well */
13669 qtdemux->segment.stop = duration;
13672 /* parse all traks */
13673 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13675 qtdemux_parse_trak (qtdemux, trak);
13676 /* iterate all siblings */
13677 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13680 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13683 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13685 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13687 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13690 /* maybe also some tags in meta box */
13691 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13693 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13694 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13696 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13699 /* parse any protection system info */
13700 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13702 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13703 qtdemux_parse_pssh (qtdemux, pssh);
13704 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13707 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13712 /* taken from ffmpeg */
13714 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13726 len = (len << 7) | (c & 0x7f);
13735 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13736 gsize codec_data_size)
13738 GList *list = NULL;
13739 guint8 *p = codec_data;
13740 gint i, offset, num_packets;
13741 guint *length, last;
13743 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13745 if (codec_data == NULL || codec_data_size == 0)
13748 /* start of the stream and vorbis audio or theora video, need to
13749 * send the codec_priv data as first three packets */
13750 num_packets = p[0] + 1;
13751 GST_DEBUG_OBJECT (qtdemux,
13752 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13753 (guint) num_packets, codec_data_size);
13755 /* Let's put some limits, Don't think there even is a xiph codec
13756 * with more than 3-4 headers */
13757 if (G_UNLIKELY (num_packets > 16)) {
13758 GST_WARNING_OBJECT (qtdemux,
13759 "Unlikely number of xiph headers, most likely not valid");
13763 length = g_alloca (num_packets * sizeof (guint));
13767 /* first packets, read length values */
13768 for (i = 0; i < num_packets - 1; i++) {
13770 while (offset < codec_data_size) {
13771 length[i] += p[offset];
13772 if (p[offset++] != 0xff)
13777 if (offset + last > codec_data_size)
13780 /* last packet is the remaining size */
13781 length[i] = codec_data_size - offset - last;
13783 for (i = 0; i < num_packets; i++) {
13786 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
13788 if (offset + length[i] > codec_data_size)
13791 hdr = gst_buffer_new_memdup (p + offset, length[i]);
13792 list = g_list_append (list, hdr);
13794 offset += length[i];
13803 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
13809 /* this can change the codec originally present in @list */
13811 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13812 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13814 int len = QT_UINT32 (esds->data);
13815 guint8 *ptr = esds->data;
13816 guint8 *end = ptr + len;
13818 guint8 *data_ptr = NULL;
13820 guint8 object_type_id = 0;
13821 guint8 stream_type = 0;
13822 const char *codec_name = NULL;
13823 GstCaps *caps = NULL;
13825 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13827 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13829 while (ptr + 1 < end) {
13830 tag = QT_UINT8 (ptr);
13831 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13833 len = read_descr_size (ptr, end, &ptr);
13834 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13836 /* Check the stated amount of data is available for reading */
13837 if (len < 0 || ptr + len > end)
13841 case ES_DESCRIPTOR_TAG:
13842 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
13843 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
13846 case DECODER_CONFIG_DESC_TAG:{
13847 guint max_bitrate, avg_bitrate;
13849 object_type_id = QT_UINT8 (ptr);
13850 stream_type = QT_UINT8 (ptr + 1) >> 2;
13851 max_bitrate = QT_UINT32 (ptr + 5);
13852 avg_bitrate = QT_UINT32 (ptr + 9);
13853 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13854 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
13855 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13856 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13857 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13858 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13859 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13860 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13862 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13863 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13864 avg_bitrate, NULL);
13869 case DECODER_SPECIFIC_INFO_TAG:
13870 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13871 if (object_type_id == 0xe0 && len == 0x40) {
13877 GST_DEBUG_OBJECT (qtdemux,
13878 "Have VOBSUB palette. Creating palette event");
13879 /* move to decConfigDescr data and read palette */
13881 for (i = 0; i < 16; i++) {
13882 clut[i] = QT_UINT32 (data);
13886 s = gst_structure_new ("application/x-gst-dvd", "event",
13887 G_TYPE_STRING, "dvd-spu-clut-change",
13888 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13889 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13890 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13891 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13892 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13893 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13894 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13895 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13898 /* store event and trigger custom processing */
13899 stream->pending_event =
13900 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13902 /* Generic codec_data handler puts it on the caps */
13909 case SL_CONFIG_DESC_TAG:
13910 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13914 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13916 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13922 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13923 * in use, and should also be used to override some other parameters for some
13925 switch (object_type_id) {
13926 case 0x20: /* MPEG-4 */
13927 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13928 * profile_and_level_indication */
13929 if (data_ptr != NULL && data_len >= 5 &&
13930 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13931 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13932 data_ptr + 4, data_len - 4);
13934 break; /* Nothing special needed here */
13935 case 0x21: /* H.264 */
13936 codec_name = "H.264 / AVC";
13937 caps = gst_caps_new_simple ("video/x-h264",
13938 "stream-format", G_TYPE_STRING, "avc",
13939 "alignment", G_TYPE_STRING, "au", NULL);
13941 case 0x40: /* AAC (any) */
13942 case 0x66: /* AAC Main */
13943 case 0x67: /* AAC LC */
13944 case 0x68: /* AAC SSR */
13945 /* Override channels and rate based on the codec_data, as it's often
13947 /* Only do so for basic setup without HE-AAC extension */
13948 if (data_ptr && data_len == 2) {
13949 guint channels, rate;
13951 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13953 entry->n_channels = channels;
13955 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13957 entry->rate = rate;
13960 /* Set level and profile if possible */
13961 if (data_ptr != NULL && data_len >= 2) {
13962 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13963 data_ptr, data_len);
13965 const gchar *profile_str = NULL;
13968 guint8 *codec_data;
13969 gint rate_idx, profile;
13971 /* No codec_data, let's invent something.
13972 * FIXME: This is wrong for SBR! */
13974 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13976 buffer = gst_buffer_new_and_alloc (2);
13977 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13978 codec_data = map.data;
13981 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13984 switch (object_type_id) {
13986 profile_str = "main";
13990 profile_str = "lc";
13994 profile_str = "ssr";
14002 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14004 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14006 gst_buffer_unmap (buffer, &map);
14007 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14008 GST_TYPE_BUFFER, buffer, NULL);
14009 gst_buffer_unref (buffer);
14012 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14013 G_TYPE_STRING, profile_str, NULL);
14017 case 0x60: /* MPEG-2, various profiles */
14023 codec_name = "MPEG-2 video";
14024 caps = gst_caps_new_simple ("video/mpeg",
14025 "mpegversion", G_TYPE_INT, 2,
14026 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14028 case 0x69: /* MPEG-2 BC audio */
14029 case 0x6B: /* MPEG-1 audio */
14030 caps = gst_caps_new_simple ("audio/mpeg",
14031 "mpegversion", G_TYPE_INT, 1, NULL);
14032 codec_name = "MPEG-1 audio";
14034 case 0x6A: /* MPEG-1 */
14035 codec_name = "MPEG-1 video";
14036 caps = gst_caps_new_simple ("video/mpeg",
14037 "mpegversion", G_TYPE_INT, 1,
14038 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14040 case 0x6C: /* MJPEG */
14042 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14044 codec_name = "Motion-JPEG";
14046 case 0x6D: /* PNG */
14048 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14050 codec_name = "PNG still images";
14052 case 0x6E: /* JPEG2000 */
14053 codec_name = "JPEG-2000";
14054 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14056 case 0xA4: /* Dirac */
14057 codec_name = "Dirac";
14058 caps = gst_caps_new_empty_simple ("video/x-dirac");
14060 case 0xA5: /* AC3 */
14061 codec_name = "AC-3 audio";
14062 caps = gst_caps_new_simple ("audio/x-ac3",
14063 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14065 case 0xA9: /* AC3 */
14066 codec_name = "DTS audio";
14067 caps = gst_caps_new_simple ("audio/x-dts",
14068 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14071 if (stream_type == 0x05 && data_ptr) {
14073 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14076 GValue arr_val = G_VALUE_INIT;
14077 GValue buf_val = G_VALUE_INIT;
14080 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14081 codec_name = "Vorbis";
14082 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14083 g_value_init (&arr_val, GST_TYPE_ARRAY);
14084 g_value_init (&buf_val, GST_TYPE_BUFFER);
14085 for (tmp = headers; tmp; tmp = tmp->next) {
14086 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14087 gst_value_array_append_value (&arr_val, &buf_val);
14089 s = gst_caps_get_structure (caps, 0);
14090 gst_structure_take_value (s, "streamheader", &arr_val);
14091 g_value_unset (&buf_val);
14092 g_list_free (headers);
14099 case 0xE1: /* QCELP */
14100 /* QCELP, the codec_data is a riff tag (little endian) with
14101 * 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). */
14102 caps = gst_caps_new_empty_simple ("audio/qcelp");
14103 codec_name = "QCELP";
14109 /* If we have a replacement caps, then change our caps for this stream */
14111 gst_caps_unref (entry->caps);
14112 entry->caps = caps;
14115 if (codec_name && list)
14116 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14117 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14119 /* Add the codec_data attribute to caps, if we have it */
14123 buffer = gst_buffer_new_and_alloc (data_len);
14124 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14126 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14127 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14129 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14131 gst_buffer_unref (buffer);
14136 static inline GstCaps *
14137 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14141 char *s, fourstr[5];
14143 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14144 for (i = 0; i < 4; i++) {
14145 if (!g_ascii_isalnum (fourstr[i]))
14148 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14149 caps = gst_caps_new_empty_simple (s);
14154 #define _codec(name) \
14156 if (codec_name) { \
14157 *codec_name = g_strdup (name); \
14162 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14163 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14164 const guint8 * stsd_entry_data, gchar ** codec_name)
14166 GstCaps *caps = NULL;
14167 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14171 _codec ("PNG still images");
14172 caps = gst_caps_new_empty_simple ("image/png");
14175 _codec ("JPEG still images");
14177 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14180 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14181 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14182 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14183 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14184 _codec ("Motion-JPEG");
14186 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14189 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14190 _codec ("Motion-JPEG format B");
14191 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14194 _codec ("JPEG-2000");
14195 /* override to what it should be according to spec, avoid palette_data */
14196 entry->bits_per_sample = 24;
14197 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14200 _codec ("Sorensen video v.3");
14201 caps = gst_caps_new_simple ("video/x-svq",
14202 "svqversion", G_TYPE_INT, 3, NULL);
14204 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14205 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14206 _codec ("Sorensen video v.1");
14207 caps = gst_caps_new_simple ("video/x-svq",
14208 "svqversion", G_TYPE_INT, 1, NULL);
14210 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14211 caps = gst_caps_new_empty_simple ("video/x-raw");
14212 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14213 _codec ("Windows Raw RGB");
14214 stream->alignment = 32;
14220 bps = QT_UINT16 (stsd_entry_data + 82);
14223 format = GST_VIDEO_FORMAT_RGB15;
14226 format = GST_VIDEO_FORMAT_RGB16;
14229 format = GST_VIDEO_FORMAT_RGB;
14232 format = GST_VIDEO_FORMAT_ARGB;
14240 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14241 format = GST_VIDEO_FORMAT_I420;
14243 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14244 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14245 format = GST_VIDEO_FORMAT_I420;
14248 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14249 format = GST_VIDEO_FORMAT_UYVY;
14251 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14252 format = GST_VIDEO_FORMAT_v308;
14254 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14255 format = GST_VIDEO_FORMAT_v216;
14258 format = GST_VIDEO_FORMAT_v210;
14260 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14261 format = GST_VIDEO_FORMAT_r210;
14263 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14264 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14265 format = GST_VIDEO_FORMAT_v410;
14268 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14269 * but different order than AYUV
14270 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14271 format = GST_VIDEO_FORMAT_v408;
14274 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14275 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14276 _codec ("MPEG-1 video");
14277 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14278 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14280 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14281 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14282 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14283 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14284 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14285 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14286 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14287 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14288 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14289 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14290 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14291 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14292 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14293 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14294 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14295 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14296 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14297 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14298 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14299 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14300 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14301 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14302 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14303 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14304 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14305 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14306 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14307 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14308 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14309 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14310 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14311 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14312 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14313 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14314 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14315 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14316 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14317 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14318 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14319 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14320 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14321 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14322 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14323 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14324 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14325 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14326 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14327 _codec ("MPEG-2 video");
14328 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14329 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14331 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14332 _codec ("GIF still images");
14333 caps = gst_caps_new_empty_simple ("image/gif");
14336 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14338 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14340 /* ffmpeg uses the height/width props, don't know why */
14341 caps = gst_caps_new_simple ("video/x-h263",
14342 "variant", G_TYPE_STRING, "itu", NULL);
14346 _codec ("MPEG-4 video");
14347 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14348 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14350 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14351 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14352 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14353 caps = gst_caps_new_simple ("video/x-msmpeg",
14354 "msmpegversion", G_TYPE_INT, 43, NULL);
14356 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14358 caps = gst_caps_new_simple ("video/x-divx",
14359 "divxversion", G_TYPE_INT, 3, NULL);
14361 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14362 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14364 caps = gst_caps_new_simple ("video/x-divx",
14365 "divxversion", G_TYPE_INT, 4, NULL);
14367 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14369 caps = gst_caps_new_simple ("video/x-divx",
14370 "divxversion", G_TYPE_INT, 5, NULL);
14373 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14375 caps = gst_caps_new_simple ("video/x-ffv",
14376 "ffvversion", G_TYPE_INT, 1, NULL);
14379 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14380 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14385 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14386 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14387 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14391 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14392 _codec ("Cinepak");
14393 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14395 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14396 _codec ("Apple QuickDraw");
14397 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14399 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14400 _codec ("Apple video");
14401 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14406 _codec ("H.264 / AVC");
14407 caps = gst_caps_new_simple ("video/x-h264",
14408 "stream-format", G_TYPE_STRING, "avc",
14409 "alignment", G_TYPE_STRING, "au", NULL);
14413 _codec ("H.264 / AVC");
14414 caps = gst_caps_new_simple ("video/x-h264",
14415 "stream-format", G_TYPE_STRING, "avc3",
14416 "alignment", G_TYPE_STRING, "au", NULL);
14421 _codec ("H.265 / HEVC");
14422 caps = gst_caps_new_simple ("video/x-h265",
14423 "stream-format", G_TYPE_STRING, "hvc1",
14424 "alignment", G_TYPE_STRING, "au", NULL);
14428 _codec ("H.265 / HEVC");
14429 caps = gst_caps_new_simple ("video/x-h265",
14430 "stream-format", G_TYPE_STRING, "hev1",
14431 "alignment", G_TYPE_STRING, "au", NULL);
14434 _codec ("Run-length encoding");
14435 caps = gst_caps_new_simple ("video/x-rle",
14436 "layout", G_TYPE_STRING, "quicktime", NULL);
14439 _codec ("Run-length encoding");
14440 caps = gst_caps_new_simple ("video/x-rle",
14441 "layout", G_TYPE_STRING, "microsoft", NULL);
14443 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14444 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14445 _codec ("Indeo Video 3");
14446 caps = gst_caps_new_simple ("video/x-indeo",
14447 "indeoversion", G_TYPE_INT, 3, NULL);
14449 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14450 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14451 _codec ("Intel Video 4");
14452 caps = gst_caps_new_simple ("video/x-indeo",
14453 "indeoversion", G_TYPE_INT, 4, NULL);
14457 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14458 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14459 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14460 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14461 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14462 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14463 _codec ("DV Video");
14464 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14465 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14467 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14468 case FOURCC_dv5p: /* DVCPRO50 PAL */
14469 _codec ("DVCPro50 Video");
14470 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14471 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14473 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14474 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14475 _codec ("DVCProHD Video");
14476 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14477 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14479 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14480 _codec ("Apple Graphics (SMC)");
14481 caps = gst_caps_new_empty_simple ("video/x-smc");
14483 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14485 caps = gst_caps_new_empty_simple ("video/x-vp3");
14487 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14488 _codec ("VP6 Flash");
14489 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14493 caps = gst_caps_new_empty_simple ("video/x-theora");
14494 /* theora uses one byte of padding in the data stream because it does not
14495 * allow 0 sized packets while theora does */
14496 entry->padding = 1;
14500 caps = gst_caps_new_empty_simple ("video/x-dirac");
14502 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14503 _codec ("TIFF still images");
14504 caps = gst_caps_new_empty_simple ("image/tiff");
14506 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14507 _codec ("Apple Intermediate Codec");
14508 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14510 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14511 _codec ("AVID DNxHD");
14512 caps = gst_caps_from_string ("video/x-dnxhd");
14516 _codec ("On2 VP8");
14517 caps = gst_caps_from_string ("video/x-vp8");
14520 _codec ("Google VP9");
14521 caps = gst_caps_from_string ("video/x-vp9");
14524 _codec ("Apple ProRes LT");
14526 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14530 _codec ("Apple ProRes HQ");
14532 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14536 _codec ("Apple ProRes");
14538 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14542 _codec ("Apple ProRes Proxy");
14544 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14548 _codec ("Apple ProRes 4444");
14550 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14553 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14554 if (entry->bits_per_sample > 0) {
14555 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14560 _codec ("Apple ProRes 4444 XQ");
14562 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14565 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14566 if (entry->bits_per_sample > 0) {
14567 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14572 _codec ("GoPro CineForm");
14573 caps = gst_caps_from_string ("video/x-cineform");
14578 caps = gst_caps_new_simple ("video/x-wmv",
14579 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14583 caps = gst_caps_new_empty_simple ("video/x-av1");
14585 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14588 caps = _get_unknown_codec_name ("video", fourcc);
14593 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14596 gst_video_info_init (&info);
14597 gst_video_info_set_format (&info, format, entry->width, entry->height);
14599 caps = gst_video_info_to_caps (&info);
14600 *codec_name = gst_pb_utils_get_codec_description (caps);
14602 /* enable clipping for raw video streams */
14603 stream->need_clip = TRUE;
14604 stream->alignment = 32;
14611 round_up_pow2 (guint n)
14623 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14624 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14625 int len, gchar ** codec_name)
14628 const GstStructure *s;
14631 GstAudioFormat format = 0;
14634 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14636 depth = entry->bytes_per_packet * 8;
14639 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14641 /* 8-bit audio is unsigned */
14643 format = GST_AUDIO_FORMAT_U8;
14644 /* otherwise it's signed and big-endian just like 'twos' */
14646 endian = G_BIG_ENDIAN;
14653 endian = G_LITTLE_ENDIAN;
14656 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14658 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14662 caps = gst_caps_new_simple ("audio/x-raw",
14663 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14664 "layout", G_TYPE_STRING, "interleaved", NULL);
14665 stream->alignment = GST_ROUND_UP_8 (depth);
14666 stream->alignment = round_up_pow2 (stream->alignment);
14670 _codec ("Raw 64-bit floating-point audio");
14671 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14673 caps = gst_caps_new_simple ("audio/x-raw",
14674 "format", G_TYPE_STRING, "F64BE",
14675 "layout", G_TYPE_STRING, "interleaved", NULL);
14676 stream->alignment = 8;
14679 _codec ("Raw 32-bit floating-point audio");
14680 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14682 caps = gst_caps_new_simple ("audio/x-raw",
14683 "format", G_TYPE_STRING, "F32BE",
14684 "layout", G_TYPE_STRING, "interleaved", NULL);
14685 stream->alignment = 4;
14688 _codec ("Raw 24-bit PCM audio");
14689 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14691 caps = gst_caps_new_simple ("audio/x-raw",
14692 "format", G_TYPE_STRING, "S24BE",
14693 "layout", G_TYPE_STRING, "interleaved", NULL);
14694 stream->alignment = 4;
14697 _codec ("Raw 32-bit PCM audio");
14698 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14700 caps = gst_caps_new_simple ("audio/x-raw",
14701 "format", G_TYPE_STRING, "S32BE",
14702 "layout", G_TYPE_STRING, "interleaved", NULL);
14703 stream->alignment = 4;
14706 _codec ("Raw 16-bit PCM audio");
14707 caps = gst_caps_new_simple ("audio/x-raw",
14708 "format", G_TYPE_STRING, "S16LE",
14709 "layout", G_TYPE_STRING, "interleaved", NULL);
14710 stream->alignment = 2;
14713 _codec ("Mu-law audio");
14714 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14717 _codec ("A-law audio");
14718 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14722 _codec ("Microsoft ADPCM");
14723 /* Microsoft ADPCM-ACM code 2 */
14724 caps = gst_caps_new_simple ("audio/x-adpcm",
14725 "layout", G_TYPE_STRING, "microsoft", NULL);
14729 _codec ("DVI/IMA ADPCM");
14730 caps = gst_caps_new_simple ("audio/x-adpcm",
14731 "layout", G_TYPE_STRING, "dvi", NULL);
14735 _codec ("DVI/Intel IMA ADPCM");
14736 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14737 caps = gst_caps_new_simple ("audio/x-adpcm",
14738 "layout", G_TYPE_STRING, "quicktime", NULL);
14742 /* MPEG layer 3, CBR only (pre QT4.1) */
14745 _codec ("MPEG-1 layer 3");
14746 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14747 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14748 "mpegversion", G_TYPE_INT, 1, NULL);
14750 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14751 _codec ("MPEG-1 layer 2");
14753 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14754 "mpegversion", G_TYPE_INT, 1, NULL);
14757 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14758 _codec ("EAC-3 audio");
14759 caps = gst_caps_new_simple ("audio/x-eac3",
14760 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14761 entry->sampled = TRUE;
14763 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14765 _codec ("AC-3 audio");
14766 caps = gst_caps_new_simple ("audio/x-ac3",
14767 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14768 entry->sampled = TRUE;
14770 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14771 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14772 _codec ("DTS audio");
14773 caps = gst_caps_new_simple ("audio/x-dts",
14774 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14775 entry->sampled = TRUE;
14777 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14778 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14779 _codec ("DTS-HD audio");
14780 caps = gst_caps_new_simple ("audio/x-dts",
14781 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14782 entry->sampled = TRUE;
14786 caps = gst_caps_new_simple ("audio/x-mace",
14787 "maceversion", G_TYPE_INT, 3, NULL);
14791 caps = gst_caps_new_simple ("audio/x-mace",
14792 "maceversion", G_TYPE_INT, 6, NULL);
14794 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14796 caps = gst_caps_new_empty_simple ("application/ogg");
14798 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14799 _codec ("DV audio");
14800 caps = gst_caps_new_empty_simple ("audio/x-dv");
14803 _codec ("MPEG-4 AAC audio");
14804 caps = gst_caps_new_simple ("audio/mpeg",
14805 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14806 "stream-format", G_TYPE_STRING, "raw", NULL);
14808 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14809 _codec ("QDesign Music");
14810 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14813 _codec ("QDesign Music v.2");
14814 /* FIXME: QDesign music version 2 (no constant) */
14815 if (FALSE && data) {
14816 caps = gst_caps_new_simple ("audio/x-qdm2",
14817 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14818 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14819 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14821 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14825 _codec ("GSM audio");
14826 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14829 _codec ("AMR audio");
14830 caps = gst_caps_new_empty_simple ("audio/AMR");
14833 _codec ("AMR-WB audio");
14834 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14837 _codec ("Quicktime IMA ADPCM");
14838 caps = gst_caps_new_simple ("audio/x-adpcm",
14839 "layout", G_TYPE_STRING, "quicktime", NULL);
14842 _codec ("Apple lossless audio");
14843 caps = gst_caps_new_empty_simple ("audio/x-alac");
14846 _codec ("Free Lossless Audio Codec");
14847 caps = gst_caps_new_simple ("audio/x-flac",
14848 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14850 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14851 _codec ("QualComm PureVoice");
14852 caps = gst_caps_from_string ("audio/qcelp");
14857 caps = gst_caps_new_empty_simple ("audio/x-wma");
14861 caps = gst_caps_new_empty_simple ("audio/x-opus");
14868 GstAudioFormat format;
14871 FLAG_IS_FLOAT = 0x1,
14872 FLAG_IS_BIG_ENDIAN = 0x2,
14873 FLAG_IS_SIGNED = 0x4,
14874 FLAG_IS_PACKED = 0x8,
14875 FLAG_IS_ALIGNED_HIGH = 0x10,
14876 FLAG_IS_NON_INTERLEAVED = 0x20
14878 _codec ("Raw LPCM audio");
14880 if (data && len >= 36) {
14881 depth = QT_UINT32 (data + 24);
14882 flags = QT_UINT32 (data + 28);
14883 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
14885 if ((flags & FLAG_IS_FLOAT) == 0) {
14890 if ((flags & FLAG_IS_ALIGNED_HIGH))
14893 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14894 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14895 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14896 caps = gst_caps_new_simple ("audio/x-raw",
14897 "format", G_TYPE_STRING,
14899 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
14900 "UNKNOWN", "layout", G_TYPE_STRING,
14901 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
14902 "interleaved", NULL);
14903 stream->alignment = GST_ROUND_UP_8 (depth);
14904 stream->alignment = round_up_pow2 (stream->alignment);
14909 if (flags & FLAG_IS_BIG_ENDIAN)
14910 format = GST_AUDIO_FORMAT_F64BE;
14912 format = GST_AUDIO_FORMAT_F64LE;
14914 if (flags & FLAG_IS_BIG_ENDIAN)
14915 format = GST_AUDIO_FORMAT_F32BE;
14917 format = GST_AUDIO_FORMAT_F32LE;
14919 caps = gst_caps_new_simple ("audio/x-raw",
14920 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14921 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14922 "non-interleaved" : "interleaved", NULL);
14923 stream->alignment = width / 8;
14927 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
14930 caps = gst_caps_new_empty_simple ("audio/x-ac4");
14933 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14937 caps = _get_unknown_codec_name ("audio", fourcc);
14943 GstCaps *templ_caps =
14944 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14945 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14946 gst_caps_unref (caps);
14947 gst_caps_unref (templ_caps);
14948 caps = intersection;
14951 /* enable clipping for raw audio streams */
14952 s = gst_caps_get_structure (caps, 0);
14953 name = gst_structure_get_name (s);
14954 if (g_str_has_prefix (name, "audio/x-raw")) {
14955 stream->need_clip = TRUE;
14956 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
14957 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14958 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
14959 stream->max_buffer_size);
14965 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14966 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14967 const guint8 * stsd_entry_data, gchar ** codec_name)
14971 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14975 _codec ("DVD subtitle");
14976 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14977 stream->process_func = gst_qtdemux_process_buffer_dvd;
14980 _codec ("Quicktime timed text");
14983 _codec ("3GPP timed text");
14985 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14987 /* actual text piece needs to be extracted */
14988 stream->process_func = gst_qtdemux_process_buffer_text;
14991 _codec ("XML subtitles");
14992 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14995 _codec ("CEA 608 Closed Caption");
14997 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
14998 G_TYPE_STRING, "s334-1a", NULL);
14999 stream->process_func = gst_qtdemux_process_buffer_clcp;
15000 stream->need_split = TRUE;
15003 _codec ("CEA 708 Closed Caption");
15005 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15006 G_TYPE_STRING, "cdp", NULL);
15007 stream->process_func = gst_qtdemux_process_buffer_clcp;
15012 caps = _get_unknown_codec_name ("text", fourcc);
15020 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15021 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15022 const guint8 * stsd_entry_data, gchar ** codec_name)
15028 _codec ("MPEG 1 video");
15029 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15030 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15040 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15041 const gchar * system_id)
15045 if (!qtdemux->protection_system_ids)
15046 qtdemux->protection_system_ids =
15047 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15048 /* Check whether we already have an entry for this system ID. */
15049 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15050 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15051 if (g_ascii_strcasecmp (system_id, id) == 0) {
15055 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15056 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,