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->need_process = FALSE;
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 /* the input buffer metadata must be writable,
5673 * but time/duration etc not yet set and need not be preserved */
5675 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5682 /* not many cases for now */
5683 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5684 /* send a one time dvd clut event */
5685 if (stream->pending_event && stream->pad)
5686 gst_pad_push_event (stream->pad, stream->pending_event);
5687 stream->pending_event = NULL;
5690 if (G_UNLIKELY (stream->subtype != FOURCC_text
5691 && stream->subtype != FOURCC_sbtl &&
5692 stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
5696 gst_buffer_map (buf, &map, GST_MAP_READ);
5698 /* empty buffer is sent to terminate previous subtitle */
5699 if (map.size <= 2) {
5700 gst_buffer_unmap (buf, &map);
5701 gst_buffer_unref (buf);
5704 if (stream->subtype == FOURCC_subp) {
5705 /* That's all the processing needed for subpictures */
5706 gst_buffer_unmap (buf, &map);
5710 if (stream->subtype == FOURCC_clcp) {
5713 /* For closed caption, we need to extract the information from the
5714 * [cdat],[cdt2] or [ccdp] atom */
5715 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5716 gst_buffer_unmap (buf, &map);
5717 gst_buffer_unref (buf);
5719 buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5721 /* Conversion failed or there's nothing */
5727 nsize = GST_READ_UINT16_BE (map.data);
5728 nsize = MIN (nsize, map.size - 2);
5730 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5733 /* takes care of UTF-8 validation or UTF-16 recognition,
5734 * no other encoding expected */
5735 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5736 gst_buffer_unmap (buf, &map);
5738 gst_buffer_unref (buf);
5739 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5741 /* this should not really happen unless the subtitle is corrupted */
5742 gst_buffer_unref (buf);
5746 /* FIXME ? convert optional subsequent style info to markup */
5751 static GstFlowReturn
5752 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5755 GstFlowReturn ret = GST_FLOW_OK;
5756 GstClockTime pts, duration;
5758 if (stream->need_clip)
5759 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5761 if (G_UNLIKELY (buf == NULL))
5764 if (G_UNLIKELY (stream->discont)) {
5765 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5766 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5767 stream->discont = FALSE;
5769 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5772 GST_LOG_OBJECT (qtdemux,
5773 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5774 ", duration %" GST_TIME_FORMAT " on pad %s",
5775 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5776 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5777 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5779 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5780 GstStructure *crypto_info;
5781 QtDemuxAavdEncryptionInfo *info =
5782 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5784 crypto_info = gst_structure_copy (info->default_properties);
5785 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5786 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5789 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
5790 || stream->protection_scheme_type == FOURCC_cbcs)) {
5791 GstStructure *crypto_info;
5792 QtDemuxCencSampleSetInfo *info =
5793 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5797 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5798 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5799 GST_PTR_FORMAT, event);
5800 gst_pad_push_event (stream->pad, event);
5803 if (info->crypto_info == NULL) {
5804 if (stream->protection_scheme_type == FOURCC_cbcs) {
5805 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
5806 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
5807 GST_ERROR_OBJECT (qtdemux,
5808 "failed to attach cbcs metadata to buffer");
5809 qtdemux_gst_structure_free (crypto_info);
5811 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
5814 GST_DEBUG_OBJECT (qtdemux,
5815 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5818 /* The end of the crypto_info array matches our n_samples position,
5819 * so count backward from there */
5820 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5821 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5822 /* steal structure from array */
5823 crypto_info = g_ptr_array_index (info->crypto_info, index);
5824 g_ptr_array_index (info->crypto_info, index) = NULL;
5825 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5826 info->crypto_info->len);
5827 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5828 GST_ERROR_OBJECT (qtdemux,
5829 "failed to attach cenc metadata to buffer");
5831 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5832 index, stream->sample_index);
5837 if (stream->alignment > 1)
5838 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5840 pts = GST_BUFFER_PTS (buf);
5841 duration = GST_BUFFER_DURATION (buf);
5843 ret = gst_pad_push (stream->pad, buf);
5845 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5846 /* mark position in stream, we'll need this to know when to send GAP event */
5847 stream->segment.position = pts + duration;
5855 static GstFlowReturn
5856 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5859 GstFlowReturn ret = GST_FLOW_OK;
5861 if (stream->subtype == FOURCC_clcp
5862 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
5864 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
5865 guint n_triplets, i;
5866 guint field1_off = 0, field2_off = 0;
5868 /* We have to split CEA608 buffers so that each outgoing buffer contains
5869 * one byte pair per field according to the framerate of the video track.
5871 * If there is only a single byte pair per field we don't have to do
5875 gst_buffer_map (buf, &map, GST_MAP_READ);
5877 n_triplets = map.size / 3;
5878 for (i = 0; i < n_triplets; i++) {
5879 if (map.data[3 * i] & 0x80)
5885 g_assert (n_field1 || n_field2);
5887 /* If there's more than 1 frame we have to split, otherwise we can just
5889 if (n_field1 > 1 || n_field2 > 1) {
5891 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
5892 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
5894 for (i = 0; i < n_output_buffers; i++) {
5896 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
5900 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
5901 outptr = outmap.data;
5904 gboolean found = FALSE;
5906 while (map.data + field1_off < map.data + map.size) {
5907 if (map.data[field1_off] & 0x80) {
5908 memcpy (outptr, &map.data[field1_off], 3);
5917 const guint8 empty[] = { 0x80, 0x80, 0x80 };
5919 memcpy (outptr, empty, 3);
5926 gboolean found = FALSE;
5928 while (map.data + field2_off < map.data + map.size) {
5929 if ((map.data[field2_off] & 0x80) == 0) {
5930 memcpy (outptr, &map.data[field2_off], 3);
5939 const guint8 empty[] = { 0x00, 0x80, 0x80 };
5941 memcpy (outptr, empty, 3);
5947 gst_buffer_unmap (outbuf, &outmap);
5949 GST_BUFFER_PTS (outbuf) =
5950 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
5951 GST_SECOND * CUR_STREAM (stream)->fps_d,
5952 CUR_STREAM (stream)->fps_n);
5953 GST_BUFFER_DURATION (outbuf) =
5954 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
5955 CUR_STREAM (stream)->fps_n);
5956 GST_BUFFER_OFFSET (outbuf) = -1;
5957 GST_BUFFER_OFFSET_END (outbuf) = -1;
5959 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
5961 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
5964 gst_buffer_unmap (buf, &map);
5965 gst_buffer_unref (buf);
5967 gst_buffer_unmap (buf, &map);
5968 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
5971 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
5977 /* Sets a buffer's attributes properly and pushes it downstream.
5978 * Also checks for additional actions and custom processing that may
5979 * need to be done first.
5981 static GstFlowReturn
5982 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5983 QtDemuxStream * stream, GstBuffer * buf,
5984 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5985 gboolean keyframe, GstClockTime position, guint64 byte_position)
5987 GstFlowReturn ret = GST_FLOW_OK;
5989 /* offset the timestamps according to the edit list */
5991 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5995 gst_buffer_map (buf, &map, GST_MAP_READ);
5996 url = g_strndup ((gchar *) map.data, map.size);
5997 gst_buffer_unmap (buf, &map);
5998 if (url != NULL && strlen (url) != 0) {
5999 /* we have RTSP redirect now */
6000 g_free (qtdemux->redirect_location);
6001 qtdemux->redirect_location = g_strdup (url);
6002 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6003 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6004 gst_structure_new ("redirect",
6005 "new-location", G_TYPE_STRING, url, NULL)));
6007 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6013 /* position reporting */
6014 if (qtdemux->segment.rate >= 0) {
6015 qtdemux->segment.position = position;
6016 gst_qtdemux_sync_streams (qtdemux);
6019 if (G_UNLIKELY (!stream->pad)) {
6020 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6021 gst_buffer_unref (buf);
6025 /* send out pending buffers */
6026 while (stream->buffers) {
6027 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6029 if (G_UNLIKELY (stream->discont)) {
6030 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6031 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6032 stream->discont = FALSE;
6034 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6037 if (stream->alignment > 1)
6038 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6039 gst_pad_push (stream->pad, buffer);
6041 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6044 /* we're going to modify the metadata */
6045 buf = gst_buffer_make_writable (buf);
6047 if (G_UNLIKELY (stream->need_process))
6048 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
6054 GST_BUFFER_DTS (buf) = dts;
6055 GST_BUFFER_PTS (buf) = pts;
6056 GST_BUFFER_DURATION (buf) = duration;
6057 GST_BUFFER_OFFSET (buf) = -1;
6058 GST_BUFFER_OFFSET_END (buf) = -1;
6061 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6062 stream->on_keyframe = FALSE;
6064 stream->on_keyframe = TRUE;
6067 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6068 gst_buffer_append_memory (buf,
6069 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6071 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6072 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6075 if (G_UNLIKELY (qtdemux->element_index)) {
6076 GstClockTime stream_time;
6079 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6081 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6082 GST_LOG_OBJECT (qtdemux,
6083 "adding association %" GST_TIME_FORMAT "-> %"
6084 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6085 gst_index_add_association (qtdemux->element_index,
6087 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6088 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6089 GST_FORMAT_BYTES, byte_position, NULL);
6094 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6100 static const QtDemuxRandomAccessEntry *
6101 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6102 GstClockTime pos, gboolean after)
6104 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6105 guint n_entries = stream->n_ra_entries;
6108 /* we assume the table is sorted */
6109 for (i = 0; i < n_entries; ++i) {
6110 if (entries[i].ts > pos)
6114 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6115 * probably okay to assume that the index lists the very first fragment */
6122 return &entries[i - 1];
6126 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6128 const QtDemuxRandomAccessEntry *best_entry = NULL;
6131 GST_OBJECT_LOCK (qtdemux);
6133 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6135 /* first see if we can determine where to go to using mfra,
6136 * before we start clearing things */
6137 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6138 const QtDemuxRandomAccessEntry *entry;
6139 QtDemuxStream *stream;
6140 gboolean is_audio_or_video;
6142 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6144 if (stream->ra_entries == NULL)
6147 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6148 is_audio_or_video = TRUE;
6150 is_audio_or_video = FALSE;
6153 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6154 stream->time_position, !is_audio_or_video);
6156 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6157 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6159 stream->pending_seek = entry;
6161 /* decide position to jump to just based on audio/video tracks, not subs */
6162 if (!is_audio_or_video)
6165 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6169 /* no luck, will handle seek otherwise */
6170 if (best_entry == NULL) {
6171 GST_OBJECT_UNLOCK (qtdemux);
6175 /* ok, now we can prepare for processing as of located moof */
6176 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6177 QtDemuxStream *stream;
6179 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6181 g_free (stream->samples);
6182 stream->samples = NULL;
6183 stream->n_samples = 0;
6184 stream->stbl_index = -1; /* no samples have yet been parsed */
6185 stream->sample_index = -1;
6187 if (stream->protection_scheme_info) {
6188 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6189 if (stream->protection_scheme_type == FOURCC_cenc
6190 || stream->protection_scheme_type == FOURCC_cbcs) {
6191 QtDemuxCencSampleSetInfo *info =
6192 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6193 if (info->crypto_info) {
6194 g_ptr_array_free (info->crypto_info, TRUE);
6195 info->crypto_info = NULL;
6201 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6202 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6203 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6204 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6206 qtdemux->moof_offset = best_entry->moof_offset;
6208 qtdemux_add_fragmented_samples (qtdemux);
6210 GST_OBJECT_UNLOCK (qtdemux);
6214 static GstFlowReturn
6215 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6217 GstFlowReturn ret = GST_FLOW_OK;
6218 GstBuffer *buf = NULL;
6219 QtDemuxStream *stream, *target_stream = NULL;
6220 GstClockTime min_time;
6222 GstClockTime dts = GST_CLOCK_TIME_NONE;
6223 GstClockTime pts = GST_CLOCK_TIME_NONE;
6224 GstClockTime duration = 0;
6225 gboolean keyframe = FALSE;
6226 guint sample_size = 0;
6227 guint num_samples = 1;
6232 if (qtdemux->fragmented_seek_pending) {
6233 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6234 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6235 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6236 qtdemux->fragmented_seek_pending = FALSE;
6238 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6242 /* Figure out the next stream sample to output, min_time is expressed in
6243 * global time and runs over the edit list segments. */
6244 min_time = G_MAXUINT64;
6245 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6246 GstClockTime position;
6248 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6249 position = stream->time_position;
6251 if (!GST_CLOCK_TIME_IS_VALID (position))
6254 if (stream->segment_index != -1) {
6255 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6256 position += segment->media_start;
6259 /* position of -1 is EOS */
6260 if (position < min_time) {
6261 min_time = position;
6262 target_stream = stream;
6266 if (G_UNLIKELY (target_stream == NULL)) {
6267 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6271 /* check for segment end */
6272 if (G_UNLIKELY (qtdemux->segment.stop != -1
6273 && qtdemux->segment.rate >= 0
6274 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6275 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6276 target_stream->time_position = GST_CLOCK_TIME_NONE;
6280 /* gap events for subtitle streams */
6281 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6282 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6284 GstClockTime gap_threshold;
6286 /* Only send gap events on non-subtitle streams if lagging way behind. */
6287 if (stream->subtype == FOURCC_subp
6288 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)
6289 gap_threshold = 1 * GST_SECOND;
6291 gap_threshold = 3 * GST_SECOND;
6293 /* send gap events until the stream catches up */
6294 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6295 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6296 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6297 stream->segment.position + gap_threshold < min_time) {
6299 gst_event_new_gap (stream->segment.position, gap_threshold);
6300 gst_pad_push_event (stream->pad, gap);
6301 stream->segment.position += gap_threshold;
6306 stream = target_stream;
6307 /* fetch info for the current sample of this stream */
6308 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6309 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6312 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6313 if (stream->new_caps) {
6314 gst_qtdemux_configure_stream (qtdemux, stream);
6315 qtdemux_do_allocation (stream, qtdemux);
6318 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6319 if (G_UNLIKELY (qtdemux->segment.
6320 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6321 if (stream->subtype == FOURCC_vide) {
6323 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6326 } else if (qtdemux->trickmode_interval > 0) {
6327 GstClockTimeDiff interval;
6329 if (qtdemux->segment.rate > 0)
6330 interval = stream->time_position - stream->last_keyframe_dts;
6332 interval = stream->last_keyframe_dts - stream->time_position;
6334 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6335 && interval < qtdemux->trickmode_interval) {
6336 GST_LOG_OBJECT (qtdemux,
6337 "Skipping keyframe within interval on track-id %u",
6341 stream->last_keyframe_dts = stream->time_position;
6347 GST_DEBUG_OBJECT (qtdemux,
6348 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6349 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6350 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6351 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6352 GST_TIME_ARGS (duration));
6354 if (G_UNLIKELY (empty)) {
6355 /* empty segment, push a gap if there's a second or more
6356 * difference and move to the next one */
6357 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6358 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6359 stream->segment.position = pts + duration;
6363 /* hmm, empty sample, skip and move to next sample */
6364 if (G_UNLIKELY (sample_size <= 0))
6367 /* last pushed sample was out of boundary, goto next sample */
6368 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6371 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6372 GST_DEBUG_OBJECT (qtdemux,
6373 "size %d larger than stream max_buffer_size %d, trimming",
6374 sample_size, stream->max_buffer_size);
6376 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6377 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6378 && sample_size < stream->min_buffer_size) {
6379 guint start_sample_index = stream->sample_index;
6380 guint accumulated_size = sample_size;
6381 guint64 expected_next_offset = offset + sample_size;
6383 GST_DEBUG_OBJECT (qtdemux,
6384 "size %d smaller than stream min_buffer_size %d, combining with the next",
6385 sample_size, stream->min_buffer_size);
6387 while (stream->sample_index < stream->to_sample
6388 && stream->sample_index + 1 < stream->n_samples) {
6389 const QtDemuxSample *next_sample;
6391 /* Increment temporarily */
6392 stream->sample_index++;
6394 /* Failed to parse sample so let's go back to the previous one that was
6395 * still successful */
6396 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6397 stream->sample_index--;
6401 next_sample = &stream->samples[stream->sample_index];
6403 /* Not contiguous with the previous sample so let's go back to the
6404 * previous one that was still successful */
6405 if (next_sample->offset != expected_next_offset) {
6406 stream->sample_index--;
6410 accumulated_size += next_sample->size;
6411 expected_next_offset += next_sample->size;
6412 if (accumulated_size >= stream->min_buffer_size)
6416 num_samples = stream->sample_index + 1 - start_sample_index;
6417 stream->sample_index = start_sample_index;
6418 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6419 num_samples, accumulated_size);
6420 size = accumulated_size;
6425 if (qtdemux->cenc_aux_info_offset > 0) {
6428 GstBuffer *aux_info = NULL;
6430 /* pull the data stored before the sample */
6432 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6433 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6434 if (G_UNLIKELY (ret != GST_FLOW_OK))
6436 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6437 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6438 gst_byte_reader_init (&br, map.data + 8, map.size);
6439 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6440 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6441 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6442 gst_buffer_unmap (aux_info, &map);
6443 gst_buffer_unref (aux_info);
6444 ret = GST_FLOW_ERROR;
6447 gst_buffer_unmap (aux_info, &map);
6448 gst_buffer_unref (aux_info);
6451 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6454 if (stream->use_allocator) {
6455 /* if we have a per-stream allocator, use it */
6456 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6459 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6461 if (G_UNLIKELY (ret != GST_FLOW_OK))
6464 /* Update for both splitting and combining of samples */
6465 if (size != sample_size) {
6466 pts += gst_util_uint64_scale_int (GST_SECOND,
6467 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6470 gst_util_uint64_scale_int (GST_SECOND,
6471 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6474 gst_util_uint64_scale_int (GST_SECOND,
6475 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6478 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6479 dts, pts, duration, keyframe, min_time, offset);
6481 if (size < sample_size) {
6482 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6483 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6485 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6487 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6488 if (time_position >= segment->media_start) {
6489 /* inside the segment, update time_position, looks very familiar to
6490 * GStreamer segments, doesn't it? */
6491 stream->time_position = (time_position - segment->media_start) +
6494 /* not yet in segment, time does not yet increment. This means
6495 * that we are still prerolling keyframes to the decoder so it can
6496 * decode the first sample of the segment. */
6497 stream->time_position = segment->time;
6499 } else if (size > sample_size) {
6500 /* Increase to the last sample we already pulled so that advancing
6501 * below brings us to the next sample we need to pull */
6502 stream->sample_index += num_samples - 1;
6506 GST_OBJECT_LOCK (qtdemux);
6507 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6508 GST_OBJECT_UNLOCK (qtdemux);
6509 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6510 * we have no more data for the pad to push */
6511 if (ret == GST_FLOW_EOS)
6514 stream->offset_in_sample += size;
6515 if (stream->offset_in_sample >= sample_size) {
6516 gst_qtdemux_advance_sample (qtdemux, stream);
6521 gst_qtdemux_advance_sample (qtdemux, stream);
6529 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6535 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6536 /* EOS will be raised if all are EOS */
6543 gst_qtdemux_loop (GstPad * pad)
6545 GstQTDemux *qtdemux;
6549 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6551 cur_offset = qtdemux->offset;
6552 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6553 cur_offset, qt_demux_state_string (qtdemux->state));
6555 switch (qtdemux->state) {
6556 case QTDEMUX_STATE_INITIAL:
6557 case QTDEMUX_STATE_HEADER:
6558 ret = gst_qtdemux_loop_state_header (qtdemux);
6560 case QTDEMUX_STATE_MOVIE:
6561 ret = gst_qtdemux_loop_state_movie (qtdemux);
6562 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6563 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6571 /* if something went wrong, pause */
6572 if (ret != GST_FLOW_OK)
6576 gst_object_unref (qtdemux);
6582 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6583 (NULL), ("streaming stopped, invalid state"));
6584 gst_pad_pause_task (pad);
6585 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6590 const gchar *reason = gst_flow_get_name (ret);
6592 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6594 gst_pad_pause_task (pad);
6596 /* fatal errors need special actions */
6598 if (ret == GST_FLOW_EOS) {
6599 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6600 /* we have no streams, post an error */
6601 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6603 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6606 if ((stop = qtdemux->segment.stop) == -1)
6607 stop = qtdemux->segment.duration;
6609 if (qtdemux->segment.rate >= 0) {
6610 GstMessage *message;
6613 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6614 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6615 GST_FORMAT_TIME, stop);
6616 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6617 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6618 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6619 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6621 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6622 gst_qtdemux_push_event (qtdemux, event);
6624 GstMessage *message;
6627 /* For Reverse Playback */
6628 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6629 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6630 GST_FORMAT_TIME, qtdemux->segment.start);
6631 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6632 qtdemux->segment.start);
6633 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6634 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6635 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6637 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6638 gst_qtdemux_push_event (qtdemux, event);
6643 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6644 event = gst_event_new_eos ();
6645 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6646 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6647 gst_qtdemux_push_event (qtdemux, event);
6649 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6650 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6651 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6660 * Returns if there are samples to be played.
6663 has_next_entry (GstQTDemux * demux)
6665 QtDemuxStream *stream;
6668 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6670 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6671 stream = QTDEMUX_NTH_STREAM (demux, i);
6673 if (stream->sample_index == -1) {
6674 stream->sample_index = 0;
6675 stream->offset_in_sample = 0;
6678 if (stream->sample_index >= stream->n_samples) {
6679 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6682 GST_DEBUG_OBJECT (demux, "Found a sample");
6686 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6693 * Returns the size of the first entry at the current offset.
6694 * If -1, there are none (which means EOS or empty file).
6697 next_entry_size (GstQTDemux * demux)
6699 QtDemuxStream *stream, *target_stream = NULL;
6700 guint64 smalloffs = (guint64) - 1;
6701 QtDemuxSample *sample;
6704 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6707 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6708 stream = QTDEMUX_NTH_STREAM (demux, i);
6710 if (stream->sample_index == -1) {
6711 stream->sample_index = 0;
6712 stream->offset_in_sample = 0;
6715 if (stream->sample_index >= stream->n_samples) {
6716 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6720 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6721 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6722 stream->sample_index);
6726 sample = &stream->samples[stream->sample_index];
6728 GST_LOG_OBJECT (demux,
6729 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6730 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6731 stream->sample_index, sample->offset, sample->size);
6733 if (((smalloffs == -1)
6734 || (sample->offset < smalloffs)) && (sample->size)) {
6735 smalloffs = sample->offset;
6736 target_stream = stream;
6743 GST_LOG_OBJECT (demux,
6744 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6745 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6747 stream = target_stream;
6748 sample = &stream->samples[stream->sample_index];
6750 if (sample->offset >= demux->offset) {
6751 demux->todrop = sample->offset - demux->offset;
6752 return sample->size + demux->todrop;
6755 GST_DEBUG_OBJECT (demux,
6756 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6761 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6763 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6765 gst_element_post_message (GST_ELEMENT_CAST (demux),
6766 gst_message_new_element (GST_OBJECT_CAST (demux),
6767 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6771 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6776 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6779 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6780 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6781 GST_SEEK_TYPE_NONE, -1);
6783 /* store seqnum to drop flush events, they don't need to reach downstream */
6784 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6785 res = gst_pad_push_event (demux->sinkpad, event);
6786 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6791 /* check for seekable upstream, above and beyond a mere query */
6793 gst_qtdemux_check_seekability (GstQTDemux * demux)
6796 gboolean seekable = FALSE;
6797 gint64 start = -1, stop = -1;
6799 if (demux->upstream_size)
6802 if (demux->upstream_format_is_time)
6805 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6806 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6807 GST_DEBUG_OBJECT (demux, "seeking query failed");
6811 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6813 /* try harder to query upstream size if we didn't get it the first time */
6814 if (seekable && stop == -1) {
6815 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6816 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6819 /* if upstream doesn't know the size, it's likely that it's not seekable in
6820 * practice even if it technically may be seekable */
6821 if (seekable && (start != 0 || stop <= start)) {
6822 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6827 gst_query_unref (query);
6829 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6830 G_GUINT64_FORMAT ")", seekable, start, stop);
6831 demux->upstream_seekable = seekable;
6832 demux->upstream_size = seekable ? stop : -1;
6836 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6838 g_return_if_fail (bytes <= demux->todrop);
6840 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6841 gst_adapter_flush (demux->adapter, bytes);
6842 demux->neededbytes -= bytes;
6843 demux->offset += bytes;
6844 demux->todrop -= bytes;
6847 /* PUSH-MODE only: Send a segment, if not done already. */
6849 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6851 if (G_UNLIKELY (demux->need_segment)) {
6854 if (!demux->upstream_format_is_time) {
6855 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6857 GstEvent *segment_event;
6858 segment_event = gst_event_new_segment (&demux->segment);
6859 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6860 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6861 gst_qtdemux_push_event (demux, segment_event);
6864 demux->need_segment = FALSE;
6866 /* clear to send tags on all streams */
6867 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6868 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6869 gst_qtdemux_push_tags (demux, stream);
6870 if (CUR_STREAM (stream)->sparse) {
6871 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6872 gst_pad_push_event (stream->pad,
6873 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6879 /* Used for push mode only. */
6881 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6882 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6884 GstClockTime ts, dur;
6888 stream->segments[segment_index].duration - (pos -
6889 stream->segments[segment_index].time);
6890 stream->time_position += dur;
6892 /* Only gaps with a duration of at least one second are propagated.
6893 * Same workaround as in pull mode.
6894 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6895 if (dur >= GST_SECOND) {
6897 gap = gst_event_new_gap (ts, dur);
6899 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6900 "segment: %" GST_PTR_FORMAT, gap);
6901 gst_pad_push_event (stream->pad, gap);
6905 static GstFlowReturn
6906 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6910 demux = GST_QTDEMUX (parent);
6912 GST_DEBUG_OBJECT (demux,
6913 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6914 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6915 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6916 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6917 gst_buffer_get_size (inbuf), demux->offset);
6919 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6920 gboolean is_gap_input = FALSE;
6923 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6925 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6926 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
6929 /* Check if we can land back on our feet in the case where upstream is
6930 * handling the seeking/pushing of samples with gaps in between (like
6931 * in the case of trick-mode DASH for example) */
6932 if (demux->upstream_format_is_time
6933 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6934 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6936 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6937 GST_LOG_OBJECT (demux,
6938 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
6939 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
6941 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6942 stream, GST_BUFFER_OFFSET (inbuf));
6944 QtDemuxSample *sample = &stream->samples[res];
6945 GST_LOG_OBJECT (demux,
6946 "Checking if sample %d from track-id %u is valid (offset:%"
6947 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
6948 stream->track_id, sample->offset, sample->size);
6949 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6950 GST_LOG_OBJECT (demux,
6951 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6953 is_gap_input = TRUE;
6954 /* We can go back to standard playback mode */
6955 demux->state = QTDEMUX_STATE_MOVIE;
6956 /* Remember which sample this stream is at */
6957 stream->sample_index = res;
6958 /* Finally update all push-based values to the expected values */
6959 demux->neededbytes = stream->samples[res].size;
6960 demux->offset = GST_BUFFER_OFFSET (inbuf);
6962 demux->mdatsize - demux->offset + demux->mdatoffset;
6967 if (!is_gap_input) {
6968 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6969 /* Reset state if it's a real discont */
6970 demux->neededbytes = 16;
6971 demux->state = QTDEMUX_STATE_INITIAL;
6972 demux->offset = GST_BUFFER_OFFSET (inbuf);
6973 gst_adapter_clear (demux->adapter);
6976 /* Reverse fragmented playback, need to flush all we have before
6977 * consuming a new fragment.
6978 * The samples array have the timestamps calculated by accumulating the
6979 * durations but this won't work for reverse playback of fragments as
6980 * the timestamps of a subsequent fragment should be smaller than the
6981 * previously received one. */
6982 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6983 gst_qtdemux_process_adapter (demux, TRUE);
6984 g_ptr_array_foreach (demux->active_streams,
6985 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
6989 gst_adapter_push (demux->adapter, inbuf);
6991 GST_DEBUG_OBJECT (demux,
6992 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6993 demux->neededbytes, gst_adapter_available (demux->adapter));
6995 return gst_qtdemux_process_adapter (demux, FALSE);
6998 static GstFlowReturn
6999 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7001 GstFlowReturn ret = GST_FLOW_OK;
7003 /* we never really mean to buffer that much */
7004 if (demux->neededbytes == -1) {
7008 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7009 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7011 #ifndef GST_DISABLE_GST_DEBUG
7013 guint64 discont_offset, distance_from_discont;
7015 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7016 distance_from_discont =
7017 gst_adapter_distance_from_discont (demux->adapter);
7019 GST_DEBUG_OBJECT (demux,
7020 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7021 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7022 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7023 demux->offset, discont_offset, distance_from_discont);
7027 switch (demux->state) {
7028 case QTDEMUX_STATE_INITIAL:{
7033 gst_qtdemux_check_seekability (demux);
7035 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7037 /* get fourcc/length, set neededbytes */
7038 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7040 gst_adapter_unmap (demux->adapter);
7042 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7043 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7045 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7046 (_("This file is invalid and cannot be played.")),
7047 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7048 GST_FOURCC_ARGS (fourcc)));
7049 ret = GST_FLOW_ERROR;
7052 if (fourcc == FOURCC_mdat) {
7053 gint next_entry = next_entry_size (demux);
7054 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7055 || !demux->fragmented)) {
7056 /* we have the headers, start playback */
7057 demux->state = QTDEMUX_STATE_MOVIE;
7058 demux->neededbytes = next_entry;
7059 demux->mdatleft = size;
7060 demux->mdatsize = demux->mdatleft;
7062 /* no headers yet, try to get them */
7065 guint64 old, target;
7068 old = demux->offset;
7069 target = old + size;
7071 /* try to jump over the atom with a seek */
7072 /* only bother if it seems worth doing so,
7073 * and avoids possible upstream/server problems */
7074 if (demux->upstream_seekable &&
7075 demux->upstream_size > 4 * (1 << 20)) {
7076 res = qtdemux_seek_offset (demux, target);
7078 GST_DEBUG_OBJECT (demux, "skipping seek");
7083 GST_DEBUG_OBJECT (demux, "seek success");
7084 /* remember the offset fo the first mdat so we can seek back to it
7085 * after we have the headers */
7086 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7087 demux->first_mdat = old;
7088 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7091 /* seek worked, continue reading */
7092 demux->offset = target;
7093 demux->neededbytes = 16;
7094 demux->state = QTDEMUX_STATE_INITIAL;
7096 /* seek failed, need to buffer */
7097 demux->offset = old;
7098 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7099 /* there may be multiple mdat (or alike) buffers */
7101 if (demux->mdatbuffer)
7102 bs = gst_buffer_get_size (demux->mdatbuffer);
7105 if (size + bs > 10 * (1 << 20))
7107 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7108 demux->neededbytes = size;
7109 if (!demux->mdatbuffer)
7110 demux->mdatoffset = demux->offset;
7113 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7114 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7115 (_("This file is invalid and cannot be played.")),
7116 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7117 GST_FOURCC_ARGS (fourcc), size));
7118 ret = GST_FLOW_ERROR;
7121 /* this means we already started buffering and still no moov header,
7122 * let's continue buffering everything till we get moov */
7123 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7124 || fourcc == FOURCC_moof))
7126 demux->neededbytes = size;
7127 demux->state = QTDEMUX_STATE_HEADER;
7131 case QTDEMUX_STATE_HEADER:{
7135 GST_DEBUG_OBJECT (demux, "In header");
7137 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7139 /* parse the header */
7140 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7142 if (fourcc == FOURCC_moov) {
7143 /* in usual fragmented setup we could try to scan for more
7144 * and end up at the the moov (after mdat) again */
7145 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7147 || demux->last_moov_offset == demux->offset)) {
7148 GST_DEBUG_OBJECT (demux,
7149 "Skipping moov atom as we have (this) one already");
7151 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7153 if (demux->got_moov && demux->fragmented) {
7154 GST_DEBUG_OBJECT (demux,
7155 "Got a second moov, clean up data from old one");
7156 if (demux->moov_node_compressed) {
7157 g_node_destroy (demux->moov_node_compressed);
7158 if (demux->moov_node)
7159 g_free (demux->moov_node->data);
7161 demux->moov_node_compressed = NULL;
7162 if (demux->moov_node)
7163 g_node_destroy (demux->moov_node);
7164 demux->moov_node = NULL;
7167 demux->last_moov_offset = demux->offset;
7169 /* Update streams with new moov */
7170 gst_qtdemux_stream_concat (demux,
7171 demux->old_streams, demux->active_streams);
7173 qtdemux_parse_moov (demux, data, demux->neededbytes);
7174 qtdemux_node_dump (demux, demux->moov_node);
7175 qtdemux_parse_tree (demux);
7176 qtdemux_prepare_streams (demux);
7177 QTDEMUX_EXPOSE_LOCK (demux);
7178 qtdemux_expose_streams (demux);
7179 QTDEMUX_EXPOSE_UNLOCK (demux);
7181 demux->got_moov = TRUE;
7183 gst_qtdemux_check_send_pending_segment (demux);
7185 if (demux->moov_node_compressed) {
7186 g_node_destroy (demux->moov_node_compressed);
7187 g_free (demux->moov_node->data);
7189 demux->moov_node_compressed = NULL;
7190 g_node_destroy (demux->moov_node);
7191 demux->moov_node = NULL;
7192 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7194 } else if (fourcc == FOURCC_moof) {
7195 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7197 GstClockTime prev_pts;
7198 guint64 prev_offset;
7199 guint64 adapter_discont_offset, adapter_discont_dist;
7201 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7204 * The timestamp of the moof buffer is relevant as some scenarios
7205 * won't have the initial timestamp in the atoms. Whenever a new
7206 * buffer has started, we get that buffer's PTS and use it as a base
7207 * timestamp for the trun entries.
7209 * To keep track of the current buffer timestamp and starting point
7210 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7211 * from the beginning of the buffer, with the distance and demux->offset
7212 * we know if it is still the same buffer or not.
7214 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7215 prev_offset = demux->offset - dist;
7216 if (demux->fragment_start_offset == -1
7217 || prev_offset > demux->fragment_start_offset) {
7218 demux->fragment_start_offset = prev_offset;
7219 demux->fragment_start = prev_pts;
7220 GST_DEBUG_OBJECT (demux,
7221 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7222 GST_TIME_FORMAT, demux->fragment_start_offset,
7223 GST_TIME_ARGS (demux->fragment_start));
7226 /* We can't use prev_offset() here because this would require
7227 * upstream to set consistent and correct offsets on all buffers
7228 * since the discont. Nothing ever did that in the past and we
7229 * would break backwards compatibility here then.
7230 * Instead take the offset we had at the last discont and count
7231 * the bytes from there. This works with old code as there would
7232 * be no discont between moov and moof, and also works with
7233 * adaptivedemux which correctly sets offset and will set the
7234 * DISCONT flag accordingly when needed.
7236 * We also only do this for upstream TIME segments as otherwise
7237 * there are potential backwards compatibility problems with
7238 * seeking in PUSH mode and upstream providing inconsistent
7240 adapter_discont_offset =
7241 gst_adapter_offset_at_discont (demux->adapter);
7242 adapter_discont_dist =
7243 gst_adapter_distance_from_discont (demux->adapter);
7245 GST_DEBUG_OBJECT (demux,
7246 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7247 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7248 demux->offset, adapter_discont_offset, adapter_discont_dist);
7250 if (demux->upstream_format_is_time) {
7251 demux->moof_offset = adapter_discont_offset;
7252 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7253 demux->moof_offset += adapter_discont_dist;
7254 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7255 demux->moof_offset = demux->offset;
7257 demux->moof_offset = demux->offset;
7260 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7261 demux->moof_offset, NULL)) {
7262 gst_adapter_unmap (demux->adapter);
7263 ret = GST_FLOW_ERROR;
7267 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7268 if (demux->mss_mode && !demux->exposed) {
7269 QTDEMUX_EXPOSE_LOCK (demux);
7270 qtdemux_expose_streams (demux);
7271 QTDEMUX_EXPOSE_UNLOCK (demux);
7274 gst_qtdemux_check_send_pending_segment (demux);
7276 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7278 } else if (fourcc == FOURCC_ftyp) {
7279 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7280 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7281 } else if (fourcc == FOURCC_uuid) {
7282 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7283 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7284 } else if (fourcc == FOURCC_sidx) {
7285 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7286 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7290 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7294 /* [free] and [skip] are padding atoms */
7295 GST_DEBUG_OBJECT (demux,
7296 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7297 GST_FOURCC_ARGS (fourcc));
7300 GST_WARNING_OBJECT (demux,
7301 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7302 GST_FOURCC_ARGS (fourcc));
7303 /* Let's jump that one and go back to initial state */
7307 gst_adapter_unmap (demux->adapter);
7310 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7311 gsize remaining_data_size = 0;
7313 /* the mdat was before the header */
7314 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7315 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7316 /* restore our adapter/offset view of things with upstream;
7317 * put preceding buffered data ahead of current moov data.
7318 * This should also handle evil mdat, moov, mdat cases and alike */
7319 gst_adapter_flush (demux->adapter, demux->neededbytes);
7321 /* Store any remaining data after the mdat for later usage */
7322 remaining_data_size = gst_adapter_available (demux->adapter);
7323 if (remaining_data_size > 0) {
7324 g_assert (demux->restoredata_buffer == NULL);
7325 demux->restoredata_buffer =
7326 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7327 demux->restoredata_offset = demux->offset + demux->neededbytes;
7328 GST_DEBUG_OBJECT (demux,
7329 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7330 G_GUINT64_FORMAT, remaining_data_size,
7331 demux->restoredata_offset);
7334 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7335 demux->mdatbuffer = NULL;
7336 demux->offset = demux->mdatoffset;
7337 demux->neededbytes = next_entry_size (demux);
7338 demux->state = QTDEMUX_STATE_MOVIE;
7339 demux->mdatleft = gst_adapter_available (demux->adapter);
7340 demux->mdatsize = demux->mdatleft;
7342 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7343 gst_adapter_flush (demux->adapter, demux->neededbytes);
7345 /* only go back to the mdat if there are samples to play */
7346 if (demux->got_moov && demux->first_mdat != -1
7347 && has_next_entry (demux)) {
7350 /* we need to seek back */
7351 res = qtdemux_seek_offset (demux, demux->first_mdat);
7353 demux->offset = demux->first_mdat;
7355 GST_DEBUG_OBJECT (demux, "Seek back failed");
7358 demux->offset += demux->neededbytes;
7360 demux->neededbytes = 16;
7361 demux->state = QTDEMUX_STATE_INITIAL;
7366 case QTDEMUX_STATE_BUFFER_MDAT:{
7370 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7372 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7373 gst_buffer_extract (buf, 0, fourcc, 4);
7374 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7375 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7376 if (demux->mdatbuffer)
7377 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7379 demux->mdatbuffer = buf;
7380 demux->offset += demux->neededbytes;
7381 demux->neededbytes = 16;
7382 demux->state = QTDEMUX_STATE_INITIAL;
7383 gst_qtdemux_post_progress (demux, 1, 1);
7387 case QTDEMUX_STATE_MOVIE:{
7388 QtDemuxStream *stream = NULL;
7389 QtDemuxSample *sample;
7390 GstClockTime dts, pts, duration;
7394 GST_DEBUG_OBJECT (demux,
7395 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7397 if (demux->fragmented) {
7398 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7400 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7401 /* if needed data starts within this atom,
7402 * then it should not exceed this atom */
7403 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7404 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7405 (_("This file is invalid and cannot be played.")),
7406 ("sample data crosses atom boundary"));
7407 ret = GST_FLOW_ERROR;
7410 demux->mdatleft -= demux->neededbytes;
7412 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7413 /* so we are dropping more than left in this atom */
7414 gst_qtdemux_drop_data (demux, demux->mdatleft);
7415 demux->mdatleft = 0;
7417 /* need to resume atom parsing so we do not miss any other pieces */
7418 demux->state = QTDEMUX_STATE_INITIAL;
7419 demux->neededbytes = 16;
7421 /* check if there was any stored post mdat data from previous buffers */
7422 if (demux->restoredata_buffer) {
7423 g_assert (gst_adapter_available (demux->adapter) == 0);
7425 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7426 demux->restoredata_buffer = NULL;
7427 demux->offset = demux->restoredata_offset;
7434 if (demux->todrop) {
7435 if (demux->cenc_aux_info_offset > 0) {
7439 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7440 data = gst_adapter_map (demux->adapter, demux->todrop);
7441 gst_byte_reader_init (&br, data + 8, demux->todrop);
7442 if (!qtdemux_parse_cenc_aux_info (demux,
7443 QTDEMUX_NTH_STREAM (demux, 0), &br,
7444 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7445 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7446 ret = GST_FLOW_ERROR;
7447 gst_adapter_unmap (demux->adapter);
7448 g_free (demux->cenc_aux_info_sizes);
7449 demux->cenc_aux_info_sizes = NULL;
7452 demux->cenc_aux_info_offset = 0;
7453 g_free (demux->cenc_aux_info_sizes);
7454 demux->cenc_aux_info_sizes = NULL;
7455 gst_adapter_unmap (demux->adapter);
7457 gst_qtdemux_drop_data (demux, demux->todrop);
7461 /* initial newsegment sent here after having added pads,
7462 * possible others in sink_event */
7463 gst_qtdemux_check_send_pending_segment (demux);
7465 /* Figure out which stream this packet belongs to */
7466 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7467 stream = QTDEMUX_NTH_STREAM (demux, i);
7468 if (stream->sample_index >= stream->n_samples) {
7469 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7473 GST_LOG_OBJECT (demux,
7474 "Checking track-id %u (sample_index:%d / offset:%"
7475 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7476 stream->sample_index,
7477 stream->samples[stream->sample_index].offset,
7478 stream->samples[stream->sample_index].size);
7480 if (stream->samples[stream->sample_index].offset == demux->offset)
7484 if (G_UNLIKELY (stream == NULL))
7485 goto unknown_stream;
7487 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7489 if (stream->new_caps) {
7490 gst_qtdemux_configure_stream (demux, stream);
7493 /* Put data in a buffer, set timestamps, caps, ... */
7494 sample = &stream->samples[stream->sample_index];
7496 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7497 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7498 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7500 dts = QTSAMPLE_DTS (stream, sample);
7501 pts = QTSAMPLE_PTS (stream, sample);
7502 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7503 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7505 /* check for segment end */
7506 if (G_UNLIKELY (demux->segment.stop != -1
7507 && demux->segment.stop <= pts && stream->on_keyframe)
7508 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7509 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7510 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7512 /* skip this data, stream is EOS */
7513 gst_adapter_flush (demux->adapter, demux->neededbytes);
7514 demux->offset += demux->neededbytes;
7516 /* check if all streams are eos */
7518 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7519 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7528 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7530 /* FIXME: should either be an assert or a plain check */
7531 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7533 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7534 dts, pts, duration, keyframe, dts, demux->offset);
7538 GST_OBJECT_LOCK (demux);
7539 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7540 GST_OBJECT_UNLOCK (demux);
7542 /* skip this data, stream is EOS */
7543 gst_adapter_flush (demux->adapter, demux->neededbytes);
7546 stream->sample_index++;
7547 stream->offset_in_sample = 0;
7549 /* update current offset and figure out size of next buffer */
7550 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7551 demux->offset, demux->neededbytes);
7552 demux->offset += demux->neededbytes;
7553 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7557 if (ret == GST_FLOW_EOS) {
7558 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7559 demux->neededbytes = -1;
7563 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7564 if (demux->fragmented) {
7565 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7566 /* there may be more to follow, only finish this atom */
7567 demux->todrop = demux->mdatleft;
7568 demux->neededbytes = demux->todrop;
7573 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7574 goto non_ok_unlinked_flow;
7583 /* when buffering movie data, at least show user something is happening */
7584 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7585 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7586 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7587 demux->neededbytes);
7594 non_ok_unlinked_flow:
7596 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7597 gst_flow_get_name (ret));
7602 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7603 ret = GST_FLOW_ERROR;
7608 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7614 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7615 (NULL), ("qtdemuxer invalid state %d", demux->state));
7616 ret = GST_FLOW_ERROR;
7621 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7622 (NULL), ("no 'moov' atom within the first 10 MB"));
7623 ret = GST_FLOW_ERROR;
7629 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7634 query = gst_query_new_scheduling ();
7636 if (!gst_pad_peer_query (sinkpad, query)) {
7637 gst_query_unref (query);
7641 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7642 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7643 gst_query_unref (query);
7648 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7649 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7653 GST_DEBUG_OBJECT (sinkpad, "activating push");
7654 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7659 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7660 GstPadMode mode, gboolean active)
7663 GstQTDemux *demux = GST_QTDEMUX (parent);
7666 case GST_PAD_MODE_PUSH:
7667 demux->pullbased = FALSE;
7670 case GST_PAD_MODE_PULL:
7672 demux->pullbased = TRUE;
7673 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7676 res = gst_pad_stop_task (sinkpad);
7688 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7694 memset (&z, 0, sizeof (z));
7699 if ((ret = inflateInit (&z)) != Z_OK) {
7700 GST_ERROR ("inflateInit() returned %d", ret);
7704 z.next_in = z_buffer;
7705 z.avail_in = z_length;
7707 buffer = (guint8 *) g_malloc (*length);
7708 z.avail_out = *length;
7709 z.next_out = (Bytef *) buffer;
7711 ret = inflate (&z, Z_NO_FLUSH);
7712 if (ret == Z_STREAM_END) {
7714 } else if (ret != Z_OK) {
7715 GST_WARNING ("inflate() returned %d", ret);
7720 buffer = (guint8 *) g_realloc (buffer, *length);
7721 z.next_out = (Bytef *) (buffer + z.total_out);
7722 z.avail_out += 4096;
7723 } while (z.avail_in > 0);
7725 if (ret != Z_STREAM_END) {
7730 *length = z.total_out;
7737 #endif /* HAVE_ZLIB */
7740 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7744 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7746 /* counts as header data */
7747 qtdemux->header_size += length;
7749 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7750 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7752 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7759 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7760 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7761 if (dcom == NULL || cmvd == NULL)
7762 goto invalid_compression;
7764 dcom_len = QT_UINT32 (dcom->data);
7766 goto invalid_compression;
7768 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7772 guint uncompressed_length;
7773 guint compressed_length;
7777 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7779 goto invalid_compression;
7781 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7782 compressed_length = cmvd_len - 12;
7783 GST_LOG ("length = %u", uncompressed_length);
7786 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7787 compressed_length, &uncompressed_length);
7790 qtdemux->moov_node_compressed = qtdemux->moov_node;
7791 qtdemux->moov_node = g_node_new (buf);
7793 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7794 uncompressed_length);
7798 #endif /* HAVE_ZLIB */
7800 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7801 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7808 invalid_compression:
7810 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7816 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7819 while (G_UNLIKELY (buf < end)) {
7823 if (G_UNLIKELY (buf + 4 > end)) {
7824 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7827 len = QT_UINT32 (buf);
7828 if (G_UNLIKELY (len == 0)) {
7829 GST_LOG_OBJECT (qtdemux, "empty container");
7832 if (G_UNLIKELY (len < 8)) {
7833 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7836 if (G_UNLIKELY (len > (end - buf))) {
7837 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7838 (gint) (end - buf));
7842 child = g_node_new ((guint8 *) buf);
7843 g_node_append (node, child);
7844 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7845 qtdemux_parse_node (qtdemux, child, buf, len);
7853 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7856 int len = QT_UINT32 (xdxt->data);
7857 guint8 *buf = xdxt->data;
7858 guint8 *end = buf + len;
7861 /* skip size and type */
7869 size = QT_UINT32 (buf);
7870 type = QT_FOURCC (buf + 4);
7872 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7874 if (buf + size > end || size <= 0)
7880 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7881 GST_FOURCC_ARGS (type));
7885 buffer = gst_buffer_new_and_alloc (size);
7886 gst_buffer_fill (buffer, 0, buf, size);
7887 stream->buffers = g_slist_append (stream->buffers, buffer);
7888 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7891 buffer = gst_buffer_new_and_alloc (size);
7892 gst_buffer_fill (buffer, 0, buf, size);
7893 stream->buffers = g_slist_append (stream->buffers, buffer);
7894 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7897 buffer = gst_buffer_new_and_alloc (size);
7898 gst_buffer_fill (buffer, 0, buf, size);
7899 stream->buffers = g_slist_append (stream->buffers, buffer);
7900 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7903 GST_WARNING_OBJECT (qtdemux,
7904 "unknown theora cookie %" GST_FOURCC_FORMAT,
7905 GST_FOURCC_ARGS (type));
7914 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7918 guint32 node_length = 0;
7919 const QtNodeType *type;
7922 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7924 if (G_UNLIKELY (length < 8))
7925 goto not_enough_data;
7927 node_length = QT_UINT32 (buffer);
7928 fourcc = QT_FOURCC (buffer + 4);
7930 /* ignore empty nodes */
7931 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7934 type = qtdemux_type_get (fourcc);
7936 end = buffer + length;
7938 GST_LOG_OBJECT (qtdemux,
7939 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7940 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7942 if (node_length > length)
7943 goto broken_atom_size;
7945 if (type->flags & QT_FLAG_CONTAINER) {
7946 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7951 if (node_length < 20) {
7952 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7955 GST_DEBUG_OBJECT (qtdemux,
7956 "parsing stsd (sample table, sample description) atom");
7957 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7958 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7970 /* also read alac (or whatever) in stead of mp4a in the following,
7971 * since a similar layout is used in other cases as well */
7972 if (fourcc == FOURCC_mp4a)
7974 else if (fourcc == FOURCC_fLaC)
7979 /* There are two things we might encounter here: a true mp4a atom, and
7980 an mp4a entry in an stsd atom. The latter is what we're interested
7981 in, and it looks like an atom, but isn't really one. The true mp4a
7982 atom is short, so we detect it based on length here. */
7983 if (length < min_size) {
7984 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7985 GST_FOURCC_ARGS (fourcc));
7989 /* 'version' here is the sound sample description version. Types 0 and
7990 1 are documented in the QTFF reference, but type 2 is not: it's
7991 described in Apple header files instead (struct SoundDescriptionV2
7993 version = QT_UINT16 (buffer + 16);
7995 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7996 GST_FOURCC_ARGS (fourcc), version);
7998 /* parse any esds descriptors */
8010 GST_WARNING_OBJECT (qtdemux,
8011 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8012 GST_FOURCC_ARGS (fourcc), version);
8017 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8045 /* codec_data is contained inside these atoms, which all have
8046 * the same format. */
8047 /* video sample description size is 86 bytes without extension.
8048 * node_length have to be bigger than 86 bytes because video sample
8049 * description can include extensions such as esds, fiel, glbl, etc. */
8050 if (node_length < 86) {
8051 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8052 " sample description length too short (%u < 86)",
8053 GST_FOURCC_ARGS (fourcc), node_length);
8057 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8058 GST_FOURCC_ARGS (fourcc));
8060 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8062 * revision level (2 bytes) : must be set to 0. */
8063 version = QT_UINT32 (buffer + 16);
8064 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8066 /* compressor name : PASCAL string and informative purposes
8067 * first byte : the number of bytes to be displayed.
8068 * it has to be less than 32 because it is reserved
8069 * space of 32 bytes total including itself. */
8070 str_len = QT_UINT8 (buffer + 50);
8072 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8073 (char *) buffer + 51);
8075 GST_WARNING_OBJECT (qtdemux,
8076 "compressorname length too big (%u > 31)", str_len);
8078 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8080 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8085 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8087 /* You are reading this correctly. QTFF specifies that the
8088 * metadata atom is a short atom, whereas ISO BMFF specifies
8089 * it's a full atom. But since so many people are doing things
8090 * differently, we actually peek into the atom to see which
8093 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8094 GST_FOURCC_ARGS (fourcc));
8097 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8098 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8099 * starts with a 'hdlr' atom */
8100 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8101 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8102 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8103 * with version/flags both set to zero */
8104 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8106 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8111 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8112 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8113 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8122 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8123 GST_FOURCC_ARGS (fourcc));
8127 version = QT_UINT32 (buffer + 12);
8128 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8135 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8140 if (length < offset) {
8141 GST_WARNING_OBJECT (qtdemux,
8142 "skipping too small %" GST_FOURCC_FORMAT " box",
8143 GST_FOURCC_ARGS (fourcc));
8146 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8152 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8157 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8162 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8166 if (!strcmp (type->name, "unknown"))
8167 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8171 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8172 GST_FOURCC_ARGS (fourcc));
8178 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8179 (_("This file is corrupt and cannot be played.")),
8180 ("Not enough data for an atom header, got only %u bytes", length));
8185 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8186 (_("This file is corrupt and cannot be played.")),
8187 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8188 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8195 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8197 /* FIXME: This can only reliably work if demuxers have a
8198 * separate streaming thread per srcpad. This should be
8199 * done in a demuxer base class, which integrates parts
8202 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8207 query = gst_query_new_allocation (stream->caps, FALSE);
8209 if (!gst_pad_peer_query (stream->pad, query)) {
8210 /* not a problem, just debug a little */
8211 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8214 if (stream->allocator)
8215 gst_object_unref (stream->allocator);
8217 if (gst_query_get_n_allocation_params (query) > 0) {
8218 /* try the allocator */
8219 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8221 stream->use_allocator = TRUE;
8223 stream->allocator = NULL;
8224 gst_allocation_params_init (&stream->params);
8225 stream->use_allocator = FALSE;
8227 gst_query_unref (query);
8232 pad_query (const GValue * item, GValue * value, gpointer user_data)
8234 GstPad *pad = g_value_get_object (item);
8235 GstQuery *query = user_data;
8238 res = gst_pad_peer_query (pad, query);
8241 g_value_set_boolean (value, TRUE);
8245 GST_INFO_OBJECT (pad, "pad peer query failed");
8250 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8251 GstPadDirection direction)
8254 GstIteratorFoldFunction func = pad_query;
8255 GValue res = { 0, };
8257 g_value_init (&res, G_TYPE_BOOLEAN);
8258 g_value_set_boolean (&res, FALSE);
8261 if (direction == GST_PAD_SRC)
8262 it = gst_element_iterate_src_pads (element);
8264 it = gst_element_iterate_sink_pads (element);
8266 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8267 gst_iterator_resync (it);
8269 gst_iterator_free (it);
8271 return g_value_get_boolean (&res);
8275 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8276 QtDemuxStream * stream)
8280 GstElement *element = GST_ELEMENT (qtdemux);
8282 gchar **filtered_sys_ids;
8283 GValue event_list = G_VALUE_INIT;
8286 /* 1. Check if we already have the context. */
8287 if (qtdemux->preferred_protection_system_id != NULL) {
8288 GST_LOG_OBJECT (element,
8289 "already have the protection context, no need to request it again");
8293 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8294 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8295 (const gchar **) qtdemux->protection_system_ids->pdata);
8297 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8298 qtdemux->protection_system_ids->len - 1);
8299 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8300 "decryptors for %u of them, running context request",
8301 qtdemux->protection_system_ids->len,
8302 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8305 if (stream->protection_scheme_event_queue.length) {
8306 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8307 stream->protection_scheme_event_queue.length);
8308 walk = stream->protection_scheme_event_queue.tail;
8310 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8311 qtdemux->protection_event_queue.length);
8312 walk = qtdemux->protection_event_queue.tail;
8315 g_value_init (&event_list, GST_TYPE_LIST);
8316 for (; walk; walk = g_list_previous (walk)) {
8317 GValue *event_value = g_new0 (GValue, 1);
8318 g_value_init (event_value, GST_TYPE_EVENT);
8319 g_value_set_boxed (event_value, walk->data);
8320 gst_value_list_append_and_take_value (&event_list, event_value);
8323 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8324 * check if downstream already has a context of the specific type
8325 * 2b) Query upstream as above.
8327 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8328 st = gst_query_writable_structure (query);
8329 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8330 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8332 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8333 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8334 gst_query_parse_context (query, &ctxt);
8335 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8336 gst_element_set_context (element, ctxt);
8337 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8338 gst_query_parse_context (query, &ctxt);
8339 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8340 gst_element_set_context (element, ctxt);
8342 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8343 * the required context type and afterwards check if a
8344 * usable context was set now as in 1). The message could
8345 * be handled by the parent bins of the element and the
8350 GST_INFO_OBJECT (element, "posting need context message");
8351 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8352 "drm-preferred-decryption-system-id");
8353 st = (GstStructure *) gst_message_get_structure (msg);
8354 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8355 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8358 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8359 gst_element_post_message (element, msg);
8362 g_strfreev (filtered_sys_ids);
8363 g_value_unset (&event_list);
8364 gst_query_unref (query);
8368 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8369 QtDemuxStream * stream)
8372 const gchar *selected_system = NULL;
8374 g_return_val_if_fail (qtdemux != NULL, FALSE);
8375 g_return_val_if_fail (stream != NULL, FALSE);
8376 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8379 if (stream->protection_scheme_type == FOURCC_aavd) {
8380 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8381 if (!gst_structure_has_name (s, "application/x-aavd")) {
8382 gst_structure_set (s,
8383 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8385 gst_structure_set_name (s, "application/x-aavd");
8390 if (stream->protection_scheme_type != FOURCC_cenc
8391 && stream->protection_scheme_type != FOURCC_cbcs) {
8392 GST_ERROR_OBJECT (qtdemux,
8393 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8394 GST_FOURCC_ARGS (stream->protection_scheme_type));
8398 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8399 if (!gst_structure_has_name (s, "application/x-cenc")) {
8400 gst_structure_set (s,
8401 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8402 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8403 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8405 gst_structure_set_name (s, "application/x-cenc");
8408 if (qtdemux->protection_system_ids == NULL) {
8409 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8410 "cenc protection system information has been found, not setting a "
8411 "protection system UUID");
8415 gst_qtdemux_request_protection_context (qtdemux, stream);
8416 if (qtdemux->preferred_protection_system_id != NULL) {
8417 const gchar *preferred_system_array[] =
8418 { qtdemux->preferred_protection_system_id, NULL };
8420 selected_system = gst_protection_select_system (preferred_system_array);
8422 if (selected_system) {
8423 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8424 qtdemux->preferred_protection_system_id);
8426 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8427 "because there is no available decryptor",
8428 qtdemux->preferred_protection_system_id);
8432 if (!selected_system) {
8433 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8434 selected_system = gst_protection_select_system ((const gchar **)
8435 qtdemux->protection_system_ids->pdata);
8436 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8437 qtdemux->protection_system_ids->len - 1);
8440 if (!selected_system) {
8441 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8442 "suitable decryptor element has been found");
8446 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8449 gst_structure_set (s,
8450 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8457 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8459 /* fps is calculated base on the duration of the average framerate since
8460 * qt does not have a fixed framerate. */
8461 gboolean fps_available = TRUE;
8462 guint32 first_duration = 0;
8464 if (stream->n_samples > 0)
8465 first_duration = stream->samples[0].duration;
8467 if ((stream->n_samples == 1 && first_duration == 0)
8468 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8470 CUR_STREAM (stream)->fps_n = 0;
8471 CUR_STREAM (stream)->fps_d = 1;
8473 if (stream->duration == 0 || stream->n_samples < 2) {
8474 CUR_STREAM (stream)->fps_n = stream->timescale;
8475 CUR_STREAM (stream)->fps_d = 1;
8476 fps_available = FALSE;
8478 GstClockTime avg_duration;
8482 /* duration and n_samples can be updated for fragmented format
8483 * so, framerate of fragmented format is calculated using data in a moof */
8484 if (qtdemux->fragmented && stream->n_samples_moof > 0
8485 && stream->duration_moof > 0) {
8486 n_samples = stream->n_samples_moof;
8487 duration = stream->duration_moof;
8489 n_samples = stream->n_samples;
8490 duration = stream->duration;
8493 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8494 /* stream->duration is guint64, timescale, n_samples are guint32 */
8496 gst_util_uint64_scale_round (duration -
8497 first_duration, GST_SECOND,
8498 (guint64) (stream->timescale) * (n_samples - 1));
8500 GST_LOG_OBJECT (qtdemux,
8501 "Calculating avg sample duration based on stream (or moof) duration %"
8503 " minus first sample %u, leaving %d samples gives %"
8504 GST_TIME_FORMAT, duration, first_duration,
8505 n_samples - 1, GST_TIME_ARGS (avg_duration));
8508 gst_video_guess_framerate (avg_duration,
8509 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8511 GST_DEBUG_OBJECT (qtdemux,
8512 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8513 stream->timescale, CUR_STREAM (stream)->fps_n,
8514 CUR_STREAM (stream)->fps_d);
8518 return fps_available;
8522 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8524 if (stream->subtype == FOURCC_vide) {
8525 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8527 if (CUR_STREAM (stream)->caps) {
8528 CUR_STREAM (stream)->caps =
8529 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8531 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8532 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8533 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8534 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8536 /* set framerate if calculated framerate is reliable */
8537 if (fps_available) {
8538 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8539 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8540 CUR_STREAM (stream)->fps_d, NULL);
8543 /* calculate pixel-aspect-ratio using display width and height */
8544 GST_DEBUG_OBJECT (qtdemux,
8545 "video size %dx%d, target display size %dx%d",
8546 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8547 stream->display_width, stream->display_height);
8548 /* qt file might have pasp atom */
8549 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8550 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8551 CUR_STREAM (stream)->par_h);
8552 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8553 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8554 CUR_STREAM (stream)->par_h, NULL);
8555 } else if (stream->display_width > 0 && stream->display_height > 0
8556 && CUR_STREAM (stream)->width > 0
8557 && CUR_STREAM (stream)->height > 0) {
8560 /* calculate the pixel aspect ratio using the display and pixel w/h */
8561 n = stream->display_width * CUR_STREAM (stream)->height;
8562 d = stream->display_height * CUR_STREAM (stream)->width;
8565 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8566 CUR_STREAM (stream)->par_w = n;
8567 CUR_STREAM (stream)->par_h = d;
8568 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8569 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8570 CUR_STREAM (stream)->par_h, NULL);
8573 if (CUR_STREAM (stream)->interlace_mode > 0) {
8574 if (CUR_STREAM (stream)->interlace_mode == 1) {
8575 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8576 G_TYPE_STRING, "progressive", NULL);
8577 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8578 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8579 G_TYPE_STRING, "interleaved", NULL);
8580 if (CUR_STREAM (stream)->field_order == 9) {
8581 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8582 G_TYPE_STRING, "top-field-first", NULL);
8583 } else if (CUR_STREAM (stream)->field_order == 14) {
8584 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8585 G_TYPE_STRING, "bottom-field-first", NULL);
8590 /* Create incomplete colorimetry here if needed */
8591 if (CUR_STREAM (stream)->colorimetry.range ||
8592 CUR_STREAM (stream)->colorimetry.matrix ||
8593 CUR_STREAM (stream)->colorimetry.transfer
8594 || CUR_STREAM (stream)->colorimetry.primaries) {
8595 gchar *colorimetry =
8596 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8597 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8598 G_TYPE_STRING, colorimetry, NULL);
8599 g_free (colorimetry);
8602 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8603 guint par_w = 1, par_h = 1;
8605 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8606 par_w = CUR_STREAM (stream)->par_w;
8607 par_h = CUR_STREAM (stream)->par_h;
8610 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8611 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8613 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8616 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8617 "multiview-mode", G_TYPE_STRING,
8618 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8619 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8620 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8625 else if (stream->subtype == FOURCC_soun) {
8626 if (CUR_STREAM (stream)->caps) {
8627 CUR_STREAM (stream)->caps =
8628 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8629 if (CUR_STREAM (stream)->rate > 0)
8630 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8631 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8632 if (CUR_STREAM (stream)->n_channels > 0)
8633 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8634 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8635 if (CUR_STREAM (stream)->n_channels > 2) {
8636 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8637 * correctly; this is just the minimum we can do - assume
8638 * we don't actually have any channel positions. */
8639 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8640 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8645 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8646 const GstStructure *s;
8647 QtDemuxStream *fps_stream = NULL;
8648 gboolean fps_available = FALSE;
8650 /* CEA608 closed caption tracks are a bit special in that each sample
8651 * can contain CCs for multiple frames, and CCs can be omitted and have to
8652 * be inferred from the duration of the sample then.
8654 * As such we take the framerate from the (first) video track here for
8655 * CEA608 as there must be one CC byte pair for every video frame
8656 * according to the spec.
8658 * For CEA708 all is fine and there is one sample per frame.
8661 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8662 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8665 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8666 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8668 if (tmp->subtype == FOURCC_vide) {
8675 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8676 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8677 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8680 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8681 fps_stream = stream;
8684 CUR_STREAM (stream)->caps =
8685 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8687 /* set framerate if calculated framerate is reliable */
8688 if (fps_available) {
8689 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8690 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8691 CUR_STREAM (stream)->fps_d, NULL);
8696 GstCaps *prev_caps = NULL;
8698 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8699 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8700 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8701 gst_pad_set_active (stream->pad, TRUE);
8703 gst_pad_use_fixed_caps (stream->pad);
8705 if (stream->protected) {
8706 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8707 GST_ERROR_OBJECT (qtdemux,
8708 "Failed to configure protected stream caps.");
8713 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8714 CUR_STREAM (stream)->caps);
8715 if (stream->new_stream) {
8717 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8720 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8723 gst_event_parse_stream_flags (event, &stream_flags);
8724 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8725 qtdemux->have_group_id = TRUE;
8727 qtdemux->have_group_id = FALSE;
8728 gst_event_unref (event);
8729 } else if (!qtdemux->have_group_id) {
8730 qtdemux->have_group_id = TRUE;
8731 qtdemux->group_id = gst_util_group_id_next ();
8734 stream->new_stream = FALSE;
8735 event = gst_event_new_stream_start (stream->stream_id);
8736 if (qtdemux->have_group_id)
8737 gst_event_set_group_id (event, qtdemux->group_id);
8738 if (stream->disabled)
8739 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8740 if (CUR_STREAM (stream)->sparse) {
8741 stream_flags |= GST_STREAM_FLAG_SPARSE;
8743 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8745 gst_event_set_stream_flags (event, stream_flags);
8746 gst_pad_push_event (stream->pad, event);
8749 prev_caps = gst_pad_get_current_caps (stream->pad);
8751 if (CUR_STREAM (stream)->caps) {
8753 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8754 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8755 CUR_STREAM (stream)->caps);
8756 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8758 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8761 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8765 gst_caps_unref (prev_caps);
8766 stream->new_caps = FALSE;
8772 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8773 QtDemuxStream * stream)
8775 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8778 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8779 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8780 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8781 stream->stsd_entries_length)) {
8782 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8783 (_("This file is invalid and cannot be played.")),
8784 ("New sample description id is out of bounds (%d >= %d)",
8785 stream->stsd_sample_description_id, stream->stsd_entries_length));
8787 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8788 stream->new_caps = TRUE;
8793 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8794 QtDemuxStream * stream, GstTagList * list)
8796 gboolean ret = TRUE;
8798 if (stream->subtype == FOURCC_vide) {
8799 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8802 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8805 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8806 gst_object_unref (stream->pad);
8812 qtdemux->n_video_streams++;
8813 } else if (stream->subtype == FOURCC_soun) {
8814 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8817 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8819 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8820 gst_object_unref (stream->pad);
8825 qtdemux->n_audio_streams++;
8826 } else if (stream->subtype == FOURCC_strm) {
8827 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8828 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8829 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8830 || stream->subtype == FOURCC_clcp) {
8831 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8834 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8836 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8837 gst_object_unref (stream->pad);
8842 qtdemux->n_sub_streams++;
8843 } else if (CUR_STREAM (stream)->caps) {
8844 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8847 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8849 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8850 gst_object_unref (stream->pad);
8855 qtdemux->n_video_streams++;
8857 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8864 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8865 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8866 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8867 GST_OBJECT_LOCK (qtdemux);
8868 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8869 GST_OBJECT_UNLOCK (qtdemux);
8871 if (stream->stream_tags)
8872 gst_tag_list_unref (stream->stream_tags);
8873 stream->stream_tags = list;
8875 /* global tags go on each pad anyway */
8876 stream->send_global_tags = TRUE;
8877 /* send upstream GST_EVENT_PROTECTION events that were received before
8878 this source pad was created */
8879 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8880 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8884 gst_tag_list_unref (list);
8888 /* find next atom with @fourcc starting at @offset */
8889 static GstFlowReturn
8890 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8891 guint64 * length, guint32 fourcc)
8897 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8898 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8904 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8905 if (G_UNLIKELY (ret != GST_FLOW_OK))
8907 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8910 gst_buffer_unref (buf);
8913 gst_buffer_map (buf, &map, GST_MAP_READ);
8914 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8915 gst_buffer_unmap (buf, &map);
8916 gst_buffer_unref (buf);
8918 if (G_UNLIKELY (*length == 0)) {
8919 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8920 ret = GST_FLOW_ERROR;
8924 if (lfourcc == fourcc) {
8925 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
8926 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8929 GST_LOG_OBJECT (qtdemux,
8930 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8931 GST_FOURCC_ARGS (lfourcc), *offset);
8932 if (*offset == G_MAXUINT64)
8942 /* might simply have had last one */
8943 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8948 /* should only do something in pull mode */
8949 /* call with OBJECT lock */
8950 static GstFlowReturn
8951 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8953 guint64 length, offset;
8954 GstBuffer *buf = NULL;
8955 GstFlowReturn ret = GST_FLOW_OK;
8956 GstFlowReturn res = GST_FLOW_OK;
8959 offset = qtdemux->moof_offset;
8960 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8963 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8964 return GST_FLOW_EOS;
8967 /* best not do pull etc with lock held */
8968 GST_OBJECT_UNLOCK (qtdemux);
8970 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8971 if (ret != GST_FLOW_OK)
8974 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8975 if (G_UNLIKELY (ret != GST_FLOW_OK))
8977 gst_buffer_map (buf, &map, GST_MAP_READ);
8978 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8979 gst_buffer_unmap (buf, &map);
8980 gst_buffer_unref (buf);
8985 gst_buffer_unmap (buf, &map);
8986 gst_buffer_unref (buf);
8990 /* look for next moof */
8991 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8992 if (G_UNLIKELY (ret != GST_FLOW_OK))
8996 GST_OBJECT_LOCK (qtdemux);
8998 qtdemux->moof_offset = offset;
9004 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9006 res = GST_FLOW_ERROR;
9011 /* maybe upstream temporarily flushing */
9012 if (ret != GST_FLOW_FLUSHING) {
9013 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9016 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9017 /* resume at current position next time */
9025 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9029 gint32 stts_duration;
9030 GstByteWriter stsc, stts, stsz;
9032 /* Each sample has a different size, which we don't support for merging */
9033 if (stream->sample_size == 0) {
9034 GST_DEBUG_OBJECT (qtdemux,
9035 "Not all samples have the same size, not merging");
9039 /* The stream has a ctts table, we don't support that */
9040 if (stream->ctts_present) {
9041 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9045 /* If there's a sync sample table also ignore this stream */
9046 if (stream->stps_present || stream->stss_present) {
9047 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9051 /* If chunks are considered samples already ignore this stream */
9052 if (stream->chunks_are_samples) {
9053 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9057 /* Require that all samples have the same duration */
9058 if (stream->n_sample_times > 1) {
9059 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9063 /* Parse the stts to get the sample duration and number of samples */
9064 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9065 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9067 /* Parse the number of chunks from the stco manually because the
9068 * reader is already behind that */
9069 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9071 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9074 /* Now parse stsc, convert chunks into single samples and generate a
9075 * new stsc, stts and stsz from this information */
9076 gst_byte_writer_init (&stsc);
9077 gst_byte_writer_init (&stts);
9078 gst_byte_writer_init (&stsz);
9080 /* Note: we skip fourccs, size, version, flags and other fields of the new
9081 * atoms as the byte readers with them are already behind that position
9082 * anyway and only update the values of those inside the stream directly.
9084 stream->n_sample_times = 0;
9085 stream->n_samples = 0;
9086 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9088 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9090 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9091 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9092 sample_description_id =
9093 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9095 if (i == stream->n_samples_per_chunk - 1) {
9096 /* +1 because first_chunk is 1-based */
9097 last_chunk = num_chunks + 1;
9099 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9102 GST_DEBUG_OBJECT (qtdemux,
9103 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9104 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9106 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9107 /* One sample in this chunk */
9108 gst_byte_writer_put_uint32_be (&stsc, 1);
9109 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9111 /* For each chunk write a stts and stsz entry now */
9112 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9113 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9114 for (j = first_chunk; j < last_chunk; j++) {
9115 gst_byte_writer_put_uint32_be (&stsz,
9116 stream->sample_size * samples_per_chunk);
9119 stream->n_sample_times += 1;
9120 stream->n_samples += last_chunk - first_chunk;
9123 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9125 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9126 stream->n_samples, stream->n_sample_times);
9128 /* We don't have a fixed sample size anymore */
9129 stream->sample_size = 0;
9131 /* Free old data for the atoms */
9132 g_free ((gpointer) stream->stsz.data);
9133 stream->stsz.data = NULL;
9134 g_free ((gpointer) stream->stsc.data);
9135 stream->stsc.data = NULL;
9136 g_free ((gpointer) stream->stts.data);
9137 stream->stts.data = NULL;
9139 /* Store new data and replace byte readers */
9140 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9141 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9142 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9143 stream->stts.size = gst_byte_writer_get_size (&stts);
9144 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9145 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9146 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9147 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9148 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9151 /* initialise bytereaders for stbl sub-atoms */
9153 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9155 stream->stbl_index = -1; /* no samples have yet been parsed */
9156 stream->sample_index = -1;
9158 /* time-to-sample atom */
9159 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9162 /* copy atom data into a new buffer for later use */
9163 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9165 /* skip version + flags */
9166 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9167 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9169 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9171 /* make sure there's enough data */
9172 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9173 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9174 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9175 stream->n_sample_times);
9176 if (!stream->n_sample_times)
9180 /* sync sample atom */
9181 stream->stps_present = FALSE;
9182 if ((stream->stss_present =
9183 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9184 &stream->stss) ? TRUE : FALSE) == TRUE) {
9185 /* copy atom data into a new buffer for later use */
9186 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9188 /* skip version + flags */
9189 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9190 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9193 if (stream->n_sample_syncs) {
9194 /* make sure there's enough data */
9195 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9199 /* partial sync sample atom */
9200 if ((stream->stps_present =
9201 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9202 &stream->stps) ? TRUE : FALSE) == TRUE) {
9203 /* copy atom data into a new buffer for later use */
9204 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9206 /* skip version + flags */
9207 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9208 !gst_byte_reader_get_uint32_be (&stream->stps,
9209 &stream->n_sample_partial_syncs))
9212 /* if there are no entries, the stss table contains the real
9214 if (stream->n_sample_partial_syncs) {
9215 /* make sure there's enough data */
9216 if (!qt_atom_parser_has_chunks (&stream->stps,
9217 stream->n_sample_partial_syncs, 4))
9224 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9227 /* copy atom data into a new buffer for later use */
9228 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9230 /* skip version + flags */
9231 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9232 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9235 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9238 if (!stream->n_samples)
9241 /* sample-to-chunk atom */
9242 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9245 /* copy atom data into a new buffer for later use */
9246 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9248 /* skip version + flags */
9249 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9250 !gst_byte_reader_get_uint32_be (&stream->stsc,
9251 &stream->n_samples_per_chunk))
9254 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9255 stream->n_samples_per_chunk);
9257 /* make sure there's enough data */
9258 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9264 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9265 stream->co_size = sizeof (guint32);
9266 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9268 stream->co_size = sizeof (guint64);
9272 /* copy atom data into a new buffer for later use */
9273 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9275 /* skip version + flags */
9276 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9279 /* chunks_are_samples == TRUE means treat chunks as samples */
9280 stream->chunks_are_samples = stream->sample_size
9281 && !CUR_STREAM (stream)->sampled;
9282 if (stream->chunks_are_samples) {
9283 /* treat chunks as samples */
9284 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9287 /* skip number of entries */
9288 if (!gst_byte_reader_skip (&stream->stco, 4))
9291 /* make sure there are enough data in the stsz atom */
9292 if (!stream->sample_size) {
9293 /* different sizes for each sample */
9294 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9299 /* composition time-to-sample */
9300 if ((stream->ctts_present =
9301 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9302 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9303 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9305 /* copy atom data into a new buffer for later use */
9306 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9308 /* skip version + flags */
9309 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
9310 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9311 &stream->n_composition_times))
9314 /* make sure there's enough data */
9315 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9319 /* This is optional, if missing we iterate the ctts */
9320 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9321 if (!gst_byte_reader_skip (&cslg, 1 + 3)
9322 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
9323 g_free ((gpointer) cslg.data);
9327 gint32 cslg_least = 0;
9328 guint num_entries, pos;
9331 pos = gst_byte_reader_get_pos (&stream->ctts);
9332 num_entries = stream->n_composition_times;
9334 stream->cslg_shift = 0;
9336 for (i = 0; i < num_entries; i++) {
9339 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9340 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9341 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9342 * slightly inaccurate PTS could be more usable than corrupted one */
9343 if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
9344 GST_WARNING_OBJECT (qtdemux,
9345 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9346 " larger than duration %" G_GUINT64_FORMAT,
9347 offset, stream->duration);
9349 stream->cslg_shift = 0;
9350 stream->ctts_present = FALSE;
9354 if (offset < cslg_least)
9355 cslg_least = offset;
9359 stream->cslg_shift = ABS (cslg_least);
9361 stream->cslg_shift = 0;
9363 /* reset the reader so we can generate sample table */
9364 gst_byte_reader_set_pos (&stream->ctts, pos);
9367 /* Ensure the cslg_shift value is consistent so we can use it
9368 * unconditionally to produce TS and Segment */
9369 stream->cslg_shift = 0;
9372 /* For raw audio streams especially we might want to merge the samples
9373 * to not output one audio sample per buffer. We're doing this here
9374 * before allocating the sample tables so that from this point onwards
9375 * the number of container samples are static */
9376 if (stream->min_buffer_size > 0) {
9377 qtdemux_merge_sample_table (qtdemux, stream);
9381 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9382 stream->n_samples, (guint) sizeof (QtDemuxSample),
9383 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9385 if (stream->n_samples >=
9386 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9387 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9388 "be larger than %uMB (broken file?)", stream->n_samples,
9389 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9393 g_assert (stream->samples == NULL);
9394 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9395 if (!stream->samples) {
9396 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9405 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9406 (_("This file is corrupt and cannot be played.")), (NULL));
9411 gst_qtdemux_stbl_free (stream);
9412 if (!qtdemux->fragmented) {
9413 /* not quite good */
9414 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9417 /* may pick up samples elsewhere */
9423 /* collect samples from the next sample to be parsed up to sample @n for @stream
9424 * by reading the info from @stbl
9426 * This code can be executed from both the streaming thread and the seeking
9427 * thread so it takes the object lock to protect itself
9430 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9433 QtDemuxSample *samples, *first, *cur, *last;
9434 guint32 n_samples_per_chunk;
9437 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9438 GST_FOURCC_FORMAT ", pad %s",
9439 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9440 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9442 n_samples = stream->n_samples;
9445 goto out_of_samples;
9447 GST_OBJECT_LOCK (qtdemux);
9448 if (n <= stream->stbl_index)
9449 goto already_parsed;
9451 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9453 if (!stream->stsz.data) {
9454 /* so we already parsed and passed all the moov samples;
9455 * onto fragmented ones */
9456 g_assert (qtdemux->fragmented);
9460 /* pointer to the sample table */
9461 samples = stream->samples;
9463 /* starts from -1, moves to the next sample index to parse */
9464 stream->stbl_index++;
9466 /* keep track of the first and last sample to fill */
9467 first = &samples[stream->stbl_index];
9470 if (!stream->chunks_are_samples) {
9471 /* set the sample sizes */
9472 if (stream->sample_size == 0) {
9473 /* different sizes for each sample */
9474 for (cur = first; cur <= last; cur++) {
9475 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9476 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9477 (guint) (cur - samples), cur->size);
9480 /* samples have the same size */
9481 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9482 for (cur = first; cur <= last; cur++)
9483 cur->size = stream->sample_size;
9487 n_samples_per_chunk = stream->n_samples_per_chunk;
9490 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9493 if (stream->stsc_chunk_index >= stream->last_chunk
9494 || stream->stsc_chunk_index < stream->first_chunk) {
9495 stream->first_chunk =
9496 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9497 stream->samples_per_chunk =
9498 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9500 stream->stsd_sample_description_id =
9501 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9503 /* chunk numbers are counted from 1 it seems */
9504 if (G_UNLIKELY (stream->first_chunk == 0))
9507 --stream->first_chunk;
9509 /* the last chunk of each entry is calculated by taking the first chunk
9510 * of the next entry; except if there is no next, where we fake it with
9512 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9513 stream->last_chunk = G_MAXUINT32;
9515 stream->last_chunk =
9516 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9517 if (G_UNLIKELY (stream->last_chunk == 0))
9520 --stream->last_chunk;
9523 GST_LOG_OBJECT (qtdemux,
9524 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9525 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9526 stream->samples_per_chunk, stream->stsd_sample_description_id);
9528 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9531 if (stream->last_chunk != G_MAXUINT32) {
9532 if (!qt_atom_parser_peek_sub (&stream->stco,
9533 stream->first_chunk * stream->co_size,
9534 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9539 stream->co_chunk = stream->stco;
9540 if (!gst_byte_reader_skip (&stream->co_chunk,
9541 stream->first_chunk * stream->co_size))
9545 stream->stsc_chunk_index = stream->first_chunk;
9548 last_chunk = stream->last_chunk;
9550 if (stream->chunks_are_samples) {
9551 cur = &samples[stream->stsc_chunk_index];
9553 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9556 stream->stsc_chunk_index = j;
9561 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9564 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9565 "%" G_GUINT64_FORMAT, j, cur->offset);
9567 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9568 CUR_STREAM (stream)->bytes_per_frame > 0) {
9570 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9571 CUR_STREAM (stream)->samples_per_frame *
9572 CUR_STREAM (stream)->bytes_per_frame;
9574 cur->size = stream->samples_per_chunk;
9577 GST_DEBUG_OBJECT (qtdemux,
9578 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9579 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9580 stream->stco_sample_index)), cur->size);
9582 cur->timestamp = stream->stco_sample_index;
9583 cur->duration = stream->samples_per_chunk;
9584 cur->keyframe = TRUE;
9587 stream->stco_sample_index += stream->samples_per_chunk;
9589 stream->stsc_chunk_index = j;
9591 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9592 guint32 samples_per_chunk;
9593 guint64 chunk_offset;
9595 if (!stream->stsc_sample_index
9596 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9597 &stream->chunk_offset))
9600 samples_per_chunk = stream->samples_per_chunk;
9601 chunk_offset = stream->chunk_offset;
9603 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9604 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9605 G_GUINT64_FORMAT " and size %d",
9606 (guint) (cur - samples), chunk_offset, cur->size);
9608 cur->offset = chunk_offset;
9609 chunk_offset += cur->size;
9612 if (G_UNLIKELY (cur > last)) {
9614 stream->stsc_sample_index = k + 1;
9615 stream->chunk_offset = chunk_offset;
9616 stream->stsc_chunk_index = j;
9620 stream->stsc_sample_index = 0;
9622 stream->stsc_chunk_index = j;
9624 stream->stsc_index++;
9627 if (stream->chunks_are_samples)
9631 guint32 n_sample_times;
9633 n_sample_times = stream->n_sample_times;
9636 for (i = stream->stts_index; i < n_sample_times; i++) {
9637 guint32 stts_samples;
9638 gint32 stts_duration;
9641 if (stream->stts_sample_index >= stream->stts_samples
9642 || !stream->stts_sample_index) {
9644 stream->stts_samples =
9645 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9646 stream->stts_duration =
9647 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9649 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9650 i, stream->stts_samples, stream->stts_duration);
9652 stream->stts_sample_index = 0;
9655 stts_samples = stream->stts_samples;
9656 stts_duration = stream->stts_duration;
9657 stts_time = stream->stts_time;
9659 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9660 GST_DEBUG_OBJECT (qtdemux,
9661 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9662 (guint) (cur - samples), j,
9663 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9665 cur->timestamp = stts_time;
9666 cur->duration = stts_duration;
9668 /* avoid 32-bit wrap-around,
9669 * but still mind possible 'negative' duration */
9670 stts_time += (gint64) stts_duration;
9673 if (G_UNLIKELY (cur > last)) {
9675 stream->stts_time = stts_time;
9676 stream->stts_sample_index = j + 1;
9677 if (stream->stts_sample_index >= stream->stts_samples)
9678 stream->stts_index++;
9682 stream->stts_sample_index = 0;
9683 stream->stts_time = stts_time;
9684 stream->stts_index++;
9686 /* fill up empty timestamps with the last timestamp, this can happen when
9687 * the last samples do not decode and so we don't have timestamps for them.
9688 * We however look at the last timestamp to estimate the track length so we
9689 * need something in here. */
9690 for (; cur < last; cur++) {
9691 GST_DEBUG_OBJECT (qtdemux,
9692 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9693 (guint) (cur - samples),
9694 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9695 cur->timestamp = stream->stts_time;
9701 /* sample sync, can be NULL */
9702 if (stream->stss_present == TRUE) {
9703 guint32 n_sample_syncs;
9705 n_sample_syncs = stream->n_sample_syncs;
9707 if (!n_sample_syncs) {
9708 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9709 stream->all_keyframe = TRUE;
9711 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9712 /* note that the first sample is index 1, not 0 */
9715 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9717 if (G_LIKELY (index > 0 && index <= n_samples)) {
9719 samples[index].keyframe = TRUE;
9720 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9721 /* and exit if we have enough samples */
9722 if (G_UNLIKELY (index >= n)) {
9729 stream->stss_index = i;
9732 /* stps marks partial sync frames like open GOP I-Frames */
9733 if (stream->stps_present == TRUE) {
9734 guint32 n_sample_partial_syncs;
9736 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9738 /* if there are no entries, the stss table contains the real
9740 if (n_sample_partial_syncs) {
9741 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9742 /* note that the first sample is index 1, not 0 */
9745 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9747 if (G_LIKELY (index > 0 && index <= n_samples)) {
9749 samples[index].keyframe = TRUE;
9750 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9751 /* and exit if we have enough samples */
9752 if (G_UNLIKELY (index >= n)) {
9759 stream->stps_index = i;
9763 /* no stss, all samples are keyframes */
9764 stream->all_keyframe = TRUE;
9765 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9770 /* composition time to sample */
9771 if (stream->ctts_present == TRUE) {
9772 guint32 n_composition_times;
9774 gint32 ctts_soffset;
9776 /* Fill in the pts_offsets */
9778 n_composition_times = stream->n_composition_times;
9780 for (i = stream->ctts_index; i < n_composition_times; i++) {
9781 if (stream->ctts_sample_index >= stream->ctts_count
9782 || !stream->ctts_sample_index) {
9783 stream->ctts_count =
9784 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9785 stream->ctts_soffset =
9786 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9787 stream->ctts_sample_index = 0;
9790 ctts_count = stream->ctts_count;
9791 ctts_soffset = stream->ctts_soffset;
9793 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9794 cur->pts_offset = ctts_soffset;
9797 if (G_UNLIKELY (cur > last)) {
9799 stream->ctts_sample_index = j + 1;
9803 stream->ctts_sample_index = 0;
9804 stream->ctts_index++;
9808 stream->stbl_index = n;
9809 /* if index has been completely parsed, free data that is no-longer needed */
9810 if (n + 1 == stream->n_samples) {
9811 gst_qtdemux_stbl_free (stream);
9812 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9813 if (qtdemux->pullbased) {
9814 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9815 while (n + 1 == stream->n_samples)
9816 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9820 GST_OBJECT_UNLOCK (qtdemux);
9827 GST_LOG_OBJECT (qtdemux,
9828 "Tried to parse up to sample %u but this sample has already been parsed",
9830 /* if fragmented, there may be more */
9831 if (qtdemux->fragmented && n == stream->stbl_index)
9833 GST_OBJECT_UNLOCK (qtdemux);
9839 GST_LOG_OBJECT (qtdemux,
9840 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9842 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9843 (_("This file is corrupt and cannot be played.")), (NULL));
9848 GST_OBJECT_UNLOCK (qtdemux);
9849 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9850 (_("This file is corrupt and cannot be played.")), (NULL));
9855 /* collect all segment info for @stream.
9858 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9862 /* accept edts if they contain gaps at start and there is only
9863 * one media segment */
9864 gboolean allow_pushbased_edts = TRUE;
9865 gint media_segments_count = 0;
9867 /* parse and prepare segment info from the edit list */
9868 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9869 stream->n_segments = 0;
9870 stream->segments = NULL;
9871 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9874 gint segment_number, entry_size;
9877 const guint8 *buffer;
9881 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9882 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9885 buffer = elst->data;
9887 size = QT_UINT32 (buffer);
9888 /* version, flags, n_segments */
9890 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9893 version = QT_UINT8 (buffer + 8);
9894 entry_size = (version == 1) ? 20 : 12;
9896 n_segments = QT_UINT32 (buffer + 12);
9898 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9899 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9903 /* we might allocate a bit too much, at least allocate 1 segment */
9904 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9906 /* segments always start from 0 */
9910 for (segment_number = 0; segment_number < n_segments; segment_number++) {
9913 gboolean empty_edit = FALSE;
9914 QtDemuxSegment *segment;
9916 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9919 media_time = QT_UINT64 (buffer + 8);
9920 duration = QT_UINT64 (buffer);
9921 if (media_time == G_MAXUINT64)
9924 media_time = QT_UINT32 (buffer + 4);
9925 duration = QT_UINT32 (buffer);
9926 if (media_time == G_MAXUINT32)
9931 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9933 segment = &stream->segments[segment_number];
9935 /* time and duration expressed in global timescale */
9936 segment->time = stime;
9937 if (duration != 0 || empty_edit) {
9938 /* edge case: empty edits with duration=zero are treated here.
9939 * (files should not have these anyway). */
9941 /* add non scaled values so we don't cause roundoff errors */
9943 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9944 segment->duration = stime - segment->time;
9946 /* zero duration does not imply media_start == media_stop
9947 * but, only specify media_start. The edit ends with the track. */
9948 stime = segment->duration = GST_CLOCK_TIME_NONE;
9949 /* Don't allow more edits after this one. */
9950 n_segments = segment_number + 1;
9952 segment->stop_time = stime;
9954 segment->trak_media_start = media_time;
9955 /* media_time expressed in stream timescale */
9957 segment->media_start = media_start;
9958 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
9959 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
9960 media_segments_count++;
9962 segment->media_start = GST_CLOCK_TIME_NONE;
9963 segment->media_stop = GST_CLOCK_TIME_NONE;
9965 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9967 if (rate_int <= 1) {
9968 /* 0 is not allowed, some programs write 1 instead of the floating point
9970 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9974 segment->rate = rate_int / 65536.0;
9977 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9978 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9979 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9980 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9981 segment_number, GST_TIME_ARGS (segment->time),
9982 GST_TIME_ARGS (segment->duration),
9983 GST_TIME_ARGS (segment->media_start), media_time,
9984 GST_TIME_ARGS (segment->media_stop),
9985 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9987 if (segment->stop_time > qtdemux->segment.stop &&
9988 !qtdemux->upstream_format_is_time) {
9989 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9990 " extends to %" GST_TIME_FORMAT
9991 " past the end of the declared movie duration %" GST_TIME_FORMAT
9992 " movie segment will be extended", segment_number,
9993 GST_TIME_ARGS (segment->stop_time),
9994 GST_TIME_ARGS (qtdemux->segment.stop));
9995 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
9998 buffer += entry_size;
10000 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10001 stream->n_segments = n_segments;
10002 if (media_segments_count != 1)
10003 allow_pushbased_edts = FALSE;
10007 /* push based does not handle segments, so act accordingly here,
10008 * and warn if applicable */
10009 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10010 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10011 /* remove and use default one below, we stream like it anyway */
10012 g_free (stream->segments);
10013 stream->segments = NULL;
10014 stream->n_segments = 0;
10017 /* no segments, create one to play the complete trak */
10018 if (stream->n_segments == 0) {
10019 GstClockTime stream_duration =
10020 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10022 if (stream->segments == NULL)
10023 stream->segments = g_new (QtDemuxSegment, 1);
10025 /* represent unknown our way */
10026 if (stream_duration == 0)
10027 stream_duration = GST_CLOCK_TIME_NONE;
10029 stream->segments[0].time = 0;
10030 stream->segments[0].stop_time = stream_duration;
10031 stream->segments[0].duration = stream_duration;
10032 stream->segments[0].media_start = 0;
10033 stream->segments[0].media_stop = stream_duration;
10034 stream->segments[0].rate = 1.0;
10035 stream->segments[0].trak_media_start = 0;
10037 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10038 GST_TIME_ARGS (stream_duration));
10039 stream->n_segments = 1;
10040 stream->dummy_segment = TRUE;
10042 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10048 * Parses the stsd atom of a svq3 trak looking for
10049 * the SMI and gama atoms.
10052 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10053 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10055 const guint8 *_gamma = NULL;
10056 GstBuffer *_seqh = NULL;
10057 const guint8 *stsd_data = stsd_entry_data;
10058 guint32 length = QT_UINT32 (stsd_data);
10062 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10068 version = QT_UINT16 (stsd_data);
10069 if (version == 3) {
10070 if (length >= 70) {
10073 while (length > 8) {
10074 guint32 fourcc, size;
10075 const guint8 *data;
10076 size = QT_UINT32 (stsd_data);
10077 fourcc = QT_FOURCC (stsd_data + 4);
10078 data = stsd_data + 8;
10081 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10082 "svq3 atom parsing");
10091 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10092 " for gama atom, expected 12", size);
10097 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10099 if (_seqh != NULL) {
10100 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10101 " found, ignoring");
10103 seqh_size = QT_UINT32 (data + 4);
10104 if (seqh_size > 0) {
10105 _seqh = gst_buffer_new_and_alloc (seqh_size);
10106 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10113 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10114 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10118 if (size <= length) {
10124 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10127 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10128 G_GUINT16_FORMAT, version);
10138 } else if (_seqh) {
10139 gst_buffer_unref (_seqh);
10144 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10147 GstByteReader dref;
10151 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10152 * atom that might contain a 'data' atom with the rtsp uri.
10153 * This case was reported in bug #597497, some info about
10154 * the hndl atom can be found in TN1195
10156 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10157 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10160 guint32 dref_num_entries = 0;
10161 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10162 gst_byte_reader_skip (&dref, 4) &&
10163 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10166 /* search dref entries for hndl atom */
10167 for (i = 0; i < dref_num_entries; i++) {
10168 guint32 size = 0, type;
10169 guint8 string_len = 0;
10170 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10171 qt_atom_parser_get_fourcc (&dref, &type)) {
10172 if (type == FOURCC_hndl) {
10173 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10175 /* skip data reference handle bytes and the
10176 * following pascal string and some extra 4
10177 * bytes I have no idea what are */
10178 if (!gst_byte_reader_skip (&dref, 4) ||
10179 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10180 !gst_byte_reader_skip (&dref, string_len + 4)) {
10181 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10185 /* iterate over the atoms to find the data atom */
10186 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10190 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10191 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10192 if (atom_type == FOURCC_data) {
10193 const guint8 *uri_aux = NULL;
10195 /* found the data atom that might contain the rtsp uri */
10196 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10197 "hndl atom, interpreting it as an URI");
10198 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10200 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10201 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10203 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10204 "didn't contain a rtsp address");
10206 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10211 /* skipping to the next entry */
10212 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10215 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10222 /* skip to the next entry */
10223 if (!gst_byte_reader_skip (&dref, size - 8))
10226 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10229 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10235 #define AMR_NB_ALL_MODES 0x81ff
10236 #define AMR_WB_ALL_MODES 0x83ff
10238 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10240 /* The 'damr' atom is of the form:
10242 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10243 * 32 b 8 b 16 b 8 b 8 b
10245 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10246 * represents the highest mode used in the stream (and thus the maximum
10247 * bitrate), with a couple of special cases as seen below.
10250 /* Map of frame type ID -> bitrate */
10251 static const guint nb_bitrates[] = {
10252 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10254 static const guint wb_bitrates[] = {
10255 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10261 gst_buffer_map (buf, &map, GST_MAP_READ);
10263 if (map.size != 0x11) {
10264 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10268 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10269 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10270 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10274 mode_set = QT_UINT16 (map.data + 13);
10276 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10277 max_mode = 7 + (wb ? 1 : 0);
10279 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10280 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10282 if (max_mode == -1) {
10283 GST_DEBUG ("No mode indication was found (mode set) = %x",
10288 gst_buffer_unmap (buf, &map);
10289 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10292 gst_buffer_unmap (buf, &map);
10297 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10298 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10301 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10307 if (gst_byte_reader_get_remaining (reader) < 36)
10310 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10311 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10312 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10313 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10314 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10315 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10316 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10317 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10318 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10320 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10321 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10322 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10324 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10325 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10327 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10328 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10335 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10336 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10343 * This macro will only compare value abdegh, it expects cfi to have already
10346 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10347 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10349 /* only handle the cases where the last column has standard values */
10350 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10351 const gchar *rotation_tag = NULL;
10353 /* no rotation needed */
10354 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10356 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10357 rotation_tag = "rotate-90";
10358 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10359 rotation_tag = "rotate-180";
10360 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10361 rotation_tag = "rotate-270";
10363 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10366 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10367 GST_STR_NULL (rotation_tag));
10368 if (rotation_tag != NULL) {
10369 if (*taglist == NULL)
10370 *taglist = gst_tag_list_new_empty ();
10371 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10372 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10375 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10380 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10381 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10385 GstBuffer *adrm_buf = NULL;
10386 QtDemuxAavdEncryptionInfo *info;
10388 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10389 if (G_UNLIKELY (!adrm)) {
10390 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10393 adrm_size = QT_UINT32 (adrm->data);
10394 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10396 stream->protection_scheme_type = FOURCC_aavd;
10398 if (!stream->protection_scheme_info)
10399 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10401 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10403 if (info->default_properties)
10404 gst_structure_free (info->default_properties);
10405 info->default_properties = gst_structure_new ("application/x-aavd",
10406 "encrypted", G_TYPE_BOOLEAN, TRUE,
10407 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10408 gst_buffer_unref (adrm_buf);
10410 *original_fmt = FOURCC_mp4a;
10414 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10415 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10416 * Common Encryption (cenc), the function will also parse the tenc box (defined
10417 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10418 * (typically an enc[v|a|t|s] sample entry); the function will set
10419 * @original_fmt to the fourcc of the original unencrypted stream format.
10420 * Returns TRUE if successful; FALSE otherwise. */
10422 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10423 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10429 QtDemuxCencSampleSetInfo *info;
10431 const guint8 *tenc_data;
10433 g_return_val_if_fail (qtdemux != NULL, FALSE);
10434 g_return_val_if_fail (stream != NULL, FALSE);
10435 g_return_val_if_fail (container != NULL, FALSE);
10436 g_return_val_if_fail (original_fmt != NULL, FALSE);
10438 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10439 if (G_UNLIKELY (!sinf)) {
10440 if (stream->protection_scheme_type == FOURCC_cenc
10441 || stream->protection_scheme_type == FOURCC_cbcs) {
10442 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10443 "mandatory for Common Encryption");
10449 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10450 if (G_UNLIKELY (!frma)) {
10451 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10455 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10456 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10457 GST_FOURCC_ARGS (*original_fmt));
10459 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10461 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10464 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10465 stream->protection_scheme_version =
10466 QT_UINT32 ((const guint8 *) schm->data + 16);
10468 GST_DEBUG_OBJECT (qtdemux,
10469 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10470 "protection_scheme_version: %#010x",
10471 GST_FOURCC_ARGS (stream->protection_scheme_type),
10472 stream->protection_scheme_version);
10474 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10476 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10479 if (stream->protection_scheme_type != FOURCC_cenc &&
10480 stream->protection_scheme_type != FOURCC_piff &&
10481 stream->protection_scheme_type != FOURCC_cbcs) {
10482 GST_ERROR_OBJECT (qtdemux,
10483 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10484 GST_FOURCC_ARGS (stream->protection_scheme_type));
10488 if (G_UNLIKELY (!stream->protection_scheme_info))
10489 stream->protection_scheme_info =
10490 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10492 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10494 if (stream->protection_scheme_type == FOURCC_cenc
10495 || stream->protection_scheme_type == FOURCC_cbcs) {
10496 guint8 is_encrypted;
10498 guint8 constant_iv_size = 0;
10499 const guint8 *default_kid;
10500 guint8 crypt_byte_block = 0;
10501 guint8 skip_byte_block = 0;
10502 const guint8 *constant_iv = NULL;
10504 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10506 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10507 "which is mandatory for Common Encryption");
10510 tenc_data = (const guint8 *) tenc->data + 12;
10511 is_encrypted = QT_UINT8 (tenc_data + 2);
10512 iv_size = QT_UINT8 (tenc_data + 3);
10513 default_kid = (tenc_data + 4);
10514 if (stream->protection_scheme_type == FOURCC_cbcs) {
10515 guint8 possible_pattern_info;
10516 if (iv_size == 0) {
10517 constant_iv_size = QT_UINT8 (tenc_data + 20);
10518 if (constant_iv_size != 8 && constant_iv_size != 16) {
10519 GST_ERROR_OBJECT (qtdemux,
10520 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10523 constant_iv = (tenc_data + 21);
10525 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10526 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10527 skip_byte_block = possible_pattern_info & 0x0f;
10529 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10530 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10531 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10532 } else if (stream->protection_scheme_type == FOURCC_piff) {
10534 static const guint8 piff_track_encryption_uuid[] = {
10535 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10536 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10539 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10541 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10542 "which is mandatory for Common Encryption");
10546 tenc_data = (const guint8 *) tenc->data + 8;
10547 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10548 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10549 GST_ERROR_OBJECT (qtdemux,
10550 "Unsupported track encryption box with uuid: %s", box_uuid);
10554 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10555 gst_byte_reader_init (&br, tenc_data, 20);
10556 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10557 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10560 stream->protection_scheme_type = FOURCC_cenc;
10567 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10568 QtDemuxStream ** stream2)
10570 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10574 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10579 /*parse svmi header if existing */
10580 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10582 guint len = QT_UINT32 ((guint8 *) svmi->data);
10583 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10585 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10586 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10587 guint8 frame_type, frame_layout;
10588 guint32 stereo_mono_change_count;
10593 /* MPEG-A stereo video */
10594 if (qtdemux->major_brand == FOURCC_ss02)
10595 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10597 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10598 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10599 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10601 switch (frame_type) {
10603 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10606 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10609 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10612 /* mode 3 is primary/secondary view sequence, ie
10613 * left/right views in separate tracks. See section 7.2
10614 * of ISO/IEC 23000-11:2009 */
10615 /* In the future this might be supported using related
10616 * streams, like an enhancement track - if files like this
10618 GST_FIXME_OBJECT (qtdemux,
10619 "Implement stereo video in separate streams");
10622 if ((frame_layout & 0x1) == 0)
10623 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10625 GST_LOG_OBJECT (qtdemux,
10626 "StereoVideo: composition type: %u, is_left_first: %u",
10627 frame_type, frame_layout);
10629 if (stereo_mono_change_count > 1) {
10630 GST_FIXME_OBJECT (qtdemux,
10631 "Mixed-mono flags are not yet supported in qtdemux.");
10634 stream->multiview_mode = mode;
10635 stream->multiview_flags = flags;
10642 /* parse the traks.
10643 * With each track we associate a new QtDemuxStream that contains all the info
10645 * traks that do not decode to something (like strm traks) will not have a pad.
10648 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10650 GstByteReader tkhd;
10664 QtDemuxStream *stream = NULL;
10665 const guint8 *stsd_data;
10666 const guint8 *stsd_entry_data;
10667 guint remaining_stsd_len;
10668 guint stsd_entry_count;
10670 guint16 lang_code; /* quicktime lang code or packed iso code */
10672 guint32 tkhd_flags = 0;
10673 guint8 tkhd_version = 0;
10674 guint32 w = 0, h = 0;
10675 guint value_size, stsd_len, len;
10679 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10681 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10682 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10683 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10686 /* pick between 64 or 32 bits */
10687 value_size = tkhd_version == 1 ? 8 : 4;
10688 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10689 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10692 /* Check if current moov has duplicated track_id */
10693 if (qtdemux_find_stream (qtdemux, track_id))
10694 goto existing_stream;
10696 stream = _create_stream (qtdemux, track_id);
10697 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10699 /* need defaults for fragments */
10700 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10702 if ((tkhd_flags & 1) == 0)
10703 stream->disabled = TRUE;
10705 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10706 tkhd_version, tkhd_flags, stream->track_id);
10708 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10711 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10712 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10713 if (qtdemux->major_brand != FOURCC_mjp2 ||
10714 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10718 len = QT_UINT32 ((guint8 *) mdhd->data);
10719 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10720 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10721 if (version == 0x01000000) {
10724 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10725 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10726 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
10730 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10731 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10732 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10735 if (lang_code < 0x400) {
10736 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10737 } else if (lang_code == 0x7fff) {
10738 stream->lang_id[0] = 0; /* unspecified */
10740 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10741 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10742 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10743 stream->lang_id[3] = 0;
10746 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10747 stream->timescale);
10748 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10750 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10751 lang_code, stream->lang_id);
10753 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10756 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10757 /* chapters track reference */
10758 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10760 gsize length = GST_READ_UINT32_BE (chap->data);
10761 if (qtdemux->chapters_track_id)
10762 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10764 if (length >= 12) {
10765 qtdemux->chapters_track_id =
10766 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10771 /* fragmented files may have bogus duration in moov */
10772 if (!qtdemux->fragmented &&
10773 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10774 guint64 tdur1, tdur2;
10776 /* don't overflow */
10777 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10778 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10781 * some of those trailers, nowadays, have prologue images that are
10782 * themselves video tracks as well. I haven't really found a way to
10783 * identify those yet, except for just looking at their duration. */
10784 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10785 GST_WARNING_OBJECT (qtdemux,
10786 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10787 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10788 "found, assuming preview image or something; skipping track",
10789 stream->duration, stream->timescale, qtdemux->duration,
10790 qtdemux->timescale);
10791 gst_qtdemux_stream_unref (stream);
10796 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10799 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10800 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10802 len = QT_UINT32 ((guint8 *) hdlr->data);
10804 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10805 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10806 GST_FOURCC_ARGS (stream->subtype));
10808 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10811 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10814 /* Parse out svmi (and later st3d/sv3d) atoms */
10815 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
10818 /* parse rest of tkhd */
10819 if (stream->subtype == FOURCC_vide) {
10822 /* version 1 uses some 64-bit ints */
10823 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10826 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10829 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10830 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10833 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10834 &stream->stream_tags);
10838 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10840 stsd_data = (const guint8 *) stsd->data;
10842 /* stsd should at least have one entry */
10843 stsd_len = QT_UINT32 (stsd_data);
10844 if (stsd_len < 24) {
10845 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10846 if (stream->subtype == FOURCC_vivo) {
10847 gst_qtdemux_stream_unref (stream);
10854 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10855 /* each stsd entry must contain at least 8 bytes */
10856 if (stream->stsd_entries_length == 0
10857 || stream->stsd_entries_length > stsd_len / 8) {
10858 stream->stsd_entries_length = 0;
10861 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10862 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
10863 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
10865 stsd_entry_data = stsd_data + 16;
10866 remaining_stsd_len = stsd_len - 16;
10867 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10869 gchar *codec = NULL;
10870 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10872 /* and that entry should fit within stsd */
10873 len = QT_UINT32 (stsd_entry_data);
10874 if (len > remaining_stsd_len)
10877 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10878 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
10879 GST_FOURCC_ARGS (entry->fourcc));
10880 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
10882 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10883 goto error_encrypted;
10885 if (fourcc == FOURCC_aavd) {
10886 if (stream->subtype != FOURCC_soun) {
10887 GST_ERROR_OBJECT (qtdemux,
10888 "Unexpeced stsd type 'aavd' outside 'soun' track");
10890 /* encrypted audio with sound sample description v0 */
10891 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10892 stream->protected = TRUE;
10893 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
10894 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10898 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10899 /* FIXME this looks wrong, there might be multiple children
10900 * with the same type */
10901 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10902 stream->protected = TRUE;
10903 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10904 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10907 if (stream->subtype == FOURCC_vide) {
10912 gint depth, palette_size, palette_count;
10913 guint32 *palette_data = NULL;
10915 entry->sampled = TRUE;
10917 stream->display_width = w >> 16;
10918 stream->display_height = h >> 16;
10921 if (len < 86) /* TODO verify */
10924 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10925 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10926 entry->fps_n = 0; /* this is filled in later */
10927 entry->fps_d = 0; /* this is filled in later */
10928 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10929 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10931 /* if color_table_id is 0, ctab atom must follow; however some files
10932 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10933 * if color table is not present we'll correct the value */
10934 if (entry->color_table_id == 0 &&
10936 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10937 entry->color_table_id = -1;
10940 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10941 entry->width, entry->height, entry->bits_per_sample,
10942 entry->color_table_id);
10944 depth = entry->bits_per_sample;
10946 /* more than 32 bits means grayscale */
10947 gray = (depth > 32);
10948 /* low 32 bits specify the depth */
10951 /* different number of palette entries is determined by depth. */
10953 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10954 palette_count = (1 << depth);
10955 palette_size = palette_count * 4;
10957 if (entry->color_table_id) {
10958 switch (palette_count) {
10962 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
10965 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
10970 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
10972 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
10977 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
10980 g_memdup2 (ff_qt_default_palette_256, palette_size);
10983 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10984 (_("The video in this file might not play correctly.")),
10985 ("unsupported palette depth %d", depth));
10989 gint i, j, start, end;
10995 start = QT_UINT32 (stsd_entry_data + offset + 70);
10996 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10997 end = QT_UINT16 (stsd_entry_data + offset + 76);
10999 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11000 start, end, palette_count);
11007 if (len < 94 + (end - start) * 8)
11010 /* palette is always the same size */
11011 palette_data = g_malloc0 (256 * 4);
11012 palette_size = 256 * 4;
11014 for (j = 0, i = start; i <= end; j++, i++) {
11015 guint32 a, r, g, b;
11017 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11018 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11019 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11020 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11022 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11023 (g & 0xff00) | (b >> 8);
11028 gst_caps_unref (entry->caps);
11031 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11033 if (G_UNLIKELY (!entry->caps)) {
11034 g_free (palette_data);
11035 goto unknown_stream;
11039 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11040 GST_TAG_VIDEO_CODEC, codec, NULL);
11045 if (palette_data) {
11048 if (entry->rgb8_palette)
11049 gst_memory_unref (entry->rgb8_palette);
11050 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11051 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11053 s = gst_caps_get_structure (entry->caps, 0);
11055 /* non-raw video has a palette_data property. raw video has the palette as
11056 * an extra plane that we append to the output buffers before we push
11058 if (!gst_structure_has_name (s, "video/x-raw")) {
11059 GstBuffer *palette;
11061 palette = gst_buffer_new ();
11062 gst_buffer_append_memory (palette, entry->rgb8_palette);
11063 entry->rgb8_palette = NULL;
11065 gst_caps_set_simple (entry->caps, "palette_data",
11066 GST_TYPE_BUFFER, palette, NULL);
11067 gst_buffer_unref (palette);
11069 } else if (palette_count != 0) {
11070 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11071 (NULL), ("Unsupported palette depth %d", depth));
11074 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11075 QT_UINT16 (stsd_entry_data + offset + 32));
11081 /* pick 'the' stsd child */
11082 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11083 // We should skip parsing the stsd for non-protected streams if
11084 // the entry doesn't match the fourcc, since they don't change
11085 // format. However, for protected streams we can have partial
11086 // encryption, where parts of the stream are encrypted and parts
11087 // not. For both parts of such streams, we should ensure the
11088 // esds overrides are parsed for both from the stsd.
11089 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11090 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11092 else if (!stream->protected)
11097 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11098 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11099 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11100 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11104 const guint8 *pasp_data = (const guint8 *) pasp->data;
11105 gint len = QT_UINT32 (pasp_data);
11108 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11109 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11111 CUR_STREAM (stream)->par_w = 0;
11112 CUR_STREAM (stream)->par_h = 0;
11115 CUR_STREAM (stream)->par_w = 0;
11116 CUR_STREAM (stream)->par_h = 0;
11120 const guint8 *fiel_data = (const guint8 *) fiel->data;
11121 gint len = QT_UINT32 (fiel_data);
11124 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11125 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11130 const guint8 *colr_data = (const guint8 *) colr->data;
11131 gint len = QT_UINT32 (colr_data);
11133 if (len == 19 || len == 18) {
11134 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11136 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11137 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11138 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11139 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11140 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11142 CUR_STREAM (stream)->colorimetry.primaries =
11143 gst_video_color_primaries_from_iso (primaries);
11144 CUR_STREAM (stream)->colorimetry.transfer =
11145 gst_video_transfer_function_from_iso (transfer_function);
11146 CUR_STREAM (stream)->colorimetry.matrix =
11147 gst_video_color_matrix_from_iso (matrix);
11148 CUR_STREAM (stream)->colorimetry.range =
11149 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11150 GST_VIDEO_COLOR_RANGE_16_235;
11152 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11155 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11160 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11161 stream->stream_tags);
11168 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11169 const guint8 *avc_data = stsd_entry_data + 0x56;
11172 while (len >= 0x8) {
11175 if (QT_UINT32 (avc_data) <= len)
11176 size = QT_UINT32 (avc_data) - 0x8;
11181 /* No real data, so break out */
11184 switch (QT_FOURCC (avc_data + 0x4)) {
11187 /* parse, if found */
11190 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11192 /* First 4 bytes are the length of the atom, the next 4 bytes
11193 * are the fourcc, the next 1 byte is the version, and the
11194 * subsequent bytes are profile_tier_level structure like data. */
11195 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11196 avc_data + 8 + 1, size - 1);
11197 buf = gst_buffer_new_and_alloc (size);
11198 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11199 gst_caps_set_simple (entry->caps,
11200 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11201 gst_buffer_unref (buf);
11209 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11211 /* First 4 bytes are the length of the atom, the next 4 bytes
11212 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11213 * next 1 byte is the version, and the
11214 * subsequent bytes are sequence parameter set like data. */
11216 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11218 gst_codec_utils_h264_caps_set_level_and_profile
11219 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11221 buf = gst_buffer_new_and_alloc (size);
11222 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11223 gst_caps_set_simple (entry->caps,
11224 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11225 gst_buffer_unref (buf);
11231 guint avg_bitrate, max_bitrate;
11233 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11237 max_bitrate = QT_UINT32 (avc_data + 0xc);
11238 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11240 if (!max_bitrate && !avg_bitrate)
11243 /* Some muxers seem to swap the average and maximum bitrates
11244 * (I'm looking at you, YouTube), so we swap for sanity. */
11245 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11246 guint temp = avg_bitrate;
11248 avg_bitrate = max_bitrate;
11249 max_bitrate = temp;
11252 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11253 gst_tag_list_add (stream->stream_tags,
11254 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11255 max_bitrate, NULL);
11257 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11258 gst_tag_list_add (stream->stream_tags,
11259 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11271 avc_data += size + 8;
11282 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11283 const guint8 *hevc_data = stsd_entry_data + 0x56;
11286 while (len >= 0x8) {
11289 if (QT_UINT32 (hevc_data) <= len)
11290 size = QT_UINT32 (hevc_data) - 0x8;
11295 /* No real data, so break out */
11298 switch (QT_FOURCC (hevc_data + 0x4)) {
11301 /* parse, if found */
11304 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11306 /* First 4 bytes are the length of the atom, the next 4 bytes
11307 * are the fourcc, the next 1 byte is the version, and the
11308 * subsequent bytes are sequence parameter set like data. */
11309 gst_codec_utils_h265_caps_set_level_tier_and_profile
11310 (entry->caps, hevc_data + 8 + 1, size - 1);
11312 buf = gst_buffer_new_and_alloc (size);
11313 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11314 gst_caps_set_simple (entry->caps,
11315 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11316 gst_buffer_unref (buf);
11323 hevc_data += size + 8;
11336 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11337 GST_FOURCC_ARGS (fourcc));
11339 /* codec data might be in glbl extension atom */
11341 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11347 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11349 len = QT_UINT32 (data);
11352 buf = gst_buffer_new_and_alloc (len);
11353 gst_buffer_fill (buf, 0, data + 8, len);
11354 gst_caps_set_simple (entry->caps,
11355 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11356 gst_buffer_unref (buf);
11363 /* see annex I of the jpeg2000 spec */
11364 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11365 const guint8 *data;
11366 const gchar *colorspace = NULL;
11368 guint32 ncomp_map = 0;
11369 gint32 *comp_map = NULL;
11370 guint32 nchan_def = 0;
11371 gint32 *chan_def = NULL;
11373 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11374 /* some required atoms */
11375 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11378 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11382 /* number of components; redundant with info in codestream, but useful
11384 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11385 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11387 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11389 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11392 GST_DEBUG_OBJECT (qtdemux, "found colr");
11393 /* extract colour space info */
11394 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11395 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11397 colorspace = "sRGB";
11400 colorspace = "GRAY";
11403 colorspace = "sYUV";
11411 /* colr is required, and only values 16, 17, and 18 are specified,
11412 so error if we have no colorspace */
11415 /* extract component mapping */
11416 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11418 guint32 cmap_len = 0;
11420 cmap_len = QT_UINT32 (cmap->data);
11421 if (cmap_len >= 8) {
11422 /* normal box, subtract off header */
11424 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11425 if (cmap_len % 4 == 0) {
11426 ncomp_map = (cmap_len / 4);
11427 comp_map = g_new0 (gint32, ncomp_map);
11428 for (i = 0; i < ncomp_map; i++) {
11431 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11432 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11433 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11434 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11439 /* extract channel definitions */
11440 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11442 guint32 cdef_len = 0;
11444 cdef_len = QT_UINT32 (cdef->data);
11445 if (cdef_len >= 10) {
11446 /* normal box, subtract off header and len */
11448 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11449 if (cdef_len % 6 == 0) {
11450 nchan_def = (cdef_len / 6);
11451 chan_def = g_new0 (gint32, nchan_def);
11452 for (i = 0; i < nchan_def; i++)
11454 for (i = 0; i < nchan_def; i++) {
11455 guint16 cn, typ, asoc;
11456 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11457 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11458 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11459 if (cn < nchan_def) {
11462 chan_def[cn] = asoc;
11465 chan_def[cn] = 0; /* alpha */
11468 chan_def[cn] = -typ;
11476 gst_caps_set_simple (entry->caps,
11477 "num-components", G_TYPE_INT, ncomp, NULL);
11478 gst_caps_set_simple (entry->caps,
11479 "colorspace", G_TYPE_STRING, colorspace, NULL);
11482 GValue arr = { 0, };
11483 GValue elt = { 0, };
11485 g_value_init (&arr, GST_TYPE_ARRAY);
11486 g_value_init (&elt, G_TYPE_INT);
11487 for (i = 0; i < ncomp_map; i++) {
11488 g_value_set_int (&elt, comp_map[i]);
11489 gst_value_array_append_value (&arr, &elt);
11491 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11492 "component-map", &arr);
11493 g_value_unset (&elt);
11494 g_value_unset (&arr);
11499 GValue arr = { 0, };
11500 GValue elt = { 0, };
11502 g_value_init (&arr, GST_TYPE_ARRAY);
11503 g_value_init (&elt, G_TYPE_INT);
11504 for (i = 0; i < nchan_def; i++) {
11505 g_value_set_int (&elt, chan_def[i]);
11506 gst_value_array_append_value (&arr, &elt);
11508 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11509 "channel-definitions", &arr);
11510 g_value_unset (&elt);
11511 g_value_unset (&arr);
11515 /* some optional atoms */
11516 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11517 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11519 /* indicate possible fields in caps */
11521 data = (guint8 *) field->data + 8;
11523 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11524 (gint) * data, NULL);
11526 /* add codec_data if provided */
11531 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11532 data = prefix->data;
11533 len = QT_UINT32 (data);
11536 buf = gst_buffer_new_and_alloc (len);
11537 gst_buffer_fill (buf, 0, data + 8, len);
11538 gst_caps_set_simple (entry->caps,
11539 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11540 gst_buffer_unref (buf);
11549 GstBuffer *seqh = NULL;
11550 const guint8 *gamma_data = NULL;
11551 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11553 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11556 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11557 QT_FP32 (gamma_data), NULL);
11560 /* sorry for the bad name, but we don't know what this is, other
11561 * than its own fourcc */
11562 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11564 gst_buffer_unref (seqh);
11567 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11568 buf = gst_buffer_new_and_alloc (len);
11569 gst_buffer_fill (buf, 0, stsd_data, len);
11570 gst_caps_set_simple (entry->caps,
11571 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11572 gst_buffer_unref (buf);
11577 /* https://developer.apple.com/standards/qtff-2001.pdf,
11578 * page 92, "Video Sample Description", under table 3.1 */
11581 const gint compressor_offset =
11582 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11583 const gint min_size = compressor_offset + 32 + 2 + 2;
11586 guint16 color_table_id = 0;
11589 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11591 /* recover information on interlaced/progressive */
11592 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11596 len = QT_UINT32 (jpeg->data);
11597 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11599 if (len >= min_size) {
11600 gst_byte_reader_init (&br, jpeg->data, len);
11602 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11603 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11604 if (color_table_id != 0) {
11605 /* the spec says there can be concatenated chunks in the data, and we want
11606 * to find one called field. Walk through them. */
11607 gint offset = min_size;
11608 while (offset + 8 < len) {
11609 guint32 size = 0, tag;
11610 ok = gst_byte_reader_get_uint32_le (&br, &size);
11611 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11612 if (!ok || size < 8) {
11613 GST_WARNING_OBJECT (qtdemux,
11614 "Failed to walk optional chunk list");
11617 GST_DEBUG_OBJECT (qtdemux,
11618 "Found optional %4.4s chunk, size %u",
11619 (const char *) &tag, size);
11620 if (tag == FOURCC_fiel) {
11621 guint8 n_fields = 0, ordering = 0;
11622 gst_byte_reader_get_uint8 (&br, &n_fields);
11623 gst_byte_reader_get_uint8 (&br, &ordering);
11624 if (n_fields == 1 || n_fields == 2) {
11625 GST_DEBUG_OBJECT (qtdemux,
11626 "Found fiel tag with %u fields, ordering %u",
11627 n_fields, ordering);
11629 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11630 "interlace-mode", G_TYPE_STRING, "interleaved",
11633 GST_WARNING_OBJECT (qtdemux,
11634 "Found fiel tag with invalid fields (%u)", n_fields);
11640 GST_DEBUG_OBJECT (qtdemux,
11641 "Color table ID is 0, not trying to get interlacedness");
11644 GST_WARNING_OBJECT (qtdemux,
11645 "Length of jpeg chunk is too small, not trying to get interlacedness");
11653 gst_caps_set_simple (entry->caps,
11654 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11660 GNode *xith, *xdxt;
11662 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11663 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11667 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11671 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11672 /* collect the headers and store them in a stream list so that we can
11673 * send them out first */
11674 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11684 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11685 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11688 ovc1_data = ovc1->data;
11689 ovc1_len = QT_UINT32 (ovc1_data);
11690 if (ovc1_len <= 198) {
11691 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11694 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11695 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11696 gst_caps_set_simple (entry->caps,
11697 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11698 gst_buffer_unref (buf);
11703 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11704 const guint8 *vc1_data = stsd_entry_data + 0x56;
11710 if (QT_UINT32 (vc1_data) <= len)
11711 size = QT_UINT32 (vc1_data) - 8;
11716 /* No real data, so break out */
11719 switch (QT_FOURCC (vc1_data + 0x4)) {
11720 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11724 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11725 buf = gst_buffer_new_and_alloc (size);
11726 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11727 gst_caps_set_simple (entry->caps,
11728 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11729 gst_buffer_unref (buf);
11736 vc1_data += size + 8;
11742 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11743 const guint8 *av1_data = stsd_entry_data + 0x56;
11746 while (len >= 0x8) {
11749 if (QT_UINT32 (av1_data) <= len)
11750 size = QT_UINT32 (av1_data) - 0x8;
11755 /* No real data, so break out */
11758 switch (QT_FOURCC (av1_data + 0x4)) {
11761 /* parse, if found */
11763 guint8 pres_delay_field;
11765 GST_DEBUG_OBJECT (qtdemux,
11766 "found av1C codec_data in stsd of size %d", size);
11768 /* not enough data, just ignore and hope for the best */
11773 * 4 bytes: atom length
11778 * 1 bits: initial_presentation_delay_present
11779 * 4 bits: initial_presentation_delay (if present else reserved
11783 if (av1_data[9] != 0) {
11784 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11788 /* We skip initial_presentation_delay* for now */
11789 pres_delay_field = *(av1_data + 12);
11790 if (pres_delay_field & (1 << 5)) {
11791 gst_caps_set_simple (entry->caps,
11792 "presentation-delay", G_TYPE_INT,
11793 (gint) (pres_delay_field & 0x0F) + 1, NULL);
11796 buf = gst_buffer_new_and_alloc (size - 5);
11797 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11798 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
11799 gst_caps_set_simple (entry->caps,
11800 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11801 gst_buffer_unref (buf);
11810 av1_data += size + 8;
11816 /* TODO: Need to parse vpcC for VP8 codec too.
11817 * Note that VPCodecConfigurationBox (vpcC) is defined for
11818 * vp08, vp09, and vp10 fourcc. */
11821 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11822 const guint8 *vpcc_data = stsd_entry_data + 0x56;
11825 while (len >= 0x8) {
11828 if (QT_UINT32 (vpcc_data) <= len)
11829 size = QT_UINT32 (vpcc_data) - 0x8;
11834 /* No real data, so break out */
11837 switch (QT_FOURCC (vpcc_data + 0x4)) {
11840 const gchar *profile_str = NULL;
11841 const gchar *chroma_format_str = NULL;
11844 guint8 chroma_format;
11845 GstVideoColorimetry cinfo;
11847 /* parse, if found */
11848 GST_DEBUG_OBJECT (qtdemux,
11849 "found vp codec_data in stsd of size %d", size);
11851 /* the meaning of "size" is length of the atom body, excluding
11852 * atom length and fourcc fields */
11857 * 4 bytes: atom length
11864 * 3 bits: chromaSubsampling
11865 * 1 bit: videoFullRangeFlag
11866 * 1 byte: colourPrimaries
11867 * 1 byte: transferCharacteristics
11868 * 1 byte: matrixCoefficients
11869 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
11870 * rest: codecIntializationData (not used for vp8 and vp9)
11873 if (vpcc_data[8] != 1) {
11874 GST_WARNING_OBJECT (qtdemux,
11875 "unknown vpcC version %d", vpcc_data[8]);
11879 profile = vpcc_data[12];
11898 gst_caps_set_simple (entry->caps,
11899 "profile", G_TYPE_STRING, profile_str, NULL);
11902 /* skip level, the VP9 spec v0.6 defines only one level atm,
11903 * but webm spec define various ones. Add level to caps
11904 * if we really need it then */
11906 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
11907 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
11908 gst_caps_set_simple (entry->caps,
11909 "bit-depth-luma", G_TYPE_UINT, bitdepth,
11910 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
11913 chroma_format = (vpcc_data[14] & 0xe) >> 1;
11914 switch (chroma_format) {
11917 chroma_format_str = "4:2:0";
11920 chroma_format_str = "4:2:2";
11923 chroma_format_str = "4:4:4";
11929 if (chroma_format_str) {
11930 gst_caps_set_simple (entry->caps,
11931 "chroma-format", G_TYPE_STRING, chroma_format_str,
11935 if ((vpcc_data[14] & 0x1) != 0)
11936 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
11938 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
11940 gst_video_color_primaries_from_iso (vpcc_data[15]);
11942 gst_video_transfer_function_from_iso (vpcc_data[16]);
11944 gst_video_color_matrix_from_iso (vpcc_data[17]);
11946 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
11947 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
11948 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
11949 /* set this only if all values are known, otherwise this
11950 * might overwrite valid ones parsed from other color box */
11951 CUR_STREAM (stream)->colorimetry = cinfo;
11960 vpcc_data += size + 8;
11970 GST_INFO_OBJECT (qtdemux,
11971 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11972 GST_FOURCC_ARGS (fourcc), entry->caps);
11974 } else if (stream->subtype == FOURCC_soun) {
11976 int version, samplesize;
11977 guint16 compression_id;
11978 gboolean amrwb = FALSE;
11981 /* sample description entry (16) + sound sample description v0 (20) */
11985 version = QT_UINT32 (stsd_entry_data + offset);
11986 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11987 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11988 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11989 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11991 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
11992 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
11993 QT_UINT32 (stsd_entry_data + offset + 4));
11994 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11995 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
11996 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
11997 GST_LOG_OBJECT (qtdemux, "packet size: %d",
11998 QT_UINT16 (stsd_entry_data + offset + 14));
11999 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12001 if (compression_id == 0xfffe)
12002 entry->sampled = TRUE;
12004 /* first assume uncompressed audio */
12005 entry->bytes_per_sample = samplesize / 8;
12006 entry->samples_per_frame = entry->n_channels;
12007 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12008 entry->samples_per_packet = entry->samples_per_frame;
12009 entry->bytes_per_packet = entry->bytes_per_sample;
12013 if (version == 0x00010000) {
12014 /* sample description entry (16) + sound sample description v1 (20+16) */
12018 /* take information from here over the normal sample description */
12019 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12020 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12021 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12022 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12024 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12025 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12026 entry->samples_per_packet);
12027 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12028 entry->bytes_per_packet);
12029 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12030 entry->bytes_per_frame);
12031 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12032 entry->bytes_per_sample);
12034 if (!entry->sampled && entry->bytes_per_packet) {
12035 entry->samples_per_frame = (entry->bytes_per_frame /
12036 entry->bytes_per_packet) * entry->samples_per_packet;
12037 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12038 entry->samples_per_frame);
12040 } else if (version == 0x00020000) {
12041 /* sample description entry (16) + sound sample description v2 (56) */
12045 /* take information from here over the normal sample description */
12046 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12047 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12048 entry->samples_per_frame = entry->n_channels;
12049 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12050 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12051 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12052 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12054 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12055 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12056 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12057 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12058 entry->bytes_per_sample * 8);
12059 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12060 QT_UINT32 (stsd_entry_data + offset + 24));
12061 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12062 entry->bytes_per_packet);
12063 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12064 entry->samples_per_packet);
12065 } else if (version != 0x00000) {
12066 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12071 /* Yes, these have to be hard-coded */
12074 entry->samples_per_packet = 6;
12075 entry->bytes_per_packet = 1;
12076 entry->bytes_per_frame = 1 * entry->n_channels;
12077 entry->bytes_per_sample = 1;
12078 entry->samples_per_frame = 6 * entry->n_channels;
12083 entry->samples_per_packet = 3;
12084 entry->bytes_per_packet = 1;
12085 entry->bytes_per_frame = 1 * entry->n_channels;
12086 entry->bytes_per_sample = 1;
12087 entry->samples_per_frame = 3 * entry->n_channels;
12092 entry->samples_per_packet = 64;
12093 entry->bytes_per_packet = 34;
12094 entry->bytes_per_frame = 34 * entry->n_channels;
12095 entry->bytes_per_sample = 2;
12096 entry->samples_per_frame = 64 * entry->n_channels;
12102 entry->samples_per_packet = 1;
12103 entry->bytes_per_packet = 1;
12104 entry->bytes_per_frame = 1 * entry->n_channels;
12105 entry->bytes_per_sample = 1;
12106 entry->samples_per_frame = 1 * entry->n_channels;
12111 entry->samples_per_packet = 160;
12112 entry->bytes_per_packet = 33;
12113 entry->bytes_per_frame = 33 * entry->n_channels;
12114 entry->bytes_per_sample = 2;
12115 entry->samples_per_frame = 160 * entry->n_channels;
12118 /* fix up any invalid header information from above */
12123 /* Sometimes these are set to 0 in the sound sample descriptions so
12124 * let's try to infer useful values from the other information we
12125 * have available */
12126 if (entry->bytes_per_sample == 0)
12127 entry->bytes_per_sample =
12128 entry->bytes_per_frame / entry->n_channels;
12129 if (entry->bytes_per_sample == 0)
12130 entry->bytes_per_sample = samplesize / 8;
12132 if (entry->bytes_per_frame == 0)
12133 entry->bytes_per_frame =
12134 entry->bytes_per_sample * entry->n_channels;
12136 if (entry->bytes_per_packet == 0)
12137 entry->bytes_per_packet = entry->bytes_per_sample;
12139 if (entry->samples_per_frame == 0)
12140 entry->samples_per_frame = entry->n_channels;
12142 if (entry->samples_per_packet == 0)
12143 entry->samples_per_packet = entry->samples_per_frame;
12153 entry->bytes_per_sample = 3;
12157 entry->bytes_per_sample = 4;
12160 entry->bytes_per_sample = 8;
12163 entry->bytes_per_sample = 2;
12166 g_assert_not_reached ();
12169 entry->samples_per_frame = entry->n_channels;
12170 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12171 entry->samples_per_packet = entry->samples_per_frame;
12172 entry->bytes_per_packet = entry->bytes_per_sample;
12180 gst_caps_unref (entry->caps);
12182 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12183 stsd_entry_data + 32, len - 16, &codec);
12194 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12196 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12198 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12200 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12203 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12204 const gchar *format_str;
12208 format_str = (enda_value) ? "S24LE" : "S24BE";
12211 format_str = (enda_value) ? "S32LE" : "S32BE";
12214 format_str = (enda_value) ? "F32LE" : "F32BE";
12217 format_str = (enda_value) ? "F64LE" : "F64BE";
12220 g_assert_not_reached ();
12223 gst_caps_set_simple (entry->caps,
12224 "format", G_TYPE_STRING, format_str, NULL);
12230 const guint8 *owma_data;
12231 const gchar *codec_name = NULL;
12235 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12236 /* FIXME this should also be gst_riff_strf_auds,
12237 * but the latter one is actually missing bits-per-sample :( */
12242 gint32 nSamplesPerSec;
12243 gint32 nAvgBytesPerSec;
12244 gint16 nBlockAlign;
12245 gint16 wBitsPerSample;
12248 WAVEFORMATEX *wfex;
12250 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12251 owma_data = stsd_entry_data;
12252 owma_len = QT_UINT32 (owma_data);
12253 if (owma_len <= 54) {
12254 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12257 wfex = (WAVEFORMATEX *) (owma_data + 36);
12258 buf = gst_buffer_new_and_alloc (owma_len - 54);
12259 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12260 if (wfex->wFormatTag == 0x0161) {
12261 codec_name = "Windows Media Audio";
12263 } else if (wfex->wFormatTag == 0x0162) {
12264 codec_name = "Windows Media Audio 9 Pro";
12266 } else if (wfex->wFormatTag == 0x0163) {
12267 codec_name = "Windows Media Audio 9 Lossless";
12268 /* is that correct? gstffmpegcodecmap.c is missing it, but
12269 * fluendo codec seems to support it */
12273 gst_caps_set_simple (entry->caps,
12274 "codec_data", GST_TYPE_BUFFER, buf,
12275 "wmaversion", G_TYPE_INT, version,
12276 "block_align", G_TYPE_INT,
12277 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12278 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12279 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12280 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12281 gst_buffer_unref (buf);
12285 codec = g_strdup (codec_name);
12291 gint len = QT_UINT32 (stsd_entry_data) - offset;
12292 const guint8 *wfex_data = stsd_entry_data + offset;
12293 const gchar *codec_name = NULL;
12295 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12296 /* FIXME this should also be gst_riff_strf_auds,
12297 * but the latter one is actually missing bits-per-sample :( */
12302 gint32 nSamplesPerSec;
12303 gint32 nAvgBytesPerSec;
12304 gint16 nBlockAlign;
12305 gint16 wBitsPerSample;
12310 /* FIXME: unify with similar wavformatex parsing code above */
12311 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12317 if (QT_UINT32 (wfex_data) <= len)
12318 size = QT_UINT32 (wfex_data) - 8;
12323 /* No real data, so break out */
12326 switch (QT_FOURCC (wfex_data + 4)) {
12327 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12329 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12334 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12335 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12336 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12337 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12338 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12339 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12340 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12342 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12343 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12344 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12345 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12346 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12347 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12349 if (wfex.wFormatTag == 0x0161) {
12350 codec_name = "Windows Media Audio";
12352 } else if (wfex.wFormatTag == 0x0162) {
12353 codec_name = "Windows Media Audio 9 Pro";
12355 } else if (wfex.wFormatTag == 0x0163) {
12356 codec_name = "Windows Media Audio 9 Lossless";
12357 /* is that correct? gstffmpegcodecmap.c is missing it, but
12358 * fluendo codec seems to support it */
12362 gst_caps_set_simple (entry->caps,
12363 "wmaversion", G_TYPE_INT, version,
12364 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12365 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12366 "width", G_TYPE_INT, wfex.wBitsPerSample,
12367 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12369 if (size > wfex.cbSize) {
12372 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12373 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12374 size - wfex.cbSize);
12375 gst_caps_set_simple (entry->caps,
12376 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12377 gst_buffer_unref (buf);
12379 GST_WARNING_OBJECT (qtdemux, "no codec data");
12384 codec = g_strdup (codec_name);
12392 wfex_data += size + 8;
12398 const guint8 *opus_data;
12399 guint8 *channel_mapping = NULL;
12402 guint8 channel_mapping_family;
12403 guint8 stream_count;
12404 guint8 coupled_count;
12407 opus_data = stsd_entry_data;
12409 channels = GST_READ_UINT8 (opus_data + 45);
12410 rate = GST_READ_UINT32_LE (opus_data + 48);
12411 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
12412 stream_count = GST_READ_UINT8 (opus_data + 55);
12413 coupled_count = GST_READ_UINT8 (opus_data + 56);
12415 if (channels > 0) {
12416 channel_mapping = g_malloc (channels * sizeof (guint8));
12417 for (i = 0; i < channels; i++)
12418 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
12421 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12422 channel_mapping_family, stream_count, coupled_count,
12434 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12435 GST_TAG_AUDIO_CODEC, codec, NULL);
12439 /* some bitrate info may have ended up in caps */
12440 s = gst_caps_get_structure (entry->caps, 0);
12441 gst_structure_get_int (s, "bitrate", &bitrate);
12443 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12444 GST_TAG_BITRATE, bitrate, NULL);
12448 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12449 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12450 if (stream->protected) {
12451 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12452 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12454 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12464 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12466 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12468 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12472 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12473 16 bits is a byte-swapped wave-style codec identifier,
12474 and we can find a WAVE header internally to a 'wave' atom here.
12475 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12476 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12479 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12480 if (len < offset + 20) {
12481 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12483 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12484 const guint8 *data = stsd_entry_data + offset + 16;
12486 GNode *waveheadernode;
12488 wavenode = g_node_new ((guint8 *) data);
12489 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12490 const guint8 *waveheader;
12493 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12494 if (waveheadernode) {
12495 waveheader = (const guint8 *) waveheadernode->data;
12496 headerlen = QT_UINT32 (waveheader);
12498 if (headerlen > 8) {
12499 gst_riff_strf_auds *header = NULL;
12500 GstBuffer *headerbuf;
12506 headerbuf = gst_buffer_new_and_alloc (headerlen);
12507 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12509 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12510 headerbuf, &header, &extra)) {
12511 gst_caps_unref (entry->caps);
12512 /* FIXME: Need to do something with the channel reorder map */
12514 gst_riff_create_audio_caps (header->format, NULL, header,
12515 extra, NULL, NULL, NULL);
12518 gst_buffer_unref (extra);
12523 GST_DEBUG ("Didn't find waveheadernode for this codec");
12525 g_node_destroy (wavenode);
12528 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12529 stream->stream_tags);
12533 /* FIXME: what is in the chunk? */
12536 gint len = QT_UINT32 (stsd_data);
12538 /* seems to be always = 116 = 0x74 */
12544 gint len = QT_UINT32 (stsd_entry_data);
12547 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12549 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12550 gst_caps_set_simple (entry->caps,
12551 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12552 gst_buffer_unref (buf);
12554 gst_caps_set_simple (entry->caps,
12555 "samplesize", G_TYPE_INT, samplesize, NULL);
12560 GNode *alac, *wave = NULL;
12562 /* apparently, m4a has this atom appended directly in the stsd entry,
12563 * while mov has it in a wave atom */
12564 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12566 /* alac now refers to stsd entry atom */
12567 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12569 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12571 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12574 const guint8 *alac_data = alac->data;
12575 gint len = QT_UINT32 (alac->data);
12579 GST_DEBUG_OBJECT (qtdemux,
12580 "discarding alac atom with unexpected len %d", len);
12582 /* codec-data contains alac atom size and prefix,
12583 * ffmpeg likes it that way, not quite gst-ish though ...*/
12584 buf = gst_buffer_new_and_alloc (len);
12585 gst_buffer_fill (buf, 0, alac->data, len);
12586 gst_caps_set_simple (entry->caps,
12587 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12588 gst_buffer_unref (buf);
12590 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12591 entry->n_channels = QT_UINT8 (alac_data + 21);
12592 entry->rate = QT_UINT32 (alac_data + 32);
12593 samplesize = QT_UINT8 (alac_data + 16 + 1);
12596 gst_caps_set_simple (entry->caps,
12597 "samplesize", G_TYPE_INT, samplesize, NULL);
12602 /* The codingname of the sample entry is 'fLaC' */
12603 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12606 /* The 'dfLa' box is added to the sample entry to convey
12607 initializing information for the decoder. */
12608 const GNode *dfla =
12609 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12612 const guint32 len = QT_UINT32 (dfla->data);
12614 /* Must contain at least dfLa box header (12),
12615 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12617 GST_DEBUG_OBJECT (qtdemux,
12618 "discarding dfla atom with unexpected len %d", len);
12620 /* skip dfLa header to get the METADATA_BLOCKs */
12621 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12622 const guint32 metadata_blocks_len = len - 12;
12624 gchar *stream_marker = g_strdup ("fLaC");
12625 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12626 strlen (stream_marker));
12629 guint32 remainder = 0;
12630 guint32 block_size = 0;
12631 gboolean is_last = FALSE;
12633 GValue array = G_VALUE_INIT;
12634 GValue value = G_VALUE_INIT;
12636 g_value_init (&array, GST_TYPE_ARRAY);
12637 g_value_init (&value, GST_TYPE_BUFFER);
12639 gst_value_set_buffer (&value, block);
12640 gst_value_array_append_value (&array, &value);
12641 g_value_reset (&value);
12643 gst_buffer_unref (block);
12645 /* check there's at least one METADATA_BLOCK_HEADER's worth
12646 * of data, and we haven't already finished parsing */
12647 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12648 remainder = metadata_blocks_len - index;
12650 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12652 (metadata_blocks[index + 1] << 16) +
12653 (metadata_blocks[index + 2] << 8) +
12654 metadata_blocks[index + 3];
12656 /* be careful not to read off end of box */
12657 if (block_size > remainder) {
12661 is_last = metadata_blocks[index] >> 7;
12663 block = gst_buffer_new_and_alloc (block_size);
12665 gst_buffer_fill (block, 0, &metadata_blocks[index],
12668 gst_value_set_buffer (&value, block);
12669 gst_value_array_append_value (&array, &value);
12670 g_value_reset (&value);
12672 gst_buffer_unref (block);
12674 index += block_size;
12677 /* only append the metadata if we successfully read all of it */
12679 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12680 (stream)->caps, 0), "streamheader", &array);
12682 GST_WARNING_OBJECT (qtdemux,
12683 "discarding all METADATA_BLOCKs due to invalid "
12684 "block_size %d at idx %d, rem %d", block_size, index,
12688 g_value_unset (&value);
12689 g_value_unset (&array);
12691 /* The sample rate obtained from the stsd may not be accurate
12692 * since it cannot represent rates greater than 65535Hz, so
12693 * override that value with the sample rate from the
12694 * METADATA_BLOCK_STREAMINFO block */
12695 CUR_STREAM (stream)->rate =
12696 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12707 gint len = QT_UINT32 (stsd_entry_data);
12710 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12713 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12715 /* If we have enough data, let's try to get the 'damr' atom. See
12716 * the 3GPP container spec (26.244) for more details. */
12717 if ((len - 0x34) > 8 &&
12718 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12719 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12720 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12723 gst_caps_set_simple (entry->caps,
12724 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12725 gst_buffer_unref (buf);
12731 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12732 gint len = QT_UINT32 (stsd_entry_data);
12735 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
12737 if (sound_version == 1) {
12738 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
12739 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
12740 guint8 codec_data[2];
12742 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
12744 gint sample_rate_index =
12745 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12747 /* build AAC codec data */
12748 codec_data[0] = profile << 3;
12749 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12750 codec_data[1] = (sample_rate_index & 0x01) << 7;
12751 codec_data[1] |= (channels & 0xF) << 3;
12753 buf = gst_buffer_new_and_alloc (2);
12754 gst_buffer_fill (buf, 0, codec_data, 2);
12755 gst_caps_set_simple (entry->caps,
12756 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12757 gst_buffer_unref (buf);
12768 /* Fully handled elsewhere */
12771 GST_INFO_OBJECT (qtdemux,
12772 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12776 GST_INFO_OBJECT (qtdemux,
12777 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12778 GST_FOURCC_ARGS (fourcc), entry->caps);
12780 } else if (stream->subtype == FOURCC_strm) {
12781 if (fourcc == FOURCC_rtsp) {
12782 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12784 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12785 GST_FOURCC_ARGS (fourcc));
12786 goto unknown_stream;
12788 entry->sampled = TRUE;
12789 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12790 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12791 || stream->subtype == FOURCC_clcp) {
12793 entry->sampled = TRUE;
12794 entry->sparse = TRUE;
12797 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12800 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12801 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12806 /* hunt for sort-of codec data */
12810 GNode *mp4s = NULL;
12811 GNode *esds = NULL;
12813 /* look for palette in a stsd->mp4s->esds sub-atom */
12814 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12816 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12817 if (esds == NULL) {
12819 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12823 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12824 stream->stream_tags);
12828 GST_INFO_OBJECT (qtdemux,
12829 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12832 GST_INFO_OBJECT (qtdemux,
12833 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12834 GST_FOURCC_ARGS (fourcc), entry->caps);
12836 /* everything in 1 sample */
12837 entry->sampled = TRUE;
12840 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12843 if (entry->caps == NULL)
12844 goto unknown_stream;
12847 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12848 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12854 /* promote to sampled format */
12855 if (entry->fourcc == FOURCC_samr) {
12856 /* force mono 8000 Hz for AMR */
12857 entry->sampled = TRUE;
12858 entry->n_channels = 1;
12859 entry->rate = 8000;
12860 } else if (entry->fourcc == FOURCC_sawb) {
12861 /* force mono 16000 Hz for AMR-WB */
12862 entry->sampled = TRUE;
12863 entry->n_channels = 1;
12864 entry->rate = 16000;
12865 } else if (entry->fourcc == FOURCC_mp4a) {
12866 entry->sampled = TRUE;
12870 stsd_entry_data += len;
12871 remaining_stsd_len -= len;
12875 /* collect sample information */
12876 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12877 goto samples_failed;
12879 if (qtdemux->fragmented) {
12882 /* need all moov samples as basis; probably not many if any at all */
12883 /* prevent moof parsing taking of at this time */
12884 offset = qtdemux->moof_offset;
12885 qtdemux->moof_offset = 0;
12886 if (stream->n_samples &&
12887 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12888 qtdemux->moof_offset = offset;
12889 goto samples_failed;
12891 qtdemux->moof_offset = offset;
12892 /* movie duration more reliable in this case (e.g. mehd) */
12893 if (qtdemux->segment.duration &&
12894 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12896 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12899 /* configure segments */
12900 if (!qtdemux_parse_segments (qtdemux, stream, trak))
12901 goto segments_failed;
12903 /* add some language tag, if useful */
12904 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12905 strcmp (stream->lang_id, "und")) {
12906 const gchar *lang_code;
12908 /* convert ISO 639-2 code to ISO 639-1 */
12909 lang_code = gst_tag_get_language_code (stream->lang_id);
12910 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12911 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12914 /* Check for UDTA tags */
12915 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12916 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12919 /* Insert and sort new stream in track-id order.
12920 * This will help in comparing old/new streams during stream update check */
12921 g_ptr_array_add (qtdemux->active_streams, stream);
12922 g_ptr_array_sort (qtdemux->active_streams,
12923 (GCompareFunc) qtdemux_track_id_compare_func);
12924 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
12925 QTDEMUX_N_STREAMS (qtdemux));
12932 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12933 (_("This file is corrupt and cannot be played.")), (NULL));
12935 gst_qtdemux_stream_unref (stream);
12940 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12941 gst_qtdemux_stream_unref (stream);
12947 /* we posted an error already */
12948 /* free stbl sub-atoms */
12949 gst_qtdemux_stbl_free (stream);
12950 gst_qtdemux_stream_unref (stream);
12955 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
12961 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
12962 GST_FOURCC_ARGS (stream->subtype));
12963 gst_qtdemux_stream_unref (stream);
12968 /* If we can estimate the overall bitrate, and don't have information about the
12969 * stream bitrate for exactly one stream, this guesses the stream bitrate as
12970 * the overall bitrate minus the sum of the bitrates of all other streams. This
12971 * should be useful for the common case where we have one audio and one video
12972 * stream and can estimate the bitrate of one, but not the other. */
12974 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
12976 QtDemuxStream *stream = NULL;
12977 gint64 size, sys_bitrate, sum_bitrate = 0;
12978 GstClockTime duration;
12982 if (qtdemux->fragmented)
12985 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
12987 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
12989 GST_DEBUG_OBJECT (qtdemux,
12990 "Size in bytes of the stream not known - bailing");
12994 /* Subtract the header size */
12995 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
12996 size, qtdemux->header_size);
12998 if (size < qtdemux->header_size)
13001 size = size - qtdemux->header_size;
13003 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13004 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13008 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13009 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13010 switch (str->subtype) {
13013 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13014 CUR_STREAM (str)->caps);
13015 /* retrieve bitrate, prefer avg then max */
13017 if (str->stream_tags) {
13018 if (gst_tag_list_get_uint (str->stream_tags,
13019 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13020 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13021 if (gst_tag_list_get_uint (str->stream_tags,
13022 GST_TAG_NOMINAL_BITRATE, &bitrate))
13023 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13024 if (gst_tag_list_get_uint (str->stream_tags,
13025 GST_TAG_BITRATE, &bitrate))
13026 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13029 sum_bitrate += bitrate;
13032 GST_DEBUG_OBJECT (qtdemux,
13033 ">1 stream with unknown bitrate - bailing");
13040 /* For other subtypes, we assume no significant impact on bitrate */
13046 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13050 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13052 if (sys_bitrate < sum_bitrate) {
13053 /* This can happen, since sum_bitrate might be derived from maximum
13054 * bitrates and not average bitrates */
13055 GST_DEBUG_OBJECT (qtdemux,
13056 "System bitrate less than sum bitrate - bailing");
13060 bitrate = sys_bitrate - sum_bitrate;
13061 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13062 ", Stream bitrate = %u", sys_bitrate, bitrate);
13064 if (!stream->stream_tags)
13065 stream->stream_tags = gst_tag_list_new_empty ();
13067 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13069 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13070 GST_TAG_BITRATE, bitrate, NULL);
13073 static GstFlowReturn
13074 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13076 GstFlowReturn ret = GST_FLOW_OK;
13079 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13081 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13082 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13083 guint32 sample_num = 0;
13085 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13086 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13088 if (qtdemux->fragmented && qtdemux->pullbased) {
13089 /* need all moov samples first */
13090 GST_OBJECT_LOCK (qtdemux);
13091 while (stream->n_samples == 0)
13092 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13094 GST_OBJECT_UNLOCK (qtdemux);
13096 /* discard any stray moof */
13097 qtdemux->moof_offset = 0;
13100 /* prepare braking */
13101 if (ret != GST_FLOW_ERROR)
13104 /* in pull mode, we should have parsed some sample info by now;
13105 * and quite some code will not handle no samples.
13106 * in push mode, we'll just have to deal with it */
13107 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13108 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13109 g_ptr_array_remove_index (qtdemux->active_streams, i);
13112 } else if (stream->track_id == qtdemux->chapters_track_id &&
13113 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13114 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13115 so that it doesn't look like a subtitle track */
13116 g_ptr_array_remove_index (qtdemux->active_streams, i);
13121 /* parse the initial sample for use in setting the frame rate cap */
13122 while (sample_num == 0 && sample_num < stream->n_samples) {
13123 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13133 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13135 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13139 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13143 /* Different length, updated */
13144 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13147 /* streams in list are sorted in track-id order */
13148 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13149 /* Different stream-id, updated */
13150 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13151 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13159 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13160 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13162 /* Connect old stream's srcpad to new stream */
13163 newstream->pad = oldstream->pad;
13164 oldstream->pad = NULL;
13166 /* unset new_stream to prevent stream-start event */
13167 newstream->new_stream = FALSE;
13169 return gst_qtdemux_configure_stream (qtdemux, newstream);
13173 qtdemux_update_streams (GstQTDemux * qtdemux)
13176 g_assert (qtdemux->streams_aware);
13178 /* At below, figure out which stream in active_streams has identical stream-id
13179 * with that of in old_streams. If there is matching stream-id,
13180 * corresponding newstream will not be exposed again,
13181 * but demux will reuse srcpad of matched old stream
13183 * active_streams : newly created streams from the latest moov
13184 * old_streams : existing streams (belong to previous moov)
13187 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13188 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13189 QtDemuxStream *oldstream = NULL;
13192 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13193 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13195 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13196 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13197 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13199 /* null pad stream cannot be reused */
13200 if (oldstream->pad == NULL)
13205 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13207 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13210 /* we don't need to preserve order of old streams */
13211 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13215 /* now we have all info and can expose */
13216 list = stream->stream_tags;
13217 stream->stream_tags = NULL;
13218 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13226 /* Must be called with expose lock */
13227 static GstFlowReturn
13228 qtdemux_expose_streams (GstQTDemux * qtdemux)
13232 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13234 if (!qtdemux_is_streams_update (qtdemux)) {
13235 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13236 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13237 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13238 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13239 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13240 return GST_FLOW_ERROR;
13243 g_ptr_array_set_size (qtdemux->old_streams, 0);
13244 qtdemux->need_segment = TRUE;
13246 return GST_FLOW_OK;
13249 if (qtdemux->streams_aware) {
13250 if (!qtdemux_update_streams (qtdemux))
13251 return GST_FLOW_ERROR;
13253 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13254 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
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))
13261 return GST_FLOW_ERROR;
13266 gst_qtdemux_guess_bitrate (qtdemux);
13268 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13270 /* If we have still old_streams, it's no more used stream */
13271 for (i = 0; i < qtdemux->old_streams->len; i++) {
13272 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13277 event = gst_event_new_eos ();
13278 if (qtdemux->segment_seqnum)
13279 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13281 gst_pad_push_event (stream->pad, event);
13285 g_ptr_array_set_size (qtdemux->old_streams, 0);
13287 /* check if we should post a redirect in case there is a single trak
13288 * and it is a redirecting trak */
13289 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13290 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13293 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13294 "an external content");
13295 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13296 gst_structure_new ("redirect",
13297 "new-location", G_TYPE_STRING,
13298 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13299 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13300 g_free (qtdemux->redirect_location);
13301 qtdemux->redirect_location =
13302 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13305 g_ptr_array_foreach (qtdemux->active_streams,
13306 (GFunc) qtdemux_do_allocation, qtdemux);
13308 qtdemux->need_segment = TRUE;
13310 qtdemux->exposed = TRUE;
13311 return GST_FLOW_OK;
13316 GstStructure *structure; /* helper for sort function */
13318 guint min_req_bitrate;
13319 guint min_req_qt_version;
13323 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13325 GstQtReference *ref_a = (GstQtReference *) a;
13326 GstQtReference *ref_b = (GstQtReference *) b;
13328 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13329 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13331 /* known bitrates go before unknown; higher bitrates go first */
13332 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13335 /* sort the redirects and post a message for the application.
13338 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13340 GstQtReference *best;
13343 GValue list_val = { 0, };
13346 g_assert (references != NULL);
13348 references = g_list_sort (references, qtdemux_redirects_sort_func);
13350 best = (GstQtReference *) references->data;
13352 g_value_init (&list_val, GST_TYPE_LIST);
13354 for (l = references; l != NULL; l = l->next) {
13355 GstQtReference *ref = (GstQtReference *) l->data;
13356 GValue struct_val = { 0, };
13358 ref->structure = gst_structure_new ("redirect",
13359 "new-location", G_TYPE_STRING, ref->location, NULL);
13361 if (ref->min_req_bitrate > 0) {
13362 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13363 ref->min_req_bitrate, NULL);
13366 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13367 g_value_set_boxed (&struct_val, ref->structure);
13368 gst_value_list_append_value (&list_val, &struct_val);
13369 g_value_unset (&struct_val);
13370 /* don't free anything here yet, since we need best->structure below */
13373 g_assert (best != NULL);
13374 s = gst_structure_copy (best->structure);
13376 if (g_list_length (references) > 1) {
13377 gst_structure_set_value (s, "locations", &list_val);
13380 g_value_unset (&list_val);
13382 for (l = references; l != NULL; l = l->next) {
13383 GstQtReference *ref = (GstQtReference *) l->data;
13385 gst_structure_free (ref->structure);
13386 g_free (ref->location);
13389 g_list_free (references);
13391 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13392 g_free (qtdemux->redirect_location);
13393 qtdemux->redirect_location =
13394 g_strdup (gst_structure_get_string (s, "new-location"));
13395 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13396 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13399 /* look for redirect nodes, collect all redirect information and
13403 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13405 GNode *rmra, *rmda, *rdrf;
13407 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13409 GList *redirects = NULL;
13411 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13413 GstQtReference ref = { NULL, NULL, 0, 0 };
13414 GNode *rmdr, *rmvc;
13416 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13417 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13418 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13419 ref.min_req_bitrate);
13422 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13423 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13424 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13426 #ifndef GST_DISABLE_GST_DEBUG
13427 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13429 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13431 GST_LOG_OBJECT (qtdemux,
13432 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13433 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13434 bitmask, check_type);
13435 if (package == FOURCC_qtim && check_type == 0) {
13436 ref.min_req_qt_version = version;
13440 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13446 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13447 if (ref_len > 20) {
13448 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13449 ref_data = (guint8 *) rdrf->data + 20;
13450 if (ref_type == FOURCC_alis) {
13451 guint record_len, record_version, fn_len;
13453 if (ref_len > 70) {
13454 /* MacOSX alias record, google for alias-layout.txt */
13455 record_len = QT_UINT16 (ref_data + 4);
13456 record_version = QT_UINT16 (ref_data + 4 + 2);
13457 fn_len = QT_UINT8 (ref_data + 50);
13458 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13459 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13462 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13465 } else if (ref_type == FOURCC_url_) {
13466 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13468 GST_DEBUG_OBJECT (qtdemux,
13469 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13470 GST_FOURCC_ARGS (ref_type));
13472 if (ref.location != NULL) {
13473 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13475 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13477 GST_WARNING_OBJECT (qtdemux,
13478 "Failed to extract redirect location from rdrf atom");
13481 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13485 /* look for others */
13486 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13489 if (redirects != NULL) {
13490 qtdemux_process_redirects (qtdemux, redirects);
13496 static GstTagList *
13497 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13501 if (tags == NULL) {
13502 tags = gst_tag_list_new_empty ();
13503 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13506 if (qtdemux->major_brand == FOURCC_mjp2)
13507 fmt = "Motion JPEG 2000";
13508 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13510 else if (qtdemux->major_brand == FOURCC_qt__)
13512 else if (qtdemux->fragmented)
13515 fmt = "ISO MP4/M4A";
13517 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13518 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13520 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13526 /* we have read the complete moov node now.
13527 * This function parses all of the relevant info, creates the traks and
13528 * prepares all data structures for playback
13531 qtdemux_parse_tree (GstQTDemux * qtdemux)
13538 guint64 creation_time;
13539 GstDateTime *datetime = NULL;
13542 /* make sure we have a usable taglist */
13543 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13545 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13546 if (mvhd == NULL) {
13547 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13548 return qtdemux_parse_redirects (qtdemux);
13551 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13552 if (version == 1) {
13553 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13554 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13555 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13556 } else if (version == 0) {
13557 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13558 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13559 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13561 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13565 /* Moving qt creation time (secs since 1904) to unix time */
13566 if (creation_time != 0) {
13567 /* Try to use epoch first as it should be faster and more commonly found */
13568 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13571 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13572 /* some data cleansing sanity */
13573 now_s = g_get_real_time () / G_USEC_PER_SEC;
13574 if (now_s + 24 * 3600 < creation_time) {
13575 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13577 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13580 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13581 GDateTime *dt, *dt_local;
13583 dt = g_date_time_add_seconds (base_dt, creation_time);
13584 dt_local = g_date_time_to_local (dt);
13585 datetime = gst_date_time_new_from_g_date_time (dt_local);
13587 g_date_time_unref (base_dt);
13588 g_date_time_unref (dt);
13592 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13593 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13595 gst_date_time_unref (datetime);
13598 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13599 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13601 /* check for fragmented file and get some (default) data */
13602 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13605 GstByteReader mehd_data;
13607 /* let track parsing or anyone know weird stuff might happen ... */
13608 qtdemux->fragmented = TRUE;
13610 /* compensate for total duration */
13611 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13613 qtdemux_parse_mehd (qtdemux, &mehd_data);
13616 /* Update the movie segment duration, unless it was directly given to us
13617 * by upstream. Otherwise let it as is, as we don't want to mangle the
13618 * duration provided by upstream that may come e.g. from a MPD file. */
13619 if (!qtdemux->upstream_format_is_time) {
13620 GstClockTime duration;
13621 /* set duration in the segment info */
13622 gst_qtdemux_get_duration (qtdemux, &duration);
13623 qtdemux->segment.duration = duration;
13624 /* also do not exceed duration; stop is set that way post seek anyway,
13625 * and segment activation falls back to duration,
13626 * whereas loop only checks stop, so let's align this here as well */
13627 qtdemux->segment.stop = duration;
13630 /* parse all traks */
13631 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13633 qtdemux_parse_trak (qtdemux, trak);
13634 /* iterate all siblings */
13635 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13638 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13641 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13643 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13645 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13648 /* maybe also some tags in meta box */
13649 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13651 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13652 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13654 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13657 /* parse any protection system info */
13658 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13660 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13661 qtdemux_parse_pssh (qtdemux, pssh);
13662 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13665 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13670 /* taken from ffmpeg */
13672 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13684 len = (len << 7) | (c & 0x7f);
13693 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13694 gsize codec_data_size)
13696 GList *list = NULL;
13697 guint8 *p = codec_data;
13698 gint i, offset, num_packets;
13699 guint *length, last;
13701 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13703 if (codec_data == NULL || codec_data_size == 0)
13706 /* start of the stream and vorbis audio or theora video, need to
13707 * send the codec_priv data as first three packets */
13708 num_packets = p[0] + 1;
13709 GST_DEBUG_OBJECT (qtdemux,
13710 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13711 (guint) num_packets, codec_data_size);
13713 /* Let's put some limits, Don't think there even is a xiph codec
13714 * with more than 3-4 headers */
13715 if (G_UNLIKELY (num_packets > 16)) {
13716 GST_WARNING_OBJECT (qtdemux,
13717 "Unlikely number of xiph headers, most likely not valid");
13721 length = g_alloca (num_packets * sizeof (guint));
13725 /* first packets, read length values */
13726 for (i = 0; i < num_packets - 1; i++) {
13728 while (offset < codec_data_size) {
13729 length[i] += p[offset];
13730 if (p[offset++] != 0xff)
13735 if (offset + last > codec_data_size)
13738 /* last packet is the remaining size */
13739 length[i] = codec_data_size - offset - last;
13741 for (i = 0; i < num_packets; i++) {
13744 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
13746 if (offset + length[i] > codec_data_size)
13749 hdr = gst_buffer_new_memdup (p + offset, length[i]);
13750 list = g_list_append (list, hdr);
13752 offset += length[i];
13761 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
13767 /* this can change the codec originally present in @list */
13769 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13770 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13772 int len = QT_UINT32 (esds->data);
13773 guint8 *ptr = esds->data;
13774 guint8 *end = ptr + len;
13776 guint8 *data_ptr = NULL;
13778 guint8 object_type_id = 0;
13779 guint8 stream_type = 0;
13780 const char *codec_name = NULL;
13781 GstCaps *caps = NULL;
13783 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13785 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13787 while (ptr + 1 < end) {
13788 tag = QT_UINT8 (ptr);
13789 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13791 len = read_descr_size (ptr, end, &ptr);
13792 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13794 /* Check the stated amount of data is available for reading */
13795 if (len < 0 || ptr + len > end)
13799 case ES_DESCRIPTOR_TAG:
13800 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
13801 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
13804 case DECODER_CONFIG_DESC_TAG:{
13805 guint max_bitrate, avg_bitrate;
13807 object_type_id = QT_UINT8 (ptr);
13808 stream_type = QT_UINT8 (ptr + 1) >> 2;
13809 max_bitrate = QT_UINT32 (ptr + 5);
13810 avg_bitrate = QT_UINT32 (ptr + 9);
13811 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13812 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
13813 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13814 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13815 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13816 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13817 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13818 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13820 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13821 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13822 avg_bitrate, NULL);
13827 case DECODER_SPECIFIC_INFO_TAG:
13828 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13829 if (object_type_id == 0xe0 && len == 0x40) {
13835 GST_DEBUG_OBJECT (qtdemux,
13836 "Have VOBSUB palette. Creating palette event");
13837 /* move to decConfigDescr data and read palette */
13839 for (i = 0; i < 16; i++) {
13840 clut[i] = QT_UINT32 (data);
13844 s = gst_structure_new ("application/x-gst-dvd", "event",
13845 G_TYPE_STRING, "dvd-spu-clut-change",
13846 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13847 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13848 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13849 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13850 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13851 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13852 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13853 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13856 /* store event and trigger custom processing */
13857 stream->pending_event =
13858 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13860 /* Generic codec_data handler puts it on the caps */
13867 case SL_CONFIG_DESC_TAG:
13868 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13872 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13874 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13880 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13881 * in use, and should also be used to override some other parameters for some
13883 switch (object_type_id) {
13884 case 0x20: /* MPEG-4 */
13885 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13886 * profile_and_level_indication */
13887 if (data_ptr != NULL && data_len >= 5 &&
13888 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13889 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13890 data_ptr + 4, data_len - 4);
13892 break; /* Nothing special needed here */
13893 case 0x21: /* H.264 */
13894 codec_name = "H.264 / AVC";
13895 caps = gst_caps_new_simple ("video/x-h264",
13896 "stream-format", G_TYPE_STRING, "avc",
13897 "alignment", G_TYPE_STRING, "au", NULL);
13899 case 0x40: /* AAC (any) */
13900 case 0x66: /* AAC Main */
13901 case 0x67: /* AAC LC */
13902 case 0x68: /* AAC SSR */
13903 /* Override channels and rate based on the codec_data, as it's often
13905 /* Only do so for basic setup without HE-AAC extension */
13906 if (data_ptr && data_len == 2) {
13907 guint channels, rate;
13909 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13911 entry->n_channels = channels;
13913 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13915 entry->rate = rate;
13918 /* Set level and profile if possible */
13919 if (data_ptr != NULL && data_len >= 2) {
13920 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13921 data_ptr, data_len);
13923 const gchar *profile_str = NULL;
13926 guint8 *codec_data;
13927 gint rate_idx, profile;
13929 /* No codec_data, let's invent something.
13930 * FIXME: This is wrong for SBR! */
13932 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13934 buffer = gst_buffer_new_and_alloc (2);
13935 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13936 codec_data = map.data;
13939 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13942 switch (object_type_id) {
13944 profile_str = "main";
13948 profile_str = "lc";
13952 profile_str = "ssr";
13960 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13962 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13964 gst_buffer_unmap (buffer, &map);
13965 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13966 GST_TYPE_BUFFER, buffer, NULL);
13967 gst_buffer_unref (buffer);
13970 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13971 G_TYPE_STRING, profile_str, NULL);
13975 case 0x60: /* MPEG-2, various profiles */
13981 codec_name = "MPEG-2 video";
13982 caps = gst_caps_new_simple ("video/mpeg",
13983 "mpegversion", G_TYPE_INT, 2,
13984 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13986 case 0x69: /* MPEG-2 BC audio */
13987 case 0x6B: /* MPEG-1 audio */
13988 caps = gst_caps_new_simple ("audio/mpeg",
13989 "mpegversion", G_TYPE_INT, 1, NULL);
13990 codec_name = "MPEG-1 audio";
13992 case 0x6A: /* MPEG-1 */
13993 codec_name = "MPEG-1 video";
13994 caps = gst_caps_new_simple ("video/mpeg",
13995 "mpegversion", G_TYPE_INT, 1,
13996 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13998 case 0x6C: /* MJPEG */
14000 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14002 codec_name = "Motion-JPEG";
14004 case 0x6D: /* PNG */
14006 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14008 codec_name = "PNG still images";
14010 case 0x6E: /* JPEG2000 */
14011 codec_name = "JPEG-2000";
14012 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14014 case 0xA4: /* Dirac */
14015 codec_name = "Dirac";
14016 caps = gst_caps_new_empty_simple ("video/x-dirac");
14018 case 0xA5: /* AC3 */
14019 codec_name = "AC-3 audio";
14020 caps = gst_caps_new_simple ("audio/x-ac3",
14021 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14023 case 0xA9: /* AC3 */
14024 codec_name = "DTS audio";
14025 caps = gst_caps_new_simple ("audio/x-dts",
14026 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14029 if (stream_type == 0x05 && data_ptr) {
14031 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14034 GValue arr_val = G_VALUE_INIT;
14035 GValue buf_val = G_VALUE_INIT;
14038 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14039 codec_name = "Vorbis";
14040 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14041 g_value_init (&arr_val, GST_TYPE_ARRAY);
14042 g_value_init (&buf_val, GST_TYPE_BUFFER);
14043 for (tmp = headers; tmp; tmp = tmp->next) {
14044 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14045 gst_value_array_append_value (&arr_val, &buf_val);
14047 s = gst_caps_get_structure (caps, 0);
14048 gst_structure_take_value (s, "streamheader", &arr_val);
14049 g_value_unset (&buf_val);
14050 g_list_free (headers);
14057 case 0xE1: /* QCELP */
14058 /* QCELP, the codec_data is a riff tag (little endian) with
14059 * 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). */
14060 caps = gst_caps_new_empty_simple ("audio/qcelp");
14061 codec_name = "QCELP";
14067 /* If we have a replacement caps, then change our caps for this stream */
14069 gst_caps_unref (entry->caps);
14070 entry->caps = caps;
14073 if (codec_name && list)
14074 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14075 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14077 /* Add the codec_data attribute to caps, if we have it */
14081 buffer = gst_buffer_new_and_alloc (data_len);
14082 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14084 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14085 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14087 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14089 gst_buffer_unref (buffer);
14094 static inline GstCaps *
14095 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14099 char *s, fourstr[5];
14101 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14102 for (i = 0; i < 4; i++) {
14103 if (!g_ascii_isalnum (fourstr[i]))
14106 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14107 caps = gst_caps_new_empty_simple (s);
14112 #define _codec(name) \
14114 if (codec_name) { \
14115 *codec_name = g_strdup (name); \
14120 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14121 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14122 const guint8 * stsd_entry_data, gchar ** codec_name)
14124 GstCaps *caps = NULL;
14125 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14129 _codec ("PNG still images");
14130 caps = gst_caps_new_empty_simple ("image/png");
14133 _codec ("JPEG still images");
14135 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14138 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14139 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14140 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14141 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14142 _codec ("Motion-JPEG");
14144 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14147 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14148 _codec ("Motion-JPEG format B");
14149 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14152 _codec ("JPEG-2000");
14153 /* override to what it should be according to spec, avoid palette_data */
14154 entry->bits_per_sample = 24;
14155 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14158 _codec ("Sorensen video v.3");
14159 caps = gst_caps_new_simple ("video/x-svq",
14160 "svqversion", G_TYPE_INT, 3, NULL);
14162 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14163 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14164 _codec ("Sorensen video v.1");
14165 caps = gst_caps_new_simple ("video/x-svq",
14166 "svqversion", G_TYPE_INT, 1, NULL);
14168 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14169 caps = gst_caps_new_empty_simple ("video/x-raw");
14170 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14171 _codec ("Windows Raw RGB");
14172 stream->alignment = 32;
14178 bps = QT_UINT16 (stsd_entry_data + 82);
14181 format = GST_VIDEO_FORMAT_RGB15;
14184 format = GST_VIDEO_FORMAT_RGB16;
14187 format = GST_VIDEO_FORMAT_RGB;
14190 format = GST_VIDEO_FORMAT_ARGB;
14198 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14199 format = GST_VIDEO_FORMAT_I420;
14201 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14202 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14203 format = GST_VIDEO_FORMAT_I420;
14206 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14207 format = GST_VIDEO_FORMAT_UYVY;
14209 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14210 format = GST_VIDEO_FORMAT_v308;
14212 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14213 format = GST_VIDEO_FORMAT_v216;
14216 format = GST_VIDEO_FORMAT_v210;
14218 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14219 format = GST_VIDEO_FORMAT_r210;
14221 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14222 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14223 format = GST_VIDEO_FORMAT_v410;
14226 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14227 * but different order than AYUV
14228 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14229 format = GST_VIDEO_FORMAT_v408;
14232 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14233 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14234 _codec ("MPEG-1 video");
14235 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14236 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14238 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14239 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14240 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14241 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14242 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14243 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14244 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14245 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14246 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14247 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14248 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14249 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14250 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14251 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14252 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14253 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14254 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14255 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14256 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14257 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14258 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14259 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14260 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14261 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14262 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14263 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14264 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14265 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14266 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14267 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14268 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14269 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14270 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14271 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14272 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14273 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14274 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14275 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14276 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14277 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14278 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14279 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14280 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14281 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14282 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14283 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14284 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14285 _codec ("MPEG-2 video");
14286 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14287 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14289 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14290 _codec ("GIF still images");
14291 caps = gst_caps_new_empty_simple ("image/gif");
14294 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14296 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14298 /* ffmpeg uses the height/width props, don't know why */
14299 caps = gst_caps_new_simple ("video/x-h263",
14300 "variant", G_TYPE_STRING, "itu", NULL);
14304 _codec ("MPEG-4 video");
14305 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14306 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14308 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14309 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14310 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14311 caps = gst_caps_new_simple ("video/x-msmpeg",
14312 "msmpegversion", G_TYPE_INT, 43, NULL);
14314 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14316 caps = gst_caps_new_simple ("video/x-divx",
14317 "divxversion", G_TYPE_INT, 3, NULL);
14319 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14320 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14322 caps = gst_caps_new_simple ("video/x-divx",
14323 "divxversion", G_TYPE_INT, 4, NULL);
14325 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14327 caps = gst_caps_new_simple ("video/x-divx",
14328 "divxversion", G_TYPE_INT, 5, NULL);
14331 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14333 caps = gst_caps_new_simple ("video/x-ffv",
14334 "ffvversion", G_TYPE_INT, 1, NULL);
14337 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14338 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14343 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14344 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14345 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14349 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14350 _codec ("Cinepak");
14351 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14353 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14354 _codec ("Apple QuickDraw");
14355 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14357 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14358 _codec ("Apple video");
14359 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14364 _codec ("H.264 / AVC");
14365 caps = gst_caps_new_simple ("video/x-h264",
14366 "stream-format", G_TYPE_STRING, "avc",
14367 "alignment", G_TYPE_STRING, "au", NULL);
14371 _codec ("H.264 / AVC");
14372 caps = gst_caps_new_simple ("video/x-h264",
14373 "stream-format", G_TYPE_STRING, "avc3",
14374 "alignment", G_TYPE_STRING, "au", NULL);
14379 _codec ("H.265 / HEVC");
14380 caps = gst_caps_new_simple ("video/x-h265",
14381 "stream-format", G_TYPE_STRING, "hvc1",
14382 "alignment", G_TYPE_STRING, "au", NULL);
14386 _codec ("H.265 / HEVC");
14387 caps = gst_caps_new_simple ("video/x-h265",
14388 "stream-format", G_TYPE_STRING, "hev1",
14389 "alignment", G_TYPE_STRING, "au", NULL);
14392 _codec ("Run-length encoding");
14393 caps = gst_caps_new_simple ("video/x-rle",
14394 "layout", G_TYPE_STRING, "quicktime", NULL);
14397 _codec ("Run-length encoding");
14398 caps = gst_caps_new_simple ("video/x-rle",
14399 "layout", G_TYPE_STRING, "microsoft", NULL);
14401 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14402 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14403 _codec ("Indeo Video 3");
14404 caps = gst_caps_new_simple ("video/x-indeo",
14405 "indeoversion", G_TYPE_INT, 3, NULL);
14407 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14408 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14409 _codec ("Intel Video 4");
14410 caps = gst_caps_new_simple ("video/x-indeo",
14411 "indeoversion", G_TYPE_INT, 4, NULL);
14415 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14416 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14417 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14418 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14419 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14420 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14421 _codec ("DV Video");
14422 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14423 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14425 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14426 case FOURCC_dv5p: /* DVCPRO50 PAL */
14427 _codec ("DVCPro50 Video");
14428 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14429 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14431 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14432 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14433 _codec ("DVCProHD Video");
14434 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14435 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14437 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14438 _codec ("Apple Graphics (SMC)");
14439 caps = gst_caps_new_empty_simple ("video/x-smc");
14441 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14443 caps = gst_caps_new_empty_simple ("video/x-vp3");
14445 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14446 _codec ("VP6 Flash");
14447 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14451 caps = gst_caps_new_empty_simple ("video/x-theora");
14452 /* theora uses one byte of padding in the data stream because it does not
14453 * allow 0 sized packets while theora does */
14454 entry->padding = 1;
14458 caps = gst_caps_new_empty_simple ("video/x-dirac");
14460 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14461 _codec ("TIFF still images");
14462 caps = gst_caps_new_empty_simple ("image/tiff");
14464 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14465 _codec ("Apple Intermediate Codec");
14466 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14468 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14469 _codec ("AVID DNxHD");
14470 caps = gst_caps_from_string ("video/x-dnxhd");
14474 _codec ("On2 VP8");
14475 caps = gst_caps_from_string ("video/x-vp8");
14478 _codec ("Google VP9");
14479 caps = gst_caps_from_string ("video/x-vp9");
14482 _codec ("Apple ProRes LT");
14484 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14488 _codec ("Apple ProRes HQ");
14490 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14494 _codec ("Apple ProRes");
14496 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14500 _codec ("Apple ProRes Proxy");
14502 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14506 _codec ("Apple ProRes 4444");
14508 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14512 _codec ("Apple ProRes 4444 XQ");
14514 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14518 _codec ("GoPro CineForm");
14519 caps = gst_caps_from_string ("video/x-cineform");
14524 caps = gst_caps_new_simple ("video/x-wmv",
14525 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14529 caps = gst_caps_new_empty_simple ("video/x-av1");
14531 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14534 caps = _get_unknown_codec_name ("video", fourcc);
14539 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14542 gst_video_info_init (&info);
14543 gst_video_info_set_format (&info, format, entry->width, entry->height);
14545 caps = gst_video_info_to_caps (&info);
14546 *codec_name = gst_pb_utils_get_codec_description (caps);
14548 /* enable clipping for raw video streams */
14549 stream->need_clip = TRUE;
14550 stream->alignment = 32;
14557 round_up_pow2 (guint n)
14569 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14570 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14571 int len, gchar ** codec_name)
14574 const GstStructure *s;
14577 GstAudioFormat format = 0;
14580 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14582 depth = entry->bytes_per_packet * 8;
14585 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14587 /* 8-bit audio is unsigned */
14589 format = GST_AUDIO_FORMAT_U8;
14590 /* otherwise it's signed and big-endian just like 'twos' */
14592 endian = G_BIG_ENDIAN;
14599 endian = G_LITTLE_ENDIAN;
14602 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14604 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14608 caps = gst_caps_new_simple ("audio/x-raw",
14609 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14610 "layout", G_TYPE_STRING, "interleaved", NULL);
14611 stream->alignment = GST_ROUND_UP_8 (depth);
14612 stream->alignment = round_up_pow2 (stream->alignment);
14616 _codec ("Raw 64-bit floating-point audio");
14617 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14619 caps = gst_caps_new_simple ("audio/x-raw",
14620 "format", G_TYPE_STRING, "F64BE",
14621 "layout", G_TYPE_STRING, "interleaved", NULL);
14622 stream->alignment = 8;
14625 _codec ("Raw 32-bit floating-point audio");
14626 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14628 caps = gst_caps_new_simple ("audio/x-raw",
14629 "format", G_TYPE_STRING, "F32BE",
14630 "layout", G_TYPE_STRING, "interleaved", NULL);
14631 stream->alignment = 4;
14634 _codec ("Raw 24-bit PCM audio");
14635 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14637 caps = gst_caps_new_simple ("audio/x-raw",
14638 "format", G_TYPE_STRING, "S24BE",
14639 "layout", G_TYPE_STRING, "interleaved", NULL);
14640 stream->alignment = 4;
14643 _codec ("Raw 32-bit PCM audio");
14644 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14646 caps = gst_caps_new_simple ("audio/x-raw",
14647 "format", G_TYPE_STRING, "S32BE",
14648 "layout", G_TYPE_STRING, "interleaved", NULL);
14649 stream->alignment = 4;
14652 _codec ("Raw 16-bit PCM audio");
14653 caps = gst_caps_new_simple ("audio/x-raw",
14654 "format", G_TYPE_STRING, "S16LE",
14655 "layout", G_TYPE_STRING, "interleaved", NULL);
14656 stream->alignment = 2;
14659 _codec ("Mu-law audio");
14660 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14663 _codec ("A-law audio");
14664 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14668 _codec ("Microsoft ADPCM");
14669 /* Microsoft ADPCM-ACM code 2 */
14670 caps = gst_caps_new_simple ("audio/x-adpcm",
14671 "layout", G_TYPE_STRING, "microsoft", NULL);
14675 _codec ("DVI/IMA ADPCM");
14676 caps = gst_caps_new_simple ("audio/x-adpcm",
14677 "layout", G_TYPE_STRING, "dvi", NULL);
14681 _codec ("DVI/Intel IMA ADPCM");
14682 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14683 caps = gst_caps_new_simple ("audio/x-adpcm",
14684 "layout", G_TYPE_STRING, "quicktime", NULL);
14688 /* MPEG layer 3, CBR only (pre QT4.1) */
14691 _codec ("MPEG-1 layer 3");
14692 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14693 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14694 "mpegversion", G_TYPE_INT, 1, NULL);
14696 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14697 _codec ("MPEG-1 layer 2");
14699 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14700 "mpegversion", G_TYPE_INT, 1, NULL);
14703 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14704 _codec ("EAC-3 audio");
14705 caps = gst_caps_new_simple ("audio/x-eac3",
14706 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14707 entry->sampled = TRUE;
14709 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14711 _codec ("AC-3 audio");
14712 caps = gst_caps_new_simple ("audio/x-ac3",
14713 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14714 entry->sampled = TRUE;
14716 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14717 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14718 _codec ("DTS audio");
14719 caps = gst_caps_new_simple ("audio/x-dts",
14720 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14721 entry->sampled = TRUE;
14723 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14724 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14725 _codec ("DTS-HD audio");
14726 caps = gst_caps_new_simple ("audio/x-dts",
14727 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14728 entry->sampled = TRUE;
14732 caps = gst_caps_new_simple ("audio/x-mace",
14733 "maceversion", G_TYPE_INT, 3, NULL);
14737 caps = gst_caps_new_simple ("audio/x-mace",
14738 "maceversion", G_TYPE_INT, 6, NULL);
14740 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14742 caps = gst_caps_new_empty_simple ("application/ogg");
14744 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14745 _codec ("DV audio");
14746 caps = gst_caps_new_empty_simple ("audio/x-dv");
14749 _codec ("MPEG-4 AAC audio");
14750 caps = gst_caps_new_simple ("audio/mpeg",
14751 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14752 "stream-format", G_TYPE_STRING, "raw", NULL);
14754 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14755 _codec ("QDesign Music");
14756 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14759 _codec ("QDesign Music v.2");
14760 /* FIXME: QDesign music version 2 (no constant) */
14761 if (FALSE && data) {
14762 caps = gst_caps_new_simple ("audio/x-qdm2",
14763 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14764 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14765 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14767 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14771 _codec ("GSM audio");
14772 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14775 _codec ("AMR audio");
14776 caps = gst_caps_new_empty_simple ("audio/AMR");
14779 _codec ("AMR-WB audio");
14780 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14783 _codec ("Quicktime IMA ADPCM");
14784 caps = gst_caps_new_simple ("audio/x-adpcm",
14785 "layout", G_TYPE_STRING, "quicktime", NULL);
14788 _codec ("Apple lossless audio");
14789 caps = gst_caps_new_empty_simple ("audio/x-alac");
14792 _codec ("Free Lossless Audio Codec");
14793 caps = gst_caps_new_simple ("audio/x-flac",
14794 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14796 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14797 _codec ("QualComm PureVoice");
14798 caps = gst_caps_from_string ("audio/qcelp");
14803 caps = gst_caps_new_empty_simple ("audio/x-wma");
14807 caps = gst_caps_new_empty_simple ("audio/x-opus");
14814 GstAudioFormat format;
14817 FLAG_IS_FLOAT = 0x1,
14818 FLAG_IS_BIG_ENDIAN = 0x2,
14819 FLAG_IS_SIGNED = 0x4,
14820 FLAG_IS_PACKED = 0x8,
14821 FLAG_IS_ALIGNED_HIGH = 0x10,
14822 FLAG_IS_NON_INTERLEAVED = 0x20
14824 _codec ("Raw LPCM audio");
14826 if (data && len >= 36) {
14827 depth = QT_UINT32 (data + 24);
14828 flags = QT_UINT32 (data + 28);
14829 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
14831 if ((flags & FLAG_IS_FLOAT) == 0) {
14836 if ((flags & FLAG_IS_ALIGNED_HIGH))
14839 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14840 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14841 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14842 caps = gst_caps_new_simple ("audio/x-raw",
14843 "format", G_TYPE_STRING,
14845 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
14846 "UNKNOWN", "layout", G_TYPE_STRING,
14847 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
14848 "interleaved", NULL);
14849 stream->alignment = GST_ROUND_UP_8 (depth);
14850 stream->alignment = round_up_pow2 (stream->alignment);
14855 if (flags & FLAG_IS_BIG_ENDIAN)
14856 format = GST_AUDIO_FORMAT_F64BE;
14858 format = GST_AUDIO_FORMAT_F64LE;
14860 if (flags & FLAG_IS_BIG_ENDIAN)
14861 format = GST_AUDIO_FORMAT_F32BE;
14863 format = GST_AUDIO_FORMAT_F32LE;
14865 caps = gst_caps_new_simple ("audio/x-raw",
14866 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14867 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14868 "non-interleaved" : "interleaved", NULL);
14869 stream->alignment = width / 8;
14873 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
14876 caps = gst_caps_new_empty_simple ("audio/x-ac4");
14879 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14883 caps = _get_unknown_codec_name ("audio", fourcc);
14889 GstCaps *templ_caps =
14890 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14891 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14892 gst_caps_unref (caps);
14893 gst_caps_unref (templ_caps);
14894 caps = intersection;
14897 /* enable clipping for raw audio streams */
14898 s = gst_caps_get_structure (caps, 0);
14899 name = gst_structure_get_name (s);
14900 if (g_str_has_prefix (name, "audio/x-raw")) {
14901 stream->need_clip = TRUE;
14902 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
14903 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14904 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
14905 stream->max_buffer_size);
14911 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14912 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14913 const guint8 * stsd_entry_data, gchar ** codec_name)
14917 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14921 _codec ("DVD subtitle");
14922 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14923 stream->need_process = TRUE;
14926 _codec ("Quicktime timed text");
14929 _codec ("3GPP timed text");
14931 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14933 /* actual text piece needs to be extracted */
14934 stream->need_process = TRUE;
14937 _codec ("XML subtitles");
14938 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14941 _codec ("CEA 608 Closed Caption");
14943 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
14944 G_TYPE_STRING, "s334-1a", NULL);
14945 stream->need_process = TRUE;
14946 stream->need_split = TRUE;
14949 _codec ("CEA 708 Closed Caption");
14951 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
14952 G_TYPE_STRING, "cdp", NULL);
14953 stream->need_process = TRUE;
14958 caps = _get_unknown_codec_name ("text", fourcc);
14966 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14967 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14968 const guint8 * stsd_entry_data, gchar ** codec_name)
14974 _codec ("MPEG 1 video");
14975 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14976 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14986 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14987 const gchar * system_id)
14991 if (!qtdemux->protection_system_ids)
14992 qtdemux->protection_system_ids =
14993 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14994 /* Check whether we already have an entry for this system ID. */
14995 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14996 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14997 if (g_ascii_strcasecmp (system_id, id) == 0) {
15001 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15002 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,