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"
73 #include "qtdemux-webvtt.h"
79 #include <gst/math-compat.h>
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
97 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
99 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
101 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
103 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
104 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
105 #define QTDEMUX_NTH_STREAM(demux,idx) \
106 QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
107 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
108 QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
110 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
112 GST_DEBUG_CATEGORY (qtdemux_debug);
113 #define GST_CAT_DEFAULT qtdemux_debug
115 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
116 typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
118 /* Macros for converting to/from timescale */
119 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
120 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
122 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
123 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
125 /* timestamp is the DTS */
126 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
127 /* timestamp + offset + cslg_shift is the outgoing PTS */
128 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
129 /* timestamp + offset is the PTS used for internal seek calculations */
130 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
131 /* timestamp + duration - dts is the duration */
132 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
134 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
136 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
137 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
138 GST_TRACE("Locking from thread %p", g_thread_self()); \
139 g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
140 GST_TRACE("Locked from thread %p", g_thread_self()); \
143 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
144 GST_TRACE("Unlocking from thread %p", g_thread_self()); \
145 g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
149 * Quicktime has tracks and segments. A track is a continuous piece of
150 * multimedia content. The track is not always played from start to finish but
151 * instead, pieces of the track are 'cut out' and played in sequence. This is
152 * what the segments do.
154 * Inside the track we have keyframes (K) and delta frames. The track has its
155 * own timing, which starts from 0 and extends to end. The position in the track
156 * is called the media_time.
158 * The segments now describe the pieces that should be played from this track
159 * and are basically tuples of media_time/duration/rate entries. We can have
160 * multiple segments and they are all played after one another. An example:
162 * segment 1: media_time: 1 second, duration: 1 second, rate 1
163 * segment 2: media_time: 3 second, duration: 2 second, rate 2
165 * To correctly play back this track, one must play: 1 second of media starting
166 * from media_time 1 followed by 2 seconds of media starting from media_time 3
169 * Each of the segments will be played at a specific time, the first segment at
170 * time 0, the second one after the duration of the first one, etc.. Note that
171 * the time in resulting playback is not identical to the media_time of the
174 * Visually, assuming the track has 4 second of media_time:
177 * .-----------------------------------------------------------.
178 * track: | K.....K.........K........K.......K.......K...........K... |
179 * '-----------------------------------------------------------'
181 * .------------^ ^ .----------^ ^
182 * / .-------------' / .------------------'
184 * .--------------. .--------------.
185 * | segment 1 | | segment 2 |
186 * '--------------' '--------------'
188 * The challenge here is to cut out the right pieces of the track for each of
189 * the playback segments. This fortunately can easily be done with the SEGMENT
190 * events of GStreamer.
192 * For playback of segment 1, we need to provide the decoder with the keyframe
193 * (a), in the above figure, but we must instruct it only to output the decoded
194 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
195 * position set to the time of the segment: 0.
197 * We then proceed to push data from keyframe (a) to frame (b). The decoder
198 * decodes but clips all before media_time 1.
200 * After finishing a segment, we push out a new SEGMENT event with the clipping
201 * boundaries of the new data.
203 * This is a good usecase for the GStreamer accumulated SEGMENT events.
206 struct _QtDemuxSegment
208 /* global time and duration, all gst time */
210 GstClockTime stop_time;
211 GstClockTime duration;
212 /* media time of trak, all gst time */
213 GstClockTime media_start;
214 GstClockTime media_stop;
216 /* Media start time in trak timescale units */
217 guint32 trak_media_start;
220 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
222 /* Used with fragmented MP4 files (mfra atom) */
223 struct _QtDemuxRandomAccessEntry
230 /* Contains properties and cryptographic info for a set of samples from a
231 * track protected using Common Encryption (cenc) */
232 struct _QtDemuxCencSampleSetInfo
234 GstStructure *default_properties;
236 /* @crypto_info holds one GstStructure per sample */
237 GPtrArray *crypto_info;
240 struct _QtDemuxAavdEncryptionInfo
242 GstStructure *default_properties;
246 qt_demux_state_string (enum QtDemuxState state)
249 case QTDEMUX_STATE_INITIAL:
251 case QTDEMUX_STATE_HEADER:
253 case QTDEMUX_STATE_MOVIE:
255 case QTDEMUX_STATE_BUFFER_MDAT:
256 return "<BUFFER_MDAT>";
262 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
264 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
266 static GstStaticPadTemplate gst_qtdemux_sink_template =
267 GST_STATIC_PAD_TEMPLATE ("sink",
270 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
274 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
275 GST_STATIC_PAD_TEMPLATE ("video_%u",
278 GST_STATIC_CAPS_ANY);
280 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
281 GST_STATIC_PAD_TEMPLATE ("audio_%u",
284 GST_STATIC_CAPS_ANY);
286 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
287 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
290 GST_STATIC_CAPS_ANY);
292 #define gst_qtdemux_parent_class parent_class
293 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
294 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
295 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
297 static void gst_qtdemux_dispose (GObject * object);
298 static void gst_qtdemux_finalize (GObject * object);
301 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
302 GstClockTime media_time);
304 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
305 QtDemuxStream * str, gint64 media_offset);
308 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
309 static GstIndex *gst_qtdemux_get_index (GstElement * element);
311 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
312 GstStateChange transition);
313 static void gst_qtdemux_set_context (GstElement * element,
314 GstContext * context);
315 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
316 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
317 GstObject * parent, GstPadMode mode, gboolean active);
319 static void gst_qtdemux_loop (GstPad * pad);
320 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
322 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
324 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
326 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
327 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
328 QtDemuxStream * stream);
329 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
330 QtDemuxStream * stream);
331 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
334 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
336 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
337 const guint8 * buffer, guint length);
338 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
339 const guint8 * buffer, guint length);
340 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
342 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
343 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
345 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
346 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
347 const guint8 * stsd_entry_data, gchar ** codec_name);
348 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
349 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
350 const guint8 * data, int len, gchar ** codec_name);
351 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
352 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
353 gchar ** codec_name);
354 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
355 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
356 const guint8 * stsd_entry_data, gchar ** codec_name);
358 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
359 QtDemuxStream * stream, guint32 n);
360 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
361 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
362 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
363 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
364 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
365 static void qtdemux_do_allocation (QtDemuxStream * stream,
366 GstQTDemux * qtdemux);
367 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
368 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
369 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
370 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
371 GstClockTime * _start, GstClockTime * _stop);
372 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
373 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
375 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
376 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
378 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
380 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
381 QtDemuxStream * stream, guint sample_index);
382 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
384 static void qtdemux_gst_structure_free (GstStructure * gststructure);
385 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
388 gst_qtdemux_class_init (GstQTDemuxClass * klass)
390 GObjectClass *gobject_class;
391 GstElementClass *gstelement_class;
393 gobject_class = (GObjectClass *) klass;
394 gstelement_class = (GstElementClass *) klass;
396 parent_class = g_type_class_peek_parent (klass);
398 gobject_class->dispose = gst_qtdemux_dispose;
399 gobject_class->finalize = gst_qtdemux_finalize;
401 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
403 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
404 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
406 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
408 gst_tag_register_musicbrainz_tags ();
410 gst_element_class_add_static_pad_template (gstelement_class,
411 &gst_qtdemux_sink_template);
412 gst_element_class_add_static_pad_template (gstelement_class,
413 &gst_qtdemux_videosrc_template);
414 gst_element_class_add_static_pad_template (gstelement_class,
415 &gst_qtdemux_audiosrc_template);
416 gst_element_class_add_static_pad_template (gstelement_class,
417 &gst_qtdemux_subsrc_template);
418 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
420 "Demultiplex a QuickTime file into audio and video streams",
421 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
423 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
428 gst_qtdemux_init (GstQTDemux * qtdemux)
431 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
432 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
433 gst_pad_set_activatemode_function (qtdemux->sinkpad,
434 qtdemux_sink_activate_mode);
435 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
436 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
437 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
438 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
440 qtdemux->adapter = gst_adapter_new ();
441 g_queue_init (&qtdemux->protection_event_queue);
442 qtdemux->flowcombiner = gst_flow_combiner_new ();
443 g_mutex_init (&qtdemux->expose_lock);
445 qtdemux->active_streams = g_ptr_array_new_with_free_func
446 ((GDestroyNotify) gst_qtdemux_stream_unref);
447 qtdemux->old_streams = g_ptr_array_new_with_free_func
448 ((GDestroyNotify) gst_qtdemux_stream_unref);
450 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
452 gst_qtdemux_reset (qtdemux, TRUE);
456 gst_qtdemux_finalize (GObject * object)
458 GstQTDemux *qtdemux = GST_QTDEMUX (object);
460 g_free (qtdemux->redirect_location);
462 G_OBJECT_CLASS (parent_class)->finalize (object);
466 gst_qtdemux_dispose (GObject * object)
468 GstQTDemux *qtdemux = GST_QTDEMUX (object);
470 if (qtdemux->adapter) {
471 g_object_unref (G_OBJECT (qtdemux->adapter));
472 qtdemux->adapter = NULL;
474 gst_tag_list_unref (qtdemux->tag_list);
475 gst_flow_combiner_free (qtdemux->flowcombiner);
476 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
478 g_queue_clear (&qtdemux->protection_event_queue);
480 g_free (qtdemux->cenc_aux_info_sizes);
481 qtdemux->cenc_aux_info_sizes = NULL;
482 g_mutex_clear (&qtdemux->expose_lock);
484 g_ptr_array_free (qtdemux->active_streams, TRUE);
485 g_ptr_array_free (qtdemux->old_streams, TRUE);
487 G_OBJECT_CLASS (parent_class)->dispose (object);
491 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
493 if (qtdemux->redirect_location) {
494 GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
495 (_("This file contains no playable streams.")),
496 ("no known streams found, a redirect message has been posted"),
497 ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
499 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
500 (_("This file contains no playable streams.")),
501 ("no known streams found"));
506 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
508 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
509 mem, size, 0, size, mem, free_func);
513 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
520 if (G_UNLIKELY (size == 0)) {
522 GstBuffer *tmp = NULL;
524 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
525 if (ret != GST_FLOW_OK)
528 gst_buffer_map (tmp, &map, GST_MAP_READ);
529 size = QT_UINT32 (map.data);
530 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
532 gst_buffer_unmap (tmp, &map);
533 gst_buffer_unref (tmp);
536 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
537 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
538 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
539 /* we're pulling header but already got most interesting bits,
540 * so never mind the rest (e.g. tags) (that much) */
541 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
545 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
546 (_("This file is invalid and cannot be played.")),
547 ("atom has bogus size %" G_GUINT64_FORMAT, size));
548 return GST_FLOW_ERROR;
552 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
554 if (G_UNLIKELY (flow != GST_FLOW_OK))
557 bsize = gst_buffer_get_size (*buf);
558 /* Catch short reads - we don't want any partial atoms */
559 if (G_UNLIKELY (bsize < size)) {
560 GST_WARNING_OBJECT (qtdemux,
561 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
562 gst_buffer_unref (*buf);
572 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
573 GstFormat src_format, gint64 src_value, GstFormat dest_format,
577 QtDemuxStream *stream = gst_pad_get_element_private (pad);
580 if (stream->subtype != FOURCC_vide) {
585 switch (src_format) {
586 case GST_FORMAT_TIME:
587 switch (dest_format) {
588 case GST_FORMAT_BYTES:{
589 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
595 *dest_value = stream->samples[index].offset;
597 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
598 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
599 GST_TIME_ARGS (src_value), *dest_value);
607 case GST_FORMAT_BYTES:
608 switch (dest_format) {
609 case GST_FORMAT_TIME:{
611 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
620 QTSTREAMTIME_TO_GSTTIME (stream,
621 stream->samples[index].timestamp);
622 GST_DEBUG_OBJECT (qtdemux,
623 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
624 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
643 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
645 gboolean res = FALSE;
647 *duration = GST_CLOCK_TIME_NONE;
649 if (qtdemux->duration != 0 &&
650 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
651 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
654 *duration = GST_CLOCK_TIME_NONE;
661 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
664 gboolean res = FALSE;
665 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
667 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
669 switch (GST_QUERY_TYPE (query)) {
670 case GST_QUERY_POSITION:{
673 gst_query_parse_position (query, &fmt, NULL);
674 if (fmt == GST_FORMAT_TIME
675 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
676 gst_query_set_position (query, GST_FORMAT_TIME,
677 qtdemux->segment.position);
682 case GST_QUERY_DURATION:{
685 gst_query_parse_duration (query, &fmt, NULL);
686 if (fmt == GST_FORMAT_TIME) {
687 /* First try to query upstream */
688 res = gst_pad_query_default (pad, parent, query);
690 GstClockTime duration;
691 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
692 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
699 case GST_QUERY_CONVERT:{
700 GstFormat src_fmt, dest_fmt;
701 gint64 src_value, dest_value = 0;
703 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
705 res = gst_qtdemux_src_convert (qtdemux, pad,
706 src_fmt, src_value, dest_fmt, &dest_value);
708 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
712 case GST_QUERY_FORMATS:
713 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
716 case GST_QUERY_SEEKING:{
720 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
722 if (fmt == GST_FORMAT_BYTES) {
723 /* We always refuse BYTES seeks from downstream */
727 /* try upstream first */
728 res = gst_pad_query_default (pad, parent, query);
731 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
732 if (fmt == GST_FORMAT_TIME) {
733 GstClockTime duration;
735 gst_qtdemux_get_duration (qtdemux, &duration);
737 if (!qtdemux->pullbased) {
740 /* we might be able with help from upstream */
742 q = gst_query_new_seeking (GST_FORMAT_BYTES);
743 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
744 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
745 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
749 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
755 case GST_QUERY_SEGMENT:
760 format = qtdemux->segment.format;
763 gst_segment_to_stream_time (&qtdemux->segment, format,
764 qtdemux->segment.start);
765 if ((stop = qtdemux->segment.stop) == -1)
766 stop = qtdemux->segment.duration;
768 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
770 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
775 res = gst_pad_query_default (pad, parent, query);
783 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
785 if (G_LIKELY (stream->pad)) {
786 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
787 GST_DEBUG_PAD_NAME (stream->pad));
789 if (!gst_tag_list_is_empty (stream->stream_tags)) {
790 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
791 stream->stream_tags);
792 gst_pad_push_event (stream->pad,
793 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
796 if (G_UNLIKELY (stream->send_global_tags)) {
797 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
799 gst_pad_push_event (stream->pad,
800 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
801 stream->send_global_tags = FALSE;
806 /* push event on all source pads; takes ownership of the event */
808 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
810 gboolean has_valid_stream = FALSE;
811 GstEventType etype = GST_EVENT_TYPE (event);
814 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
815 GST_EVENT_TYPE_NAME (event));
817 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
819 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
820 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
822 if ((pad = stream->pad)) {
823 has_valid_stream = TRUE;
825 if (etype == GST_EVENT_EOS) {
826 /* let's not send twice */
827 if (stream->sent_eos)
829 stream->sent_eos = TRUE;
832 gst_pad_push_event (pad, gst_event_ref (event));
836 gst_event_unref (event);
838 /* if it is EOS and there are no pads, post an error */
839 if (!has_valid_stream && etype == GST_EVENT_EOS) {
840 gst_qtdemux_post_no_playable_stream_error (qtdemux);
850 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
852 if ((gint64) s1->timestamp > *media_time)
854 if ((gint64) s1->timestamp == *media_time)
860 /* find the index of the sample that includes the data for @media_time using a
861 * binary search. Only to be called in optimized cases of linear search below.
863 * Returns the index of the sample with the corresponding *DTS*.
866 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
869 QtDemuxSample *result;
872 /* convert media_time to mov format */
874 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
876 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
877 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
878 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
880 if (G_LIKELY (result))
881 index = result - str->samples;
890 /* find the index of the sample that includes the data for @media_offset using a
893 * Returns the index of the sample.
896 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
897 QtDemuxStream * str, gint64 media_offset)
899 QtDemuxSample *result = str->samples;
902 if (result == NULL || str->n_samples == 0)
905 if (media_offset == result->offset)
909 while (index < str->n_samples - 1) {
910 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
913 if (media_offset < result->offset)
924 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
929 /* find the index of the sample that includes the data for @media_time using a
930 * linear search, and keeping in mind that not all samples may have been parsed
931 * yet. If possible, it will delegate to binary search.
933 * Returns the index of the sample.
936 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
937 GstClockTime media_time)
941 QtDemuxSample *sample;
943 /* convert media_time to mov format */
945 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
947 sample = str->samples;
948 if (mov_time == sample->timestamp + sample->pts_offset)
951 /* use faster search if requested time in already parsed range */
952 sample = str->samples + str->stbl_index;
953 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
954 index = gst_qtdemux_find_index (qtdemux, str, media_time);
955 sample = str->samples + index;
957 while (index < str->n_samples - 1) {
958 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
961 sample = str->samples + index + 1;
962 if (mov_time < sample->timestamp) {
963 sample = str->samples + index;
971 /* sample->timestamp is now <= media_time, need to find the corresponding
972 * PTS now by looking backwards */
973 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
975 sample = str->samples + index;
983 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
988 /* find the index of the keyframe needed to decode the sample at @index
989 * of stream @str, or of a subsequent keyframe (depending on @next)
991 * Returns the index of the keyframe.
994 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
995 guint32 index, gboolean next)
997 guint32 new_index = index;
999 if (index >= str->n_samples) {
1000 new_index = str->n_samples;
1004 /* all keyframes, return index */
1005 if (str->all_keyframe) {
1010 /* else search until we have a keyframe */
1011 while (new_index < str->n_samples) {
1012 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1015 if (str->samples[new_index].keyframe)
1027 if (new_index == str->n_samples) {
1028 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1033 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1034 "gave %u", next ? "after" : "before", index, new_index);
1041 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1046 /* find the segment for @time_position for @stream
1048 * Returns the index of the segment containing @time_position.
1049 * Returns the last segment and sets the @eos variable to TRUE
1050 * if the time is beyond the end. @eos may be NULL
1053 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1054 GstClockTime time_position)
1059 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1060 GST_TIME_ARGS (time_position));
1063 for (i = 0; i < stream->n_segments; i++) {
1064 QtDemuxSegment *segment = &stream->segments[i];
1066 GST_LOG_OBJECT (stream->pad,
1067 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1068 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1070 /* For the last segment we include stop_time in the last segment */
1071 if (i < stream->n_segments - 1) {
1072 if (segment->time <= time_position && time_position < segment->stop_time) {
1073 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1078 /* Last segment always matches */
1086 /* move the stream @str to the sample position @index.
1088 * Updates @str->sample_index and marks discontinuity if needed.
1091 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1094 /* no change needed */
1095 if (index == str->sample_index)
1098 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1101 /* position changed, we have a discont */
1102 str->sample_index = index;
1103 str->offset_in_sample = 0;
1104 /* Each time we move in the stream we store the position where we are
1106 str->from_sample = index;
1107 str->discont = TRUE;
1111 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1112 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1115 gint64 min_byte_offset = -1;
1118 min_offset = desired_time;
1120 /* for each stream, find the index of the sample in the segment
1121 * and move back to the previous keyframe. */
1122 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1124 guint32 index, kindex;
1126 GstClockTime media_start;
1127 GstClockTime media_time;
1128 GstClockTime seg_time;
1129 QtDemuxSegment *seg;
1130 gboolean empty_segment = FALSE;
1132 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1134 if (CUR_STREAM (str)->sparse && !use_sparse)
1137 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1138 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1140 /* get segment and time in the segment */
1141 seg = &str->segments[seg_idx];
1142 seg_time = (desired_time - seg->time) * seg->rate;
1144 while (QTSEGMENT_IS_EMPTY (seg)) {
1146 empty_segment = TRUE;
1147 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1150 if (seg_idx == str->n_segments)
1152 seg = &str->segments[seg_idx];
1155 if (seg_idx == str->n_segments) {
1156 /* FIXME track shouldn't have the last segment as empty, but if it
1157 * happens we better handle it */
1161 /* get the media time in the segment */
1162 media_start = seg->media_start + seg_time;
1164 /* get the index of the sample with media time */
1165 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1166 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1167 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1168 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1171 /* shift to next frame if we are looking for next keyframe */
1172 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1173 && index < str->stbl_index)
1176 if (!empty_segment) {
1177 /* find previous keyframe */
1178 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1180 /* we will settle for one before if none found after */
1181 if (next && kindex == -1)
1182 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1184 /* Update the requested time whenever a keyframe was found, to make it
1185 * accurate and avoid having the first buffer fall outside of the segment
1190 /* get timestamp of keyframe */
1191 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1192 GST_DEBUG_OBJECT (qtdemux,
1193 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1194 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1195 str->samples[kindex].offset);
1197 /* keyframes in the segment get a chance to change the
1198 * desired_offset. keyframes out of the segment are
1200 if (media_time >= seg->media_start) {
1201 GstClockTime seg_time;
1203 /* this keyframe is inside the segment, convert back to
1205 seg_time = (media_time - seg->media_start) + seg->time;
1206 if ((!next && (seg_time < min_offset)) ||
1207 (next && (seg_time > min_offset)))
1208 min_offset = seg_time;
1213 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1214 min_byte_offset = str->samples[index].offset;
1218 *key_time = min_offset;
1220 *key_offset = min_byte_offset;
1224 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1225 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1229 g_return_val_if_fail (format != NULL, FALSE);
1230 g_return_val_if_fail (cur != NULL, FALSE);
1231 g_return_val_if_fail (stop != NULL, FALSE);
1233 if (*format == GST_FORMAT_TIME)
1237 if (cur_type != GST_SEEK_TYPE_NONE)
1238 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1239 if (res && stop_type != GST_SEEK_TYPE_NONE)
1240 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1243 *format = GST_FORMAT_TIME;
1248 /* perform seek in push based mode:
1249 find BYTE position to move to based on time and delegate to upstream
1252 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1257 GstSeekType cur_type, stop_type;
1258 gint64 cur, stop, key_cur;
1261 gint64 original_stop;
1264 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1266 gst_event_parse_seek (event, &rate, &format, &flags,
1267 &cur_type, &cur, &stop_type, &stop);
1268 seqnum = gst_event_get_seqnum (event);
1270 /* Directly send the instant-rate-change event here before taking the
1271 * stream-lock so that it can be applied as soon as possible */
1272 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1275 /* instant rate change only supported if direction does not change. All
1276 * other requirements are already checked before creating the seek event
1277 * but let's double-check here to be sure */
1278 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1279 (qtdemux->segment.rate < 0 && rate > 0) ||
1280 cur_type != GST_SEEK_TYPE_NONE ||
1281 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1282 GST_ERROR_OBJECT (qtdemux,
1283 "Instant rate change seeks only supported in the "
1284 "same direction, without flushing and position change");
1288 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1289 (GstSegmentFlags) flags);
1290 gst_event_set_seqnum (ev, seqnum);
1291 gst_qtdemux_push_event (qtdemux, ev);
1295 /* only forward streaming and seeking is possible */
1297 goto unsupported_seek;
1299 /* convert to TIME if needed and possible */
1300 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1304 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1305 * the original stop position to use when upstream pushes the new segment
1307 original_stop = stop;
1310 /* find reasonable corresponding BYTE position,
1311 * also try to mind about keyframes, since we can not go back a bit for them
1313 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1314 * mostly just work, but let's not yet boldly go there ... */
1315 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1320 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1321 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1324 GST_OBJECT_LOCK (qtdemux);
1325 qtdemux->seek_offset = byte_cur;
1326 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1327 qtdemux->push_seek_start = cur;
1329 qtdemux->push_seek_start = key_cur;
1332 if (stop_type == GST_SEEK_TYPE_NONE) {
1333 qtdemux->push_seek_stop = qtdemux->segment.stop;
1335 qtdemux->push_seek_stop = original_stop;
1337 GST_OBJECT_UNLOCK (qtdemux);
1339 qtdemux->segment_seqnum = seqnum;
1340 /* BYTE seek event */
1341 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1343 gst_event_set_seqnum (event, seqnum);
1344 res = gst_pad_push_event (qtdemux->sinkpad, event);
1351 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1357 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1362 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1367 /* perform the seek.
1369 * We set all segment_indexes in the streams to unknown and
1370 * adjust the time_position to the desired position. this is enough
1371 * to trigger a segment switch in the streaming thread to start
1372 * streaming from the desired position.
1374 * Keyframe seeking is a little more complicated when dealing with
1375 * segments. Ideally we want to move to the previous keyframe in
1376 * the segment but there might not be a keyframe in the segment. In
1377 * fact, none of the segments could contain a keyframe. We take a
1378 * practical approach: seek to the previous keyframe in the segment,
1379 * if there is none, seek to the beginning of the segment.
1381 * Called with STREAM_LOCK
1384 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1385 guint32 seqnum, GstSeekFlags flags)
1387 gint64 desired_offset;
1390 desired_offset = segment->position;
1392 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1393 GST_TIME_ARGS (desired_offset));
1395 /* may not have enough fragmented info to do this adjustment,
1396 * and we can't scan (and probably should not) at this time with
1397 * possibly flushing upstream */
1398 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1400 gboolean next, before, after;
1402 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1403 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1404 next = after && !before;
1405 if (segment->rate < 0)
1408 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1410 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1411 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1412 desired_offset = min_offset;
1415 /* and set all streams to the final position */
1416 GST_OBJECT_LOCK (qtdemux);
1417 gst_flow_combiner_reset (qtdemux->flowcombiner);
1418 GST_OBJECT_UNLOCK (qtdemux);
1419 qtdemux->segment_seqnum = seqnum;
1420 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1421 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1423 stream->time_position = desired_offset;
1424 stream->accumulated_base = 0;
1425 stream->sample_index = -1;
1426 stream->offset_in_sample = 0;
1427 stream->segment_index = -1;
1428 stream->sent_eos = FALSE;
1429 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1431 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1432 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1434 segment->position = desired_offset;
1435 if (segment->rate >= 0) {
1436 segment->start = desired_offset;
1437 /* We need to update time as we update start in that direction */
1438 segment->time = desired_offset;
1440 /* we stop at the end */
1441 if (segment->stop == -1)
1442 segment->stop = segment->duration;
1444 segment->stop = desired_offset;
1447 if (qtdemux->fragmented)
1448 qtdemux->fragmented_seek_pending = TRUE;
1453 /* do a seek in pull based mode */
1455 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1460 GstSeekType cur_type, stop_type;
1462 gboolean flush, instant_rate_change;
1464 GstSegment seeksegment;
1465 guint32 seqnum = GST_SEQNUM_INVALID;
1466 GstEvent *flush_event;
1469 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1471 gst_event_parse_seek (event, &rate, &format, &flags,
1472 &cur_type, &cur, &stop_type, &stop);
1473 seqnum = gst_event_get_seqnum (event);
1475 /* we have to have a format as the segment format. Try to convert
1477 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1481 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1483 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1484 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1486 /* Directly send the instant-rate-change event here before taking the
1487 * stream-lock so that it can be applied as soon as possible */
1488 if (instant_rate_change) {
1491 /* instant rate change only supported if direction does not change. All
1492 * other requirements are already checked before creating the seek event
1493 * but let's double-check here to be sure */
1494 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1495 (qtdemux->segment.rate < 0 && rate > 0) ||
1496 cur_type != GST_SEEK_TYPE_NONE ||
1497 stop_type != GST_SEEK_TYPE_NONE || flush) {
1498 GST_ERROR_OBJECT (qtdemux,
1499 "Instant rate change seeks only supported in the "
1500 "same direction, without flushing and position change");
1504 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1505 (GstSegmentFlags) flags);
1506 gst_event_set_seqnum (ev, seqnum);
1507 gst_qtdemux_push_event (qtdemux, ev);
1511 /* stop streaming, either by flushing or by pausing the task */
1513 flush_event = gst_event_new_flush_start ();
1514 if (seqnum != GST_SEQNUM_INVALID)
1515 gst_event_set_seqnum (flush_event, seqnum);
1516 /* unlock upstream pull_range */
1517 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1518 /* make sure out loop function exits */
1519 gst_qtdemux_push_event (qtdemux, flush_event);
1521 /* non flushing seek, pause the task */
1522 gst_pad_pause_task (qtdemux->sinkpad);
1525 /* wait for streaming to finish */
1526 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1528 /* copy segment, we need this because we still need the old
1529 * segment when we close the current segment. */
1530 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1532 /* configure the segment with the seek variables */
1533 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1534 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1535 cur_type, cur, stop_type, stop, &update)) {
1537 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1539 /* now do the seek */
1540 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1543 /* prepare for streaming again */
1545 flush_event = gst_event_new_flush_stop (TRUE);
1546 if (seqnum != GST_SEQNUM_INVALID)
1547 gst_event_set_seqnum (flush_event, seqnum);
1549 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1550 gst_qtdemux_push_event (qtdemux, flush_event);
1553 /* commit the new segment */
1554 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1556 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1557 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1558 qtdemux->segment.format, qtdemux->segment.position);
1559 if (seqnum != GST_SEQNUM_INVALID)
1560 gst_message_set_seqnum (msg, seqnum);
1561 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1564 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1565 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1566 qtdemux->sinkpad, NULL);
1568 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1575 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1581 qtdemux_ensure_index (GstQTDemux * qtdemux)
1585 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1587 /* Build complete index */
1588 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1589 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1591 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1592 GST_LOG_OBJECT (qtdemux,
1593 "Building complete index of track-id %u for seeking failed!",
1603 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1606 gboolean res = TRUE;
1607 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1609 switch (GST_EVENT_TYPE (event)) {
1610 case GST_EVENT_RECONFIGURE:
1611 GST_OBJECT_LOCK (qtdemux);
1612 gst_flow_combiner_reset (qtdemux->flowcombiner);
1613 GST_OBJECT_UNLOCK (qtdemux);
1614 res = gst_pad_event_default (pad, parent, event);
1616 case GST_EVENT_SEEK:
1618 GstSeekFlags flags = 0;
1619 GstFormat seek_format;
1620 gboolean instant_rate_change;
1622 #ifndef GST_DISABLE_GST_DEBUG
1623 GstClockTime ts = gst_util_get_timestamp ();
1625 guint32 seqnum = gst_event_get_seqnum (event);
1627 qtdemux->received_seek = TRUE;
1629 gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1631 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1633 if (seqnum == qtdemux->segment_seqnum) {
1634 GST_LOG_OBJECT (pad,
1635 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1636 gst_event_unref (event);
1640 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1641 /* seek should be handled by upstream, we might need to re-download fragments */
1642 GST_DEBUG_OBJECT (qtdemux,
1643 "let upstream handle seek for fragmented playback");
1647 if (seek_format == GST_FORMAT_BYTES) {
1648 GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1649 gst_event_unref (event);
1653 gst_event_parse_seek_trickmode_interval (event,
1654 &qtdemux->trickmode_interval);
1656 /* Build complete index for seeking;
1657 * if not a fragmented file at least and we're really doing a seek,
1658 * not just an instant-rate-change */
1659 if (!qtdemux->fragmented && !instant_rate_change) {
1660 if (!qtdemux_ensure_index (qtdemux))
1663 #ifndef GST_DISABLE_GST_DEBUG
1664 ts = gst_util_get_timestamp () - ts;
1665 GST_INFO_OBJECT (qtdemux,
1666 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1668 if (qtdemux->pullbased) {
1669 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1670 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1671 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1673 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1674 && QTDEMUX_N_STREAMS (qtdemux)
1675 && !qtdemux->fragmented) {
1676 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1678 GST_DEBUG_OBJECT (qtdemux,
1679 "ignoring seek in push mode in current state");
1682 gst_event_unref (event);
1687 res = gst_pad_event_default (pad, parent, event);
1697 GST_ERROR_OBJECT (qtdemux, "Index failed");
1698 gst_event_unref (event);
1704 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1706 * If @fw is false, the coding order is explored backwards.
1708 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1709 * sample is found for that track.
1711 * The stream and sample index of the sample with the minimum offset in the direction explored
1712 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1714 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1715 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1716 * @_stream and @_index. */
1718 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1719 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1722 gint64 time, min_time;
1723 QtDemuxStream *stream;
1730 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1733 gboolean set_sample;
1735 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1742 i = str->n_samples - 1;
1746 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1747 if (str->samples[i].size == 0)
1750 if (fw && (str->samples[i].offset < byte_pos))
1753 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1756 /* move stream to first available sample */
1758 gst_qtdemux_move_stream (qtdemux, str, i);
1762 /* avoid index from sparse streams since they might be far away */
1763 if (!CUR_STREAM (str)->sparse) {
1764 /* determine min/max time */
1765 time = QTSAMPLE_PTS (str, &str->samples[i]);
1766 if (min_time == -1 || (!fw && time > min_time) ||
1767 (fw && time < min_time)) {
1771 /* determine stream with leading sample, to get its position */
1773 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1774 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1782 /* no sample for this stream, mark eos */
1784 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1795 /* Copied from mpegtsbase code */
1796 /* FIXME: replace this function when we add new util function for stream-id creation */
1798 _get_upstream_id (GstQTDemux * demux)
1800 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1803 /* Try to create one from the upstream URI, else use a randome number */
1807 /* Try to generate one from the URI query and
1808 * if it fails take a random number instead */
1809 query = gst_query_new_uri ();
1810 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1811 gst_query_parse_uri (query, &uri);
1817 /* And then generate an SHA256 sum of the URI */
1818 cs = g_checksum_new (G_CHECKSUM_SHA256);
1819 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1821 upstream_id = g_strdup (g_checksum_get_string (cs));
1822 g_checksum_free (cs);
1824 /* Just get some random number if the URI query fails */
1825 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1826 "implementing a deterministic way of creating a stream-id");
1828 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1829 g_random_int (), g_random_int ());
1832 gst_query_unref (query);
1837 static QtDemuxStream *
1838 _create_stream (GstQTDemux * demux, guint32 track_id)
1840 QtDemuxStream *stream;
1843 stream = g_new0 (QtDemuxStream, 1);
1844 stream->demux = demux;
1845 stream->track_id = track_id;
1846 upstream_id = _get_upstream_id (demux);
1847 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1848 g_free (upstream_id);
1849 /* new streams always need a discont */
1850 stream->discont = TRUE;
1851 /* we enable clipping for raw audio/video streams */
1852 stream->need_clip = FALSE;
1853 stream->process_func = NULL;
1854 stream->segment_index = -1;
1855 stream->time_position = 0;
1856 stream->sample_index = -1;
1857 stream->offset_in_sample = 0;
1858 stream->new_stream = TRUE;
1859 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1860 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1861 stream->protected = FALSE;
1862 stream->protection_scheme_type = 0;
1863 stream->protection_scheme_version = 0;
1864 stream->protection_scheme_info = NULL;
1865 stream->n_samples_moof = 0;
1866 stream->duration_moof = 0;
1867 stream->duration_last_moof = 0;
1868 stream->alignment = 1;
1869 stream->stream_tags = gst_tag_list_new_empty ();
1870 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1871 g_queue_init (&stream->protection_scheme_event_queue);
1872 stream->ref_count = 1;
1873 /* consistent default for push based mode */
1874 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1879 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1881 GstStructure *structure;
1882 const gchar *variant;
1883 const GstCaps *mediacaps = NULL;
1885 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1887 structure = gst_caps_get_structure (caps, 0);
1888 variant = gst_structure_get_string (structure, "variant");
1890 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1891 QtDemuxStream *stream;
1892 const GValue *value;
1894 demux->fragmented = TRUE;
1895 demux->mss_mode = TRUE;
1897 if (QTDEMUX_N_STREAMS (demux) > 1) {
1898 /* can't do this, we can only renegotiate for another mss format */
1902 value = gst_structure_get_value (structure, "media-caps");
1905 const GValue *timescale_v;
1907 /* TODO update when stream changes during playback */
1909 if (QTDEMUX_N_STREAMS (demux) == 0) {
1910 stream = _create_stream (demux, 1);
1911 g_ptr_array_add (demux->active_streams, stream);
1912 /* mss has no stsd/stsd entry, use id 0 as default */
1913 stream->stsd_entries_length = 1;
1914 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1915 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1917 stream = QTDEMUX_NTH_STREAM (demux, 0);
1920 timescale_v = gst_structure_get_value (structure, "timescale");
1922 stream->timescale = g_value_get_uint64 (timescale_v);
1924 /* default mss timescale */
1925 stream->timescale = 10000000;
1927 demux->timescale = stream->timescale;
1929 mediacaps = gst_value_get_caps (value);
1930 if (!CUR_STREAM (stream)->caps
1931 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1932 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1934 stream->new_caps = TRUE;
1936 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1937 structure = gst_caps_get_structure (mediacaps, 0);
1938 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1939 stream->subtype = FOURCC_vide;
1941 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1942 gst_structure_get_int (structure, "height",
1943 &CUR_STREAM (stream)->height);
1944 gst_structure_get_fraction (structure, "framerate",
1945 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1946 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1948 stream->subtype = FOURCC_soun;
1949 gst_structure_get_int (structure, "channels",
1950 &CUR_STREAM (stream)->n_channels);
1951 gst_structure_get_int (structure, "rate", &rate);
1952 CUR_STREAM (stream)->rate = rate;
1953 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1954 if (gst_structure_has_field (structure, "original-media-type")) {
1955 const gchar *media_type =
1956 gst_structure_get_string (structure, "original-media-type");
1957 if (g_str_has_prefix (media_type, "video")) {
1958 stream->subtype = FOURCC_vide;
1959 } else if (g_str_has_prefix (media_type, "audio")) {
1960 stream->subtype = FOURCC_soun;
1965 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1967 demux->mss_mode = FALSE;
1974 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1978 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1979 gst_pad_stop_task (qtdemux->sinkpad);
1981 if (hard || qtdemux->upstream_format_is_time) {
1982 qtdemux->state = QTDEMUX_STATE_INITIAL;
1983 qtdemux->neededbytes = 16;
1984 qtdemux->todrop = 0;
1985 qtdemux->pullbased = FALSE;
1986 g_clear_pointer (&qtdemux->redirect_location, g_free);
1987 qtdemux->first_mdat = -1;
1988 qtdemux->header_size = 0;
1989 qtdemux->mdatoffset = -1;
1990 qtdemux->restoredata_offset = -1;
1991 if (qtdemux->mdatbuffer)
1992 gst_buffer_unref (qtdemux->mdatbuffer);
1993 if (qtdemux->restoredata_buffer)
1994 gst_buffer_unref (qtdemux->restoredata_buffer);
1995 qtdemux->mdatbuffer = NULL;
1996 qtdemux->restoredata_buffer = NULL;
1997 qtdemux->mdatleft = 0;
1998 qtdemux->mdatsize = 0;
1999 if (qtdemux->comp_brands)
2000 gst_buffer_unref (qtdemux->comp_brands);
2001 qtdemux->comp_brands = NULL;
2002 qtdemux->last_moov_offset = -1;
2003 if (qtdemux->moov_node_compressed) {
2004 g_node_destroy (qtdemux->moov_node_compressed);
2005 if (qtdemux->moov_node)
2006 g_free (qtdemux->moov_node->data);
2008 qtdemux->moov_node_compressed = NULL;
2009 if (qtdemux->moov_node)
2010 g_node_destroy (qtdemux->moov_node);
2011 qtdemux->moov_node = NULL;
2012 if (qtdemux->tag_list)
2013 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2014 qtdemux->tag_list = gst_tag_list_new_empty ();
2015 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2017 if (qtdemux->element_index)
2018 gst_object_unref (qtdemux->element_index);
2019 qtdemux->element_index = NULL;
2021 qtdemux->major_brand = 0;
2022 qtdemux->upstream_format_is_time = FALSE;
2023 qtdemux->upstream_seekable = FALSE;
2024 qtdemux->upstream_size = 0;
2026 qtdemux->fragment_start = -1;
2027 qtdemux->fragment_start_offset = -1;
2028 qtdemux->duration = 0;
2029 qtdemux->moof_offset = 0;
2030 qtdemux->chapters_track_id = 0;
2031 qtdemux->have_group_id = FALSE;
2032 qtdemux->group_id = G_MAXUINT;
2034 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2036 g_queue_clear (&qtdemux->protection_event_queue);
2038 qtdemux->received_seek = FALSE;
2039 qtdemux->first_moof_already_parsed = FALSE;
2041 qtdemux->offset = 0;
2042 gst_adapter_clear (qtdemux->adapter);
2043 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2044 qtdemux->need_segment = TRUE;
2047 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2048 qtdemux->trickmode_interval = 0;
2049 g_ptr_array_set_size (qtdemux->active_streams, 0);
2050 g_ptr_array_set_size (qtdemux->old_streams, 0);
2051 qtdemux->n_video_streams = 0;
2052 qtdemux->n_audio_streams = 0;
2053 qtdemux->n_sub_streams = 0;
2054 qtdemux->exposed = FALSE;
2055 qtdemux->fragmented = FALSE;
2056 qtdemux->mss_mode = FALSE;
2057 gst_caps_replace (&qtdemux->media_caps, NULL);
2058 qtdemux->timescale = 0;
2059 qtdemux->got_moov = FALSE;
2060 qtdemux->cenc_aux_info_offset = 0;
2061 qtdemux->cenc_aux_info_sizes = NULL;
2062 qtdemux->cenc_aux_sample_count = 0;
2063 if (qtdemux->protection_system_ids) {
2064 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2065 qtdemux->protection_system_ids = NULL;
2067 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2068 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2069 GST_BIN_FLAG_STREAMS_AWARE);
2071 if (qtdemux->preferred_protection_system_id) {
2072 g_free (qtdemux->preferred_protection_system_id);
2073 qtdemux->preferred_protection_system_id = NULL;
2075 } else if (qtdemux->mss_mode) {
2076 gst_flow_combiner_reset (qtdemux->flowcombiner);
2077 g_ptr_array_foreach (qtdemux->active_streams,
2078 (GFunc) gst_qtdemux_stream_clear, NULL);
2080 gst_flow_combiner_reset (qtdemux->flowcombiner);
2081 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2082 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2083 stream->sent_eos = FALSE;
2084 stream->time_position = 0;
2085 stream->accumulated_base = 0;
2086 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2092 /* Maps the @segment to the qt edts internal segments and pushes
2093 * the corresponding segment event.
2095 * If it ends up being at a empty segment, a gap will be pushed and the next
2096 * edts segment will be activated in sequence.
2098 * To be used in push-mode only */
2100 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2104 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2105 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2107 stream->time_position = segment->start;
2109 /* in push mode we should be guaranteed that we will have empty segments
2110 * at the beginning and then one segment after, other scenarios are not
2111 * supported and are discarded when parsing the edts */
2112 for (i = 0; i < stream->n_segments; i++) {
2113 if (stream->segments[i].stop_time > segment->start) {
2114 /* push the empty segment and move to the next one */
2115 gst_qtdemux_activate_segment (qtdemux, stream, i,
2116 stream->time_position);
2117 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2118 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2119 stream->time_position);
2121 /* accumulate previous segments */
2122 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2123 stream->accumulated_base +=
2124 (stream->segment.stop -
2125 stream->segment.start) / ABS (stream->segment.rate);
2129 g_assert (i == stream->n_segments - 1);
2136 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2147 for (i = 0; i < len; i++) {
2148 QtDemuxStream *stream = g_ptr_array_index (src, i);
2150 #ifndef GST_DISABLE_GST_DEBUG
2151 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2152 stream, GST_STR_NULL (stream->stream_id), dest);
2154 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2157 g_ptr_array_set_size (src, 0);
2161 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2164 GstQTDemux *demux = GST_QTDEMUX (parent);
2165 gboolean res = TRUE;
2167 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2169 switch (GST_EVENT_TYPE (event)) {
2170 case GST_EVENT_SEGMENT:
2173 QtDemuxStream *stream;
2177 /* some debug output */
2178 gst_event_copy_segment (event, &segment);
2179 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2182 if (segment.format == GST_FORMAT_TIME) {
2183 demux->upstream_format_is_time = TRUE;
2184 demux->segment_seqnum = gst_event_get_seqnum (event);
2186 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2187 "not in time format");
2189 /* chain will send initial newsegment after pads have been added */
2190 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2191 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2196 /* check if this matches a time seek we received previously
2197 * FIXME for backwards compatibility reasons we use the
2198 * seek_offset here to compare. In the future we might want to
2199 * change this to use the seqnum as it uniquely should identify
2200 * the segment that corresponds to the seek. */
2201 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2202 ", received segment offset %" G_GINT64_FORMAT,
2203 demux->seek_offset, segment.start);
2204 if (segment.format == GST_FORMAT_BYTES
2205 && demux->seek_offset == segment.start) {
2206 GST_OBJECT_LOCK (demux);
2207 offset = segment.start;
2209 segment.format = GST_FORMAT_TIME;
2210 segment.start = demux->push_seek_start;
2211 segment.stop = demux->push_seek_stop;
2212 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2213 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2214 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2215 GST_OBJECT_UNLOCK (demux);
2218 /* we only expect a BYTE segment, e.g. following a seek */
2219 if (segment.format == GST_FORMAT_BYTES) {
2220 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2221 offset = segment.start;
2223 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2224 NULL, (gint64 *) & segment.start);
2225 if ((gint64) segment.start < 0)
2228 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2229 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2230 NULL, (gint64 *) & segment.stop);
2231 /* keyframe seeking should already arrange for start >= stop,
2232 * but make sure in other rare cases */
2233 segment.stop = MAX (segment.stop, segment.start);
2235 } else if (segment.format == GST_FORMAT_TIME) {
2236 /* push all data on the adapter before starting this
2238 gst_qtdemux_process_adapter (demux, TRUE);
2240 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2244 /* We shouldn't modify upstream driven TIME FORMAT segment */
2245 if (!demux->upstream_format_is_time) {
2246 /* accept upstream's notion of segment and distribute along */
2247 segment.format = GST_FORMAT_TIME;
2248 segment.position = segment.time = segment.start;
2249 segment.duration = demux->segment.duration;
2250 segment.base = gst_segment_to_running_time (&demux->segment,
2251 GST_FORMAT_TIME, demux->segment.position);
2254 gst_segment_copy_into (&segment, &demux->segment);
2255 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2257 /* map segment to internal qt segments and push on each stream */
2258 if (QTDEMUX_N_STREAMS (demux)) {
2259 demux->need_segment = TRUE;
2260 gst_qtdemux_check_send_pending_segment (demux);
2263 /* clear leftover in current segment, if any */
2264 gst_adapter_clear (demux->adapter);
2266 /* set up streaming thread */
2267 demux->offset = offset;
2268 if (demux->upstream_format_is_time) {
2269 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2270 "set values to restart reading from a new atom");
2271 demux->neededbytes = 16;
2274 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2277 demux->todrop = stream->samples[idx].offset - offset;
2278 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2280 /* set up for EOS */
2281 demux->neededbytes = -1;
2286 gst_event_unref (event);
2290 case GST_EVENT_FLUSH_START:
2292 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2293 gst_event_unref (event);
2296 QTDEMUX_EXPOSE_LOCK (demux);
2297 res = gst_pad_event_default (demux->sinkpad, parent, event);
2298 QTDEMUX_EXPOSE_UNLOCK (demux);
2301 case GST_EVENT_FLUSH_STOP:
2305 dur = demux->segment.duration;
2306 gst_qtdemux_reset (demux, FALSE);
2307 demux->segment.duration = dur;
2309 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2310 gst_event_unref (event);
2316 /* If we are in push mode, and get an EOS before we've seen any streams,
2317 * then error out - we have nowhere to send the EOS */
2318 if (!demux->pullbased) {
2320 gboolean has_valid_stream = FALSE;
2321 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2322 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2323 has_valid_stream = TRUE;
2327 if (!has_valid_stream)
2328 gst_qtdemux_post_no_playable_stream_error (demux);
2330 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2331 (guint) gst_adapter_available (demux->adapter));
2332 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2338 case GST_EVENT_CAPS:{
2339 GstCaps *caps = NULL;
2341 gst_event_parse_caps (event, &caps);
2342 gst_qtdemux_setcaps (demux, caps);
2344 gst_event_unref (event);
2347 case GST_EVENT_PROTECTION:
2349 const gchar *system_id = NULL;
2351 gst_event_parse_protection (event, &system_id, NULL, NULL);
2352 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2354 gst_qtdemux_append_protection_system_id (demux, system_id);
2355 /* save the event for later, for source pads that have not been created */
2356 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2357 /* send it to all pads that already exist */
2358 gst_qtdemux_push_event (demux, event);
2362 case GST_EVENT_STREAM_START:
2365 gst_event_unref (event);
2367 /* Drain all the buffers */
2368 gst_qtdemux_process_adapter (demux, TRUE);
2369 gst_qtdemux_reset (demux, FALSE);
2370 /* We expect new moov box after new stream-start event */
2371 if (demux->exposed) {
2372 gst_qtdemux_stream_concat (demux,
2373 demux->old_streams, demux->active_streams);
2382 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2389 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2392 GstQTDemux *demux = GST_QTDEMUX (parent);
2393 gboolean res = FALSE;
2395 switch (GST_QUERY_TYPE (query)) {
2396 case GST_QUERY_BITRATE:
2398 GstClockTime duration;
2400 /* populate demux->upstream_size if not done yet */
2401 gst_qtdemux_check_seekability (demux);
2403 if (demux->upstream_size != -1
2404 && gst_qtdemux_get_duration (demux, &duration)) {
2406 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2409 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2410 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2411 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2413 /* TODO: better results based on ranges/index tables */
2414 gst_query_set_bitrate (query, bitrate);
2420 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2430 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2432 GstQTDemux *demux = GST_QTDEMUX (element);
2434 GST_OBJECT_LOCK (demux);
2435 if (demux->element_index)
2436 gst_object_unref (demux->element_index);
2438 demux->element_index = gst_object_ref (index);
2440 demux->element_index = NULL;
2442 GST_OBJECT_UNLOCK (demux);
2443 /* object lock might be taken again */
2445 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2446 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2447 demux->element_index, demux->index_id);
2451 gst_qtdemux_get_index (GstElement * element)
2453 GstIndex *result = NULL;
2454 GstQTDemux *demux = GST_QTDEMUX (element);
2456 GST_OBJECT_LOCK (demux);
2457 if (demux->element_index)
2458 result = gst_object_ref (demux->element_index);
2459 GST_OBJECT_UNLOCK (demux);
2461 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2468 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2470 g_free ((gpointer) stream->stco.data);
2471 stream->stco.data = NULL;
2472 g_free ((gpointer) stream->stsz.data);
2473 stream->stsz.data = NULL;
2474 g_free ((gpointer) stream->stsc.data);
2475 stream->stsc.data = NULL;
2476 g_free ((gpointer) stream->stts.data);
2477 stream->stts.data = NULL;
2478 g_free ((gpointer) stream->stss.data);
2479 stream->stss.data = NULL;
2480 g_free ((gpointer) stream->stps.data);
2481 stream->stps.data = NULL;
2482 g_free ((gpointer) stream->ctts.data);
2483 stream->ctts.data = NULL;
2487 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2489 g_free (stream->segments);
2490 stream->segments = NULL;
2491 stream->segment_index = -1;
2492 stream->accumulated_base = 0;
2496 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2498 g_free (stream->samples);
2499 stream->samples = NULL;
2500 gst_qtdemux_stbl_free (stream);
2503 g_free (stream->ra_entries);
2504 stream->ra_entries = NULL;
2505 stream->n_ra_entries = 0;
2507 stream->sample_index = -1;
2508 stream->stbl_index = -1;
2509 stream->n_samples = 0;
2510 stream->time_position = 0;
2512 stream->n_samples_moof = 0;
2513 stream->duration_moof = 0;
2514 stream->duration_last_moof = 0;
2518 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2521 if (stream->allocator)
2522 gst_object_unref (stream->allocator);
2523 while (stream->buffers) {
2524 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2525 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2527 for (i = 0; i < stream->stsd_entries_length; i++) {
2528 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2529 if (entry->rgb8_palette) {
2530 gst_memory_unref (entry->rgb8_palette);
2531 entry->rgb8_palette = NULL;
2533 entry->sparse = FALSE;
2536 if (stream->stream_tags)
2537 gst_tag_list_unref (stream->stream_tags);
2539 stream->stream_tags = gst_tag_list_new_empty ();
2540 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2541 g_free (stream->redirect_uri);
2542 stream->redirect_uri = NULL;
2543 stream->sent_eos = FALSE;
2544 stream->protected = FALSE;
2545 if (stream->protection_scheme_info) {
2546 if (stream->protection_scheme_type == FOURCC_cenc
2547 || stream->protection_scheme_type == FOURCC_cbcs) {
2548 QtDemuxCencSampleSetInfo *info =
2549 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2550 if (info->default_properties)
2551 gst_structure_free (info->default_properties);
2552 if (info->crypto_info)
2553 g_ptr_array_free (info->crypto_info, TRUE);
2555 if (stream->protection_scheme_type == FOURCC_aavd) {
2556 QtDemuxAavdEncryptionInfo *info =
2557 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2558 if (info->default_properties)
2559 gst_structure_free (info->default_properties);
2561 g_free (stream->protection_scheme_info);
2562 stream->protection_scheme_info = NULL;
2564 stream->protection_scheme_type = 0;
2565 stream->protection_scheme_version = 0;
2566 g_queue_foreach (&stream->protection_scheme_event_queue,
2567 (GFunc) gst_event_unref, NULL);
2568 g_queue_clear (&stream->protection_scheme_event_queue);
2569 gst_qtdemux_stream_flush_segments_data (stream);
2570 gst_qtdemux_stream_flush_samples_data (stream);
2574 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2577 gst_qtdemux_stream_clear (stream);
2578 for (i = 0; i < stream->stsd_entries_length; i++) {
2579 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2581 gst_caps_unref (entry->caps);
2585 g_free (stream->stsd_entries);
2586 stream->stsd_entries = NULL;
2587 stream->stsd_entries_length = 0;
2590 static QtDemuxStream *
2591 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2593 g_atomic_int_add (&stream->ref_count, 1);
2599 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2601 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2602 gst_qtdemux_stream_reset (stream);
2603 gst_tag_list_unref (stream->stream_tags);
2605 GstQTDemux *demux = stream->demux;
2606 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2607 GST_OBJECT_LOCK (demux);
2608 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2609 GST_OBJECT_UNLOCK (demux);
2611 g_free (stream->stream_id);
2616 static GstStateChangeReturn
2617 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2619 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2620 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2622 switch (transition) {
2623 case GST_STATE_CHANGE_READY_TO_PAUSED:
2624 gst_qtdemux_reset (qtdemux, TRUE);
2630 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2632 switch (transition) {
2633 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2634 gst_qtdemux_reset (qtdemux, TRUE);
2645 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2647 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2649 g_return_if_fail (GST_IS_CONTEXT (context));
2651 if (gst_context_has_context_type (context,
2652 "drm-preferred-decryption-system-id")) {
2653 const GstStructure *s;
2655 s = gst_context_get_structure (context);
2656 g_free (qtdemux->preferred_protection_system_id);
2657 qtdemux->preferred_protection_system_id =
2658 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2659 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2660 qtdemux->preferred_protection_system_id);
2663 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2667 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2669 /* counts as header data */
2670 qtdemux->header_size += length;
2672 /* only consider at least a sufficiently complete ftyp atom */
2676 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2677 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2678 GST_FOURCC_ARGS (qtdemux->major_brand));
2679 if (qtdemux->comp_brands)
2680 gst_buffer_unref (qtdemux->comp_brands);
2681 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2682 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2687 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2688 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2689 guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2690 guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2691 const guint8 * constant_iv)
2693 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2694 gst_buffer_fill (kid_buf, 0, kid, 16);
2695 if (info->default_properties)
2696 gst_structure_free (info->default_properties);
2697 info->default_properties =
2698 gst_structure_new ("application/x-cenc",
2699 "iv_size", G_TYPE_UINT, iv_size,
2700 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2701 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2702 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2703 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2704 gst_buffer_unref (kid_buf);
2705 if (protection_scheme_type == FOURCC_cbcs) {
2706 if (crypt_byte_block != 0 || skip_byte_block != 0) {
2707 gst_structure_set (info->default_properties, "crypt_byte_block",
2708 G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2709 skip_byte_block, NULL);
2711 if (constant_iv != NULL) {
2712 GstBuffer *constant_iv_buf =
2713 gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2714 gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2715 gst_structure_set (info->default_properties, "constant_iv_size",
2716 G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2718 gst_buffer_unref (constant_iv_buf);
2720 gst_structure_set (info->default_properties, "cipher-mode",
2721 G_TYPE_STRING, "cbcs", NULL);
2723 gst_structure_set (info->default_properties, "cipher-mode",
2724 G_TYPE_STRING, "cenc", NULL);
2729 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2730 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2732 guint32 algorithm_id = 0;
2734 gboolean is_encrypted = TRUE;
2737 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2738 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2743 if (algorithm_id == 0) {
2744 is_encrypted = FALSE;
2745 } else if (algorithm_id == 1) {
2746 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2747 } else if (algorithm_id == 2) {
2748 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2751 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2754 if (!gst_byte_reader_get_data (br, 16, &kid))
2757 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2758 is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2759 gst_structure_set (info->default_properties, "piff_algorithm_id",
2760 G_TYPE_UINT, algorithm_id, NULL);
2766 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2774 QtDemuxStream *stream;
2775 GstStructure *structure;
2776 QtDemuxCencSampleSetInfo *ss_info = NULL;
2777 const gchar *system_id;
2778 gboolean uses_sub_sample_encryption = FALSE;
2779 guint32 sample_count;
2781 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2784 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2786 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2787 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2788 GST_WARNING_OBJECT (qtdemux,
2789 "Attempting PIFF box parsing on an unencrypted stream.");
2793 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2794 G_TYPE_STRING, &system_id, NULL);
2795 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2797 stream->protected = TRUE;
2798 stream->protection_scheme_type = FOURCC_cenc;
2800 if (!stream->protection_scheme_info)
2801 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2803 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2804 if (!ss_info->default_properties) {
2805 ss_info->default_properties =
2806 gst_structure_new ("application/x-cenc",
2807 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2812 if (ss_info->crypto_info) {
2813 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2814 g_ptr_array_free (ss_info->crypto_info, TRUE);
2815 ss_info->crypto_info = NULL;
2819 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2821 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2822 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2826 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2827 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2831 if ((flags & 0x000001)) {
2832 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2835 } else if ((flags & 0x000002)) {
2836 uses_sub_sample_encryption = TRUE;
2839 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2841 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2845 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2846 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2850 ss_info->crypto_info =
2851 g_ptr_array_new_full (sample_count,
2852 (GDestroyNotify) qtdemux_gst_structure_free);
2854 for (i = 0; i < sample_count; ++i) {
2855 GstStructure *properties;
2859 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2860 if (properties == NULL) {
2861 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2862 qtdemux->cenc_aux_sample_count = i;
2866 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2867 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2868 gst_structure_free (properties);
2869 qtdemux->cenc_aux_sample_count = i;
2872 buf = gst_buffer_new_wrapped (data, iv_size);
2873 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2874 gst_buffer_unref (buf);
2876 if (uses_sub_sample_encryption) {
2877 guint16 n_subsamples;
2878 const GValue *kid_buf_value;
2880 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2881 || n_subsamples == 0) {
2882 GST_ERROR_OBJECT (qtdemux,
2883 "failed to get subsample count for sample %u", i);
2884 gst_structure_free (properties);
2885 qtdemux->cenc_aux_sample_count = i;
2888 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2889 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2890 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2892 gst_structure_free (properties);
2893 qtdemux->cenc_aux_sample_count = i;
2896 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2899 gst_structure_get_value (ss_info->default_properties, "kid");
2901 gst_structure_set (properties,
2902 "subsample_count", G_TYPE_UINT, n_subsamples,
2903 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2904 gst_structure_set_value (properties, "kid", kid_buf_value);
2905 gst_buffer_unref (buf);
2907 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2910 g_ptr_array_add (ss_info->crypto_info, properties);
2913 qtdemux->cenc_aux_sample_count = sample_count;
2917 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2919 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2920 0x97, 0xA9, 0x42, 0xE8,
2921 0x9C, 0x71, 0x99, 0x94,
2922 0x91, 0xE3, 0xAF, 0xAC
2924 static const guint8 playready_uuid[] = {
2925 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2926 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2929 static const guint8 piff_sample_encryption_uuid[] = {
2930 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2931 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2936 /* counts as header data */
2937 qtdemux->header_size += length;
2939 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2941 if (length <= offset + 16) {
2942 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2946 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2948 GstTagList *taglist;
2950 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2951 length - offset - 16, NULL);
2952 taglist = gst_tag_list_from_xmp_buffer (buf);
2953 gst_buffer_unref (buf);
2955 /* make sure we have a usable taglist */
2956 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2958 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2960 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2962 const gunichar2 *s_utf16;
2965 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2966 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2967 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2968 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2972 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2973 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2975 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2976 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2978 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2979 GST_READ_UINT32_LE (buffer + offset),
2980 GST_READ_UINT32_LE (buffer + offset + 4),
2981 GST_READ_UINT32_LE (buffer + offset + 8),
2982 GST_READ_UINT32_LE (buffer + offset + 12));
2987 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2989 GstSidxParser sidx_parser;
2990 GstIsoffParserResult res;
2993 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2996 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2998 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2999 if (res == GST_ISOFF_QT_PARSER_DONE) {
3000 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3002 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3005 /* caller verifies at least 8 bytes in buf */
3007 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3008 guint64 * plength, guint32 * pfourcc)
3013 length = QT_UINT32 (data);
3014 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3015 fourcc = QT_FOURCC (data + 4);
3016 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3019 length = G_MAXUINT64;
3020 } else if (length == 1 && size >= 16) {
3021 /* this means we have an extended size, which is the 64 bit value of
3022 * the next 8 bytes */
3023 length = QT_UINT64 (data + 8);
3024 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3034 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3036 guint32 version = 0;
3037 GstClockTime duration = 0;
3039 if (!gst_byte_reader_get_uint32_be (br, &version))
3044 if (!gst_byte_reader_get_uint64_be (br, &duration))
3049 if (!gst_byte_reader_get_uint32_be (br, &dur))
3054 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3055 qtdemux->duration = duration;
3061 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3067 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3068 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3070 if (!stream->parsed_trex && qtdemux->moov_node) {
3072 GstByteReader trex_data;
3074 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3076 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3079 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3081 /* skip version/flags */
3082 if (!gst_byte_reader_skip (&trex_data, 4))
3084 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3086 if (id != stream->track_id)
3088 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3090 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3092 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3094 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3097 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3098 "duration %d, size %d, flags 0x%x", stream->track_id,
3101 stream->parsed_trex = TRUE;
3102 stream->def_sample_description_index = sdi;
3103 stream->def_sample_duration = dur;
3104 stream->def_sample_size = size;
3105 stream->def_sample_flags = flags;
3108 /* iterate all siblings */
3109 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3115 *ds_duration = stream->def_sample_duration;
3116 *ds_size = stream->def_sample_size;
3117 *ds_flags = stream->def_sample_flags;
3119 /* even then, above values are better than random ... */
3120 if (G_UNLIKELY (!stream->parsed_trex)) {
3121 GST_WARNING_OBJECT (qtdemux,
3122 "failed to find fragment defaults for stream %d", stream->track_id);
3129 /* This method should be called whenever a more accurate duration might
3130 * have been found. It will update all relevant variables if/where needed
3133 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3137 GstClockTime prevdur;
3139 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3141 if (movdur > qtdemux->duration) {
3142 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3143 GST_DEBUG_OBJECT (qtdemux,
3144 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3145 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3146 qtdemux->duration = movdur;
3147 GST_DEBUG_OBJECT (qtdemux,
3148 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3149 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3150 GST_TIME_ARGS (qtdemux->segment.stop));
3151 if (qtdemux->segment.duration == prevdur) {
3152 /* If the current segment has duration/stop identical to previous duration
3153 * update them also (because they were set at that point in time with
3154 * the wrong duration */
3155 /* We convert the value *from* the timescale version to avoid rounding errors */
3156 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3157 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3158 qtdemux->segment.duration = fixeddur;
3159 qtdemux->segment.stop = fixeddur;
3163 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3164 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3166 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3167 if (movdur > stream->duration) {
3168 GST_DEBUG_OBJECT (qtdemux,
3169 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3170 GST_TIME_ARGS (duration));
3171 stream->duration = movdur;
3172 /* internal duration tracking state has been updated above, so */
3173 /* preserve an open-ended dummy segment rather than repeatedly updating
3174 * it and spamming downstream accordingly with segment events */
3175 /* also mangle the edit list end time when fragmented with a single edit
3176 * list that may only cover any non-fragmented data */
3177 if ((stream->dummy_segment ||
3178 (qtdemux->fragmented && stream->n_segments == 1)) &&
3179 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3180 /* Update all dummy values to new duration */
3181 stream->segments[0].stop_time = duration;
3182 stream->segments[0].duration = duration;
3183 stream->segments[0].media_stop = duration;
3185 /* let downstream know we possibly have a new stop time */
3186 if (stream->segment_index != -1) {
3189 if (qtdemux->segment.rate >= 0) {
3190 pos = stream->segment.start;
3192 pos = stream->segment.stop;
3195 gst_qtdemux_stream_update_segment (qtdemux, stream,
3196 stream->segment_index, pos, NULL, NULL);
3204 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3205 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3206 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3207 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3210 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3212 gint32 data_offset = 0;
3214 guint32 flags = 0, first_flags = 0, samples_count = 0;
3217 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3218 QtDemuxSample *sample;
3219 gboolean ismv = FALSE;
3220 gint64 initial_offset;
3223 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3224 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3225 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3226 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3228 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3229 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3233 /* presence of stss or not can't really tell us much,
3234 * and flags and so on tend to be marginally reliable in these files */
3235 if (stream->subtype == FOURCC_soun) {
3236 GST_DEBUG_OBJECT (qtdemux,
3237 "sound track in fragmented file; marking all keyframes");
3238 stream->all_keyframe = TRUE;
3241 if (!gst_byte_reader_get_uint8 (trun, &version) ||
3242 !gst_byte_reader_get_uint24_be (trun, &flags))
3245 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3248 if (flags & TR_DATA_OFFSET) {
3249 /* note this is really signed */
3250 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3252 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3253 /* default base offset = first byte of moof */
3254 if (*base_offset == -1) {
3255 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3256 *base_offset = moof_offset;
3258 *running_offset = *base_offset + data_offset;
3260 /* if no offset at all, that would mean data starts at moof start,
3261 * which is a bit wrong and is ismv crappy way, so compensate
3262 * assuming data is in mdat following moof */
3263 if (*base_offset == -1) {
3264 *base_offset = moof_offset + moof_length + 8;
3265 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3268 if (*running_offset == -1)
3269 *running_offset = *base_offset;
3272 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3274 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3275 data_offset, flags, samples_count);
3277 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3278 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3279 GST_DEBUG_OBJECT (qtdemux,
3280 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3281 flags ^= TR_FIRST_SAMPLE_FLAGS;
3283 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3285 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3289 /* FIXME ? spec says other bits should also be checked to determine
3290 * entry size (and prefix size for that matter) */
3292 dur_offset = size_offset = 0;
3293 if (flags & TR_SAMPLE_DURATION) {
3294 GST_LOG_OBJECT (qtdemux, "entry duration present");
3295 dur_offset = entry_size;
3298 if (flags & TR_SAMPLE_SIZE) {
3299 GST_LOG_OBJECT (qtdemux, "entry size present");
3300 size_offset = entry_size;
3303 if (flags & TR_SAMPLE_FLAGS) {
3304 GST_LOG_OBJECT (qtdemux, "entry flags present");
3305 flags_offset = entry_size;
3308 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3309 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3310 ct_offset = entry_size;
3314 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3316 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3318 if (stream->n_samples + samples_count >=
3319 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3322 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3323 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3324 (stream->n_samples + samples_count) *
3325 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3327 /* create a new array of samples if it's the first sample parsed */
3328 if (stream->n_samples == 0) {
3329 g_assert (stream->samples == NULL);
3330 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3331 /* or try to reallocate it with space enough to insert the new samples */
3333 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3334 stream->n_samples + samples_count);
3335 if (stream->samples == NULL)
3338 if (qtdemux->fragment_start != -1) {
3339 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3340 qtdemux->fragment_start = -1;
3342 if (stream->n_samples == 0) {
3343 if (decode_ts > 0) {
3344 timestamp = decode_ts;
3345 } else if (stream->pending_seek != NULL) {
3346 /* if we don't have a timestamp from a tfdt box, we'll use the one
3347 * from the mfra seek table */
3348 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3349 GST_TIME_ARGS (stream->pending_seek->ts));
3351 /* FIXME: this is not fully correct, the timestamp refers to the random
3352 * access sample refered to in the tfra entry, which may not necessarily
3353 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3354 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3359 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3360 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3361 GST_TIME_ARGS (gst_ts));
3363 /* subsequent fragments extend stream */
3365 stream->samples[stream->n_samples - 1].timestamp +
3366 stream->samples[stream->n_samples - 1].duration;
3368 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3369 * difference (1 sec.) between decode_ts and timestamp, prefer the
3371 if (has_tfdt && !qtdemux->upstream_format_is_time
3372 && ABSDIFF (decode_ts, timestamp) >
3373 MAX (stream->duration_last_moof / 2,
3374 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3375 GST_INFO_OBJECT (qtdemux,
3376 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3377 ") are significantly different (more than %" GST_TIME_FORMAT
3378 "), using decode_ts",
3379 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3380 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3381 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3382 MAX (stream->duration_last_moof / 2,
3383 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3384 timestamp = decode_ts;
3387 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3388 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3389 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3393 initial_offset = *running_offset;
3395 sample = stream->samples + stream->n_samples;
3396 for (i = 0; i < samples_count; i++) {
3397 guint32 dur, size, sflags;
3400 /* first read sample data */
3401 if (flags & TR_SAMPLE_DURATION) {
3402 dur = QT_UINT32 (data + dur_offset);
3404 dur = d_sample_duration;
3406 if (flags & TR_SAMPLE_SIZE) {
3407 size = QT_UINT32 (data + size_offset);
3409 size = d_sample_size;
3411 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3413 sflags = first_flags;
3415 sflags = d_sample_flags;
3417 } else if (flags & TR_SAMPLE_FLAGS) {
3418 sflags = QT_UINT32 (data + flags_offset);
3420 sflags = d_sample_flags;
3423 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3424 /* Read offsets as signed numbers regardless of trun version as very
3425 * high offsets are unlikely and there are files out there that use
3426 * version=0 truns with negative offsets */
3427 ct = QT_UINT32 (data + ct_offset);
3433 /* fill the sample information */
3434 sample->offset = *running_offset;
3435 sample->pts_offset = ct;
3436 sample->size = size;
3437 sample->timestamp = timestamp;
3438 sample->duration = dur;
3439 /* sample-is-difference-sample */
3440 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3441 * now idea how it relates to bitfield other than massive LE/BE confusion */
3442 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3443 *running_offset += size;
3445 stream->duration_moof += dur;
3452 /* Shift PTS/DTS to allow for negative composition offsets while keeping
3453 * A/V sync in place. This is similar to the code handling ctts/cslg in the
3454 * non-fragmented case.
3457 stream->cslg_shift = -min_ct;
3459 stream->cslg_shift = 0;
3461 /* Update total duration if needed */
3462 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3464 /* Pre-emptively figure out size of mdat based on trun information.
3465 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3466 * size, else we will still be able to use this when dealing with gap'ed
3468 qtdemux->mdatleft = *running_offset - initial_offset;
3469 qtdemux->mdatoffset = initial_offset;
3470 qtdemux->mdatsize = qtdemux->mdatleft;
3472 stream->n_samples += samples_count;
3473 stream->n_samples_moof += samples_count;
3475 if (stream->pending_seek != NULL)
3476 stream->pending_seek = NULL;
3482 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3487 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3493 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3494 "be larger than %uMB (broken file?)", stream->n_samples,
3495 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3500 /* find stream with @id */
3501 static inline QtDemuxStream *
3502 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3504 QtDemuxStream *stream;
3508 if (G_UNLIKELY (!id)) {
3509 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3513 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3514 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3515 if (stream->track_id == id)
3518 if (qtdemux->mss_mode) {
3519 /* mss should have only 1 stream anyway */
3520 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3527 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3528 guint32 * fragment_number)
3530 if (!gst_byte_reader_skip (mfhd, 4))
3532 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3537 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3543 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3544 QtDemuxStream ** stream, guint32 * default_sample_duration,
3545 guint32 * default_sample_size, guint32 * default_sample_flags,
3546 gint64 * base_offset)
3549 guint32 track_id = 0;
3551 if (!gst_byte_reader_skip (tfhd, 1) ||
3552 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3555 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3558 *stream = qtdemux_find_stream (qtdemux, track_id);
3559 if (G_UNLIKELY (!*stream))
3560 goto unknown_stream;
3562 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3563 *base_offset = qtdemux->moof_offset;
3565 if (flags & TF_BASE_DATA_OFFSET)
3566 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3569 /* obtain stream defaults */
3570 qtdemux_parse_trex (qtdemux, *stream,
3571 default_sample_duration, default_sample_size, default_sample_flags);
3573 (*stream)->stsd_sample_description_id =
3574 (*stream)->def_sample_description_index - 1;
3576 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3577 guint32 sample_description_index;
3578 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3580 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3583 if (qtdemux->mss_mode) {
3584 /* mss has no stsd entry */
3585 (*stream)->stsd_sample_description_id = 0;
3588 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3589 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3592 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3593 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3596 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3597 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3604 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3609 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3615 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3616 guint64 * decode_time)
3618 guint32 version = 0;
3620 if (!gst_byte_reader_get_uint32_be (br, &version))
3625 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3628 guint32 dec_time = 0;
3629 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3631 *decode_time = dec_time;
3634 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3641 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3646 /* Returns a pointer to a GstStructure containing the properties of
3647 * the stream sample identified by @sample_index. The caller must unref
3648 * the returned object after use. Returns NULL if unsuccessful. */
3649 static GstStructure *
3650 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3651 QtDemuxStream * stream, guint sample_index)
3653 QtDemuxCencSampleSetInfo *info = NULL;
3655 g_return_val_if_fail (stream != NULL, NULL);
3656 g_return_val_if_fail (stream->protected, NULL);
3657 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3659 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3661 /* Currently, cenc properties for groups of samples are not supported, so
3662 * simply return a copy of the default sample properties */
3663 return gst_structure_copy (info->default_properties);
3666 /* Parses the sizes of sample auxiliary information contained within a stream,
3667 * as given in a saiz box. Returns array of sample_count guint8 size values,
3668 * or NULL on failure */
3670 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3671 GstByteReader * br, guint32 * sample_count)
3675 guint8 default_info_size;
3677 g_return_val_if_fail (qtdemux != NULL, NULL);
3678 g_return_val_if_fail (stream != NULL, NULL);
3679 g_return_val_if_fail (br != NULL, NULL);
3680 g_return_val_if_fail (sample_count != NULL, NULL);
3682 if (!gst_byte_reader_get_uint32_be (br, &flags))
3686 /* aux_info_type and aux_info_type_parameter are ignored */
3687 if (!gst_byte_reader_skip (br, 8))
3691 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3693 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3695 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3697 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3700 if (default_info_size == 0) {
3701 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3705 info_sizes = g_new (guint8, *sample_count);
3706 memset (info_sizes, default_info_size, *sample_count);
3712 /* Parses the offset of sample auxiliary information contained within a stream,
3713 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3715 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3716 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3721 guint32 aux_info_type = 0;
3722 guint32 aux_info_type_parameter = 0;
3723 guint32 entry_count;
3726 const guint8 *aux_info_type_data = NULL;
3728 g_return_val_if_fail (qtdemux != NULL, FALSE);
3729 g_return_val_if_fail (stream != NULL, FALSE);
3730 g_return_val_if_fail (br != NULL, FALSE);
3731 g_return_val_if_fail (offset != NULL, FALSE);
3733 if (!gst_byte_reader_get_uint8 (br, &version))
3736 if (!gst_byte_reader_get_uint24_be (br, &flags))
3741 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3743 aux_info_type = QT_FOURCC (aux_info_type_data);
3745 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3747 } else if (stream->protected) {
3748 aux_info_type = stream->protection_scheme_type;
3750 aux_info_type = CUR_STREAM (stream)->fourcc;
3754 *info_type = aux_info_type;
3755 if (info_type_parameter)
3756 *info_type_parameter = aux_info_type_parameter;
3758 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3759 "aux_info_type_parameter: %#06x",
3760 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3762 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3765 if (entry_count != 1) {
3766 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3771 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3773 *offset = (guint64) off_32;
3775 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3780 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3785 qtdemux_gst_structure_free (GstStructure * gststructure)
3788 gst_structure_free (gststructure);
3792 /* Parses auxiliary information relating to samples protected using
3793 * Common Encryption (cenc); the format of this information
3794 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3797 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3798 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3800 QtDemuxCencSampleSetInfo *ss_info = NULL;
3803 GPtrArray *old_crypto_info = NULL;
3804 guint old_entries = 0;
3806 g_return_val_if_fail (qtdemux != NULL, FALSE);
3807 g_return_val_if_fail (stream != NULL, FALSE);
3808 g_return_val_if_fail (br != NULL, FALSE);
3809 g_return_val_if_fail (stream->protected, FALSE);
3810 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3812 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3814 if (ss_info->crypto_info) {
3815 old_crypto_info = ss_info->crypto_info;
3816 /* Count number of non-null entries remaining at the tail end */
3817 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3818 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3824 ss_info->crypto_info =
3825 g_ptr_array_new_full (sample_count + old_entries,
3826 (GDestroyNotify) qtdemux_gst_structure_free);
3828 /* We preserve old entries because we parse the next moof in advance
3829 * of consuming all samples from the previous moof, and otherwise
3830 * we'd discard the corresponding crypto info for the samples
3831 * from the previous fragment. */
3833 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3835 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3836 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3838 g_ptr_array_index (old_crypto_info, i) = NULL;
3842 if (old_crypto_info) {
3843 /* Everything now belongs to the new array */
3844 g_ptr_array_free (old_crypto_info, TRUE);
3847 for (i = 0; i < sample_count; ++i) {
3848 GstStructure *properties;
3849 guint16 n_subsamples = 0;
3853 gboolean could_read_iv;
3855 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3856 if (properties == NULL) {
3857 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3860 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3861 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3862 gst_structure_free (properties);
3866 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3867 if (could_read_iv) {
3868 buf = gst_buffer_new_wrapped (data, iv_size);
3869 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3870 gst_buffer_unref (buf);
3871 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3872 const GValue *constant_iv_size_value =
3873 gst_structure_get_value (properties, "constant_iv_size");
3874 const GValue *constant_iv_value =
3875 gst_structure_get_value (properties, "iv");
3876 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3877 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3878 gst_structure_free (properties);
3881 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3882 gst_structure_remove_field (properties, "constant_iv_size");
3883 } else if (stream->protection_scheme_type == FOURCC_cenc) {
3884 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3885 gst_structure_free (properties);
3888 size = info_sizes[i];
3889 if (size > iv_size) {
3890 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3891 || !(n_subsamples > 0)) {
3892 gst_structure_free (properties);
3893 GST_ERROR_OBJECT (qtdemux,
3894 "failed to get subsample count for sample %u", i);
3897 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3898 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3899 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3901 gst_structure_free (properties);
3904 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3906 gst_structure_free (properties);
3909 gst_structure_set (properties,
3910 "subsample_count", G_TYPE_UINT, n_subsamples,
3911 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3912 gst_buffer_unref (buf);
3914 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3916 g_ptr_array_add (ss_info->crypto_info, properties);
3921 /* Converts a UUID in raw byte form to a string representation, as defined in
3922 * RFC 4122. The caller takes ownership of the returned string and is
3923 * responsible for freeing it after use. */
3925 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3927 const guint8 *uuid = (const guint8 *) uuid_bytes;
3929 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3930 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3931 uuid[0], uuid[1], uuid[2], uuid[3],
3932 uuid[4], uuid[5], uuid[6], uuid[7],
3933 uuid[8], uuid[9], uuid[10], uuid[11],
3934 uuid[12], uuid[13], uuid[14], uuid[15]);
3937 /* Parses a Protection System Specific Header box (pssh), as defined in the
3938 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3939 * information needed by a specific content protection system in order to
3940 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3943 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3945 gchar *sysid_string;
3946 guint32 pssh_size = QT_UINT32 (node->data);
3947 GstBuffer *pssh = NULL;
3948 GstEvent *event = NULL;
3949 guint32 parent_box_type;
3952 if (G_UNLIKELY (pssh_size < 32U)) {
3953 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3958 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3960 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3962 pssh = gst_buffer_new_memdup (node->data, pssh_size);
3963 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3964 gst_buffer_get_size (pssh));
3966 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3968 /* Push an event containing the pssh box onto the queues of all streams. */
3969 event = gst_event_new_protection (sysid_string, pssh,
3970 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3971 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3972 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3973 GST_TRACE_OBJECT (qtdemux,
3974 "adding protection event for stream %s and system %s",
3975 stream->stream_id, sysid_string);
3976 g_queue_push_tail (&stream->protection_scheme_event_queue,
3977 gst_event_ref (event));
3979 g_free (sysid_string);
3980 gst_event_unref (event);
3981 gst_buffer_unref (pssh);
3986 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3987 guint64 moof_offset, QtDemuxStream * stream)
3989 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3991 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3992 GNode *saiz_node, *saio_node, *pssh_node;
3993 GstByteReader saiz_data, saio_data;
3994 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3995 gint64 base_offset, running_offset;
3997 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
3999 /* NOTE @stream ignored */
4001 moof_node = g_node_new ((guint8 *) buffer);
4002 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4003 qtdemux_node_dump (qtdemux, moof_node);
4005 /* Get fragment number from mfhd and check it's valid */
4007 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4008 if (mfhd_node == NULL)
4010 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4012 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4014 /* unknown base_offset to start with */
4015 base_offset = running_offset = -1;
4016 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4018 guint64 decode_time = 0;
4020 /* Fragment Header node */
4022 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4026 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4027 &ds_size, &ds_flags, &base_offset))
4030 /* The following code assumes at most a single set of sample auxiliary
4031 * data in the fragment (consisting of a saiz box and a corresponding saio
4032 * box); in theory, however, there could be multiple sets of sample
4033 * auxiliary data in a fragment. */
4035 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4038 guint32 info_type = 0;
4040 guint32 info_type_parameter = 0;
4042 g_free (qtdemux->cenc_aux_info_sizes);
4044 qtdemux->cenc_aux_info_sizes =
4045 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4046 &qtdemux->cenc_aux_sample_count);
4047 if (qtdemux->cenc_aux_info_sizes == NULL) {
4048 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4052 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4055 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4056 g_free (qtdemux->cenc_aux_info_sizes);
4057 qtdemux->cenc_aux_info_sizes = NULL;
4061 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4062 &info_type, &info_type_parameter, &offset))) {
4063 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4064 g_free (qtdemux->cenc_aux_info_sizes);
4065 qtdemux->cenc_aux_info_sizes = NULL;
4068 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4069 offset += (guint64) (base_offset - qtdemux->moof_offset);
4070 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4071 && info_type_parameter == 0U) {
4073 if (offset > length) {
4074 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4075 qtdemux->cenc_aux_info_offset = offset;
4077 gst_byte_reader_init (&br, buffer + offset, length - offset);
4078 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4079 qtdemux->cenc_aux_info_sizes,
4080 qtdemux->cenc_aux_sample_count)) {
4081 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4082 g_free (qtdemux->cenc_aux_info_sizes);
4083 qtdemux->cenc_aux_info_sizes = NULL;
4091 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4094 /* We'll use decode_time to interpolate timestamps
4095 * in case the input timestamps are missing */
4096 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4098 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4099 " (%" GST_TIME_FORMAT ")", decode_time,
4100 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4101 decode_time) : GST_CLOCK_TIME_NONE));
4103 /* Discard the fragment buffer timestamp info to avoid using it.
4104 * Rely on tfdt instead as it is more accurate than the timestamp
4105 * that is fetched from a manifest/playlist and is usually
4107 qtdemux->fragment_start = -1;
4110 if (G_UNLIKELY (!stream)) {
4111 /* we lost track of offset, we'll need to regain it,
4112 * but can delay complaining until later or avoid doing so altogether */
4116 if (G_UNLIKELY (base_offset < -1))
4119 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4121 if (!qtdemux->pullbased) {
4122 /* Sample tables can grow enough to be problematic if the system memory
4123 * is very low (e.g. embedded devices) and the videos very long
4124 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4125 * Fortunately, we can easily discard them for each new fragment when
4126 * we know qtdemux will not receive seeks outside of the current fragment.
4127 * adaptivedemux honors this assumption.
4128 * This optimization is also useful for applications that use qtdemux as
4129 * a push-based simple demuxer, like Media Source Extensions. */
4130 gst_qtdemux_stream_flush_samples_data (stream);
4133 /* initialise moof sample data */
4134 stream->n_samples_moof = 0;
4135 stream->duration_last_moof = stream->duration_moof;
4136 stream->duration_moof = 0;
4138 /* Track Run node */
4140 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4143 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4144 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4145 &running_offset, decode_time, (tfdt_node != NULL));
4146 /* iterate all siblings */
4147 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4151 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4153 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4154 guint32 box_length = QT_UINT32 (uuid_buffer);
4156 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4159 /* if no new base_offset provided for next traf,
4160 * base is end of current traf */
4161 base_offset = running_offset;
4162 running_offset = -1;
4164 if (stream->n_samples_moof && stream->duration_moof)
4165 stream->new_caps = TRUE;
4168 /* iterate all siblings */
4169 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4172 /* parse any protection system info */
4173 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4175 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4176 qtdemux_parse_pssh (qtdemux, pssh_node);
4177 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4180 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4181 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4183 /* Unless the user has explicitly requested another seek, perform an
4184 * internal seek to the time specified in the tfdt.
4186 * This way if the user opens a file where the first tfdt is 1 hour
4187 * into the presentation, they will not have to wait 1 hour for run
4188 * time to catch up and actual playback to start. */
4191 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4192 "performing an internal seek to %" GST_TIME_FORMAT,
4193 GST_TIME_ARGS (min_dts));
4195 qtdemux->segment.start = min_dts;
4196 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4198 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4199 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4200 stream->time_position = min_dts;
4203 /* Before this code was run a segment was already sent when the moov was
4204 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4205 * be emitted after a moov, and we can emit a second segment anyway for
4206 * special cases like this. */
4207 qtdemux->need_segment = TRUE;
4210 qtdemux->first_moof_already_parsed = TRUE;
4212 g_node_destroy (moof_node);
4217 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4222 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4227 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4232 g_node_destroy (moof_node);
4233 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4234 (_("This file is corrupt and cannot be played.")), (NULL));
4240 /* might be used if some day we actually use mfra & co
4241 * for random access to fragments,
4242 * but that will require quite some modifications and much less relying
4243 * on a sample array */
4247 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4249 QtDemuxStream *stream;
4250 guint32 ver_flags, track_id, len, num_entries, i;
4251 guint value_size, traf_size, trun_size, sample_size;
4252 guint64 time = 0, moof_offset = 0;
4254 GstBuffer *buf = NULL;
4259 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4261 if (!gst_byte_reader_skip (&tfra, 8))
4264 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4267 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4268 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4269 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4272 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4274 stream = qtdemux_find_stream (qtdemux, track_id);
4276 goto unknown_trackid;
4278 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4279 sample_size = (len & 3) + 1;
4280 trun_size = ((len & 12) >> 2) + 1;
4281 traf_size = ((len & 48) >> 4) + 1;
4283 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4284 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4286 if (num_entries == 0)
4289 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4290 value_size + value_size + traf_size + trun_size + sample_size))
4293 g_free (stream->ra_entries);
4294 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4295 stream->n_ra_entries = num_entries;
4297 for (i = 0; i < num_entries; i++) {
4298 qt_atom_parser_get_offset (&tfra, value_size, &time);
4299 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4300 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4301 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4302 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4304 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4306 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4307 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4309 stream->ra_entries[i].ts = time;
4310 stream->ra_entries[i].moof_offset = moof_offset;
4312 /* don't want to go through the entire file and read all moofs at startup */
4314 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4315 if (ret != GST_FLOW_OK)
4317 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4318 moof_offset, stream);
4319 gst_buffer_unref (buf);
4323 check_update_duration (qtdemux, time);
4330 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4335 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4340 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4346 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4348 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4349 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4350 GstBuffer *mfro = NULL, *mfra = NULL;
4352 gboolean ret = FALSE;
4353 GNode *mfra_node, *tfra_node;
4354 guint64 mfra_offset = 0;
4355 guint32 fourcc, mfra_size;
4358 /* query upstream size in bytes */
4359 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4360 goto size_query_failed;
4362 /* mfro box should be at the very end of the file */
4363 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4364 if (flow != GST_FLOW_OK)
4367 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4369 fourcc = QT_FOURCC (mfro_map.data + 4);
4370 if (fourcc != FOURCC_mfro)
4373 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4374 if (mfro_map.size < 16)
4375 goto invalid_mfro_size;
4377 mfra_size = QT_UINT32 (mfro_map.data + 12);
4378 if (mfra_size >= len)
4379 goto invalid_mfra_size;
4381 mfra_offset = len - mfra_size;
4383 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4384 mfra_offset, mfra_size);
4386 /* now get and parse mfra box */
4387 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4388 if (flow != GST_FLOW_OK)
4391 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4393 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4394 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4396 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4399 qtdemux_parse_tfra (qtdemux, tfra_node);
4400 /* iterate all siblings */
4401 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4403 g_node_destroy (mfra_node);
4405 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4411 if (mfro_map.memory != NULL)
4412 gst_buffer_unmap (mfro, &mfro_map);
4413 gst_buffer_unref (mfro);
4416 if (mfra_map.memory != NULL)
4417 gst_buffer_unmap (mfra, &mfra_map);
4418 gst_buffer_unref (mfra);
4425 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4430 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4435 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4440 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4446 add_offset (guint64 offset, guint64 advance)
4448 /* Avoid 64-bit overflow by clamping */
4449 if (offset > G_MAXUINT64 - advance)
4451 return offset + advance;
4454 static GstFlowReturn
4455 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4459 GstBuffer *buf = NULL;
4460 GstFlowReturn ret = GST_FLOW_OK;
4461 guint64 cur_offset = qtdemux->offset;
4464 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4465 if (G_UNLIKELY (ret != GST_FLOW_OK))
4467 gst_buffer_map (buf, &map, GST_MAP_READ);
4468 if (G_LIKELY (map.size >= 8))
4469 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4470 gst_buffer_unmap (buf, &map);
4471 gst_buffer_unref (buf);
4473 /* maybe we already got most we needed, so only consider this eof */
4474 if (G_UNLIKELY (length == 0)) {
4475 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4476 (_("Invalid atom size.")),
4477 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4478 GST_FOURCC_ARGS (fourcc)));
4485 /* record for later parsing when needed */
4486 if (!qtdemux->moof_offset) {
4487 qtdemux->moof_offset = qtdemux->offset;
4489 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4492 qtdemux->offset += length; /* skip moof and keep going */
4494 if (qtdemux->got_moov) {
4495 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4507 GST_LOG_OBJECT (qtdemux,
4508 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4509 GST_FOURCC_ARGS (fourcc), cur_offset);
4510 qtdemux->offset = add_offset (qtdemux->offset, length);
4515 GstBuffer *moov = NULL;
4517 if (qtdemux->got_moov) {
4518 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4519 qtdemux->offset = add_offset (qtdemux->offset, length);
4523 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4524 if (ret != GST_FLOW_OK)
4526 gst_buffer_map (moov, &map, GST_MAP_READ);
4528 if (length != map.size) {
4529 /* Some files have a 'moov' atom at the end of the file which contains
4530 * a terminal 'free' atom where the body of the atom is missing.
4531 * Check for, and permit, this special case.
4533 if (map.size >= 8) {
4534 guint8 *final_data = map.data + (map.size - 8);
4535 guint32 final_length = QT_UINT32 (final_data);
4536 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4538 if (final_fourcc == FOURCC_free
4539 && map.size + final_length - 8 == length) {
4540 /* Ok, we've found that special case. Allocate a new buffer with
4541 * that free atom actually present. */
4542 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4543 gst_buffer_fill (newmoov, 0, map.data, map.size);
4544 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4545 gst_buffer_unmap (moov, &map);
4546 gst_buffer_unref (moov);
4548 gst_buffer_map (moov, &map, GST_MAP_READ);
4553 if (length != map.size) {
4554 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4555 (_("This file is incomplete and cannot be played.")),
4556 ("We got less than expected (received %" G_GSIZE_FORMAT
4557 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4558 (guint) length, cur_offset));
4559 gst_buffer_unmap (moov, &map);
4560 gst_buffer_unref (moov);
4561 ret = GST_FLOW_ERROR;
4564 qtdemux->offset += length;
4566 qtdemux_parse_moov (qtdemux, map.data, length);
4567 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4569 qtdemux_parse_tree (qtdemux);
4570 if (qtdemux->moov_node_compressed) {
4571 g_node_destroy (qtdemux->moov_node_compressed);
4572 g_free (qtdemux->moov_node->data);
4574 qtdemux->moov_node_compressed = NULL;
4575 g_node_destroy (qtdemux->moov_node);
4576 qtdemux->moov_node = NULL;
4577 gst_buffer_unmap (moov, &map);
4578 gst_buffer_unref (moov);
4579 qtdemux->got_moov = TRUE;
4585 GstBuffer *ftyp = NULL;
4587 /* extract major brand; might come in handy for ISO vs QT issues */
4588 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4589 if (ret != GST_FLOW_OK)
4591 qtdemux->offset += length;
4592 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4593 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4594 gst_buffer_unmap (ftyp, &map);
4595 gst_buffer_unref (ftyp);
4600 GstBuffer *uuid = NULL;
4602 /* uuid are extension atoms */
4603 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4604 if (ret != GST_FLOW_OK)
4606 qtdemux->offset += length;
4607 gst_buffer_map (uuid, &map, GST_MAP_READ);
4608 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4609 gst_buffer_unmap (uuid, &map);
4610 gst_buffer_unref (uuid);
4615 GstBuffer *sidx = NULL;
4616 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4617 if (ret != GST_FLOW_OK)
4619 qtdemux->offset += length;
4620 gst_buffer_map (sidx, &map, GST_MAP_READ);
4621 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4622 gst_buffer_unmap (sidx, &map);
4623 gst_buffer_unref (sidx);
4628 GstBuffer *unknown = NULL;
4630 GST_LOG_OBJECT (qtdemux,
4631 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4632 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4634 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4635 if (ret != GST_FLOW_OK)
4637 gst_buffer_map (unknown, &map, GST_MAP_READ);
4638 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4639 gst_buffer_unmap (unknown, &map);
4640 gst_buffer_unref (unknown);
4641 qtdemux->offset += length;
4647 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4648 /* digested all data, show what we have */
4649 qtdemux_prepare_streams (qtdemux);
4650 QTDEMUX_EXPOSE_LOCK (qtdemux);
4651 ret = qtdemux_expose_streams (qtdemux);
4652 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4654 qtdemux->state = QTDEMUX_STATE_MOVIE;
4655 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4662 /* Seeks to the previous keyframe of the indexed stream and
4663 * aligns other streams with respect to the keyframe timestamp
4664 * of indexed stream. Only called in case of Reverse Playback
4666 static GstFlowReturn
4667 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4669 guint32 seg_idx = 0, k_index = 0;
4670 guint32 ref_seg_idx, ref_k_index;
4671 GstClockTime k_pos = 0, last_stop = 0;
4672 QtDemuxSegment *seg = NULL;
4673 QtDemuxStream *ref_str = NULL;
4674 guint64 seg_media_start_mov; /* segment media start time in mov format */
4678 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4679 * and finally align all the other streams on that timestamp with their
4680 * respective keyframes */
4681 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4682 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4684 /* No candidate yet, take the first stream */
4690 /* So that stream has a segment, we prefer video streams */
4691 if (str->subtype == FOURCC_vide) {
4697 if (G_UNLIKELY (!ref_str)) {
4698 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4702 if (G_UNLIKELY (!ref_str->from_sample)) {
4703 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4707 /* So that stream has been playing from from_sample to to_sample. We will
4708 * get the timestamp of the previous sample and search for a keyframe before
4709 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4710 if (ref_str->subtype == FOURCC_vide) {
4711 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4712 ref_str->from_sample - 1, FALSE);
4714 if (ref_str->from_sample >= 10)
4715 k_index = ref_str->from_sample - 10;
4721 ref_str->samples[k_index].timestamp +
4722 ref_str->samples[k_index].pts_offset;
4724 /* get current segment for that stream */
4725 seg = &ref_str->segments[ref_str->segment_index];
4726 /* Use segment start in original timescale for comparisons */
4727 seg_media_start_mov = seg->trak_media_start;
4729 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4730 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4731 k_index, target_ts, seg_media_start_mov,
4732 GST_TIME_ARGS (seg->media_start));
4734 /* Crawl back through segments to find the one containing this I frame */
4735 while (target_ts < seg_media_start_mov) {
4736 GST_DEBUG_OBJECT (qtdemux,
4737 "keyframe position (sample %u) is out of segment %u " " target %"
4738 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4739 ref_str->segment_index, target_ts, seg_media_start_mov);
4741 if (G_UNLIKELY (!ref_str->segment_index)) {
4742 /* Reached first segment, let's consider it's EOS */
4745 ref_str->segment_index--;
4746 seg = &ref_str->segments[ref_str->segment_index];
4747 /* Use segment start in original timescale for comparisons */
4748 seg_media_start_mov = seg->trak_media_start;
4750 /* Calculate time position of the keyframe and where we should stop */
4752 QTSTREAMTIME_TO_GSTTIME (ref_str,
4753 target_ts - seg->trak_media_start) + seg->time;
4755 QTSTREAMTIME_TO_GSTTIME (ref_str,
4756 ref_str->samples[ref_str->from_sample].timestamp -
4757 seg->trak_media_start) + seg->time;
4759 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4760 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4761 k_index, GST_TIME_ARGS (k_pos));
4763 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4764 qtdemux->segment.position = last_stop;
4765 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4766 GST_TIME_ARGS (last_stop));
4768 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4769 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4773 ref_seg_idx = ref_str->segment_index;
4774 ref_k_index = k_index;
4776 /* Align them all on this */
4777 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4779 GstClockTime seg_time = 0;
4780 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4782 /* aligning reference stream again might lead to backing up to yet another
4783 * keyframe (due to timestamp rounding issues),
4784 * potentially putting more load on downstream; so let's try to avoid */
4785 if (str == ref_str) {
4786 seg_idx = ref_seg_idx;
4787 seg = &str->segments[seg_idx];
4788 k_index = ref_k_index;
4789 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4790 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4792 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4793 GST_DEBUG_OBJECT (qtdemux,
4794 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4795 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4797 /* get segment and time in the segment */
4798 seg = &str->segments[seg_idx];
4799 seg_time = k_pos - seg->time;
4801 /* get the media time in the segment.
4802 * No adjustment for empty "filler" segments */
4803 if (seg->media_start != GST_CLOCK_TIME_NONE)
4804 seg_time += seg->media_start;
4806 /* get the index of the sample with media time */
4807 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4808 GST_DEBUG_OBJECT (qtdemux,
4809 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4810 GST_TIME_ARGS (seg_time), index);
4812 /* find previous keyframe */
4813 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4816 /* Remember until where we want to go */
4817 str->to_sample = str->from_sample - 1;
4818 /* Define our time position */
4820 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4821 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4822 if (seg->media_start != GST_CLOCK_TIME_NONE)
4823 str->time_position -= seg->media_start;
4825 /* Now seek back in time */
4826 gst_qtdemux_move_stream (qtdemux, str, k_index);
4827 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4828 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4829 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4835 return GST_FLOW_EOS;
4839 * Gets the current qt segment start, stop and position for the
4840 * given time offset. This is used in update_segment()
4843 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4844 QtDemuxStream * stream, GstClockTime offset,
4845 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4847 GstClockTime seg_time;
4848 GstClockTime start, stop, time;
4849 QtDemuxSegment *segment;
4851 segment = &stream->segments[stream->segment_index];
4853 /* get time in this segment */
4854 seg_time = (offset - segment->time) * segment->rate;
4856 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4857 GST_TIME_ARGS (seg_time));
4859 if (G_UNLIKELY (seg_time > segment->duration)) {
4860 GST_LOG_OBJECT (stream->pad,
4861 "seg_time > segment->duration %" GST_TIME_FORMAT,
4862 GST_TIME_ARGS (segment->duration));
4863 seg_time = segment->duration;
4866 /* qtdemux->segment.stop is in outside-time-realm, whereas
4867 * segment->media_stop is in track-time-realm.
4869 * In order to compare the two, we need to bring segment.stop
4870 * into the track-time-realm
4872 * FIXME - does this comment still hold? Don't see any conversion here */
4874 stop = qtdemux->segment.stop;
4875 if (stop == GST_CLOCK_TIME_NONE)
4876 stop = qtdemux->segment.duration;
4877 if (stop == GST_CLOCK_TIME_NONE)
4878 stop = segment->media_stop;
4881 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4883 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4884 start = segment->time + seg_time;
4886 stop = start - seg_time + segment->duration;
4887 } else if (qtdemux->segment.rate >= 0) {
4888 start = MIN (segment->media_start + seg_time, stop);
4891 if (segment->media_start >= qtdemux->segment.start) {
4892 time = segment->time;
4894 time = segment->time + (qtdemux->segment.start - segment->media_start);
4897 start = MAX (segment->media_start, qtdemux->segment.start);
4898 stop = MIN (segment->media_start + seg_time, stop);
4907 * Updates the qt segment used for the stream and pushes a new segment event
4908 * downstream on this stream's pad.
4911 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4912 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4913 GstClockTime * _stop)
4915 QtDemuxSegment *segment;
4916 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4920 /* update the current segment */
4921 stream->segment_index = seg_idx;
4923 /* get the segment */
4924 segment = &stream->segments[seg_idx];
4926 if (G_UNLIKELY (offset < segment->time)) {
4927 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4928 GST_TIME_ARGS (segment->time));
4932 /* segment lies beyond total indicated duration */
4933 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4934 segment->time > qtdemux->segment.duration)) {
4935 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4936 " < segment->time %" GST_TIME_FORMAT,
4937 GST_TIME_ARGS (qtdemux->segment.duration),
4938 GST_TIME_ARGS (segment->time));
4942 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4943 &start, &stop, &time);
4945 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4946 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4947 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4949 /* combine global rate with that of the segment */
4950 rate = segment->rate * qtdemux->segment.rate;
4952 /* Copy flags from main segment */
4953 stream->segment.flags = qtdemux->segment.flags;
4955 /* update the segment values used for clipping */
4956 stream->segment.offset = qtdemux->segment.offset;
4957 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4958 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4959 stream->segment.rate = rate;
4960 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4961 stream->cslg_shift);
4963 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4964 stream->cslg_shift);
4966 stream->segment.stop = stop;
4967 stream->segment.time = time;
4968 stream->segment.position = stream->segment.start;
4970 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4973 /* now prepare and send the segment */
4975 event = gst_event_new_segment (&stream->segment);
4976 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4977 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4979 gst_pad_push_event (stream->pad, event);
4980 /* assume we can send more data now */
4981 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4982 /* clear to send tags on this pad now */
4983 gst_qtdemux_push_tags (qtdemux, stream);
4994 /* activate the given segment number @seg_idx of @stream at time @offset.
4995 * @offset is an absolute global position over all the segments.
4997 * This will push out a NEWSEGMENT event with the right values and
4998 * position the stream index to the first decodable sample before
5002 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5003 guint32 seg_idx, GstClockTime offset)
5005 QtDemuxSegment *segment;
5006 guint32 index, kf_index;
5007 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5009 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5010 seg_idx, GST_TIME_ARGS (offset));
5012 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5016 segment = &stream->segments[stream->segment_index];
5018 /* in the fragmented case, we pick a fragment that starts before our
5019 * desired position and rely on downstream to wait for a keyframe
5020 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5021 * tfra entries tells us which trun/sample the key unit is in, but we don't
5022 * make use of this additional information at the moment) */
5023 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5024 stream->to_sample = G_MAXUINT32;
5027 /* well, it will be taken care of below */
5028 qtdemux->fragmented_seek_pending = FALSE;
5029 /* FIXME ideally the do_fragmented_seek can be done right here,
5030 * rather than at loop level
5031 * (which might even allow handling edit lists in a fragmented file) */
5034 /* We don't need to look for a sample in push-based */
5035 if (!qtdemux->pullbased)
5038 /* and move to the keyframe before the indicated media time of the
5040 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5041 if (qtdemux->segment.rate >= 0) {
5042 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5043 stream->to_sample = G_MAXUINT32;
5044 GST_DEBUG_OBJECT (stream->pad,
5045 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5046 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5047 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5049 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5050 stream->to_sample = index;
5051 GST_DEBUG_OBJECT (stream->pad,
5052 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5053 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5054 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5057 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5058 "this is an empty segment");
5062 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5063 * encountered an error and printed a message so we return appropriately */
5067 /* we're at the right spot */
5068 if (index == stream->sample_index) {
5069 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5073 /* find keyframe of the target index */
5074 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5076 /* go back two frames to provide lead-in for non-raw audio decoders */
5077 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5078 guint32 lead_in = 2;
5079 guint32 old_index = kf_index;
5080 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5082 if (gst_structure_has_name (s, "audio/mpeg")) {
5084 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5085 && mpegversion == 1) {
5086 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5091 kf_index = MAX (kf_index, lead_in) - lead_in;
5092 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5093 GST_DEBUG_OBJECT (stream->pad,
5094 "Moving backwards %u frames to ensure sufficient sound lead-in",
5095 old_index - kf_index);
5097 kf_index = old_index;
5101 /* if we move forwards, we don't have to go back to the previous
5102 * keyframe since we already sent that. We can also just jump to
5103 * the keyframe right before the target index if there is one. */
5104 if (index > stream->sample_index) {
5105 /* moving forwards check if we move past a keyframe */
5106 if (kf_index > stream->sample_index) {
5107 GST_DEBUG_OBJECT (stream->pad,
5108 "moving forwards to keyframe at %u "
5109 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5111 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5112 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5113 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5115 GST_DEBUG_OBJECT (stream->pad,
5116 "moving forwards, keyframe at %u "
5117 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5119 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5120 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5123 GST_DEBUG_OBJECT (stream->pad,
5124 "moving backwards to %sframe at %u "
5125 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5126 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5127 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5128 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5129 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5135 /* prepare to get the current sample of @stream, getting essential values.
5137 * This function will also prepare and send the segment when needed.
5139 * Return FALSE if the stream is EOS.
5144 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5145 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5146 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5147 gboolean * keyframe)
5149 QtDemuxSample *sample;
5150 GstClockTime time_position;
5153 g_return_val_if_fail (stream != NULL, FALSE);
5155 time_position = stream->time_position;
5156 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5159 seg_idx = stream->segment_index;
5160 if (G_UNLIKELY (seg_idx == -1)) {
5161 /* find segment corresponding to time_position if we are looking
5163 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5166 /* different segment, activate it, sample_index will be set. */
5167 if (G_UNLIKELY (stream->segment_index != seg_idx))
5168 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5170 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5171 segments[stream->segment_index]))) {
5172 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5174 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5175 " prepare empty sample");
5178 *pts = *dts = time_position;
5179 *duration = seg->duration - (time_position - seg->time);
5186 if (stream->sample_index == -1)
5187 stream->sample_index = 0;
5189 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5190 stream->sample_index, stream->n_samples);
5192 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5193 if (!qtdemux->fragmented)
5196 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5200 GST_OBJECT_LOCK (qtdemux);
5201 flow = qtdemux_add_fragmented_samples (qtdemux);
5202 GST_OBJECT_UNLOCK (qtdemux);
5204 if (flow != GST_FLOW_OK)
5207 while (stream->sample_index >= stream->n_samples);
5210 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5211 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5212 stream->sample_index);
5216 /* now get the info for the sample we're at */
5217 sample = &stream->samples[stream->sample_index];
5219 *dts = QTSAMPLE_DTS (stream, sample);
5220 *pts = QTSAMPLE_PTS (stream, sample);
5221 *offset = sample->offset;
5222 *size = sample->size;
5223 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5224 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5231 stream->time_position = GST_CLOCK_TIME_NONE;
5236 /* move to the next sample in @stream.
5238 * Moves to the next segment when needed.
5241 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5243 QtDemuxSample *sample;
5244 QtDemuxSegment *segment;
5246 /* get current segment */
5247 segment = &stream->segments[stream->segment_index];
5249 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5250 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5254 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5255 /* Mark the stream as EOS */
5256 GST_DEBUG_OBJECT (qtdemux,
5257 "reached max allowed sample %u, mark EOS", stream->to_sample);
5258 stream->time_position = GST_CLOCK_TIME_NONE;
5262 /* move to next sample */
5263 stream->sample_index++;
5264 stream->offset_in_sample = 0;
5266 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5269 /* reached the last sample, we need the next segment */
5270 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5273 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5274 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5275 stream->sample_index);
5279 /* get next sample */
5280 sample = &stream->samples[stream->sample_index];
5282 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5283 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5284 GST_TIME_ARGS (segment->media_stop));
5286 /* see if we are past the segment */
5287 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5290 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5291 /* inside the segment, update time_position, looks very familiar to
5292 * GStreamer segments, doesn't it? */
5293 stream->time_position =
5294 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5296 /* not yet in segment, time does not yet increment. This means
5297 * that we are still prerolling keyframes to the decoder so it can
5298 * decode the first sample of the segment. */
5299 stream->time_position = segment->time;
5303 /* move to the next segment */
5306 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5308 if (stream->segment_index == stream->n_segments - 1) {
5309 /* are we at the end of the last segment, we're EOS */
5310 stream->time_position = GST_CLOCK_TIME_NONE;
5312 /* else we're only at the end of the current segment */
5313 stream->time_position = segment->stop_time;
5315 /* make sure we select a new segment */
5317 /* accumulate previous segments */
5318 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5319 stream->accumulated_base +=
5320 (stream->segment.stop -
5321 stream->segment.start) / ABS (stream->segment.rate);
5323 stream->segment_index = -1;
5328 gst_qtdemux_sync_streams (GstQTDemux * demux)
5332 if (QTDEMUX_N_STREAMS (demux) <= 1)
5335 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5336 QtDemuxStream *stream;
5337 GstClockTime end_time;
5339 stream = QTDEMUX_NTH_STREAM (demux, i);
5344 /* TODO advance time on subtitle streams here, if any some day */
5346 /* some clips/trailers may have unbalanced streams at the end,
5347 * so send EOS on shorter stream to prevent stalling others */
5349 /* do not mess with EOS if SEGMENT seeking */
5350 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5353 if (demux->pullbased) {
5354 /* loop mode is sample time based */
5355 if (!STREAM_IS_EOS (stream))
5358 /* push mode is byte position based */
5359 if (stream->n_samples &&
5360 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5364 if (stream->sent_eos)
5367 /* only act if some gap */
5368 end_time = stream->segments[stream->n_segments - 1].stop_time;
5369 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5370 ", stream end: %" GST_TIME_FORMAT,
5371 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5372 if (GST_CLOCK_TIME_IS_VALID (end_time)
5373 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5376 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5377 GST_PAD_NAME (stream->pad));
5378 stream->sent_eos = TRUE;
5379 event = gst_event_new_eos ();
5380 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5381 gst_event_set_seqnum (event, demux->segment_seqnum);
5382 gst_pad_push_event (stream->pad, event);
5387 /* EOS and NOT_LINKED need to be combined. This means that we return:
5389 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5390 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5392 static GstFlowReturn
5393 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5396 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5399 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5402 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5404 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5408 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5409 * completely clipped
5411 * Should be used only with raw buffers */
5413 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5416 guint64 start, stop, cstart, cstop, diff;
5417 GstClockTime pts, duration;
5419 gint num_rate, denom_rate;
5424 osize = size = gst_buffer_get_size (buf);
5427 /* depending on the type, setup the clip parameters */
5428 if (stream->subtype == FOURCC_soun) {
5429 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5430 num_rate = GST_SECOND;
5431 denom_rate = (gint) CUR_STREAM (stream)->rate;
5433 } else if (stream->subtype == FOURCC_vide) {
5435 num_rate = CUR_STREAM (stream)->fps_n;
5436 denom_rate = CUR_STREAM (stream)->fps_d;
5441 if (frame_size <= 0)
5442 goto bad_frame_size;
5444 /* we can only clip if we have a valid pts */
5445 pts = GST_BUFFER_PTS (buf);
5446 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5449 duration = GST_BUFFER_DURATION (buf);
5451 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5453 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5457 stop = start + duration;
5459 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5460 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5463 /* see if some clipping happened */
5464 diff = cstart - start;
5470 /* bring clipped time to samples and to bytes */
5471 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5474 GST_DEBUG_OBJECT (qtdemux,
5475 "clipping start to %" GST_TIME_FORMAT " %"
5476 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5482 diff = stop - cstop;
5487 /* bring clipped time to samples and then to bytes */
5488 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5490 GST_DEBUG_OBJECT (qtdemux,
5491 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5492 " bytes", GST_TIME_ARGS (cstop), diff);
5497 if (offset != 0 || size != osize)
5498 gst_buffer_resize (buf, offset, size);
5500 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5501 GST_BUFFER_PTS (buf) = pts;
5502 GST_BUFFER_DURATION (buf) = duration;
5506 /* dropped buffer */
5509 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5514 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5519 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5524 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5525 gst_buffer_unref (buf);
5531 gst_qtdemux_align_buffer (GstQTDemux * demux,
5532 GstBuffer * buffer, gsize alignment)
5536 gst_buffer_map (buffer, &map, GST_MAP_READ);
5538 if (map.size < sizeof (guintptr)) {
5539 gst_buffer_unmap (buffer, &map);
5543 if (((guintptr) map.data) & (alignment - 1)) {
5544 GstBuffer *new_buffer;
5545 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5547 new_buffer = gst_buffer_new_allocate (NULL,
5548 gst_buffer_get_size (buffer), ¶ms);
5550 /* Copy data "by hand", so ensure alignment is kept: */
5551 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5553 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5554 GST_DEBUG_OBJECT (demux,
5555 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5558 gst_buffer_unmap (buffer, &map);
5559 gst_buffer_unref (buffer);
5564 gst_buffer_unmap (buffer, &map);
5569 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5575 /* We are converting from pairs to triplets */
5576 *res = ccpair_size / 2 * 3;
5577 storage = g_malloc (*res);
5578 for (i = 0; i * 2 < ccpair_size; i += 1) {
5579 /* FIXME: Use line offset 0 as we simply can't know here */
5581 storage[i * 3] = 0x80 | 0x00;
5583 storage[i * 3] = 0x00 | 0x00;
5584 storage[i * 3 + 1] = ccpair[i * 2];
5585 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5592 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5596 guint32 atom_length, fourcc;
5597 QtDemuxStreamStsdEntry *stsd_entry;
5599 GST_MEMDUMP ("caption atom", data, size);
5601 /* There might be multiple atoms */
5606 atom_length = QT_UINT32 (data);
5607 fourcc = QT_FOURCC (data + 4);
5608 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5611 GST_DEBUG_OBJECT (stream->pad, "here");
5613 /* Check if we have something compatible */
5614 stsd_entry = CUR_STREAM (stream);
5615 switch (stsd_entry->fourcc) {
5617 guint8 *cdat = NULL, *cdt2 = NULL;
5618 gsize cdat_size = 0, cdt2_size = 0;
5619 /* Should be cdat or cdt2 */
5620 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5621 GST_WARNING_OBJECT (stream->pad,
5622 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5623 GST_FOURCC_ARGS (fourcc));
5627 /* Convert to S334-1 Annex A byte triplet */
5628 if (fourcc == FOURCC_cdat)
5629 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5631 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5632 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5635 /* Check for another atom ? */
5636 if (size > atom_length + 8) {
5637 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5638 if (size >= atom_length + new_atom_length) {
5639 fourcc = QT_FOURCC (data + atom_length + 4);
5640 if (fourcc == FOURCC_cdat) {
5643 convert_to_s334_1a (data + atom_length + 8,
5644 new_atom_length - 8, 1, &cdat_size);
5646 GST_WARNING_OBJECT (stream->pad,
5647 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5651 convert_to_s334_1a (data + atom_length + 8,
5652 new_atom_length - 8, 2, &cdt2_size);
5654 GST_WARNING_OBJECT (stream->pad,
5655 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5660 *cclen = cdat_size + cdt2_size;
5661 res = g_malloc (*cclen);
5663 memcpy (res, cdat, cdat_size);
5665 memcpy (res + cdat_size, cdt2, cdt2_size);
5671 if (fourcc != FOURCC_ccdp) {
5672 GST_WARNING_OBJECT (stream->pad,
5673 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5674 GST_FOURCC_ARGS (fourcc));
5677 *cclen = atom_length - 8;
5678 res = g_memdup2 (data + 8, *cclen);
5681 /* Keep this here in case other closed caption formats are added */
5682 g_assert_not_reached ();
5686 GST_MEMDUMP ("Output", res, *cclen);
5691 GST_WARNING ("[cdat] atom is too small or invalid");
5695 /* Handle Closed Caption sample buffers.
5696 * The input buffer metadata must be writable,
5697 * but time/duration etc not yet set and need not be preserved */
5699 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5702 GstBuffer *outbuf = NULL;
5707 gst_buffer_map (buf, &map, GST_MAP_READ);
5709 /* empty buffer is sent to terminate previous subtitle */
5710 if (map.size <= 2) {
5711 gst_buffer_unmap (buf, &map);
5712 gst_buffer_unref (buf);
5716 /* For closed caption, we need to extract the information from the
5717 * [cdat],[cdt2] or [ccdp] atom */
5718 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5719 gst_buffer_unmap (buf, &map);
5721 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5722 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5724 /* Conversion failed or there's nothing */
5726 gst_buffer_unref (buf);
5731 /* DVD subpicture specific sample handling.
5732 * the input buffer metadata must be writable,
5733 * but time/duration etc not yet set and need not be preserved */
5735 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5738 /* send a one time dvd clut event */
5739 if (stream->pending_event && stream->pad)
5740 gst_pad_push_event (stream->pad, stream->pending_event);
5741 stream->pending_event = NULL;
5743 /* empty buffer is sent to terminate previous subtitle */
5744 if (gst_buffer_get_size (buf) <= 2) {
5745 gst_buffer_unref (buf);
5749 /* That's all the processing needed for subpictures */
5753 /* Timed text formats
5754 * the input buffer metadata must be writable,
5755 * but time/duration etc not yet set and need not be preserved */
5757 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5760 GstBuffer *outbuf = NULL;
5765 /* not many cases for now */
5766 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5767 stream->subtype != FOURCC_sbtl)) {
5771 gst_buffer_map (buf, &map, GST_MAP_READ);
5773 /* empty buffer is sent to terminate previous subtitle */
5774 if (map.size <= 2) {
5775 gst_buffer_unmap (buf, &map);
5776 gst_buffer_unref (buf);
5780 nsize = GST_READ_UINT16_BE (map.data);
5781 nsize = MIN (nsize, map.size - 2);
5783 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5786 /* takes care of UTF-8 validation or UTF-16 recognition,
5787 * no other encoding expected */
5788 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5789 gst_buffer_unmap (buf, &map);
5792 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5793 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5795 /* this should not really happen unless the subtitle is corrupted */
5797 gst_buffer_unref (buf);
5799 /* FIXME ? convert optional subsequent style info to markup */
5804 /* WebVTT sample handling according to 14496-30 */
5806 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5809 GstBuffer *outbuf = NULL;
5812 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5813 g_assert_not_reached (); /* The buffer must be mappable */
5816 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5817 GstEvent *gap = NULL;
5818 /* Push a gap event */
5819 stream->segment.position = GST_BUFFER_PTS (buf);
5821 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5822 gst_pad_push_event (stream->pad, gap);
5824 if (GST_BUFFER_DURATION_IS_VALID (buf))
5825 stream->segment.position += GST_BUFFER_DURATION (buf);
5828 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5829 GST_BUFFER_DURATION (buf), map.data, map.size);
5830 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5833 gst_buffer_unmap (buf, &map);
5834 gst_buffer_unref (buf);
5839 static GstFlowReturn
5840 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5843 GstFlowReturn ret = GST_FLOW_OK;
5844 GstClockTime pts, duration;
5846 if (stream->need_clip)
5847 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5849 if (G_UNLIKELY (buf == NULL))
5852 if (G_UNLIKELY (stream->discont)) {
5853 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5854 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5855 stream->discont = FALSE;
5857 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5860 GST_LOG_OBJECT (qtdemux,
5861 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5862 ", duration %" GST_TIME_FORMAT " on pad %s",
5863 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5864 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5865 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5867 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5868 GstStructure *crypto_info;
5869 QtDemuxAavdEncryptionInfo *info =
5870 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5872 crypto_info = gst_structure_copy (info->default_properties);
5873 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5874 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5877 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
5878 || stream->protection_scheme_type == FOURCC_cbcs)) {
5879 GstStructure *crypto_info;
5880 QtDemuxCencSampleSetInfo *info =
5881 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5885 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5886 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5887 GST_PTR_FORMAT, event);
5888 gst_pad_push_event (stream->pad, event);
5891 if (info->crypto_info == NULL) {
5892 if (stream->protection_scheme_type == FOURCC_cbcs) {
5893 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
5894 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
5895 GST_ERROR_OBJECT (qtdemux,
5896 "failed to attach cbcs metadata to buffer");
5897 qtdemux_gst_structure_free (crypto_info);
5899 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
5902 GST_DEBUG_OBJECT (qtdemux,
5903 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5906 /* The end of the crypto_info array matches our n_samples position,
5907 * so count backward from there */
5908 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5909 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5910 /* steal structure from array */
5911 crypto_info = g_ptr_array_index (info->crypto_info, index);
5912 g_ptr_array_index (info->crypto_info, index) = NULL;
5913 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5914 info->crypto_info->len);
5915 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5916 GST_ERROR_OBJECT (qtdemux,
5917 "failed to attach cenc metadata to buffer");
5919 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5920 index, stream->sample_index);
5925 if (stream->alignment > 1)
5926 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5928 pts = GST_BUFFER_PTS (buf);
5929 duration = GST_BUFFER_DURATION (buf);
5931 ret = gst_pad_push (stream->pad, buf);
5933 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5934 /* mark position in stream, we'll need this to know when to send GAP event */
5935 stream->segment.position = pts + duration;
5943 static GstFlowReturn
5944 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5947 GstFlowReturn ret = GST_FLOW_OK;
5949 if (stream->subtype == FOURCC_clcp
5950 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
5952 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
5953 guint n_triplets, i;
5954 guint field1_off = 0, field2_off = 0;
5956 /* We have to split CEA608 buffers so that each outgoing buffer contains
5957 * one byte pair per field according to the framerate of the video track.
5959 * If there is only a single byte pair per field we don't have to do
5963 gst_buffer_map (buf, &map, GST_MAP_READ);
5965 n_triplets = map.size / 3;
5966 for (i = 0; i < n_triplets; i++) {
5967 if (map.data[3 * i] & 0x80)
5973 g_assert (n_field1 || n_field2);
5975 /* If there's more than 1 frame we have to split, otherwise we can just
5977 if (n_field1 > 1 || n_field2 > 1) {
5979 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
5980 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
5982 for (i = 0; i < n_output_buffers; i++) {
5984 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
5988 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
5989 outptr = outmap.data;
5992 gboolean found = FALSE;
5994 while (map.data + field1_off < map.data + map.size) {
5995 if (map.data[field1_off] & 0x80) {
5996 memcpy (outptr, &map.data[field1_off], 3);
6005 const guint8 empty[] = { 0x80, 0x80, 0x80 };
6007 memcpy (outptr, empty, 3);
6014 gboolean found = FALSE;
6016 while (map.data + field2_off < map.data + map.size) {
6017 if ((map.data[field2_off] & 0x80) == 0) {
6018 memcpy (outptr, &map.data[field2_off], 3);
6027 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6029 memcpy (outptr, empty, 3);
6035 gst_buffer_unmap (outbuf, &outmap);
6037 GST_BUFFER_PTS (outbuf) =
6038 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6039 GST_SECOND * CUR_STREAM (stream)->fps_d,
6040 CUR_STREAM (stream)->fps_n);
6041 GST_BUFFER_DURATION (outbuf) =
6042 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6043 CUR_STREAM (stream)->fps_n);
6044 GST_BUFFER_OFFSET (outbuf) = -1;
6045 GST_BUFFER_OFFSET_END (outbuf) = -1;
6047 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6049 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6052 gst_buffer_unmap (buf, &map);
6053 gst_buffer_unref (buf);
6055 gst_buffer_unmap (buf, &map);
6056 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6059 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6065 /* Sets a buffer's attributes properly and pushes it downstream.
6066 * Also checks for additional actions and custom processing that may
6067 * need to be done first.
6069 static GstFlowReturn
6070 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6071 QtDemuxStream * stream, GstBuffer * buf,
6072 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6073 gboolean keyframe, GstClockTime position, guint64 byte_position)
6075 GstFlowReturn ret = GST_FLOW_OK;
6077 /* offset the timestamps according to the edit list */
6079 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6083 gst_buffer_map (buf, &map, GST_MAP_READ);
6084 url = g_strndup ((gchar *) map.data, map.size);
6085 gst_buffer_unmap (buf, &map);
6086 if (url != NULL && strlen (url) != 0) {
6087 /* we have RTSP redirect now */
6088 g_free (qtdemux->redirect_location);
6089 qtdemux->redirect_location = g_strdup (url);
6090 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6091 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6092 gst_structure_new ("redirect",
6093 "new-location", G_TYPE_STRING, url, NULL)));
6095 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6101 /* position reporting */
6102 if (qtdemux->segment.rate >= 0) {
6103 qtdemux->segment.position = position;
6104 gst_qtdemux_sync_streams (qtdemux);
6107 if (G_UNLIKELY (!stream->pad)) {
6108 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6109 gst_buffer_unref (buf);
6113 /* send out pending buffers */
6114 while (stream->buffers) {
6115 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6117 if (G_UNLIKELY (stream->discont)) {
6118 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6119 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6120 stream->discont = FALSE;
6122 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6125 if (stream->alignment > 1)
6126 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6127 gst_pad_push (stream->pad, buffer);
6129 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6132 /* we're going to modify the metadata */
6133 buf = gst_buffer_make_writable (buf);
6135 GST_BUFFER_DTS (buf) = dts;
6136 GST_BUFFER_PTS (buf) = pts;
6137 GST_BUFFER_DURATION (buf) = duration;
6138 GST_BUFFER_OFFSET (buf) = -1;
6139 GST_BUFFER_OFFSET_END (buf) = -1;
6141 if (G_UNLIKELY (stream->process_func))
6142 buf = stream->process_func (qtdemux, stream, buf);
6149 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6150 stream->on_keyframe = FALSE;
6152 stream->on_keyframe = TRUE;
6155 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6156 gst_buffer_append_memory (buf,
6157 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6159 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6160 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6163 if (G_UNLIKELY (qtdemux->element_index)) {
6164 GstClockTime stream_time;
6167 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6169 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6170 GST_LOG_OBJECT (qtdemux,
6171 "adding association %" GST_TIME_FORMAT "-> %"
6172 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6173 gst_index_add_association (qtdemux->element_index,
6175 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6176 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6177 GST_FORMAT_BYTES, byte_position, NULL);
6182 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6188 static const QtDemuxRandomAccessEntry *
6189 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6190 GstClockTime pos, gboolean after)
6192 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6193 guint n_entries = stream->n_ra_entries;
6196 /* we assume the table is sorted */
6197 for (i = 0; i < n_entries; ++i) {
6198 if (entries[i].ts > pos)
6202 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6203 * probably okay to assume that the index lists the very first fragment */
6210 return &entries[i - 1];
6214 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6216 const QtDemuxRandomAccessEntry *best_entry = NULL;
6219 GST_OBJECT_LOCK (qtdemux);
6221 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6223 /* first see if we can determine where to go to using mfra,
6224 * before we start clearing things */
6225 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6226 const QtDemuxRandomAccessEntry *entry;
6227 QtDemuxStream *stream;
6228 gboolean is_audio_or_video;
6230 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6232 if (stream->ra_entries == NULL)
6235 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6236 is_audio_or_video = TRUE;
6238 is_audio_or_video = FALSE;
6241 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6242 stream->time_position, !is_audio_or_video);
6244 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6245 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6247 stream->pending_seek = entry;
6249 /* decide position to jump to just based on audio/video tracks, not subs */
6250 if (!is_audio_or_video)
6253 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6257 /* no luck, will handle seek otherwise */
6258 if (best_entry == NULL) {
6259 GST_OBJECT_UNLOCK (qtdemux);
6263 /* ok, now we can prepare for processing as of located moof */
6264 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6265 QtDemuxStream *stream;
6267 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6269 g_free (stream->samples);
6270 stream->samples = NULL;
6271 stream->n_samples = 0;
6272 stream->stbl_index = -1; /* no samples have yet been parsed */
6273 stream->sample_index = -1;
6275 if (stream->protection_scheme_info) {
6276 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6277 if (stream->protection_scheme_type == FOURCC_cenc
6278 || stream->protection_scheme_type == FOURCC_cbcs) {
6279 QtDemuxCencSampleSetInfo *info =
6280 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6281 if (info->crypto_info) {
6282 g_ptr_array_free (info->crypto_info, TRUE);
6283 info->crypto_info = NULL;
6289 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6290 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6291 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6292 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6294 qtdemux->moof_offset = best_entry->moof_offset;
6296 qtdemux_add_fragmented_samples (qtdemux);
6298 GST_OBJECT_UNLOCK (qtdemux);
6302 static GstFlowReturn
6303 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6305 GstFlowReturn ret = GST_FLOW_OK;
6306 GstBuffer *buf = NULL;
6307 QtDemuxStream *stream, *target_stream = NULL;
6308 GstClockTime min_time;
6310 GstClockTime dts = GST_CLOCK_TIME_NONE;
6311 GstClockTime pts = GST_CLOCK_TIME_NONE;
6312 GstClockTime duration = 0;
6313 gboolean keyframe = FALSE;
6314 guint sample_size = 0;
6315 guint num_samples = 1;
6320 if (qtdemux->fragmented_seek_pending) {
6321 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6322 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6323 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6324 qtdemux->fragmented_seek_pending = FALSE;
6326 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6330 /* Figure out the next stream sample to output, min_time is expressed in
6331 * global time and runs over the edit list segments. */
6332 min_time = G_MAXUINT64;
6333 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6334 GstClockTime position;
6336 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6337 position = stream->time_position;
6339 if (!GST_CLOCK_TIME_IS_VALID (position))
6342 if (stream->segment_index != -1) {
6343 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6344 position += segment->media_start;
6347 /* position of -1 is EOS */
6348 if (position < min_time) {
6349 min_time = position;
6350 target_stream = stream;
6354 if (G_UNLIKELY (target_stream == NULL)) {
6355 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6359 /* check for segment end */
6360 if (G_UNLIKELY (qtdemux->segment.stop != -1
6361 && qtdemux->segment.rate >= 0
6362 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6363 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6364 target_stream->time_position = GST_CLOCK_TIME_NONE;
6368 /* gap events for subtitle streams */
6369 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6370 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6372 GstClockTime gap_threshold;
6374 /* Only send gap events on non-subtitle streams if lagging way behind. */
6375 if (stream->subtype == FOURCC_subp
6376 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6377 stream->subtype == FOURCC_wvtt)
6378 gap_threshold = 1 * GST_SECOND;
6380 gap_threshold = 3 * GST_SECOND;
6382 /* send gap events until the stream catches up */
6383 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6384 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6385 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6386 stream->segment.position + gap_threshold < min_time) {
6388 gst_event_new_gap (stream->segment.position, gap_threshold);
6389 gst_pad_push_event (stream->pad, gap);
6390 stream->segment.position += gap_threshold;
6395 stream = target_stream;
6396 /* fetch info for the current sample of this stream */
6397 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6398 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6401 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6402 if (stream->new_caps) {
6403 gst_qtdemux_configure_stream (qtdemux, stream);
6404 qtdemux_do_allocation (stream, qtdemux);
6407 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6408 if (G_UNLIKELY (qtdemux->segment.
6409 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6410 if (stream->subtype == FOURCC_vide) {
6412 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6415 } else if (qtdemux->trickmode_interval > 0) {
6416 GstClockTimeDiff interval;
6418 if (qtdemux->segment.rate > 0)
6419 interval = stream->time_position - stream->last_keyframe_dts;
6421 interval = stream->last_keyframe_dts - stream->time_position;
6423 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6424 && interval < qtdemux->trickmode_interval) {
6425 GST_LOG_OBJECT (qtdemux,
6426 "Skipping keyframe within interval on track-id %u",
6430 stream->last_keyframe_dts = stream->time_position;
6436 GST_DEBUG_OBJECT (qtdemux,
6437 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6438 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6439 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6440 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6441 GST_TIME_ARGS (duration));
6443 if (G_UNLIKELY (empty)) {
6444 /* empty segment, push a gap if there's a second or more
6445 * difference and move to the next one */
6446 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6447 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6448 stream->segment.position = pts + duration;
6452 /* hmm, empty sample, skip and move to next sample */
6453 if (G_UNLIKELY (sample_size <= 0))
6456 /* last pushed sample was out of boundary, goto next sample */
6457 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6460 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6461 GST_DEBUG_OBJECT (qtdemux,
6462 "size %d larger than stream max_buffer_size %d, trimming",
6463 sample_size, stream->max_buffer_size);
6465 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6466 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6467 && sample_size < stream->min_buffer_size) {
6468 guint start_sample_index = stream->sample_index;
6469 guint accumulated_size = sample_size;
6470 guint64 expected_next_offset = offset + sample_size;
6472 GST_DEBUG_OBJECT (qtdemux,
6473 "size %d smaller than stream min_buffer_size %d, combining with the next",
6474 sample_size, stream->min_buffer_size);
6476 while (stream->sample_index < stream->to_sample
6477 && stream->sample_index + 1 < stream->n_samples) {
6478 const QtDemuxSample *next_sample;
6480 /* Increment temporarily */
6481 stream->sample_index++;
6483 /* Failed to parse sample so let's go back to the previous one that was
6484 * still successful */
6485 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6486 stream->sample_index--;
6490 next_sample = &stream->samples[stream->sample_index];
6492 /* Not contiguous with the previous sample so let's go back to the
6493 * previous one that was still successful */
6494 if (next_sample->offset != expected_next_offset) {
6495 stream->sample_index--;
6499 accumulated_size += next_sample->size;
6500 expected_next_offset += next_sample->size;
6501 if (accumulated_size >= stream->min_buffer_size)
6505 num_samples = stream->sample_index + 1 - start_sample_index;
6506 stream->sample_index = start_sample_index;
6507 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6508 num_samples, accumulated_size);
6509 size = accumulated_size;
6514 if (qtdemux->cenc_aux_info_offset > 0) {
6517 GstBuffer *aux_info = NULL;
6519 /* pull the data stored before the sample */
6521 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6522 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6523 if (G_UNLIKELY (ret != GST_FLOW_OK))
6525 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6526 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6527 gst_byte_reader_init (&br, map.data + 8, map.size);
6528 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6529 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6530 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6531 gst_buffer_unmap (aux_info, &map);
6532 gst_buffer_unref (aux_info);
6533 ret = GST_FLOW_ERROR;
6536 gst_buffer_unmap (aux_info, &map);
6537 gst_buffer_unref (aux_info);
6540 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6543 if (stream->use_allocator) {
6544 /* if we have a per-stream allocator, use it */
6545 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6548 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6550 if (G_UNLIKELY (ret != GST_FLOW_OK))
6553 /* Update for both splitting and combining of samples */
6554 if (size != sample_size) {
6555 pts += gst_util_uint64_scale_int (GST_SECOND,
6556 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6559 gst_util_uint64_scale_int (GST_SECOND,
6560 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6563 gst_util_uint64_scale_int (GST_SECOND,
6564 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6567 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6568 dts, pts, duration, keyframe, min_time, offset);
6570 if (size < sample_size) {
6571 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6572 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6574 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6576 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6577 if (time_position >= segment->media_start) {
6578 /* inside the segment, update time_position, looks very familiar to
6579 * GStreamer segments, doesn't it? */
6580 stream->time_position = (time_position - segment->media_start) +
6583 /* not yet in segment, time does not yet increment. This means
6584 * that we are still prerolling keyframes to the decoder so it can
6585 * decode the first sample of the segment. */
6586 stream->time_position = segment->time;
6588 } else if (size > sample_size) {
6589 /* Increase to the last sample we already pulled so that advancing
6590 * below brings us to the next sample we need to pull */
6591 stream->sample_index += num_samples - 1;
6595 GST_OBJECT_LOCK (qtdemux);
6596 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6597 GST_OBJECT_UNLOCK (qtdemux);
6598 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6599 * we have no more data for the pad to push */
6600 if (ret == GST_FLOW_EOS)
6603 stream->offset_in_sample += size;
6604 if (stream->offset_in_sample >= sample_size) {
6605 gst_qtdemux_advance_sample (qtdemux, stream);
6610 gst_qtdemux_advance_sample (qtdemux, stream);
6618 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6624 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6625 /* EOS will be raised if all are EOS */
6632 gst_qtdemux_loop (GstPad * pad)
6634 GstQTDemux *qtdemux;
6638 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6640 cur_offset = qtdemux->offset;
6641 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6642 cur_offset, qt_demux_state_string (qtdemux->state));
6644 switch (qtdemux->state) {
6645 case QTDEMUX_STATE_INITIAL:
6646 case QTDEMUX_STATE_HEADER:
6647 ret = gst_qtdemux_loop_state_header (qtdemux);
6649 case QTDEMUX_STATE_MOVIE:
6650 ret = gst_qtdemux_loop_state_movie (qtdemux);
6651 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6652 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6660 /* if something went wrong, pause */
6661 if (ret != GST_FLOW_OK)
6665 gst_object_unref (qtdemux);
6671 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6672 (NULL), ("streaming stopped, invalid state"));
6673 gst_pad_pause_task (pad);
6674 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6679 const gchar *reason = gst_flow_get_name (ret);
6681 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6683 gst_pad_pause_task (pad);
6685 /* fatal errors need special actions */
6687 if (ret == GST_FLOW_EOS) {
6688 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6689 /* we have no streams, post an error */
6690 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6692 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6695 if ((stop = qtdemux->segment.stop) == -1)
6696 stop = qtdemux->segment.duration;
6698 if (qtdemux->segment.rate >= 0) {
6699 GstMessage *message;
6702 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6703 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6704 GST_FORMAT_TIME, stop);
6705 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6706 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6707 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6708 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6710 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6711 gst_qtdemux_push_event (qtdemux, event);
6713 GstMessage *message;
6716 /* For Reverse Playback */
6717 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6718 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6719 GST_FORMAT_TIME, qtdemux->segment.start);
6720 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6721 qtdemux->segment.start);
6722 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6723 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6724 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6726 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6727 gst_qtdemux_push_event (qtdemux, event);
6732 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6733 event = gst_event_new_eos ();
6734 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6735 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6736 gst_qtdemux_push_event (qtdemux, event);
6738 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6739 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6740 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6749 * Returns if there are samples to be played.
6752 has_next_entry (GstQTDemux * demux)
6754 QtDemuxStream *stream;
6757 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6759 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6760 stream = QTDEMUX_NTH_STREAM (demux, i);
6762 if (stream->sample_index == -1) {
6763 stream->sample_index = 0;
6764 stream->offset_in_sample = 0;
6767 if (stream->sample_index >= stream->n_samples) {
6768 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6771 GST_DEBUG_OBJECT (demux, "Found a sample");
6775 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6782 * Returns the size of the first entry at the current offset.
6783 * If -1, there are none (which means EOS or empty file).
6786 next_entry_size (GstQTDemux * demux)
6788 QtDemuxStream *stream, *target_stream = NULL;
6789 guint64 smalloffs = (guint64) - 1;
6790 QtDemuxSample *sample;
6793 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6796 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6797 stream = QTDEMUX_NTH_STREAM (demux, i);
6799 if (stream->sample_index == -1) {
6800 stream->sample_index = 0;
6801 stream->offset_in_sample = 0;
6804 if (stream->sample_index >= stream->n_samples) {
6805 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6809 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6810 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6811 stream->sample_index);
6815 sample = &stream->samples[stream->sample_index];
6817 GST_LOG_OBJECT (demux,
6818 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6819 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6820 stream->sample_index, sample->offset, sample->size);
6822 if (((smalloffs == -1)
6823 || (sample->offset < smalloffs)) && (sample->size)) {
6824 smalloffs = sample->offset;
6825 target_stream = stream;
6832 GST_LOG_OBJECT (demux,
6833 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6834 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6836 stream = target_stream;
6837 sample = &stream->samples[stream->sample_index];
6839 if (sample->offset >= demux->offset) {
6840 demux->todrop = sample->offset - demux->offset;
6841 return sample->size + demux->todrop;
6844 GST_DEBUG_OBJECT (demux,
6845 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6850 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6852 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6854 gst_element_post_message (GST_ELEMENT_CAST (demux),
6855 gst_message_new_element (GST_OBJECT_CAST (demux),
6856 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6860 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6865 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6868 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6869 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6870 GST_SEEK_TYPE_NONE, -1);
6872 /* store seqnum to drop flush events, they don't need to reach downstream */
6873 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6874 res = gst_pad_push_event (demux->sinkpad, event);
6875 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6880 /* check for seekable upstream, above and beyond a mere query */
6882 gst_qtdemux_check_seekability (GstQTDemux * demux)
6885 gboolean seekable = FALSE;
6886 gint64 start = -1, stop = -1;
6888 if (demux->upstream_size)
6891 if (demux->upstream_format_is_time)
6894 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6895 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6896 GST_DEBUG_OBJECT (demux, "seeking query failed");
6900 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6902 /* try harder to query upstream size if we didn't get it the first time */
6903 if (seekable && stop == -1) {
6904 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6905 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6908 /* if upstream doesn't know the size, it's likely that it's not seekable in
6909 * practice even if it technically may be seekable */
6910 if (seekable && (start != 0 || stop <= start)) {
6911 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6916 gst_query_unref (query);
6918 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6919 G_GUINT64_FORMAT ")", seekable, start, stop);
6920 demux->upstream_seekable = seekable;
6921 demux->upstream_size = seekable ? stop : -1;
6925 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6927 g_return_if_fail (bytes <= demux->todrop);
6929 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6930 gst_adapter_flush (demux->adapter, bytes);
6931 demux->neededbytes -= bytes;
6932 demux->offset += bytes;
6933 demux->todrop -= bytes;
6936 /* PUSH-MODE only: Send a segment, if not done already. */
6938 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6940 if (G_UNLIKELY (demux->need_segment)) {
6943 if (!demux->upstream_format_is_time) {
6944 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6946 GstEvent *segment_event;
6947 segment_event = gst_event_new_segment (&demux->segment);
6948 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6949 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6950 gst_qtdemux_push_event (demux, segment_event);
6953 demux->need_segment = FALSE;
6955 /* clear to send tags on all streams */
6956 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6957 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6958 gst_qtdemux_push_tags (demux, stream);
6959 if (CUR_STREAM (stream)->sparse) {
6960 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6961 gst_pad_push_event (stream->pad,
6962 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6968 /* Used for push mode only. */
6970 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6971 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6973 GstClockTime ts, dur;
6977 stream->segments[segment_index].duration - (pos -
6978 stream->segments[segment_index].time);
6979 stream->time_position += dur;
6981 /* Only gaps with a duration of at least one second are propagated.
6982 * Same workaround as in pull mode.
6983 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6984 if (dur >= GST_SECOND) {
6986 gap = gst_event_new_gap (ts, dur);
6988 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6989 "segment: %" GST_PTR_FORMAT, gap);
6990 gst_pad_push_event (stream->pad, gap);
6994 static GstFlowReturn
6995 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6999 demux = GST_QTDEMUX (parent);
7001 GST_DEBUG_OBJECT (demux,
7002 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7003 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7004 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7005 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7006 gst_buffer_get_size (inbuf), demux->offset);
7008 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7009 gboolean is_gap_input = FALSE;
7012 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7014 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7015 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7018 /* Check if we can land back on our feet in the case where upstream is
7019 * handling the seeking/pushing of samples with gaps in between (like
7020 * in the case of trick-mode DASH for example) */
7021 if (demux->upstream_format_is_time
7022 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7023 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7025 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7026 GST_LOG_OBJECT (demux,
7027 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7028 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7030 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7031 stream, GST_BUFFER_OFFSET (inbuf));
7033 QtDemuxSample *sample = &stream->samples[res];
7034 GST_LOG_OBJECT (demux,
7035 "Checking if sample %d from track-id %u is valid (offset:%"
7036 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7037 stream->track_id, sample->offset, sample->size);
7038 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7039 GST_LOG_OBJECT (demux,
7040 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7042 is_gap_input = TRUE;
7043 /* We can go back to standard playback mode */
7044 demux->state = QTDEMUX_STATE_MOVIE;
7045 /* Remember which sample this stream is at */
7046 stream->sample_index = res;
7047 /* Finally update all push-based values to the expected values */
7048 demux->neededbytes = stream->samples[res].size;
7049 demux->offset = GST_BUFFER_OFFSET (inbuf);
7051 demux->mdatsize - demux->offset + demux->mdatoffset;
7056 if (!is_gap_input) {
7057 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7058 /* Reset state if it's a real discont */
7059 demux->neededbytes = 16;
7060 demux->state = QTDEMUX_STATE_INITIAL;
7061 demux->offset = GST_BUFFER_OFFSET (inbuf);
7062 gst_adapter_clear (demux->adapter);
7065 /* Reverse fragmented playback, need to flush all we have before
7066 * consuming a new fragment.
7067 * The samples array have the timestamps calculated by accumulating the
7068 * durations but this won't work for reverse playback of fragments as
7069 * the timestamps of a subsequent fragment should be smaller than the
7070 * previously received one. */
7071 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7072 gst_qtdemux_process_adapter (demux, TRUE);
7073 g_ptr_array_foreach (demux->active_streams,
7074 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7078 gst_adapter_push (demux->adapter, inbuf);
7080 GST_DEBUG_OBJECT (demux,
7081 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7082 demux->neededbytes, gst_adapter_available (demux->adapter));
7084 return gst_qtdemux_process_adapter (demux, FALSE);
7087 static GstFlowReturn
7088 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7090 GstFlowReturn ret = GST_FLOW_OK;
7092 /* we never really mean to buffer that much */
7093 if (demux->neededbytes == -1) {
7097 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7098 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7100 #ifndef GST_DISABLE_GST_DEBUG
7102 guint64 discont_offset, distance_from_discont;
7104 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7105 distance_from_discont =
7106 gst_adapter_distance_from_discont (demux->adapter);
7108 GST_DEBUG_OBJECT (demux,
7109 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7110 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7111 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7112 demux->offset, discont_offset, distance_from_discont);
7116 switch (demux->state) {
7117 case QTDEMUX_STATE_INITIAL:{
7122 gst_qtdemux_check_seekability (demux);
7124 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7126 /* get fourcc/length, set neededbytes */
7127 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7129 gst_adapter_unmap (demux->adapter);
7131 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7132 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7134 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7135 (_("This file is invalid and cannot be played.")),
7136 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7137 GST_FOURCC_ARGS (fourcc)));
7138 ret = GST_FLOW_ERROR;
7141 if (fourcc == FOURCC_mdat) {
7142 gint next_entry = next_entry_size (demux);
7143 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7144 || !demux->fragmented)) {
7145 /* we have the headers, start playback */
7146 demux->state = QTDEMUX_STATE_MOVIE;
7147 demux->neededbytes = next_entry;
7148 demux->mdatleft = size;
7149 demux->mdatsize = demux->mdatleft;
7151 /* no headers yet, try to get them */
7154 guint64 old, target;
7157 old = demux->offset;
7158 target = old + size;
7160 /* try to jump over the atom with a seek */
7161 /* only bother if it seems worth doing so,
7162 * and avoids possible upstream/server problems */
7163 if (demux->upstream_seekable &&
7164 demux->upstream_size > 4 * (1 << 20)) {
7165 res = qtdemux_seek_offset (demux, target);
7167 GST_DEBUG_OBJECT (demux, "skipping seek");
7172 GST_DEBUG_OBJECT (demux, "seek success");
7173 /* remember the offset fo the first mdat so we can seek back to it
7174 * after we have the headers */
7175 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7176 demux->first_mdat = old;
7177 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7180 /* seek worked, continue reading */
7181 demux->offset = target;
7182 demux->neededbytes = 16;
7183 demux->state = QTDEMUX_STATE_INITIAL;
7185 /* seek failed, need to buffer */
7186 demux->offset = old;
7187 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7188 /* there may be multiple mdat (or alike) buffers */
7190 if (demux->mdatbuffer)
7191 bs = gst_buffer_get_size (demux->mdatbuffer);
7194 if (size + bs > 10 * (1 << 20))
7196 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7197 demux->neededbytes = size;
7198 if (!demux->mdatbuffer)
7199 demux->mdatoffset = demux->offset;
7202 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7203 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7204 (_("This file is invalid and cannot be played.")),
7205 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7206 GST_FOURCC_ARGS (fourcc), size));
7207 ret = GST_FLOW_ERROR;
7210 /* this means we already started buffering and still no moov header,
7211 * let's continue buffering everything till we get moov */
7212 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7213 || fourcc == FOURCC_moof))
7215 demux->neededbytes = size;
7216 demux->state = QTDEMUX_STATE_HEADER;
7220 case QTDEMUX_STATE_HEADER:{
7224 GST_DEBUG_OBJECT (demux, "In header");
7226 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7228 /* parse the header */
7229 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7231 if (fourcc == FOURCC_moov) {
7232 /* in usual fragmented setup we could try to scan for more
7233 * and end up at the the moov (after mdat) again */
7234 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7236 || demux->last_moov_offset == demux->offset)) {
7237 GST_DEBUG_OBJECT (demux,
7238 "Skipping moov atom as we have (this) one already");
7240 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7242 if (demux->got_moov && demux->fragmented) {
7243 GST_DEBUG_OBJECT (demux,
7244 "Got a second moov, clean up data from old one");
7245 if (demux->moov_node_compressed) {
7246 g_node_destroy (demux->moov_node_compressed);
7247 if (demux->moov_node)
7248 g_free (demux->moov_node->data);
7250 demux->moov_node_compressed = NULL;
7251 if (demux->moov_node)
7252 g_node_destroy (demux->moov_node);
7253 demux->moov_node = NULL;
7256 demux->last_moov_offset = demux->offset;
7258 /* Update streams with new moov */
7259 gst_qtdemux_stream_concat (demux,
7260 demux->old_streams, demux->active_streams);
7262 qtdemux_parse_moov (demux, data, demux->neededbytes);
7263 qtdemux_node_dump (demux, demux->moov_node);
7264 qtdemux_parse_tree (demux);
7265 qtdemux_prepare_streams (demux);
7266 QTDEMUX_EXPOSE_LOCK (demux);
7267 qtdemux_expose_streams (demux);
7268 QTDEMUX_EXPOSE_UNLOCK (demux);
7270 demux->got_moov = TRUE;
7272 gst_qtdemux_check_send_pending_segment (demux);
7274 if (demux->moov_node_compressed) {
7275 g_node_destroy (demux->moov_node_compressed);
7276 g_free (demux->moov_node->data);
7278 demux->moov_node_compressed = NULL;
7279 g_node_destroy (demux->moov_node);
7280 demux->moov_node = NULL;
7281 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7283 } else if (fourcc == FOURCC_moof) {
7284 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7286 GstClockTime prev_pts;
7287 guint64 prev_offset;
7288 guint64 adapter_discont_offset, adapter_discont_dist;
7290 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7293 * The timestamp of the moof buffer is relevant as some scenarios
7294 * won't have the initial timestamp in the atoms. Whenever a new
7295 * buffer has started, we get that buffer's PTS and use it as a base
7296 * timestamp for the trun entries.
7298 * To keep track of the current buffer timestamp and starting point
7299 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7300 * from the beginning of the buffer, with the distance and demux->offset
7301 * we know if it is still the same buffer or not.
7303 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7304 prev_offset = demux->offset - dist;
7305 if (demux->fragment_start_offset == -1
7306 || prev_offset > demux->fragment_start_offset) {
7307 demux->fragment_start_offset = prev_offset;
7308 demux->fragment_start = prev_pts;
7309 GST_DEBUG_OBJECT (demux,
7310 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7311 GST_TIME_FORMAT, demux->fragment_start_offset,
7312 GST_TIME_ARGS (demux->fragment_start));
7315 /* We can't use prev_offset() here because this would require
7316 * upstream to set consistent and correct offsets on all buffers
7317 * since the discont. Nothing ever did that in the past and we
7318 * would break backwards compatibility here then.
7319 * Instead take the offset we had at the last discont and count
7320 * the bytes from there. This works with old code as there would
7321 * be no discont between moov and moof, and also works with
7322 * adaptivedemux which correctly sets offset and will set the
7323 * DISCONT flag accordingly when needed.
7325 * We also only do this for upstream TIME segments as otherwise
7326 * there are potential backwards compatibility problems with
7327 * seeking in PUSH mode and upstream providing inconsistent
7329 adapter_discont_offset =
7330 gst_adapter_offset_at_discont (demux->adapter);
7331 adapter_discont_dist =
7332 gst_adapter_distance_from_discont (demux->adapter);
7334 GST_DEBUG_OBJECT (demux,
7335 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7336 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7337 demux->offset, adapter_discont_offset, adapter_discont_dist);
7339 if (demux->upstream_format_is_time) {
7340 demux->moof_offset = adapter_discont_offset;
7341 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7342 demux->moof_offset += adapter_discont_dist;
7343 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7344 demux->moof_offset = demux->offset;
7346 demux->moof_offset = demux->offset;
7349 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7350 demux->moof_offset, NULL)) {
7351 gst_adapter_unmap (demux->adapter);
7352 ret = GST_FLOW_ERROR;
7356 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7357 if (demux->mss_mode && !demux->exposed) {
7358 QTDEMUX_EXPOSE_LOCK (demux);
7359 qtdemux_expose_streams (demux);
7360 QTDEMUX_EXPOSE_UNLOCK (demux);
7363 gst_qtdemux_check_send_pending_segment (demux);
7365 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7367 } else if (fourcc == FOURCC_ftyp) {
7368 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7369 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7370 } else if (fourcc == FOURCC_uuid) {
7371 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7372 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7373 } else if (fourcc == FOURCC_sidx) {
7374 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7375 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7379 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7383 /* [free] and [skip] are padding atoms */
7384 GST_DEBUG_OBJECT (demux,
7385 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7386 GST_FOURCC_ARGS (fourcc));
7389 GST_WARNING_OBJECT (demux,
7390 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7391 GST_FOURCC_ARGS (fourcc));
7392 /* Let's jump that one and go back to initial state */
7396 gst_adapter_unmap (demux->adapter);
7399 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7400 gsize remaining_data_size = 0;
7402 /* the mdat was before the header */
7403 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7404 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7405 /* restore our adapter/offset view of things with upstream;
7406 * put preceding buffered data ahead of current moov data.
7407 * This should also handle evil mdat, moov, mdat cases and alike */
7408 gst_adapter_flush (demux->adapter, demux->neededbytes);
7410 /* Store any remaining data after the mdat for later usage */
7411 remaining_data_size = gst_adapter_available (demux->adapter);
7412 if (remaining_data_size > 0) {
7413 g_assert (demux->restoredata_buffer == NULL);
7414 demux->restoredata_buffer =
7415 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7416 demux->restoredata_offset = demux->offset + demux->neededbytes;
7417 GST_DEBUG_OBJECT (demux,
7418 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7419 G_GUINT64_FORMAT, remaining_data_size,
7420 demux->restoredata_offset);
7423 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7424 demux->mdatbuffer = NULL;
7425 demux->offset = demux->mdatoffset;
7426 demux->neededbytes = next_entry_size (demux);
7427 demux->state = QTDEMUX_STATE_MOVIE;
7428 demux->mdatleft = gst_adapter_available (demux->adapter);
7429 demux->mdatsize = demux->mdatleft;
7431 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7432 gst_adapter_flush (demux->adapter, demux->neededbytes);
7434 /* only go back to the mdat if there are samples to play */
7435 if (demux->got_moov && demux->first_mdat != -1
7436 && has_next_entry (demux)) {
7439 /* we need to seek back */
7440 res = qtdemux_seek_offset (demux, demux->first_mdat);
7442 demux->offset = demux->first_mdat;
7444 GST_DEBUG_OBJECT (demux, "Seek back failed");
7447 demux->offset += demux->neededbytes;
7449 demux->neededbytes = 16;
7450 demux->state = QTDEMUX_STATE_INITIAL;
7455 case QTDEMUX_STATE_BUFFER_MDAT:{
7459 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7461 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7462 gst_buffer_extract (buf, 0, fourcc, 4);
7463 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7464 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7465 if (demux->mdatbuffer)
7466 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7468 demux->mdatbuffer = buf;
7469 demux->offset += demux->neededbytes;
7470 demux->neededbytes = 16;
7471 demux->state = QTDEMUX_STATE_INITIAL;
7472 gst_qtdemux_post_progress (demux, 1, 1);
7476 case QTDEMUX_STATE_MOVIE:{
7477 QtDemuxStream *stream = NULL;
7478 QtDemuxSample *sample;
7479 GstClockTime dts, pts, duration;
7483 GST_DEBUG_OBJECT (demux,
7484 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7486 if (demux->fragmented) {
7487 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7489 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7490 /* if needed data starts within this atom,
7491 * then it should not exceed this atom */
7492 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7493 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7494 (_("This file is invalid and cannot be played.")),
7495 ("sample data crosses atom boundary"));
7496 ret = GST_FLOW_ERROR;
7499 demux->mdatleft -= demux->neededbytes;
7501 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7502 /* so we are dropping more than left in this atom */
7503 gst_qtdemux_drop_data (demux, demux->mdatleft);
7504 demux->mdatleft = 0;
7506 /* need to resume atom parsing so we do not miss any other pieces */
7507 demux->state = QTDEMUX_STATE_INITIAL;
7508 demux->neededbytes = 16;
7510 /* check if there was any stored post mdat data from previous buffers */
7511 if (demux->restoredata_buffer) {
7512 g_assert (gst_adapter_available (demux->adapter) == 0);
7514 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7515 demux->restoredata_buffer = NULL;
7516 demux->offset = demux->restoredata_offset;
7523 if (demux->todrop) {
7524 if (demux->cenc_aux_info_offset > 0) {
7528 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7529 data = gst_adapter_map (demux->adapter, demux->todrop);
7530 gst_byte_reader_init (&br, data + 8, demux->todrop);
7531 if (!qtdemux_parse_cenc_aux_info (demux,
7532 QTDEMUX_NTH_STREAM (demux, 0), &br,
7533 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7534 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7535 ret = GST_FLOW_ERROR;
7536 gst_adapter_unmap (demux->adapter);
7537 g_free (demux->cenc_aux_info_sizes);
7538 demux->cenc_aux_info_sizes = NULL;
7541 demux->cenc_aux_info_offset = 0;
7542 g_free (demux->cenc_aux_info_sizes);
7543 demux->cenc_aux_info_sizes = NULL;
7544 gst_adapter_unmap (demux->adapter);
7546 gst_qtdemux_drop_data (demux, demux->todrop);
7550 /* initial newsegment sent here after having added pads,
7551 * possible others in sink_event */
7552 gst_qtdemux_check_send_pending_segment (demux);
7554 /* Figure out which stream this packet belongs to */
7555 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7556 stream = QTDEMUX_NTH_STREAM (demux, i);
7557 if (stream->sample_index >= stream->n_samples) {
7558 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7562 GST_LOG_OBJECT (demux,
7563 "Checking track-id %u (sample_index:%d / offset:%"
7564 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7565 stream->sample_index,
7566 stream->samples[stream->sample_index].offset,
7567 stream->samples[stream->sample_index].size);
7569 if (stream->samples[stream->sample_index].offset == demux->offset)
7573 if (G_UNLIKELY (stream == NULL))
7574 goto unknown_stream;
7576 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7578 if (stream->new_caps) {
7579 gst_qtdemux_configure_stream (demux, stream);
7582 /* Put data in a buffer, set timestamps, caps, ... */
7583 sample = &stream->samples[stream->sample_index];
7585 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7586 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7587 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7589 dts = QTSAMPLE_DTS (stream, sample);
7590 pts = QTSAMPLE_PTS (stream, sample);
7591 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7592 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7594 /* check for segment end */
7595 if (G_UNLIKELY (demux->segment.stop != -1
7596 && demux->segment.stop <= pts && stream->on_keyframe)
7597 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7598 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7599 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7601 /* skip this data, stream is EOS */
7602 gst_adapter_flush (demux->adapter, demux->neededbytes);
7603 demux->offset += demux->neededbytes;
7605 /* check if all streams are eos */
7607 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7608 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7617 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7619 /* FIXME: should either be an assert or a plain check */
7620 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7622 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7623 dts, pts, duration, keyframe, dts, demux->offset);
7627 GST_OBJECT_LOCK (demux);
7628 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7629 GST_OBJECT_UNLOCK (demux);
7631 /* skip this data, stream is EOS */
7632 gst_adapter_flush (demux->adapter, demux->neededbytes);
7635 stream->sample_index++;
7636 stream->offset_in_sample = 0;
7638 /* update current offset and figure out size of next buffer */
7639 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7640 demux->offset, demux->neededbytes);
7641 demux->offset += demux->neededbytes;
7642 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7646 if (ret == GST_FLOW_EOS) {
7647 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7648 demux->neededbytes = -1;
7652 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7653 if (demux->fragmented) {
7654 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7655 /* there may be more to follow, only finish this atom */
7656 demux->todrop = demux->mdatleft;
7657 demux->neededbytes = demux->todrop;
7662 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7663 goto non_ok_unlinked_flow;
7672 /* when buffering movie data, at least show user something is happening */
7673 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7674 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7675 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7676 demux->neededbytes);
7683 non_ok_unlinked_flow:
7685 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7686 gst_flow_get_name (ret));
7691 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7692 ret = GST_FLOW_ERROR;
7697 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7703 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7704 (NULL), ("qtdemuxer invalid state %d", demux->state));
7705 ret = GST_FLOW_ERROR;
7710 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7711 (NULL), ("no 'moov' atom within the first 10 MB"));
7712 ret = GST_FLOW_ERROR;
7718 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7723 query = gst_query_new_scheduling ();
7725 if (!gst_pad_peer_query (sinkpad, query)) {
7726 gst_query_unref (query);
7730 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7731 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7732 gst_query_unref (query);
7737 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7738 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7742 GST_DEBUG_OBJECT (sinkpad, "activating push");
7743 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7748 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7749 GstPadMode mode, gboolean active)
7752 GstQTDemux *demux = GST_QTDEMUX (parent);
7755 case GST_PAD_MODE_PUSH:
7756 demux->pullbased = FALSE;
7759 case GST_PAD_MODE_PULL:
7761 demux->pullbased = TRUE;
7762 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7765 res = gst_pad_stop_task (sinkpad);
7777 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7783 memset (&z, 0, sizeof (z));
7788 if ((ret = inflateInit (&z)) != Z_OK) {
7789 GST_ERROR ("inflateInit() returned %d", ret);
7793 z.next_in = z_buffer;
7794 z.avail_in = z_length;
7796 buffer = (guint8 *) g_malloc (*length);
7797 z.avail_out = *length;
7798 z.next_out = (Bytef *) buffer;
7800 ret = inflate (&z, Z_NO_FLUSH);
7801 if (ret == Z_STREAM_END) {
7803 } else if (ret != Z_OK) {
7804 GST_WARNING ("inflate() returned %d", ret);
7809 buffer = (guint8 *) g_realloc (buffer, *length);
7810 z.next_out = (Bytef *) (buffer + z.total_out);
7811 z.avail_out += 4096;
7812 } while (z.avail_in > 0);
7814 if (ret != Z_STREAM_END) {
7819 *length = z.total_out;
7826 #endif /* HAVE_ZLIB */
7829 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7833 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7835 /* counts as header data */
7836 qtdemux->header_size += length;
7838 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7839 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7841 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7848 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7849 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7850 if (dcom == NULL || cmvd == NULL)
7851 goto invalid_compression;
7853 dcom_len = QT_UINT32 (dcom->data);
7855 goto invalid_compression;
7857 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7861 guint uncompressed_length;
7862 guint compressed_length;
7866 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7868 goto invalid_compression;
7870 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7871 compressed_length = cmvd_len - 12;
7872 GST_LOG ("length = %u", uncompressed_length);
7875 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7876 compressed_length, &uncompressed_length);
7879 qtdemux->moov_node_compressed = qtdemux->moov_node;
7880 qtdemux->moov_node = g_node_new (buf);
7882 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7883 uncompressed_length);
7887 #endif /* HAVE_ZLIB */
7889 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7890 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7897 invalid_compression:
7899 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7905 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7908 while (G_UNLIKELY (buf < end)) {
7912 if (G_UNLIKELY (buf + 4 > end)) {
7913 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7916 len = QT_UINT32 (buf);
7917 if (G_UNLIKELY (len == 0)) {
7918 GST_LOG_OBJECT (qtdemux, "empty container");
7921 if (G_UNLIKELY (len < 8)) {
7922 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7925 if (G_UNLIKELY (len > (end - buf))) {
7926 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7927 (gint) (end - buf));
7931 child = g_node_new ((guint8 *) buf);
7932 g_node_append (node, child);
7933 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7934 qtdemux_parse_node (qtdemux, child, buf, len);
7942 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7945 int len = QT_UINT32 (xdxt->data);
7946 guint8 *buf = xdxt->data;
7947 guint8 *end = buf + len;
7950 /* skip size and type */
7958 size = QT_UINT32 (buf);
7959 type = QT_FOURCC (buf + 4);
7961 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7963 if (buf + size > end || size <= 0)
7969 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7970 GST_FOURCC_ARGS (type));
7974 buffer = gst_buffer_new_and_alloc (size);
7975 gst_buffer_fill (buffer, 0, buf, size);
7976 stream->buffers = g_slist_append (stream->buffers, buffer);
7977 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7980 buffer = gst_buffer_new_and_alloc (size);
7981 gst_buffer_fill (buffer, 0, buf, size);
7982 stream->buffers = g_slist_append (stream->buffers, buffer);
7983 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7986 buffer = gst_buffer_new_and_alloc (size);
7987 gst_buffer_fill (buffer, 0, buf, size);
7988 stream->buffers = g_slist_append (stream->buffers, buffer);
7989 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7992 GST_WARNING_OBJECT (qtdemux,
7993 "unknown theora cookie %" GST_FOURCC_FORMAT,
7994 GST_FOURCC_ARGS (type));
8003 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8007 guint32 node_length = 0;
8008 const QtNodeType *type;
8011 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8013 if (G_UNLIKELY (length < 8))
8014 goto not_enough_data;
8016 node_length = QT_UINT32 (buffer);
8017 fourcc = QT_FOURCC (buffer + 4);
8019 /* ignore empty nodes */
8020 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8023 type = qtdemux_type_get (fourcc);
8025 end = buffer + length;
8027 GST_LOG_OBJECT (qtdemux,
8028 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8029 GST_FOURCC_ARGS (fourcc), node_length, type->name);
8031 if (node_length > length)
8032 goto broken_atom_size;
8034 if (type->flags & QT_FLAG_CONTAINER) {
8035 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8040 if (node_length < 20) {
8041 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8044 GST_DEBUG_OBJECT (qtdemux,
8045 "parsing stsd (sample table, sample description) atom");
8046 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8047 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8059 /* also read alac (or whatever) in stead of mp4a in the following,
8060 * since a similar layout is used in other cases as well */
8061 if (fourcc == FOURCC_mp4a)
8063 else if (fourcc == FOURCC_fLaC)
8068 /* There are two things we might encounter here: a true mp4a atom, and
8069 an mp4a entry in an stsd atom. The latter is what we're interested
8070 in, and it looks like an atom, but isn't really one. The true mp4a
8071 atom is short, so we detect it based on length here. */
8072 if (length < min_size) {
8073 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8074 GST_FOURCC_ARGS (fourcc));
8078 /* 'version' here is the sound sample description version. Types 0 and
8079 1 are documented in the QTFF reference, but type 2 is not: it's
8080 described in Apple header files instead (struct SoundDescriptionV2
8082 version = QT_UINT16 (buffer + 16);
8084 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8085 GST_FOURCC_ARGS (fourcc), version);
8087 /* parse any esds descriptors */
8099 GST_WARNING_OBJECT (qtdemux,
8100 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8101 GST_FOURCC_ARGS (fourcc), version);
8106 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8134 /* codec_data is contained inside these atoms, which all have
8135 * the same format. */
8136 /* video sample description size is 86 bytes without extension.
8137 * node_length have to be bigger than 86 bytes because video sample
8138 * description can include extensions such as esds, fiel, glbl, etc. */
8139 if (node_length < 86) {
8140 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8141 " sample description length too short (%u < 86)",
8142 GST_FOURCC_ARGS (fourcc), node_length);
8146 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8147 GST_FOURCC_ARGS (fourcc));
8149 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8151 * revision level (2 bytes) : must be set to 0. */
8152 version = QT_UINT32 (buffer + 16);
8153 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8155 /* compressor name : PASCAL string and informative purposes
8156 * first byte : the number of bytes to be displayed.
8157 * it has to be less than 32 because it is reserved
8158 * space of 32 bytes total including itself. */
8159 str_len = QT_UINT8 (buffer + 50);
8161 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8162 (char *) buffer + 51);
8164 GST_WARNING_OBJECT (qtdemux,
8165 "compressorname length too big (%u > 31)", str_len);
8167 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8169 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8174 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8176 /* You are reading this correctly. QTFF specifies that the
8177 * metadata atom is a short atom, whereas ISO BMFF specifies
8178 * it's a full atom. But since so many people are doing things
8179 * differently, we actually peek into the atom to see which
8182 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8183 GST_FOURCC_ARGS (fourcc));
8186 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8187 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8188 * starts with a 'hdlr' atom */
8189 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8190 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8191 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8192 * with version/flags both set to zero */
8193 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8195 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8200 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8201 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8202 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8211 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8212 GST_FOURCC_ARGS (fourcc));
8216 version = QT_UINT32 (buffer + 12);
8217 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8224 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8229 if (length < offset) {
8230 GST_WARNING_OBJECT (qtdemux,
8231 "skipping too small %" GST_FOURCC_FORMAT " box",
8232 GST_FOURCC_ARGS (fourcc));
8235 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8241 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8246 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8251 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8255 if (!strcmp (type->name, "unknown"))
8256 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8260 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8261 GST_FOURCC_ARGS (fourcc));
8267 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8268 (_("This file is corrupt and cannot be played.")),
8269 ("Not enough data for an atom header, got only %u bytes", length));
8274 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8275 (_("This file is corrupt and cannot be played.")),
8276 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8277 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8284 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8286 /* FIXME: This can only reliably work if demuxers have a
8287 * separate streaming thread per srcpad. This should be
8288 * done in a demuxer base class, which integrates parts
8291 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8296 query = gst_query_new_allocation (stream->caps, FALSE);
8298 if (!gst_pad_peer_query (stream->pad, query)) {
8299 /* not a problem, just debug a little */
8300 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8303 if (stream->allocator)
8304 gst_object_unref (stream->allocator);
8306 if (gst_query_get_n_allocation_params (query) > 0) {
8307 /* try the allocator */
8308 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8310 stream->use_allocator = TRUE;
8312 stream->allocator = NULL;
8313 gst_allocation_params_init (&stream->params);
8314 stream->use_allocator = FALSE;
8316 gst_query_unref (query);
8321 pad_query (const GValue * item, GValue * value, gpointer user_data)
8323 GstPad *pad = g_value_get_object (item);
8324 GstQuery *query = user_data;
8327 res = gst_pad_peer_query (pad, query);
8330 g_value_set_boolean (value, TRUE);
8334 GST_INFO_OBJECT (pad, "pad peer query failed");
8339 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8340 GstPadDirection direction)
8343 GstIteratorFoldFunction func = pad_query;
8344 GValue res = { 0, };
8346 g_value_init (&res, G_TYPE_BOOLEAN);
8347 g_value_set_boolean (&res, FALSE);
8350 if (direction == GST_PAD_SRC)
8351 it = gst_element_iterate_src_pads (element);
8353 it = gst_element_iterate_sink_pads (element);
8355 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8356 gst_iterator_resync (it);
8358 gst_iterator_free (it);
8360 return g_value_get_boolean (&res);
8364 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8365 QtDemuxStream * stream)
8369 GstElement *element = GST_ELEMENT (qtdemux);
8371 gchar **filtered_sys_ids;
8372 GValue event_list = G_VALUE_INIT;
8375 /* 1. Check if we already have the context. */
8376 if (qtdemux->preferred_protection_system_id != NULL) {
8377 GST_LOG_OBJECT (element,
8378 "already have the protection context, no need to request it again");
8382 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8383 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8384 (const gchar **) qtdemux->protection_system_ids->pdata);
8386 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8387 qtdemux->protection_system_ids->len - 1);
8388 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8389 "decryptors for %u of them, running context request",
8390 qtdemux->protection_system_ids->len,
8391 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8394 if (stream->protection_scheme_event_queue.length) {
8395 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8396 stream->protection_scheme_event_queue.length);
8397 walk = stream->protection_scheme_event_queue.tail;
8399 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8400 qtdemux->protection_event_queue.length);
8401 walk = qtdemux->protection_event_queue.tail;
8404 g_value_init (&event_list, GST_TYPE_LIST);
8405 for (; walk; walk = g_list_previous (walk)) {
8406 GValue *event_value = g_new0 (GValue, 1);
8407 g_value_init (event_value, GST_TYPE_EVENT);
8408 g_value_set_boxed (event_value, walk->data);
8409 gst_value_list_append_and_take_value (&event_list, event_value);
8412 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8413 * check if downstream already has a context of the specific type
8414 * 2b) Query upstream as above.
8416 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8417 st = gst_query_writable_structure (query);
8418 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8419 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8421 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8422 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8423 gst_query_parse_context (query, &ctxt);
8424 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8425 gst_element_set_context (element, ctxt);
8426 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8427 gst_query_parse_context (query, &ctxt);
8428 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8429 gst_element_set_context (element, ctxt);
8431 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8432 * the required context type and afterwards check if a
8433 * usable context was set now as in 1). The message could
8434 * be handled by the parent bins of the element and the
8439 GST_INFO_OBJECT (element, "posting need context message");
8440 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8441 "drm-preferred-decryption-system-id");
8442 st = (GstStructure *) gst_message_get_structure (msg);
8443 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8444 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8447 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8448 gst_element_post_message (element, msg);
8451 g_strfreev (filtered_sys_ids);
8452 g_value_unset (&event_list);
8453 gst_query_unref (query);
8457 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8458 QtDemuxStream * stream)
8461 const gchar *selected_system = NULL;
8463 g_return_val_if_fail (qtdemux != NULL, FALSE);
8464 g_return_val_if_fail (stream != NULL, FALSE);
8465 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8468 if (stream->protection_scheme_type == FOURCC_aavd) {
8469 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8470 if (!gst_structure_has_name (s, "application/x-aavd")) {
8471 gst_structure_set (s,
8472 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8474 gst_structure_set_name (s, "application/x-aavd");
8479 if (stream->protection_scheme_type != FOURCC_cenc
8480 && stream->protection_scheme_type != FOURCC_cbcs) {
8481 GST_ERROR_OBJECT (qtdemux,
8482 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8483 GST_FOURCC_ARGS (stream->protection_scheme_type));
8487 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8488 if (!gst_structure_has_name (s, "application/x-cenc")) {
8489 gst_structure_set (s,
8490 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8491 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8492 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8494 gst_structure_set_name (s, "application/x-cenc");
8497 if (qtdemux->protection_system_ids == NULL) {
8498 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8499 "cenc protection system information has been found, not setting a "
8500 "protection system UUID");
8504 gst_qtdemux_request_protection_context (qtdemux, stream);
8505 if (qtdemux->preferred_protection_system_id != NULL) {
8506 const gchar *preferred_system_array[] =
8507 { qtdemux->preferred_protection_system_id, NULL };
8509 selected_system = gst_protection_select_system (preferred_system_array);
8511 if (selected_system) {
8512 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8513 qtdemux->preferred_protection_system_id);
8515 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8516 "because there is no available decryptor",
8517 qtdemux->preferred_protection_system_id);
8521 if (!selected_system) {
8522 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8523 selected_system = gst_protection_select_system ((const gchar **)
8524 qtdemux->protection_system_ids->pdata);
8525 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8526 qtdemux->protection_system_ids->len - 1);
8529 if (!selected_system) {
8530 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8531 "suitable decryptor element has been found");
8535 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8538 gst_structure_set (s,
8539 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8546 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8548 /* fps is calculated base on the duration of the average framerate since
8549 * qt does not have a fixed framerate. */
8550 gboolean fps_available = TRUE;
8551 guint32 first_duration = 0;
8553 if (stream->n_samples > 0)
8554 first_duration = stream->samples[0].duration;
8556 if ((stream->n_samples == 1 && first_duration == 0)
8557 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8559 CUR_STREAM (stream)->fps_n = 0;
8560 CUR_STREAM (stream)->fps_d = 1;
8562 if (stream->duration == 0 || stream->n_samples < 2) {
8563 CUR_STREAM (stream)->fps_n = stream->timescale;
8564 CUR_STREAM (stream)->fps_d = 1;
8565 fps_available = FALSE;
8567 GstClockTime avg_duration;
8571 /* duration and n_samples can be updated for fragmented format
8572 * so, framerate of fragmented format is calculated using data in a moof */
8573 if (qtdemux->fragmented && stream->n_samples_moof > 0
8574 && stream->duration_moof > 0) {
8575 n_samples = stream->n_samples_moof;
8576 duration = stream->duration_moof;
8578 n_samples = stream->n_samples;
8579 duration = stream->duration;
8582 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8583 /* stream->duration is guint64, timescale, n_samples are guint32 */
8585 gst_util_uint64_scale_round (duration -
8586 first_duration, GST_SECOND,
8587 (guint64) (stream->timescale) * (n_samples - 1));
8589 GST_LOG_OBJECT (qtdemux,
8590 "Calculating avg sample duration based on stream (or moof) duration %"
8592 " minus first sample %u, leaving %d samples gives %"
8593 GST_TIME_FORMAT, duration, first_duration,
8594 n_samples - 1, GST_TIME_ARGS (avg_duration));
8597 gst_video_guess_framerate (avg_duration,
8598 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8600 GST_DEBUG_OBJECT (qtdemux,
8601 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8602 stream->timescale, CUR_STREAM (stream)->fps_n,
8603 CUR_STREAM (stream)->fps_d);
8607 return fps_available;
8611 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8613 if (stream->subtype == FOURCC_vide) {
8614 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8616 if (CUR_STREAM (stream)->caps) {
8617 CUR_STREAM (stream)->caps =
8618 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8620 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8621 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8622 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8623 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8625 /* set framerate if calculated framerate is reliable */
8626 if (fps_available) {
8627 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8628 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8629 CUR_STREAM (stream)->fps_d, NULL);
8632 /* calculate pixel-aspect-ratio using display width and height */
8633 GST_DEBUG_OBJECT (qtdemux,
8634 "video size %dx%d, target display size %dx%d",
8635 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8636 stream->display_width, stream->display_height);
8637 /* qt file might have pasp atom */
8638 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8639 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8640 CUR_STREAM (stream)->par_h);
8641 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8642 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8643 CUR_STREAM (stream)->par_h, NULL);
8644 } else if (stream->display_width > 0 && stream->display_height > 0
8645 && CUR_STREAM (stream)->width > 0
8646 && CUR_STREAM (stream)->height > 0) {
8649 /* calculate the pixel aspect ratio using the display and pixel w/h */
8650 n = stream->display_width * CUR_STREAM (stream)->height;
8651 d = stream->display_height * CUR_STREAM (stream)->width;
8654 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8655 CUR_STREAM (stream)->par_w = n;
8656 CUR_STREAM (stream)->par_h = d;
8657 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8658 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8659 CUR_STREAM (stream)->par_h, NULL);
8662 if (CUR_STREAM (stream)->interlace_mode > 0) {
8663 if (CUR_STREAM (stream)->interlace_mode == 1) {
8664 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8665 G_TYPE_STRING, "progressive", NULL);
8666 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8667 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8668 G_TYPE_STRING, "interleaved", NULL);
8669 if (CUR_STREAM (stream)->field_order == 9) {
8670 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8671 G_TYPE_STRING, "top-field-first", NULL);
8672 } else if (CUR_STREAM (stream)->field_order == 14) {
8673 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8674 G_TYPE_STRING, "bottom-field-first", NULL);
8679 /* Create incomplete colorimetry here if needed */
8680 if (CUR_STREAM (stream)->colorimetry.range ||
8681 CUR_STREAM (stream)->colorimetry.matrix ||
8682 CUR_STREAM (stream)->colorimetry.transfer
8683 || CUR_STREAM (stream)->colorimetry.primaries) {
8684 gchar *colorimetry =
8685 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8686 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8687 G_TYPE_STRING, colorimetry, NULL);
8688 g_free (colorimetry);
8691 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8692 guint par_w = 1, par_h = 1;
8694 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8695 par_w = CUR_STREAM (stream)->par_w;
8696 par_h = CUR_STREAM (stream)->par_h;
8699 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8700 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8702 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8705 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8706 "multiview-mode", G_TYPE_STRING,
8707 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8708 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8709 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8714 else if (stream->subtype == FOURCC_soun) {
8715 if (CUR_STREAM (stream)->caps) {
8716 CUR_STREAM (stream)->caps =
8717 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8718 if (CUR_STREAM (stream)->rate > 0)
8719 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8720 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8721 if (CUR_STREAM (stream)->n_channels > 0)
8722 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8723 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8724 if (CUR_STREAM (stream)->n_channels > 2) {
8725 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8726 * correctly; this is just the minimum we can do - assume
8727 * we don't actually have any channel positions. */
8728 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8729 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8734 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8735 const GstStructure *s;
8736 QtDemuxStream *fps_stream = NULL;
8737 gboolean fps_available = FALSE;
8739 /* CEA608 closed caption tracks are a bit special in that each sample
8740 * can contain CCs for multiple frames, and CCs can be omitted and have to
8741 * be inferred from the duration of the sample then.
8743 * As such we take the framerate from the (first) video track here for
8744 * CEA608 as there must be one CC byte pair for every video frame
8745 * according to the spec.
8747 * For CEA708 all is fine and there is one sample per frame.
8750 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8751 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8754 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8755 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8757 if (tmp->subtype == FOURCC_vide) {
8764 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8765 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8766 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8769 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8770 fps_stream = stream;
8773 CUR_STREAM (stream)->caps =
8774 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8776 /* set framerate if calculated framerate is reliable */
8777 if (fps_available) {
8778 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8779 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8780 CUR_STREAM (stream)->fps_d, NULL);
8785 GstCaps *prev_caps = NULL;
8787 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8788 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8789 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8790 gst_pad_set_active (stream->pad, TRUE);
8792 gst_pad_use_fixed_caps (stream->pad);
8794 if (stream->protected) {
8795 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8796 GST_ERROR_OBJECT (qtdemux,
8797 "Failed to configure protected stream caps.");
8802 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8803 CUR_STREAM (stream)->caps);
8804 if (stream->new_stream) {
8806 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8809 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8812 gst_event_parse_stream_flags (event, &stream_flags);
8813 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8814 qtdemux->have_group_id = TRUE;
8816 qtdemux->have_group_id = FALSE;
8817 gst_event_unref (event);
8818 } else if (!qtdemux->have_group_id) {
8819 qtdemux->have_group_id = TRUE;
8820 qtdemux->group_id = gst_util_group_id_next ();
8823 stream->new_stream = FALSE;
8824 event = gst_event_new_stream_start (stream->stream_id);
8825 if (qtdemux->have_group_id)
8826 gst_event_set_group_id (event, qtdemux->group_id);
8827 if (stream->disabled)
8828 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8829 if (CUR_STREAM (stream)->sparse) {
8830 stream_flags |= GST_STREAM_FLAG_SPARSE;
8832 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8834 gst_event_set_stream_flags (event, stream_flags);
8835 gst_pad_push_event (stream->pad, event);
8838 prev_caps = gst_pad_get_current_caps (stream->pad);
8840 if (CUR_STREAM (stream)->caps) {
8842 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8843 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8844 CUR_STREAM (stream)->caps);
8845 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8847 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8850 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8854 gst_caps_unref (prev_caps);
8855 stream->new_caps = FALSE;
8861 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8862 QtDemuxStream * stream)
8864 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8867 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8868 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8869 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8870 stream->stsd_entries_length)) {
8871 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8872 (_("This file is invalid and cannot be played.")),
8873 ("New sample description id is out of bounds (%d >= %d)",
8874 stream->stsd_sample_description_id, stream->stsd_entries_length));
8876 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8877 stream->new_caps = TRUE;
8882 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8883 QtDemuxStream * stream, GstTagList * list)
8885 gboolean ret = TRUE;
8887 if (stream->subtype == FOURCC_vide) {
8888 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8891 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8894 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8895 gst_object_unref (stream->pad);
8901 qtdemux->n_video_streams++;
8902 } else if (stream->subtype == FOURCC_soun) {
8903 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8906 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8908 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8909 gst_object_unref (stream->pad);
8914 qtdemux->n_audio_streams++;
8915 } else if (stream->subtype == FOURCC_strm) {
8916 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8917 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8918 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8919 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
8920 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8923 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8925 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8926 gst_object_unref (stream->pad);
8931 qtdemux->n_sub_streams++;
8932 } else if (CUR_STREAM (stream)->caps) {
8933 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8936 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8938 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8939 gst_object_unref (stream->pad);
8944 qtdemux->n_video_streams++;
8946 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8953 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8954 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8955 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8956 GST_OBJECT_LOCK (qtdemux);
8957 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8958 GST_OBJECT_UNLOCK (qtdemux);
8960 if (stream->stream_tags)
8961 gst_tag_list_unref (stream->stream_tags);
8962 stream->stream_tags = list;
8964 /* global tags go on each pad anyway */
8965 stream->send_global_tags = TRUE;
8966 /* send upstream GST_EVENT_PROTECTION events that were received before
8967 this source pad was created */
8968 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8969 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8973 gst_tag_list_unref (list);
8977 /* find next atom with @fourcc starting at @offset */
8978 static GstFlowReturn
8979 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8980 guint64 * length, guint32 fourcc)
8986 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8987 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8993 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8994 if (G_UNLIKELY (ret != GST_FLOW_OK))
8996 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8999 gst_buffer_unref (buf);
9002 gst_buffer_map (buf, &map, GST_MAP_READ);
9003 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9004 gst_buffer_unmap (buf, &map);
9005 gst_buffer_unref (buf);
9007 if (G_UNLIKELY (*length == 0)) {
9008 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9009 ret = GST_FLOW_ERROR;
9013 if (lfourcc == fourcc) {
9014 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9015 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9018 GST_LOG_OBJECT (qtdemux,
9019 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9020 GST_FOURCC_ARGS (lfourcc), *offset);
9021 if (*offset == G_MAXUINT64)
9031 /* might simply have had last one */
9032 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9037 /* should only do something in pull mode */
9038 /* call with OBJECT lock */
9039 static GstFlowReturn
9040 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9042 guint64 length, offset;
9043 GstBuffer *buf = NULL;
9044 GstFlowReturn ret = GST_FLOW_OK;
9045 GstFlowReturn res = GST_FLOW_OK;
9048 offset = qtdemux->moof_offset;
9049 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9052 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9053 return GST_FLOW_EOS;
9056 /* best not do pull etc with lock held */
9057 GST_OBJECT_UNLOCK (qtdemux);
9059 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9060 if (ret != GST_FLOW_OK)
9063 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9064 if (G_UNLIKELY (ret != GST_FLOW_OK))
9066 gst_buffer_map (buf, &map, GST_MAP_READ);
9067 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9068 gst_buffer_unmap (buf, &map);
9069 gst_buffer_unref (buf);
9074 gst_buffer_unmap (buf, &map);
9075 gst_buffer_unref (buf);
9079 /* look for next moof */
9080 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9081 if (G_UNLIKELY (ret != GST_FLOW_OK))
9085 GST_OBJECT_LOCK (qtdemux);
9087 qtdemux->moof_offset = offset;
9093 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9095 res = GST_FLOW_ERROR;
9100 /* maybe upstream temporarily flushing */
9101 if (ret != GST_FLOW_FLUSHING) {
9102 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9105 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9106 /* resume at current position next time */
9114 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9118 gint32 stts_duration;
9119 GstByteWriter stsc, stts, stsz;
9121 /* Each sample has a different size, which we don't support for merging */
9122 if (stream->sample_size == 0) {
9123 GST_DEBUG_OBJECT (qtdemux,
9124 "Not all samples have the same size, not merging");
9128 /* The stream has a ctts table, we don't support that */
9129 if (stream->ctts_present) {
9130 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9134 /* If there's a sync sample table also ignore this stream */
9135 if (stream->stps_present || stream->stss_present) {
9136 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9140 /* If chunks are considered samples already ignore this stream */
9141 if (stream->chunks_are_samples) {
9142 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9146 /* Require that all samples have the same duration */
9147 if (stream->n_sample_times > 1) {
9148 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9152 /* Parse the stts to get the sample duration and number of samples */
9153 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9154 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9156 /* Parse the number of chunks from the stco manually because the
9157 * reader is already behind that */
9158 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9160 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9163 /* Now parse stsc, convert chunks into single samples and generate a
9164 * new stsc, stts and stsz from this information */
9165 gst_byte_writer_init (&stsc);
9166 gst_byte_writer_init (&stts);
9167 gst_byte_writer_init (&stsz);
9169 /* Note: we skip fourccs, size, version, flags and other fields of the new
9170 * atoms as the byte readers with them are already behind that position
9171 * anyway and only update the values of those inside the stream directly.
9173 stream->n_sample_times = 0;
9174 stream->n_samples = 0;
9175 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9177 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9179 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9180 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9181 sample_description_id =
9182 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9184 if (i == stream->n_samples_per_chunk - 1) {
9185 /* +1 because first_chunk is 1-based */
9186 last_chunk = num_chunks + 1;
9188 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9191 GST_DEBUG_OBJECT (qtdemux,
9192 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9193 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9195 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9196 /* One sample in this chunk */
9197 gst_byte_writer_put_uint32_be (&stsc, 1);
9198 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9200 /* For each chunk write a stts and stsz entry now */
9201 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9202 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9203 for (j = first_chunk; j < last_chunk; j++) {
9204 gst_byte_writer_put_uint32_be (&stsz,
9205 stream->sample_size * samples_per_chunk);
9208 stream->n_sample_times += 1;
9209 stream->n_samples += last_chunk - first_chunk;
9212 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9214 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9215 stream->n_samples, stream->n_sample_times);
9217 /* We don't have a fixed sample size anymore */
9218 stream->sample_size = 0;
9220 /* Free old data for the atoms */
9221 g_free ((gpointer) stream->stsz.data);
9222 stream->stsz.data = NULL;
9223 g_free ((gpointer) stream->stsc.data);
9224 stream->stsc.data = NULL;
9225 g_free ((gpointer) stream->stts.data);
9226 stream->stts.data = NULL;
9228 /* Store new data and replace byte readers */
9229 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9230 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9231 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9232 stream->stts.size = gst_byte_writer_get_size (&stts);
9233 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9234 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9235 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9236 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9237 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9240 /* initialise bytereaders for stbl sub-atoms */
9242 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9244 stream->stbl_index = -1; /* no samples have yet been parsed */
9245 stream->sample_index = -1;
9247 /* time-to-sample atom */
9248 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9251 /* copy atom data into a new buffer for later use */
9252 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9254 /* skip version + flags */
9255 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9256 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9258 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9260 /* make sure there's enough data */
9261 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9262 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9263 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9264 stream->n_sample_times);
9265 if (!stream->n_sample_times)
9269 /* sync sample atom */
9270 stream->stps_present = FALSE;
9271 if ((stream->stss_present =
9272 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9273 &stream->stss) ? TRUE : FALSE) == TRUE) {
9274 /* copy atom data into a new buffer for later use */
9275 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9277 /* skip version + flags */
9278 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9279 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9282 if (stream->n_sample_syncs) {
9283 /* make sure there's enough data */
9284 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9288 /* partial sync sample atom */
9289 if ((stream->stps_present =
9290 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9291 &stream->stps) ? TRUE : FALSE) == TRUE) {
9292 /* copy atom data into a new buffer for later use */
9293 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9295 /* skip version + flags */
9296 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9297 !gst_byte_reader_get_uint32_be (&stream->stps,
9298 &stream->n_sample_partial_syncs))
9301 /* if there are no entries, the stss table contains the real
9303 if (stream->n_sample_partial_syncs) {
9304 /* make sure there's enough data */
9305 if (!qt_atom_parser_has_chunks (&stream->stps,
9306 stream->n_sample_partial_syncs, 4))
9313 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9316 /* copy atom data into a new buffer for later use */
9317 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9319 /* skip version + flags */
9320 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9321 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9324 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9327 if (!stream->n_samples)
9330 /* sample-to-chunk atom */
9331 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9334 /* copy atom data into a new buffer for later use */
9335 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9337 /* skip version + flags */
9338 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9339 !gst_byte_reader_get_uint32_be (&stream->stsc,
9340 &stream->n_samples_per_chunk))
9343 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9344 stream->n_samples_per_chunk);
9346 /* make sure there's enough data */
9347 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9353 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9354 stream->co_size = sizeof (guint32);
9355 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9357 stream->co_size = sizeof (guint64);
9361 /* copy atom data into a new buffer for later use */
9362 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9364 /* skip version + flags */
9365 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9368 /* chunks_are_samples == TRUE means treat chunks as samples */
9369 stream->chunks_are_samples = stream->sample_size
9370 && !CUR_STREAM (stream)->sampled;
9371 if (stream->chunks_are_samples) {
9372 /* treat chunks as samples */
9373 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9376 /* skip number of entries */
9377 if (!gst_byte_reader_skip (&stream->stco, 4))
9380 /* make sure there are enough data in the stsz atom */
9381 if (!stream->sample_size) {
9382 /* different sizes for each sample */
9383 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9388 /* composition time-to-sample */
9389 if ((stream->ctts_present =
9390 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9391 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9392 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9393 guint8 ctts_version;
9394 gboolean checked_ctts = FALSE;
9396 /* copy atom data into a new buffer for later use */
9397 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9399 /* version 1 has signed offsets */
9400 if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9404 if (!gst_byte_reader_skip (&stream->ctts, 3)
9405 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9406 &stream->n_composition_times))
9409 /* make sure there's enough data */
9410 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9414 /* This is optional, if missing we iterate the ctts */
9415 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9416 guint8 cslg_version;
9418 /* cslg version 1 has 64 bit fields */
9419 if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9423 if (!gst_byte_reader_skip (&cslg, 3))
9426 if (cslg_version == 0) {
9427 gint32 composition_to_dts_shift;
9429 if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9432 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9434 gint64 composition_to_dts_shift;
9436 if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9439 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9442 gint32 cslg_least = 0;
9443 guint num_entries, pos;
9446 pos = gst_byte_reader_get_pos (&stream->ctts);
9447 num_entries = stream->n_composition_times;
9449 checked_ctts = TRUE;
9451 stream->cslg_shift = 0;
9453 for (i = 0; i < num_entries; i++) {
9456 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9457 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9458 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9459 * slightly inaccurate PTS could be more usable than corrupted one */
9460 if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
9461 GST_WARNING_OBJECT (qtdemux,
9462 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9463 " larger than duration %" G_GUINT64_FORMAT,
9464 offset, stream->duration);
9466 stream->cslg_shift = 0;
9467 stream->ctts_present = FALSE;
9471 if (offset < cslg_least)
9472 cslg_least = offset;
9476 stream->cslg_shift = -cslg_least;
9478 stream->cslg_shift = 0;
9480 /* reset the reader so we can generate sample table */
9481 gst_byte_reader_set_pos (&stream->ctts, pos);
9484 /* Check if ctts values are looking reasonable if that didn't happen above */
9485 if (!checked_ctts) {
9486 guint num_entries, pos;
9489 pos = gst_byte_reader_get_pos (&stream->ctts);
9490 num_entries = stream->n_composition_times;
9492 for (i = 0; i < num_entries; i++) {
9495 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9496 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9497 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9498 * slightly inaccurate PTS could be more usable than corrupted one */
9499 if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
9500 GST_WARNING_OBJECT (qtdemux,
9501 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9502 " larger than duration %" G_GUINT64_FORMAT,
9503 offset, stream->duration);
9505 stream->cslg_shift = 0;
9506 stream->ctts_present = FALSE;
9511 /* reset the reader so we can generate sample table */
9512 gst_byte_reader_set_pos (&stream->ctts, pos);
9515 /* Ensure the cslg_shift value is consistent so we can use it
9516 * unconditionally to produce TS and Segment */
9517 stream->cslg_shift = 0;
9520 /* For raw audio streams especially we might want to merge the samples
9521 * to not output one audio sample per buffer. We're doing this here
9522 * before allocating the sample tables so that from this point onwards
9523 * the number of container samples are static */
9524 if (stream->min_buffer_size > 0) {
9525 qtdemux_merge_sample_table (qtdemux, stream);
9529 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9530 stream->n_samples, (guint) sizeof (QtDemuxSample),
9531 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9533 if (stream->n_samples >=
9534 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9535 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9536 "be larger than %uMB (broken file?)", stream->n_samples,
9537 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9541 g_assert (stream->samples == NULL);
9542 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9543 if (!stream->samples) {
9544 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9553 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9554 (_("This file is corrupt and cannot be played.")), (NULL));
9559 gst_qtdemux_stbl_free (stream);
9560 if (!qtdemux->fragmented) {
9561 /* not quite good */
9562 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9565 /* may pick up samples elsewhere */
9571 /* collect samples from the next sample to be parsed up to sample @n for @stream
9572 * by reading the info from @stbl
9574 * This code can be executed from both the streaming thread and the seeking
9575 * thread so it takes the object lock to protect itself
9578 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9581 QtDemuxSample *samples, *first, *cur, *last;
9582 guint32 n_samples_per_chunk;
9585 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9586 GST_FOURCC_FORMAT ", pad %s",
9587 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9588 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9590 n_samples = stream->n_samples;
9593 goto out_of_samples;
9595 GST_OBJECT_LOCK (qtdemux);
9596 if (n <= stream->stbl_index)
9597 goto already_parsed;
9599 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9601 if (!stream->stsz.data) {
9602 /* so we already parsed and passed all the moov samples;
9603 * onto fragmented ones */
9604 g_assert (qtdemux->fragmented);
9608 /* pointer to the sample table */
9609 samples = stream->samples;
9611 /* starts from -1, moves to the next sample index to parse */
9612 stream->stbl_index++;
9614 /* keep track of the first and last sample to fill */
9615 first = &samples[stream->stbl_index];
9618 if (!stream->chunks_are_samples) {
9619 /* set the sample sizes */
9620 if (stream->sample_size == 0) {
9621 /* different sizes for each sample */
9622 for (cur = first; cur <= last; cur++) {
9623 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9624 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9625 (guint) (cur - samples), cur->size);
9628 /* samples have the same size */
9629 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9630 for (cur = first; cur <= last; cur++)
9631 cur->size = stream->sample_size;
9635 n_samples_per_chunk = stream->n_samples_per_chunk;
9638 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9641 if (stream->stsc_chunk_index >= stream->last_chunk
9642 || stream->stsc_chunk_index < stream->first_chunk) {
9643 stream->first_chunk =
9644 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9645 stream->samples_per_chunk =
9646 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9648 stream->stsd_sample_description_id =
9649 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9651 /* chunk numbers are counted from 1 it seems */
9652 if (G_UNLIKELY (stream->first_chunk == 0))
9655 --stream->first_chunk;
9657 /* the last chunk of each entry is calculated by taking the first chunk
9658 * of the next entry; except if there is no next, where we fake it with
9660 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9661 stream->last_chunk = G_MAXUINT32;
9663 stream->last_chunk =
9664 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9665 if (G_UNLIKELY (stream->last_chunk == 0))
9668 --stream->last_chunk;
9671 GST_LOG_OBJECT (qtdemux,
9672 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9673 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9674 stream->samples_per_chunk, stream->stsd_sample_description_id);
9676 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9679 if (stream->last_chunk != G_MAXUINT32) {
9680 if (!qt_atom_parser_peek_sub (&stream->stco,
9681 stream->first_chunk * stream->co_size,
9682 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9687 stream->co_chunk = stream->stco;
9688 if (!gst_byte_reader_skip (&stream->co_chunk,
9689 stream->first_chunk * stream->co_size))
9693 stream->stsc_chunk_index = stream->first_chunk;
9696 last_chunk = stream->last_chunk;
9698 if (stream->chunks_are_samples) {
9699 cur = &samples[stream->stsc_chunk_index];
9701 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9704 stream->stsc_chunk_index = j;
9709 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9712 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9713 "%" G_GUINT64_FORMAT, j, cur->offset);
9715 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9716 CUR_STREAM (stream)->bytes_per_frame > 0) {
9718 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9719 CUR_STREAM (stream)->samples_per_frame *
9720 CUR_STREAM (stream)->bytes_per_frame;
9722 cur->size = stream->samples_per_chunk;
9725 GST_DEBUG_OBJECT (qtdemux,
9726 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9727 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9728 stream->stco_sample_index)), cur->size);
9730 cur->timestamp = stream->stco_sample_index;
9731 cur->duration = stream->samples_per_chunk;
9732 cur->keyframe = TRUE;
9735 stream->stco_sample_index += stream->samples_per_chunk;
9737 stream->stsc_chunk_index = j;
9739 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9740 guint32 samples_per_chunk;
9741 guint64 chunk_offset;
9743 if (!stream->stsc_sample_index
9744 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9745 &stream->chunk_offset))
9748 samples_per_chunk = stream->samples_per_chunk;
9749 chunk_offset = stream->chunk_offset;
9751 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9752 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9753 G_GUINT64_FORMAT " and size %d",
9754 (guint) (cur - samples), chunk_offset, cur->size);
9756 cur->offset = chunk_offset;
9757 chunk_offset += cur->size;
9760 if (G_UNLIKELY (cur > last)) {
9762 stream->stsc_sample_index = k + 1;
9763 stream->chunk_offset = chunk_offset;
9764 stream->stsc_chunk_index = j;
9768 stream->stsc_sample_index = 0;
9770 stream->stsc_chunk_index = j;
9772 stream->stsc_index++;
9775 if (stream->chunks_are_samples)
9779 guint32 n_sample_times;
9781 n_sample_times = stream->n_sample_times;
9784 for (i = stream->stts_index; i < n_sample_times; i++) {
9785 guint32 stts_samples;
9786 gint32 stts_duration;
9789 if (stream->stts_sample_index >= stream->stts_samples
9790 || !stream->stts_sample_index) {
9792 stream->stts_samples =
9793 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9794 stream->stts_duration =
9795 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9797 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9798 i, stream->stts_samples, stream->stts_duration);
9800 stream->stts_sample_index = 0;
9803 stts_samples = stream->stts_samples;
9804 stts_duration = stream->stts_duration;
9805 stts_time = stream->stts_time;
9807 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9808 GST_DEBUG_OBJECT (qtdemux,
9809 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9810 (guint) (cur - samples), j,
9811 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9813 cur->timestamp = stts_time;
9814 cur->duration = stts_duration;
9816 /* avoid 32-bit wrap-around,
9817 * but still mind possible 'negative' duration */
9818 stts_time += (gint64) stts_duration;
9821 if (G_UNLIKELY (cur > last)) {
9823 stream->stts_time = stts_time;
9824 stream->stts_sample_index = j + 1;
9825 if (stream->stts_sample_index >= stream->stts_samples)
9826 stream->stts_index++;
9830 stream->stts_sample_index = 0;
9831 stream->stts_time = stts_time;
9832 stream->stts_index++;
9834 /* fill up empty timestamps with the last timestamp, this can happen when
9835 * the last samples do not decode and so we don't have timestamps for them.
9836 * We however look at the last timestamp to estimate the track length so we
9837 * need something in here. */
9838 for (; cur < last; cur++) {
9839 GST_DEBUG_OBJECT (qtdemux,
9840 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9841 (guint) (cur - samples),
9842 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9843 cur->timestamp = stream->stts_time;
9849 /* sample sync, can be NULL */
9850 if (stream->stss_present == TRUE) {
9851 guint32 n_sample_syncs;
9853 n_sample_syncs = stream->n_sample_syncs;
9855 if (!n_sample_syncs) {
9856 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9857 stream->all_keyframe = TRUE;
9859 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9860 /* note that the first sample is index 1, not 0 */
9863 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9865 if (G_LIKELY (index > 0 && index <= n_samples)) {
9867 samples[index].keyframe = TRUE;
9868 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9869 /* and exit if we have enough samples */
9870 if (G_UNLIKELY (index >= n)) {
9877 stream->stss_index = i;
9880 /* stps marks partial sync frames like open GOP I-Frames */
9881 if (stream->stps_present == TRUE) {
9882 guint32 n_sample_partial_syncs;
9884 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9886 /* if there are no entries, the stss table contains the real
9888 if (n_sample_partial_syncs) {
9889 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9890 /* note that the first sample is index 1, not 0 */
9893 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9895 if (G_LIKELY (index > 0 && index <= n_samples)) {
9897 samples[index].keyframe = TRUE;
9898 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9899 /* and exit if we have enough samples */
9900 if (G_UNLIKELY (index >= n)) {
9907 stream->stps_index = i;
9911 /* no stss, all samples are keyframes */
9912 stream->all_keyframe = TRUE;
9913 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9918 /* composition time to sample */
9919 if (stream->ctts_present == TRUE) {
9920 guint32 n_composition_times;
9922 gint32 ctts_soffset;
9924 /* Fill in the pts_offsets */
9926 n_composition_times = stream->n_composition_times;
9928 for (i = stream->ctts_index; i < n_composition_times; i++) {
9929 if (stream->ctts_sample_index >= stream->ctts_count
9930 || !stream->ctts_sample_index) {
9931 stream->ctts_count =
9932 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9933 stream->ctts_soffset =
9934 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9935 stream->ctts_sample_index = 0;
9938 ctts_count = stream->ctts_count;
9939 ctts_soffset = stream->ctts_soffset;
9941 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9942 cur->pts_offset = ctts_soffset;
9945 if (G_UNLIKELY (cur > last)) {
9947 stream->ctts_sample_index = j + 1;
9951 stream->ctts_sample_index = 0;
9952 stream->ctts_index++;
9956 stream->stbl_index = n;
9957 /* if index has been completely parsed, free data that is no-longer needed */
9958 if (n + 1 == stream->n_samples) {
9959 gst_qtdemux_stbl_free (stream);
9960 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9961 if (qtdemux->pullbased) {
9962 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9963 while (n + 1 == stream->n_samples)
9964 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9968 GST_OBJECT_UNLOCK (qtdemux);
9975 GST_LOG_OBJECT (qtdemux,
9976 "Tried to parse up to sample %u but this sample has already been parsed",
9978 /* if fragmented, there may be more */
9979 if (qtdemux->fragmented && n == stream->stbl_index)
9981 GST_OBJECT_UNLOCK (qtdemux);
9987 GST_LOG_OBJECT (qtdemux,
9988 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9990 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9991 (_("This file is corrupt and cannot be played.")), (NULL));
9996 GST_OBJECT_UNLOCK (qtdemux);
9997 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9998 (_("This file is corrupt and cannot be played.")), (NULL));
10003 /* collect all segment info for @stream.
10006 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10010 /* accept edts if they contain gaps at start and there is only
10011 * one media segment */
10012 gboolean allow_pushbased_edts = TRUE;
10013 gint media_segments_count = 0;
10015 /* parse and prepare segment info from the edit list */
10016 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10017 stream->n_segments = 0;
10018 stream->segments = NULL;
10019 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10022 gint segment_number, entry_size;
10024 GstClockTime stime;
10025 const guint8 *buffer;
10029 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10030 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10033 buffer = elst->data;
10035 size = QT_UINT32 (buffer);
10036 /* version, flags, n_segments */
10038 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10041 version = QT_UINT8 (buffer + 8);
10042 entry_size = (version == 1) ? 20 : 12;
10044 n_segments = QT_UINT32 (buffer + 12);
10046 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10047 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10051 /* we might allocate a bit too much, at least allocate 1 segment */
10052 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10054 /* segments always start from 0 */
10058 for (segment_number = 0; segment_number < n_segments; segment_number++) {
10060 guint64 media_time;
10061 gboolean empty_edit = FALSE;
10062 QtDemuxSegment *segment;
10064 GstClockTime media_start = GST_CLOCK_TIME_NONE;
10066 if (version == 1) {
10067 media_time = QT_UINT64 (buffer + 8);
10068 duration = QT_UINT64 (buffer);
10069 if (media_time == G_MAXUINT64)
10072 media_time = QT_UINT32 (buffer + 4);
10073 duration = QT_UINT32 (buffer);
10074 if (media_time == G_MAXUINT32)
10079 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10081 segment = &stream->segments[segment_number];
10083 /* time and duration expressed in global timescale */
10084 segment->time = stime;
10085 if (duration != 0 || empty_edit) {
10086 /* edge case: empty edits with duration=zero are treated here.
10087 * (files should not have these anyway). */
10089 /* add non scaled values so we don't cause roundoff errors */
10091 stime = QTTIME_TO_GSTTIME (qtdemux, time);
10092 segment->duration = stime - segment->time;
10094 /* zero duration does not imply media_start == media_stop
10095 * but, only specify media_start. The edit ends with the track. */
10096 stime = segment->duration = GST_CLOCK_TIME_NONE;
10097 /* Don't allow more edits after this one. */
10098 n_segments = segment_number + 1;
10100 segment->stop_time = stime;
10102 segment->trak_media_start = media_time;
10103 /* media_time expressed in stream timescale */
10105 segment->media_start = media_start;
10106 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10107 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10108 media_segments_count++;
10110 segment->media_start = GST_CLOCK_TIME_NONE;
10111 segment->media_stop = GST_CLOCK_TIME_NONE;
10113 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10115 if (rate_int <= 1) {
10116 /* 0 is not allowed, some programs write 1 instead of the floating point
10118 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10122 segment->rate = rate_int / 65536.0;
10125 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10126 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10127 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10128 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10129 segment_number, GST_TIME_ARGS (segment->time),
10130 GST_TIME_ARGS (segment->duration),
10131 GST_TIME_ARGS (segment->media_start), media_time,
10132 GST_TIME_ARGS (segment->media_stop),
10133 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10134 stream->timescale);
10135 if (segment->stop_time > qtdemux->segment.stop &&
10136 !qtdemux->upstream_format_is_time) {
10137 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10138 " extends to %" GST_TIME_FORMAT
10139 " past the end of the declared movie duration %" GST_TIME_FORMAT
10140 " movie segment will be extended", segment_number,
10141 GST_TIME_ARGS (segment->stop_time),
10142 GST_TIME_ARGS (qtdemux->segment.stop));
10143 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10146 buffer += entry_size;
10148 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10149 stream->n_segments = n_segments;
10150 if (media_segments_count != 1)
10151 allow_pushbased_edts = FALSE;
10155 /* push based does not handle segments, so act accordingly here,
10156 * and warn if applicable */
10157 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10158 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10159 /* remove and use default one below, we stream like it anyway */
10160 g_free (stream->segments);
10161 stream->segments = NULL;
10162 stream->n_segments = 0;
10165 /* no segments, create one to play the complete trak */
10166 if (stream->n_segments == 0) {
10167 GstClockTime stream_duration =
10168 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10170 if (stream->segments == NULL)
10171 stream->segments = g_new (QtDemuxSegment, 1);
10173 /* represent unknown our way */
10174 if (stream_duration == 0)
10175 stream_duration = GST_CLOCK_TIME_NONE;
10177 stream->segments[0].time = 0;
10178 stream->segments[0].stop_time = stream_duration;
10179 stream->segments[0].duration = stream_duration;
10180 stream->segments[0].media_start = 0;
10181 stream->segments[0].media_stop = stream_duration;
10182 stream->segments[0].rate = 1.0;
10183 stream->segments[0].trak_media_start = 0;
10185 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10186 GST_TIME_ARGS (stream_duration));
10187 stream->n_segments = 1;
10188 stream->dummy_segment = TRUE;
10190 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10196 * Parses the stsd atom of a svq3 trak looking for
10197 * the SMI and gama atoms.
10200 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10201 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10203 const guint8 *_gamma = NULL;
10204 GstBuffer *_seqh = NULL;
10205 const guint8 *stsd_data = stsd_entry_data;
10206 guint32 length = QT_UINT32 (stsd_data);
10210 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10216 version = QT_UINT16 (stsd_data);
10217 if (version == 3) {
10218 if (length >= 70) {
10221 while (length > 8) {
10222 guint32 fourcc, size;
10223 const guint8 *data;
10224 size = QT_UINT32 (stsd_data);
10225 fourcc = QT_FOURCC (stsd_data + 4);
10226 data = stsd_data + 8;
10229 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10230 "svq3 atom parsing");
10239 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10240 " for gama atom, expected 12", size);
10245 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10247 if (_seqh != NULL) {
10248 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10249 " found, ignoring");
10251 seqh_size = QT_UINT32 (data + 4);
10252 if (seqh_size > 0) {
10253 _seqh = gst_buffer_new_and_alloc (seqh_size);
10254 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10261 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10262 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10266 if (size <= length) {
10272 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10275 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10276 G_GUINT16_FORMAT, version);
10286 } else if (_seqh) {
10287 gst_buffer_unref (_seqh);
10292 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10295 GstByteReader dref;
10299 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10300 * atom that might contain a 'data' atom with the rtsp uri.
10301 * This case was reported in bug #597497, some info about
10302 * the hndl atom can be found in TN1195
10304 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10305 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10308 guint32 dref_num_entries = 0;
10309 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10310 gst_byte_reader_skip (&dref, 4) &&
10311 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10314 /* search dref entries for hndl atom */
10315 for (i = 0; i < dref_num_entries; i++) {
10316 guint32 size = 0, type;
10317 guint8 string_len = 0;
10318 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10319 qt_atom_parser_get_fourcc (&dref, &type)) {
10320 if (type == FOURCC_hndl) {
10321 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10323 /* skip data reference handle bytes and the
10324 * following pascal string and some extra 4
10325 * bytes I have no idea what are */
10326 if (!gst_byte_reader_skip (&dref, 4) ||
10327 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10328 !gst_byte_reader_skip (&dref, string_len + 4)) {
10329 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10333 /* iterate over the atoms to find the data atom */
10334 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10338 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10339 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10340 if (atom_type == FOURCC_data) {
10341 const guint8 *uri_aux = NULL;
10343 /* found the data atom that might contain the rtsp uri */
10344 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10345 "hndl atom, interpreting it as an URI");
10346 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10348 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10349 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10351 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10352 "didn't contain a rtsp address");
10354 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10359 /* skipping to the next entry */
10360 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10363 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10370 /* skip to the next entry */
10371 if (!gst_byte_reader_skip (&dref, size - 8))
10374 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10377 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10383 #define AMR_NB_ALL_MODES 0x81ff
10384 #define AMR_WB_ALL_MODES 0x83ff
10386 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10388 /* The 'damr' atom is of the form:
10390 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10391 * 32 b 8 b 16 b 8 b 8 b
10393 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10394 * represents the highest mode used in the stream (and thus the maximum
10395 * bitrate), with a couple of special cases as seen below.
10398 /* Map of frame type ID -> bitrate */
10399 static const guint nb_bitrates[] = {
10400 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10402 static const guint wb_bitrates[] = {
10403 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10409 gst_buffer_map (buf, &map, GST_MAP_READ);
10411 if (map.size != 0x11) {
10412 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10416 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10417 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10418 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10422 mode_set = QT_UINT16 (map.data + 13);
10424 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10425 max_mode = 7 + (wb ? 1 : 0);
10427 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10428 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10430 if (max_mode == -1) {
10431 GST_DEBUG ("No mode indication was found (mode set) = %x",
10436 gst_buffer_unmap (buf, &map);
10437 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10440 gst_buffer_unmap (buf, &map);
10445 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10446 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10449 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10455 if (gst_byte_reader_get_remaining (reader) < 36)
10458 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10459 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10460 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10461 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10462 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10463 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10464 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10465 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10466 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10468 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10469 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10470 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10472 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10473 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10475 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10476 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10483 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10484 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10491 * This macro will only compare value abdegh, it expects cfi to have already
10494 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10495 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10497 /* only handle the cases where the last column has standard values */
10498 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10499 const gchar *rotation_tag = NULL;
10501 /* no rotation needed */
10502 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10504 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10505 rotation_tag = "rotate-90";
10506 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10507 rotation_tag = "rotate-180";
10508 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10509 rotation_tag = "rotate-270";
10511 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10514 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10515 GST_STR_NULL (rotation_tag));
10516 if (rotation_tag != NULL) {
10517 if (*taglist == NULL)
10518 *taglist = gst_tag_list_new_empty ();
10519 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10520 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10523 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10528 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10529 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10533 GstBuffer *adrm_buf = NULL;
10534 QtDemuxAavdEncryptionInfo *info;
10536 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10537 if (G_UNLIKELY (!adrm)) {
10538 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10541 adrm_size = QT_UINT32 (adrm->data);
10542 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10544 stream->protection_scheme_type = FOURCC_aavd;
10546 if (!stream->protection_scheme_info)
10547 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10549 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10551 if (info->default_properties)
10552 gst_structure_free (info->default_properties);
10553 info->default_properties = gst_structure_new ("application/x-aavd",
10554 "encrypted", G_TYPE_BOOLEAN, TRUE,
10555 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10556 gst_buffer_unref (adrm_buf);
10558 *original_fmt = FOURCC_mp4a;
10562 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10563 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10564 * Common Encryption (cenc), the function will also parse the tenc box (defined
10565 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10566 * (typically an enc[v|a|t|s] sample entry); the function will set
10567 * @original_fmt to the fourcc of the original unencrypted stream format.
10568 * Returns TRUE if successful; FALSE otherwise. */
10570 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10571 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10577 QtDemuxCencSampleSetInfo *info;
10579 const guint8 *tenc_data;
10581 g_return_val_if_fail (qtdemux != NULL, FALSE);
10582 g_return_val_if_fail (stream != NULL, FALSE);
10583 g_return_val_if_fail (container != NULL, FALSE);
10584 g_return_val_if_fail (original_fmt != NULL, FALSE);
10586 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10587 if (G_UNLIKELY (!sinf)) {
10588 if (stream->protection_scheme_type == FOURCC_cenc
10589 || stream->protection_scheme_type == FOURCC_cbcs) {
10590 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10591 "mandatory for Common Encryption");
10597 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10598 if (G_UNLIKELY (!frma)) {
10599 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10603 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10604 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10605 GST_FOURCC_ARGS (*original_fmt));
10607 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10609 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10612 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10613 stream->protection_scheme_version =
10614 QT_UINT32 ((const guint8 *) schm->data + 16);
10616 GST_DEBUG_OBJECT (qtdemux,
10617 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10618 "protection_scheme_version: %#010x",
10619 GST_FOURCC_ARGS (stream->protection_scheme_type),
10620 stream->protection_scheme_version);
10622 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10624 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10627 if (stream->protection_scheme_type != FOURCC_cenc &&
10628 stream->protection_scheme_type != FOURCC_piff &&
10629 stream->protection_scheme_type != FOURCC_cbcs) {
10630 GST_ERROR_OBJECT (qtdemux,
10631 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10632 GST_FOURCC_ARGS (stream->protection_scheme_type));
10636 if (G_UNLIKELY (!stream->protection_scheme_info))
10637 stream->protection_scheme_info =
10638 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10640 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10642 if (stream->protection_scheme_type == FOURCC_cenc
10643 || stream->protection_scheme_type == FOURCC_cbcs) {
10644 guint8 is_encrypted;
10646 guint8 constant_iv_size = 0;
10647 const guint8 *default_kid;
10648 guint8 crypt_byte_block = 0;
10649 guint8 skip_byte_block = 0;
10650 const guint8 *constant_iv = NULL;
10652 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10654 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10655 "which is mandatory for Common Encryption");
10658 tenc_data = (const guint8 *) tenc->data + 12;
10659 is_encrypted = QT_UINT8 (tenc_data + 2);
10660 iv_size = QT_UINT8 (tenc_data + 3);
10661 default_kid = (tenc_data + 4);
10662 if (stream->protection_scheme_type == FOURCC_cbcs) {
10663 guint8 possible_pattern_info;
10664 if (iv_size == 0) {
10665 constant_iv_size = QT_UINT8 (tenc_data + 20);
10666 if (constant_iv_size != 8 && constant_iv_size != 16) {
10667 GST_ERROR_OBJECT (qtdemux,
10668 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10671 constant_iv = (tenc_data + 21);
10673 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10674 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10675 skip_byte_block = possible_pattern_info & 0x0f;
10677 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10678 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10679 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10680 } else if (stream->protection_scheme_type == FOURCC_piff) {
10682 static const guint8 piff_track_encryption_uuid[] = {
10683 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10684 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10687 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10689 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10690 "which is mandatory for Common Encryption");
10694 tenc_data = (const guint8 *) tenc->data + 8;
10695 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10696 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10697 GST_ERROR_OBJECT (qtdemux,
10698 "Unsupported track encryption box with uuid: %s", box_uuid);
10702 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10703 gst_byte_reader_init (&br, tenc_data, 20);
10704 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10705 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10708 stream->protection_scheme_type = FOURCC_cenc;
10715 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10716 QtDemuxStream ** stream2)
10718 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10722 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10727 /*parse svmi header if existing */
10728 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10730 guint len = QT_UINT32 ((guint8 *) svmi->data);
10731 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10733 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10734 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10735 guint8 frame_type, frame_layout;
10736 guint32 stereo_mono_change_count;
10741 /* MPEG-A stereo video */
10742 if (qtdemux->major_brand == FOURCC_ss02)
10743 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10745 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10746 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10747 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10749 switch (frame_type) {
10751 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10754 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10757 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10760 /* mode 3 is primary/secondary view sequence, ie
10761 * left/right views in separate tracks. See section 7.2
10762 * of ISO/IEC 23000-11:2009 */
10763 /* In the future this might be supported using related
10764 * streams, like an enhancement track - if files like this
10766 GST_FIXME_OBJECT (qtdemux,
10767 "Implement stereo video in separate streams");
10770 if ((frame_layout & 0x1) == 0)
10771 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10773 GST_LOG_OBJECT (qtdemux,
10774 "StereoVideo: composition type: %u, is_left_first: %u",
10775 frame_type, frame_layout);
10777 if (stereo_mono_change_count > 1) {
10778 GST_FIXME_OBJECT (qtdemux,
10779 "Mixed-mono flags are not yet supported in qtdemux.");
10782 stream->multiview_mode = mode;
10783 stream->multiview_flags = flags;
10790 /* parse the traks.
10791 * With each track we associate a new QtDemuxStream that contains all the info
10793 * traks that do not decode to something (like strm traks) will not have a pad.
10796 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10798 GstByteReader tkhd;
10812 QtDemuxStream *stream = NULL;
10813 const guint8 *stsd_data;
10814 const guint8 *stsd_entry_data;
10815 guint remaining_stsd_len;
10816 guint stsd_entry_count;
10818 guint16 lang_code; /* quicktime lang code or packed iso code */
10820 guint32 tkhd_flags = 0;
10821 guint8 tkhd_version = 0;
10822 guint32 w = 0, h = 0;
10823 guint value_size, stsd_len, len;
10827 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10829 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10830 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10831 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10834 /* pick between 64 or 32 bits */
10835 value_size = tkhd_version == 1 ? 8 : 4;
10836 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10837 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10840 /* Check if current moov has duplicated track_id */
10841 if (qtdemux_find_stream (qtdemux, track_id))
10842 goto existing_stream;
10844 stream = _create_stream (qtdemux, track_id);
10845 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10847 /* need defaults for fragments */
10848 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10850 if ((tkhd_flags & 1) == 0)
10851 stream->disabled = TRUE;
10853 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10854 tkhd_version, tkhd_flags, stream->track_id);
10856 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10859 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10860 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10861 if (qtdemux->major_brand != FOURCC_mjp2 ||
10862 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10866 len = QT_UINT32 ((guint8 *) mdhd->data);
10867 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10868 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10869 if (version == 0x01000000) {
10872 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10873 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10874 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
10878 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10879 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10880 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10883 if (lang_code < 0x400) {
10884 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10885 } else if (lang_code == 0x7fff) {
10886 stream->lang_id[0] = 0; /* unspecified */
10888 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10889 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10890 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10891 stream->lang_id[3] = 0;
10894 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10895 stream->timescale);
10896 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10898 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10899 lang_code, stream->lang_id);
10901 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10904 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10905 /* chapters track reference */
10906 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10908 gsize length = GST_READ_UINT32_BE (chap->data);
10909 if (qtdemux->chapters_track_id)
10910 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10912 if (length >= 12) {
10913 qtdemux->chapters_track_id =
10914 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10919 /* fragmented files may have bogus duration in moov */
10920 if (!qtdemux->fragmented &&
10921 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10922 guint64 tdur1, tdur2;
10924 /* don't overflow */
10925 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10926 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10929 * some of those trailers, nowadays, have prologue images that are
10930 * themselves video tracks as well. I haven't really found a way to
10931 * identify those yet, except for just looking at their duration. */
10932 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10933 GST_WARNING_OBJECT (qtdemux,
10934 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10935 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10936 "found, assuming preview image or something; skipping track",
10937 stream->duration, stream->timescale, qtdemux->duration,
10938 qtdemux->timescale);
10939 gst_qtdemux_stream_unref (stream);
10944 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10947 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10948 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10950 len = QT_UINT32 ((guint8 *) hdlr->data);
10952 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10953 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10954 GST_FOURCC_ARGS (stream->subtype));
10956 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10959 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10962 /* Parse out svmi (and later st3d/sv3d) atoms */
10963 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
10966 /* parse rest of tkhd */
10967 if (stream->subtype == FOURCC_vide) {
10970 /* version 1 uses some 64-bit ints */
10971 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10974 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10977 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10978 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10981 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10982 &stream->stream_tags);
10986 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10988 stsd_data = (const guint8 *) stsd->data;
10990 /* stsd should at least have one entry */
10991 stsd_len = QT_UINT32 (stsd_data);
10992 if (stsd_len < 24) {
10993 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10994 if (stream->subtype == FOURCC_vivo) {
10995 gst_qtdemux_stream_unref (stream);
11002 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11003 /* each stsd entry must contain at least 8 bytes */
11004 if (stream->stsd_entries_length == 0
11005 || stream->stsd_entries_length > stsd_len / 8) {
11006 stream->stsd_entries_length = 0;
11009 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11010 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
11011 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
11013 stsd_entry_data = stsd_data + 16;
11014 remaining_stsd_len = stsd_len - 16;
11015 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11017 gchar *codec = NULL;
11018 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11020 /* and that entry should fit within stsd */
11021 len = QT_UINT32 (stsd_entry_data);
11022 if (len > remaining_stsd_len)
11025 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11026 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
11027 GST_FOURCC_ARGS (entry->fourcc));
11028 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
11030 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11031 goto error_encrypted;
11033 if (fourcc == FOURCC_aavd) {
11034 if (stream->subtype != FOURCC_soun) {
11035 GST_ERROR_OBJECT (qtdemux,
11036 "Unexpeced stsd type 'aavd' outside 'soun' track");
11038 /* encrypted audio with sound sample description v0 */
11039 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11040 stream->protected = TRUE;
11041 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11042 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11046 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11047 /* FIXME this looks wrong, there might be multiple children
11048 * with the same type */
11049 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11050 stream->protected = TRUE;
11051 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11052 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11055 if (stream->subtype == FOURCC_vide) {
11060 gint depth, palette_size, palette_count;
11061 guint32 *palette_data = NULL;
11063 entry->sampled = TRUE;
11065 stream->display_width = w >> 16;
11066 stream->display_height = h >> 16;
11069 if (len < 86) /* TODO verify */
11072 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11073 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11074 entry->fps_n = 0; /* this is filled in later */
11075 entry->fps_d = 0; /* this is filled in later */
11076 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11077 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11079 /* if color_table_id is 0, ctab atom must follow; however some files
11080 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11081 * if color table is not present we'll correct the value */
11082 if (entry->color_table_id == 0 &&
11084 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11085 entry->color_table_id = -1;
11088 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11089 entry->width, entry->height, entry->bits_per_sample,
11090 entry->color_table_id);
11092 depth = entry->bits_per_sample;
11094 /* more than 32 bits means grayscale */
11095 gray = (depth > 32);
11096 /* low 32 bits specify the depth */
11099 /* different number of palette entries is determined by depth. */
11101 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11102 palette_count = (1 << depth);
11103 palette_size = palette_count * 4;
11105 if (entry->color_table_id) {
11106 switch (palette_count) {
11110 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11113 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11118 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11120 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11125 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11128 g_memdup2 (ff_qt_default_palette_256, palette_size);
11131 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11132 (_("The video in this file might not play correctly.")),
11133 ("unsupported palette depth %d", depth));
11137 gint i, j, start, end;
11143 start = QT_UINT32 (stsd_entry_data + offset + 70);
11144 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11145 end = QT_UINT16 (stsd_entry_data + offset + 76);
11147 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11148 start, end, palette_count);
11155 if (len < 94 + (end - start) * 8)
11158 /* palette is always the same size */
11159 palette_data = g_malloc0 (256 * 4);
11160 palette_size = 256 * 4;
11162 for (j = 0, i = start; i <= end; j++, i++) {
11163 guint32 a, r, g, b;
11165 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11166 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11167 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11168 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11170 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11171 (g & 0xff00) | (b >> 8);
11176 gst_caps_unref (entry->caps);
11179 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11181 if (G_UNLIKELY (!entry->caps)) {
11182 g_free (palette_data);
11183 goto unknown_stream;
11187 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11188 GST_TAG_VIDEO_CODEC, codec, NULL);
11193 if (palette_data) {
11196 if (entry->rgb8_palette)
11197 gst_memory_unref (entry->rgb8_palette);
11198 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11199 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11201 s = gst_caps_get_structure (entry->caps, 0);
11203 /* non-raw video has a palette_data property. raw video has the palette as
11204 * an extra plane that we append to the output buffers before we push
11206 if (!gst_structure_has_name (s, "video/x-raw")) {
11207 GstBuffer *palette;
11209 palette = gst_buffer_new ();
11210 gst_buffer_append_memory (palette, entry->rgb8_palette);
11211 entry->rgb8_palette = NULL;
11213 gst_caps_set_simple (entry->caps, "palette_data",
11214 GST_TYPE_BUFFER, palette, NULL);
11215 gst_buffer_unref (palette);
11217 } else if (palette_count != 0) {
11218 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11219 (NULL), ("Unsupported palette depth %d", depth));
11222 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11223 QT_UINT16 (stsd_entry_data + offset + 32));
11229 /* pick 'the' stsd child */
11230 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11231 // We should skip parsing the stsd for non-protected streams if
11232 // the entry doesn't match the fourcc, since they don't change
11233 // format. However, for protected streams we can have partial
11234 // encryption, where parts of the stream are encrypted and parts
11235 // not. For both parts of such streams, we should ensure the
11236 // esds overrides are parsed for both from the stsd.
11237 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11238 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11240 else if (!stream->protected)
11245 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11246 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11247 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11248 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11252 const guint8 *pasp_data = (const guint8 *) pasp->data;
11253 gint len = QT_UINT32 (pasp_data);
11256 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11257 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11259 CUR_STREAM (stream)->par_w = 0;
11260 CUR_STREAM (stream)->par_h = 0;
11263 CUR_STREAM (stream)->par_w = 0;
11264 CUR_STREAM (stream)->par_h = 0;
11268 const guint8 *fiel_data = (const guint8 *) fiel->data;
11269 gint len = QT_UINT32 (fiel_data);
11272 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11273 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11278 const guint8 *colr_data = (const guint8 *) colr->data;
11279 gint len = QT_UINT32 (colr_data);
11281 if (len == 19 || len == 18) {
11282 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11284 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11285 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11286 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11287 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11288 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11290 CUR_STREAM (stream)->colorimetry.primaries =
11291 gst_video_color_primaries_from_iso (primaries);
11292 CUR_STREAM (stream)->colorimetry.transfer =
11293 gst_video_transfer_function_from_iso (transfer_function);
11294 CUR_STREAM (stream)->colorimetry.matrix =
11295 gst_video_color_matrix_from_iso (matrix);
11296 CUR_STREAM (stream)->colorimetry.range =
11297 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11298 GST_VIDEO_COLOR_RANGE_16_235;
11300 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11303 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11308 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11309 stream->stream_tags);
11316 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11317 const guint8 *avc_data = stsd_entry_data + 0x56;
11320 while (len >= 0x8) {
11323 if (QT_UINT32 (avc_data) <= len)
11324 size = QT_UINT32 (avc_data) - 0x8;
11329 /* No real data, so break out */
11332 switch (QT_FOURCC (avc_data + 0x4)) {
11335 /* parse, if found */
11338 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11340 /* First 4 bytes are the length of the atom, the next 4 bytes
11341 * are the fourcc, the next 1 byte is the version, and the
11342 * subsequent bytes are profile_tier_level structure like data. */
11343 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11344 avc_data + 8 + 1, size - 1);
11345 buf = gst_buffer_new_and_alloc (size);
11346 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11347 gst_caps_set_simple (entry->caps,
11348 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11349 gst_buffer_unref (buf);
11357 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11359 /* First 4 bytes are the length of the atom, the next 4 bytes
11360 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11361 * next 1 byte is the version, and the
11362 * subsequent bytes are sequence parameter set like data. */
11364 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11366 gst_codec_utils_h264_caps_set_level_and_profile
11367 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11369 buf = gst_buffer_new_and_alloc (size);
11370 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11371 gst_caps_set_simple (entry->caps,
11372 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11373 gst_buffer_unref (buf);
11379 guint avg_bitrate, max_bitrate;
11381 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11385 max_bitrate = QT_UINT32 (avc_data + 0xc);
11386 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11388 if (!max_bitrate && !avg_bitrate)
11391 /* Some muxers seem to swap the average and maximum bitrates
11392 * (I'm looking at you, YouTube), so we swap for sanity. */
11393 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11394 guint temp = avg_bitrate;
11396 avg_bitrate = max_bitrate;
11397 max_bitrate = temp;
11400 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11401 gst_tag_list_add (stream->stream_tags,
11402 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11403 max_bitrate, NULL);
11405 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11406 gst_tag_list_add (stream->stream_tags,
11407 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11419 avc_data += size + 8;
11430 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11431 const guint8 *hevc_data = stsd_entry_data + 0x56;
11434 while (len >= 0x8) {
11437 if (QT_UINT32 (hevc_data) <= len)
11438 size = QT_UINT32 (hevc_data) - 0x8;
11443 /* No real data, so break out */
11446 switch (QT_FOURCC (hevc_data + 0x4)) {
11449 /* parse, if found */
11452 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11454 /* First 4 bytes are the length of the atom, the next 4 bytes
11455 * are the fourcc, the next 1 byte is the version, and the
11456 * subsequent bytes are sequence parameter set like data. */
11457 gst_codec_utils_h265_caps_set_level_tier_and_profile
11458 (entry->caps, hevc_data + 8 + 1, size - 1);
11460 buf = gst_buffer_new_and_alloc (size);
11461 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11462 gst_caps_set_simple (entry->caps,
11463 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11464 gst_buffer_unref (buf);
11471 hevc_data += size + 8;
11484 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11485 GST_FOURCC_ARGS (fourcc));
11487 /* codec data might be in glbl extension atom */
11489 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11495 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11497 len = QT_UINT32 (data);
11500 buf = gst_buffer_new_and_alloc (len);
11501 gst_buffer_fill (buf, 0, data + 8, len);
11502 gst_caps_set_simple (entry->caps,
11503 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11504 gst_buffer_unref (buf);
11511 /* see annex I of the jpeg2000 spec */
11512 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11513 const guint8 *data;
11514 const gchar *colorspace = NULL;
11516 guint32 ncomp_map = 0;
11517 gint32 *comp_map = NULL;
11518 guint32 nchan_def = 0;
11519 gint32 *chan_def = NULL;
11521 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11522 /* some required atoms */
11523 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11526 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11530 /* number of components; redundant with info in codestream, but useful
11532 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11533 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11535 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11537 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11540 GST_DEBUG_OBJECT (qtdemux, "found colr");
11541 /* extract colour space info */
11542 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11543 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11545 colorspace = "sRGB";
11548 colorspace = "GRAY";
11551 colorspace = "sYUV";
11559 /* colr is required, and only values 16, 17, and 18 are specified,
11560 so error if we have no colorspace */
11563 /* extract component mapping */
11564 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11566 guint32 cmap_len = 0;
11568 cmap_len = QT_UINT32 (cmap->data);
11569 if (cmap_len >= 8) {
11570 /* normal box, subtract off header */
11572 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11573 if (cmap_len % 4 == 0) {
11574 ncomp_map = (cmap_len / 4);
11575 comp_map = g_new0 (gint32, ncomp_map);
11576 for (i = 0; i < ncomp_map; i++) {
11579 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11580 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11581 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11582 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11587 /* extract channel definitions */
11588 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11590 guint32 cdef_len = 0;
11592 cdef_len = QT_UINT32 (cdef->data);
11593 if (cdef_len >= 10) {
11594 /* normal box, subtract off header and len */
11596 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11597 if (cdef_len % 6 == 0) {
11598 nchan_def = (cdef_len / 6);
11599 chan_def = g_new0 (gint32, nchan_def);
11600 for (i = 0; i < nchan_def; i++)
11602 for (i = 0; i < nchan_def; i++) {
11603 guint16 cn, typ, asoc;
11604 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11605 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11606 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11607 if (cn < nchan_def) {
11610 chan_def[cn] = asoc;
11613 chan_def[cn] = 0; /* alpha */
11616 chan_def[cn] = -typ;
11624 gst_caps_set_simple (entry->caps,
11625 "num-components", G_TYPE_INT, ncomp, NULL);
11626 gst_caps_set_simple (entry->caps,
11627 "colorspace", G_TYPE_STRING, colorspace, NULL);
11630 GValue arr = { 0, };
11631 GValue elt = { 0, };
11633 g_value_init (&arr, GST_TYPE_ARRAY);
11634 g_value_init (&elt, G_TYPE_INT);
11635 for (i = 0; i < ncomp_map; i++) {
11636 g_value_set_int (&elt, comp_map[i]);
11637 gst_value_array_append_value (&arr, &elt);
11639 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11640 "component-map", &arr);
11641 g_value_unset (&elt);
11642 g_value_unset (&arr);
11647 GValue arr = { 0, };
11648 GValue elt = { 0, };
11650 g_value_init (&arr, GST_TYPE_ARRAY);
11651 g_value_init (&elt, G_TYPE_INT);
11652 for (i = 0; i < nchan_def; i++) {
11653 g_value_set_int (&elt, chan_def[i]);
11654 gst_value_array_append_value (&arr, &elt);
11656 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11657 "channel-definitions", &arr);
11658 g_value_unset (&elt);
11659 g_value_unset (&arr);
11663 /* some optional atoms */
11664 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11665 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11667 /* indicate possible fields in caps */
11669 data = (guint8 *) field->data + 8;
11671 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11672 (gint) * data, NULL);
11674 /* add codec_data if provided */
11679 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11680 data = prefix->data;
11681 len = QT_UINT32 (data);
11684 buf = gst_buffer_new_and_alloc (len);
11685 gst_buffer_fill (buf, 0, data + 8, len);
11686 gst_caps_set_simple (entry->caps,
11687 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11688 gst_buffer_unref (buf);
11697 GstBuffer *seqh = NULL;
11698 const guint8 *gamma_data = NULL;
11699 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11701 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11704 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11705 QT_FP32 (gamma_data), NULL);
11708 /* sorry for the bad name, but we don't know what this is, other
11709 * than its own fourcc */
11710 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11712 gst_buffer_unref (seqh);
11715 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11716 buf = gst_buffer_new_and_alloc (len);
11717 gst_buffer_fill (buf, 0, stsd_data, len);
11718 gst_caps_set_simple (entry->caps,
11719 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11720 gst_buffer_unref (buf);
11725 /* https://developer.apple.com/standards/qtff-2001.pdf,
11726 * page 92, "Video Sample Description", under table 3.1 */
11729 const gint compressor_offset =
11730 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11731 const gint min_size = compressor_offset + 32 + 2 + 2;
11734 guint16 color_table_id = 0;
11737 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11739 /* recover information on interlaced/progressive */
11740 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11744 len = QT_UINT32 (jpeg->data);
11745 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11747 if (len >= min_size) {
11748 gst_byte_reader_init (&br, jpeg->data, len);
11750 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11751 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11752 if (color_table_id != 0) {
11753 /* the spec says there can be concatenated chunks in the data, and we want
11754 * to find one called field. Walk through them. */
11755 gint offset = min_size;
11756 while (offset + 8 < len) {
11757 guint32 size = 0, tag;
11758 ok = gst_byte_reader_get_uint32_le (&br, &size);
11759 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11760 if (!ok || size < 8) {
11761 GST_WARNING_OBJECT (qtdemux,
11762 "Failed to walk optional chunk list");
11765 GST_DEBUG_OBJECT (qtdemux,
11766 "Found optional %4.4s chunk, size %u",
11767 (const char *) &tag, size);
11768 if (tag == FOURCC_fiel) {
11769 guint8 n_fields = 0, ordering = 0;
11770 gst_byte_reader_get_uint8 (&br, &n_fields);
11771 gst_byte_reader_get_uint8 (&br, &ordering);
11772 if (n_fields == 1 || n_fields == 2) {
11773 GST_DEBUG_OBJECT (qtdemux,
11774 "Found fiel tag with %u fields, ordering %u",
11775 n_fields, ordering);
11777 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11778 "interlace-mode", G_TYPE_STRING, "interleaved",
11781 GST_WARNING_OBJECT (qtdemux,
11782 "Found fiel tag with invalid fields (%u)", n_fields);
11788 GST_DEBUG_OBJECT (qtdemux,
11789 "Color table ID is 0, not trying to get interlacedness");
11792 GST_WARNING_OBJECT (qtdemux,
11793 "Length of jpeg chunk is too small, not trying to get interlacedness");
11801 gst_caps_set_simple (entry->caps,
11802 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11808 GNode *xith, *xdxt;
11810 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11811 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11815 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11819 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11820 /* collect the headers and store them in a stream list so that we can
11821 * send them out first */
11822 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11832 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11833 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11836 ovc1_data = ovc1->data;
11837 ovc1_len = QT_UINT32 (ovc1_data);
11838 if (ovc1_len <= 198) {
11839 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11842 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11843 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11844 gst_caps_set_simple (entry->caps,
11845 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11846 gst_buffer_unref (buf);
11851 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11852 const guint8 *vc1_data = stsd_entry_data + 0x56;
11858 if (QT_UINT32 (vc1_data) <= len)
11859 size = QT_UINT32 (vc1_data) - 8;
11864 /* No real data, so break out */
11867 switch (QT_FOURCC (vc1_data + 0x4)) {
11868 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11872 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11873 buf = gst_buffer_new_and_alloc (size);
11874 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11875 gst_caps_set_simple (entry->caps,
11876 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11877 gst_buffer_unref (buf);
11884 vc1_data += size + 8;
11890 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11891 const guint8 *av1_data = stsd_entry_data + 0x56;
11894 while (len >= 0x8) {
11897 if (QT_UINT32 (av1_data) <= len)
11898 size = QT_UINT32 (av1_data) - 0x8;
11903 /* No real data, so break out */
11906 switch (QT_FOURCC (av1_data + 0x4)) {
11909 /* parse, if found */
11911 guint8 pres_delay_field;
11913 GST_DEBUG_OBJECT (qtdemux,
11914 "found av1C codec_data in stsd of size %d", size);
11916 /* not enough data, just ignore and hope for the best */
11921 * 4 bytes: atom length
11926 * 1 bits: initial_presentation_delay_present
11927 * 4 bits: initial_presentation_delay (if present else reserved
11931 if (av1_data[9] != 0) {
11932 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11936 /* We skip initial_presentation_delay* for now */
11937 pres_delay_field = *(av1_data + 12);
11938 if (pres_delay_field & (1 << 5)) {
11939 gst_caps_set_simple (entry->caps,
11940 "presentation-delay", G_TYPE_INT,
11941 (gint) (pres_delay_field & 0x0F) + 1, NULL);
11944 buf = gst_buffer_new_and_alloc (size - 5);
11945 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11946 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
11947 gst_caps_set_simple (entry->caps,
11948 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11949 gst_buffer_unref (buf);
11958 av1_data += size + 8;
11964 /* TODO: Need to parse vpcC for VP8 codec too.
11965 * Note that VPCodecConfigurationBox (vpcC) is defined for
11966 * vp08, vp09, and vp10 fourcc. */
11969 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11970 const guint8 *vpcc_data = stsd_entry_data + 0x56;
11973 while (len >= 0x8) {
11976 if (QT_UINT32 (vpcc_data) <= len)
11977 size = QT_UINT32 (vpcc_data) - 0x8;
11982 /* No real data, so break out */
11985 switch (QT_FOURCC (vpcc_data + 0x4)) {
11988 const gchar *profile_str = NULL;
11989 const gchar *chroma_format_str = NULL;
11992 guint8 chroma_format;
11993 GstVideoColorimetry cinfo;
11995 /* parse, if found */
11996 GST_DEBUG_OBJECT (qtdemux,
11997 "found vp codec_data in stsd of size %d", size);
11999 /* the meaning of "size" is length of the atom body, excluding
12000 * atom length and fourcc fields */
12005 * 4 bytes: atom length
12012 * 3 bits: chromaSubsampling
12013 * 1 bit: videoFullRangeFlag
12014 * 1 byte: colourPrimaries
12015 * 1 byte: transferCharacteristics
12016 * 1 byte: matrixCoefficients
12017 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
12018 * rest: codecIntializationData (not used for vp8 and vp9)
12021 if (vpcc_data[8] != 1) {
12022 GST_WARNING_OBJECT (qtdemux,
12023 "unknown vpcC version %d", vpcc_data[8]);
12027 profile = vpcc_data[12];
12046 gst_caps_set_simple (entry->caps,
12047 "profile", G_TYPE_STRING, profile_str, NULL);
12050 /* skip level, the VP9 spec v0.6 defines only one level atm,
12051 * but webm spec define various ones. Add level to caps
12052 * if we really need it then */
12054 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12055 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12056 gst_caps_set_simple (entry->caps,
12057 "bit-depth-luma", G_TYPE_UINT, bitdepth,
12058 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12061 chroma_format = (vpcc_data[14] & 0xe) >> 1;
12062 switch (chroma_format) {
12065 chroma_format_str = "4:2:0";
12068 chroma_format_str = "4:2:2";
12071 chroma_format_str = "4:4:4";
12077 if (chroma_format_str) {
12078 gst_caps_set_simple (entry->caps,
12079 "chroma-format", G_TYPE_STRING, chroma_format_str,
12083 if ((vpcc_data[14] & 0x1) != 0)
12084 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12086 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12088 gst_video_color_primaries_from_iso (vpcc_data[15]);
12090 gst_video_transfer_function_from_iso (vpcc_data[16]);
12092 gst_video_color_matrix_from_iso (vpcc_data[17]);
12094 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12095 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12096 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12097 /* set this only if all values are known, otherwise this
12098 * might overwrite valid ones parsed from other color box */
12099 CUR_STREAM (stream)->colorimetry = cinfo;
12108 vpcc_data += size + 8;
12118 GST_INFO_OBJECT (qtdemux,
12119 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12120 GST_FOURCC_ARGS (fourcc), entry->caps);
12122 } else if (stream->subtype == FOURCC_soun) {
12124 int version, samplesize;
12125 guint16 compression_id;
12126 gboolean amrwb = FALSE;
12129 /* sample description entry (16) + sound sample description v0 (20) */
12133 version = QT_UINT32 (stsd_entry_data + offset);
12134 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12135 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12136 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12137 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12139 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12140 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12141 QT_UINT32 (stsd_entry_data + offset + 4));
12142 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12143 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12144 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12145 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12146 QT_UINT16 (stsd_entry_data + offset + 14));
12147 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12149 if (compression_id == 0xfffe)
12150 entry->sampled = TRUE;
12152 /* first assume uncompressed audio */
12153 entry->bytes_per_sample = samplesize / 8;
12154 entry->samples_per_frame = entry->n_channels;
12155 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12156 entry->samples_per_packet = entry->samples_per_frame;
12157 entry->bytes_per_packet = entry->bytes_per_sample;
12161 if (version == 0x00010000) {
12162 /* sample description entry (16) + sound sample description v1 (20+16) */
12166 /* take information from here over the normal sample description */
12167 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12168 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12169 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12170 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12172 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12173 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12174 entry->samples_per_packet);
12175 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12176 entry->bytes_per_packet);
12177 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12178 entry->bytes_per_frame);
12179 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12180 entry->bytes_per_sample);
12182 if (!entry->sampled && entry->bytes_per_packet) {
12183 entry->samples_per_frame = (entry->bytes_per_frame /
12184 entry->bytes_per_packet) * entry->samples_per_packet;
12185 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12186 entry->samples_per_frame);
12188 } else if (version == 0x00020000) {
12189 /* sample description entry (16) + sound sample description v2 (56) */
12193 /* take information from here over the normal sample description */
12194 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12195 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12196 entry->samples_per_frame = entry->n_channels;
12197 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12198 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12199 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12200 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12202 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12203 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12204 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12205 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12206 entry->bytes_per_sample * 8);
12207 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12208 QT_UINT32 (stsd_entry_data + offset + 24));
12209 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12210 entry->bytes_per_packet);
12211 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12212 entry->samples_per_packet);
12213 } else if (version != 0x00000) {
12214 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12219 /* Yes, these have to be hard-coded */
12222 entry->samples_per_packet = 6;
12223 entry->bytes_per_packet = 1;
12224 entry->bytes_per_frame = 1 * entry->n_channels;
12225 entry->bytes_per_sample = 1;
12226 entry->samples_per_frame = 6 * entry->n_channels;
12231 entry->samples_per_packet = 3;
12232 entry->bytes_per_packet = 1;
12233 entry->bytes_per_frame = 1 * entry->n_channels;
12234 entry->bytes_per_sample = 1;
12235 entry->samples_per_frame = 3 * entry->n_channels;
12240 entry->samples_per_packet = 64;
12241 entry->bytes_per_packet = 34;
12242 entry->bytes_per_frame = 34 * entry->n_channels;
12243 entry->bytes_per_sample = 2;
12244 entry->samples_per_frame = 64 * entry->n_channels;
12250 entry->samples_per_packet = 1;
12251 entry->bytes_per_packet = 1;
12252 entry->bytes_per_frame = 1 * entry->n_channels;
12253 entry->bytes_per_sample = 1;
12254 entry->samples_per_frame = 1 * entry->n_channels;
12259 entry->samples_per_packet = 160;
12260 entry->bytes_per_packet = 33;
12261 entry->bytes_per_frame = 33 * entry->n_channels;
12262 entry->bytes_per_sample = 2;
12263 entry->samples_per_frame = 160 * entry->n_channels;
12266 /* fix up any invalid header information from above */
12271 /* Sometimes these are set to 0 in the sound sample descriptions so
12272 * let's try to infer useful values from the other information we
12273 * have available */
12274 if (entry->bytes_per_sample == 0)
12275 entry->bytes_per_sample =
12276 entry->bytes_per_frame / entry->n_channels;
12277 if (entry->bytes_per_sample == 0)
12278 entry->bytes_per_sample = samplesize / 8;
12280 if (entry->bytes_per_frame == 0)
12281 entry->bytes_per_frame =
12282 entry->bytes_per_sample * entry->n_channels;
12284 if (entry->bytes_per_packet == 0)
12285 entry->bytes_per_packet = entry->bytes_per_sample;
12287 if (entry->samples_per_frame == 0)
12288 entry->samples_per_frame = entry->n_channels;
12290 if (entry->samples_per_packet == 0)
12291 entry->samples_per_packet = entry->samples_per_frame;
12301 entry->bytes_per_sample = 3;
12305 entry->bytes_per_sample = 4;
12308 entry->bytes_per_sample = 8;
12311 entry->bytes_per_sample = 2;
12314 g_assert_not_reached ();
12317 entry->samples_per_frame = entry->n_channels;
12318 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12319 entry->samples_per_packet = entry->samples_per_frame;
12320 entry->bytes_per_packet = entry->bytes_per_sample;
12328 gst_caps_unref (entry->caps);
12330 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12331 stsd_entry_data + 32, len - 16, &codec);
12342 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12344 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12346 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12348 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12351 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12352 const gchar *format_str;
12356 format_str = (enda_value) ? "S24LE" : "S24BE";
12359 format_str = (enda_value) ? "S32LE" : "S32BE";
12362 format_str = (enda_value) ? "F32LE" : "F32BE";
12365 format_str = (enda_value) ? "F64LE" : "F64BE";
12368 g_assert_not_reached ();
12371 gst_caps_set_simple (entry->caps,
12372 "format", G_TYPE_STRING, format_str, NULL);
12378 const guint8 *owma_data;
12379 const gchar *codec_name = NULL;
12383 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12384 /* FIXME this should also be gst_riff_strf_auds,
12385 * but the latter one is actually missing bits-per-sample :( */
12390 gint32 nSamplesPerSec;
12391 gint32 nAvgBytesPerSec;
12392 gint16 nBlockAlign;
12393 gint16 wBitsPerSample;
12396 WAVEFORMATEX *wfex;
12398 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12399 owma_data = stsd_entry_data;
12400 owma_len = QT_UINT32 (owma_data);
12401 if (owma_len <= 54) {
12402 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12405 wfex = (WAVEFORMATEX *) (owma_data + 36);
12406 buf = gst_buffer_new_and_alloc (owma_len - 54);
12407 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12408 if (wfex->wFormatTag == 0x0161) {
12409 codec_name = "Windows Media Audio";
12411 } else if (wfex->wFormatTag == 0x0162) {
12412 codec_name = "Windows Media Audio 9 Pro";
12414 } else if (wfex->wFormatTag == 0x0163) {
12415 codec_name = "Windows Media Audio 9 Lossless";
12416 /* is that correct? gstffmpegcodecmap.c is missing it, but
12417 * fluendo codec seems to support it */
12421 gst_caps_set_simple (entry->caps,
12422 "codec_data", GST_TYPE_BUFFER, buf,
12423 "wmaversion", G_TYPE_INT, version,
12424 "block_align", G_TYPE_INT,
12425 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12426 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12427 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12428 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12429 gst_buffer_unref (buf);
12433 codec = g_strdup (codec_name);
12439 gint len = QT_UINT32 (stsd_entry_data) - offset;
12440 const guint8 *wfex_data = stsd_entry_data + offset;
12441 const gchar *codec_name = NULL;
12443 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12444 /* FIXME this should also be gst_riff_strf_auds,
12445 * but the latter one is actually missing bits-per-sample :( */
12450 gint32 nSamplesPerSec;
12451 gint32 nAvgBytesPerSec;
12452 gint16 nBlockAlign;
12453 gint16 wBitsPerSample;
12458 /* FIXME: unify with similar wavformatex parsing code above */
12459 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12465 if (QT_UINT32 (wfex_data) <= len)
12466 size = QT_UINT32 (wfex_data) - 8;
12471 /* No real data, so break out */
12474 switch (QT_FOURCC (wfex_data + 4)) {
12475 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12477 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12482 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12483 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12484 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12485 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12486 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12487 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12488 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12490 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12491 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12492 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12493 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12494 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12495 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12497 if (wfex.wFormatTag == 0x0161) {
12498 codec_name = "Windows Media Audio";
12500 } else if (wfex.wFormatTag == 0x0162) {
12501 codec_name = "Windows Media Audio 9 Pro";
12503 } else if (wfex.wFormatTag == 0x0163) {
12504 codec_name = "Windows Media Audio 9 Lossless";
12505 /* is that correct? gstffmpegcodecmap.c is missing it, but
12506 * fluendo codec seems to support it */
12510 gst_caps_set_simple (entry->caps,
12511 "wmaversion", G_TYPE_INT, version,
12512 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12513 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12514 "width", G_TYPE_INT, wfex.wBitsPerSample,
12515 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12517 if (size > wfex.cbSize) {
12520 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12521 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12522 size - wfex.cbSize);
12523 gst_caps_set_simple (entry->caps,
12524 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12525 gst_buffer_unref (buf);
12527 GST_WARNING_OBJECT (qtdemux, "no codec data");
12532 codec = g_strdup (codec_name);
12540 wfex_data += size + 8;
12546 const guint8 *dops_data;
12547 guint8 *channel_mapping = NULL;
12550 guint8 channel_mapping_family;
12551 guint8 stream_count;
12552 guint8 coupled_count;
12555 version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12557 dops_data = stsd_entry_data + 51;
12559 dops_data = stsd_entry_data + 35;
12561 channels = GST_READ_UINT8 (dops_data + 10);
12562 rate = GST_READ_UINT32_LE (dops_data + 13);
12563 channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12564 stream_count = GST_READ_UINT8 (dops_data + 20);
12565 coupled_count = GST_READ_UINT8 (dops_data + 21);
12567 if (channels > 0) {
12568 channel_mapping = g_malloc (channels * sizeof (guint8));
12569 for (i = 0; i < channels; i++)
12570 channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12573 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12574 channel_mapping_family, stream_count, coupled_count,
12586 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12587 GST_TAG_AUDIO_CODEC, codec, NULL);
12591 /* some bitrate info may have ended up in caps */
12592 s = gst_caps_get_structure (entry->caps, 0);
12593 gst_structure_get_int (s, "bitrate", &bitrate);
12595 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12596 GST_TAG_BITRATE, bitrate, NULL);
12600 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12601 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12602 if (stream->protected) {
12603 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12604 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12606 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12616 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12618 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12620 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12624 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12625 16 bits is a byte-swapped wave-style codec identifier,
12626 and we can find a WAVE header internally to a 'wave' atom here.
12627 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12628 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12631 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12632 if (len < offset + 20) {
12633 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12635 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12636 const guint8 *data = stsd_entry_data + offset + 16;
12638 GNode *waveheadernode;
12640 wavenode = g_node_new ((guint8 *) data);
12641 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12642 const guint8 *waveheader;
12645 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12646 if (waveheadernode) {
12647 waveheader = (const guint8 *) waveheadernode->data;
12648 headerlen = QT_UINT32 (waveheader);
12650 if (headerlen > 8) {
12651 gst_riff_strf_auds *header = NULL;
12652 GstBuffer *headerbuf;
12658 headerbuf = gst_buffer_new_and_alloc (headerlen);
12659 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12661 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12662 headerbuf, &header, &extra)) {
12663 gst_caps_unref (entry->caps);
12664 /* FIXME: Need to do something with the channel reorder map */
12666 gst_riff_create_audio_caps (header->format, NULL, header,
12667 extra, NULL, NULL, NULL);
12670 gst_buffer_unref (extra);
12675 GST_DEBUG ("Didn't find waveheadernode for this codec");
12677 g_node_destroy (wavenode);
12680 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12681 stream->stream_tags);
12685 /* FIXME: what is in the chunk? */
12688 gint len = QT_UINT32 (stsd_data);
12690 /* seems to be always = 116 = 0x74 */
12696 gint len = QT_UINT32 (stsd_entry_data);
12699 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12701 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12702 gst_caps_set_simple (entry->caps,
12703 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12704 gst_buffer_unref (buf);
12706 gst_caps_set_simple (entry->caps,
12707 "samplesize", G_TYPE_INT, samplesize, NULL);
12712 GNode *alac, *wave = NULL;
12714 /* apparently, m4a has this atom appended directly in the stsd entry,
12715 * while mov has it in a wave atom */
12716 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12718 /* alac now refers to stsd entry atom */
12719 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12721 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12723 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12726 const guint8 *alac_data = alac->data;
12727 gint len = QT_UINT32 (alac->data);
12731 GST_DEBUG_OBJECT (qtdemux,
12732 "discarding alac atom with unexpected len %d", len);
12734 /* codec-data contains alac atom size and prefix,
12735 * ffmpeg likes it that way, not quite gst-ish though ...*/
12736 buf = gst_buffer_new_and_alloc (len);
12737 gst_buffer_fill (buf, 0, alac->data, len);
12738 gst_caps_set_simple (entry->caps,
12739 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12740 gst_buffer_unref (buf);
12742 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12743 entry->n_channels = QT_UINT8 (alac_data + 21);
12744 entry->rate = QT_UINT32 (alac_data + 32);
12745 samplesize = QT_UINT8 (alac_data + 16 + 1);
12748 gst_caps_set_simple (entry->caps,
12749 "samplesize", G_TYPE_INT, samplesize, NULL);
12754 /* The codingname of the sample entry is 'fLaC' */
12755 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12758 /* The 'dfLa' box is added to the sample entry to convey
12759 initializing information for the decoder. */
12760 const GNode *dfla =
12761 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12764 const guint32 len = QT_UINT32 (dfla->data);
12766 /* Must contain at least dfLa box header (12),
12767 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12769 GST_DEBUG_OBJECT (qtdemux,
12770 "discarding dfla atom with unexpected len %d", len);
12772 /* skip dfLa header to get the METADATA_BLOCKs */
12773 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12774 const guint32 metadata_blocks_len = len - 12;
12776 gchar *stream_marker = g_strdup ("fLaC");
12777 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12778 strlen (stream_marker));
12781 guint32 remainder = 0;
12782 guint32 block_size = 0;
12783 gboolean is_last = FALSE;
12785 GValue array = G_VALUE_INIT;
12786 GValue value = G_VALUE_INIT;
12788 g_value_init (&array, GST_TYPE_ARRAY);
12789 g_value_init (&value, GST_TYPE_BUFFER);
12791 gst_value_set_buffer (&value, block);
12792 gst_value_array_append_value (&array, &value);
12793 g_value_reset (&value);
12795 gst_buffer_unref (block);
12797 /* check there's at least one METADATA_BLOCK_HEADER's worth
12798 * of data, and we haven't already finished parsing */
12799 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12800 remainder = metadata_blocks_len - index;
12802 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12804 (metadata_blocks[index + 1] << 16) +
12805 (metadata_blocks[index + 2] << 8) +
12806 metadata_blocks[index + 3];
12808 /* be careful not to read off end of box */
12809 if (block_size > remainder) {
12813 is_last = metadata_blocks[index] >> 7;
12815 block = gst_buffer_new_and_alloc (block_size);
12817 gst_buffer_fill (block, 0, &metadata_blocks[index],
12820 gst_value_set_buffer (&value, block);
12821 gst_value_array_append_value (&array, &value);
12822 g_value_reset (&value);
12824 gst_buffer_unref (block);
12826 index += block_size;
12829 /* only append the metadata if we successfully read all of it */
12831 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12832 (stream)->caps, 0), "streamheader", &array);
12834 GST_WARNING_OBJECT (qtdemux,
12835 "discarding all METADATA_BLOCKs due to invalid "
12836 "block_size %d at idx %d, rem %d", block_size, index,
12840 g_value_unset (&value);
12841 g_value_unset (&array);
12843 /* The sample rate obtained from the stsd may not be accurate
12844 * since it cannot represent rates greater than 65535Hz, so
12845 * override that value with the sample rate from the
12846 * METADATA_BLOCK_STREAMINFO block */
12847 CUR_STREAM (stream)->rate =
12848 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12859 gint len = QT_UINT32 (stsd_entry_data);
12862 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12865 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12867 /* If we have enough data, let's try to get the 'damr' atom. See
12868 * the 3GPP container spec (26.244) for more details. */
12869 if ((len - 0x34) > 8 &&
12870 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12871 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12872 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12875 gst_caps_set_simple (entry->caps,
12876 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12877 gst_buffer_unref (buf);
12883 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12884 gint len = QT_UINT32 (stsd_entry_data);
12885 guint16 sound_version = 0;
12886 /* FIXME: Can this be determined somehow? There doesn't seem to be
12887 * anything in mp4a atom that specifis compression */
12889 guint16 channels = entry->n_channels;
12890 guint32 time_scale = (guint32) entry->rate;
12891 gint sample_rate_index = -1;
12894 sound_version = QT_UINT16 (stsd_entry_data + 16);
12896 if (sound_version == 1) {
12897 channels = QT_UINT16 (stsd_entry_data + 24);
12898 time_scale = QT_UINT32 (stsd_entry_data + 30);
12900 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
12904 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
12908 sample_rate_index =
12909 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12910 if (sample_rate_index >= 0 && channels > 0) {
12911 guint8 codec_data[2];
12914 /* build AAC codec data */
12915 codec_data[0] = profile << 3;
12916 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12917 codec_data[1] = (sample_rate_index & 0x01) << 7;
12918 codec_data[1] |= (channels & 0xF) << 3;
12920 buf = gst_buffer_new_and_alloc (2);
12921 gst_buffer_fill (buf, 0, codec_data, 2);
12922 gst_caps_set_simple (entry->caps,
12923 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12924 gst_buffer_unref (buf);
12934 /* Fully handled elsewhere */
12937 GST_INFO_OBJECT (qtdemux,
12938 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12942 GST_INFO_OBJECT (qtdemux,
12943 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12944 GST_FOURCC_ARGS (fourcc), entry->caps);
12946 } else if (stream->subtype == FOURCC_strm) {
12947 if (fourcc == FOURCC_rtsp) {
12948 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12950 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12951 GST_FOURCC_ARGS (fourcc));
12952 goto unknown_stream;
12954 entry->sampled = TRUE;
12955 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12956 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12957 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
12959 entry->sampled = TRUE;
12960 entry->sparse = TRUE;
12963 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12966 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12967 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12972 /* hunt for sort-of codec data */
12976 GNode *mp4s = NULL;
12977 GNode *esds = NULL;
12979 /* look for palette in a stsd->mp4s->esds sub-atom */
12980 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12982 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12983 if (esds == NULL) {
12985 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12989 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12990 stream->stream_tags);
12994 GST_INFO_OBJECT (qtdemux,
12995 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12998 GST_INFO_OBJECT (qtdemux,
12999 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13000 GST_FOURCC_ARGS (fourcc), entry->caps);
13002 /* everything in 1 sample */
13003 entry->sampled = TRUE;
13006 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13009 if (entry->caps == NULL)
13010 goto unknown_stream;
13013 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13014 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13020 /* promote to sampled format */
13021 if (entry->fourcc == FOURCC_samr) {
13022 /* force mono 8000 Hz for AMR */
13023 entry->sampled = TRUE;
13024 entry->n_channels = 1;
13025 entry->rate = 8000;
13026 } else if (entry->fourcc == FOURCC_sawb) {
13027 /* force mono 16000 Hz for AMR-WB */
13028 entry->sampled = TRUE;
13029 entry->n_channels = 1;
13030 entry->rate = 16000;
13031 } else if (entry->fourcc == FOURCC_mp4a) {
13032 entry->sampled = TRUE;
13036 stsd_entry_data += len;
13037 remaining_stsd_len -= len;
13041 /* collect sample information */
13042 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13043 goto samples_failed;
13045 if (qtdemux->fragmented) {
13048 /* need all moov samples as basis; probably not many if any at all */
13049 /* prevent moof parsing taking of at this time */
13050 offset = qtdemux->moof_offset;
13051 qtdemux->moof_offset = 0;
13052 if (stream->n_samples &&
13053 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13054 qtdemux->moof_offset = offset;
13055 goto samples_failed;
13057 qtdemux->moof_offset = offset;
13058 /* movie duration more reliable in this case (e.g. mehd) */
13059 if (qtdemux->segment.duration &&
13060 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13062 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13065 /* configure segments */
13066 if (!qtdemux_parse_segments (qtdemux, stream, trak))
13067 goto segments_failed;
13069 /* add some language tag, if useful */
13070 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13071 strcmp (stream->lang_id, "und")) {
13072 const gchar *lang_code;
13074 /* convert ISO 639-2 code to ISO 639-1 */
13075 lang_code = gst_tag_get_language_code (stream->lang_id);
13076 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13077 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13080 /* Check for UDTA tags */
13081 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13082 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13085 /* Insert and sort new stream in track-id order.
13086 * This will help in comparing old/new streams during stream update check */
13087 g_ptr_array_add (qtdemux->active_streams, stream);
13088 g_ptr_array_sort (qtdemux->active_streams,
13089 (GCompareFunc) qtdemux_track_id_compare_func);
13090 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13091 QTDEMUX_N_STREAMS (qtdemux));
13098 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13099 (_("This file is corrupt and cannot be played.")), (NULL));
13101 gst_qtdemux_stream_unref (stream);
13106 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13107 gst_qtdemux_stream_unref (stream);
13113 /* we posted an error already */
13114 /* free stbl sub-atoms */
13115 gst_qtdemux_stbl_free (stream);
13116 gst_qtdemux_stream_unref (stream);
13121 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13127 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13128 GST_FOURCC_ARGS (stream->subtype));
13129 gst_qtdemux_stream_unref (stream);
13134 /* If we can estimate the overall bitrate, and don't have information about the
13135 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13136 * the overall bitrate minus the sum of the bitrates of all other streams. This
13137 * should be useful for the common case where we have one audio and one video
13138 * stream and can estimate the bitrate of one, but not the other. */
13140 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13142 QtDemuxStream *stream = NULL;
13143 gint64 size, sys_bitrate, sum_bitrate = 0;
13144 GstClockTime duration;
13148 if (qtdemux->fragmented)
13151 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13153 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13155 GST_DEBUG_OBJECT (qtdemux,
13156 "Size in bytes of the stream not known - bailing");
13160 /* Subtract the header size */
13161 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13162 size, qtdemux->header_size);
13164 if (size < qtdemux->header_size)
13167 size = size - qtdemux->header_size;
13169 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13170 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13174 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13175 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13176 switch (str->subtype) {
13179 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13180 CUR_STREAM (str)->caps);
13181 /* retrieve bitrate, prefer avg then max */
13183 if (str->stream_tags) {
13184 if (gst_tag_list_get_uint (str->stream_tags,
13185 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13186 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13187 if (gst_tag_list_get_uint (str->stream_tags,
13188 GST_TAG_NOMINAL_BITRATE, &bitrate))
13189 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13190 if (gst_tag_list_get_uint (str->stream_tags,
13191 GST_TAG_BITRATE, &bitrate))
13192 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13195 sum_bitrate += bitrate;
13198 GST_DEBUG_OBJECT (qtdemux,
13199 ">1 stream with unknown bitrate - bailing");
13206 /* For other subtypes, we assume no significant impact on bitrate */
13212 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13216 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13218 if (sys_bitrate < sum_bitrate) {
13219 /* This can happen, since sum_bitrate might be derived from maximum
13220 * bitrates and not average bitrates */
13221 GST_DEBUG_OBJECT (qtdemux,
13222 "System bitrate less than sum bitrate - bailing");
13226 bitrate = sys_bitrate - sum_bitrate;
13227 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13228 ", Stream bitrate = %u", sys_bitrate, bitrate);
13230 if (!stream->stream_tags)
13231 stream->stream_tags = gst_tag_list_new_empty ();
13233 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13235 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13236 GST_TAG_BITRATE, bitrate, NULL);
13239 static GstFlowReturn
13240 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13242 GstFlowReturn ret = GST_FLOW_OK;
13245 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13247 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13248 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13249 guint32 sample_num = 0;
13251 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13252 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13254 if (qtdemux->fragmented && qtdemux->pullbased) {
13255 /* need all moov samples first */
13256 GST_OBJECT_LOCK (qtdemux);
13257 while (stream->n_samples == 0)
13258 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13260 GST_OBJECT_UNLOCK (qtdemux);
13262 /* discard any stray moof */
13263 qtdemux->moof_offset = 0;
13266 /* prepare braking */
13267 if (ret != GST_FLOW_ERROR)
13270 /* in pull mode, we should have parsed some sample info by now;
13271 * and quite some code will not handle no samples.
13272 * in push mode, we'll just have to deal with it */
13273 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13274 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13275 g_ptr_array_remove_index (qtdemux->active_streams, i);
13278 } else if (stream->track_id == qtdemux->chapters_track_id &&
13279 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13280 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13281 so that it doesn't look like a subtitle track */
13282 g_ptr_array_remove_index (qtdemux->active_streams, i);
13287 /* parse the initial sample for use in setting the frame rate cap */
13288 while (sample_num == 0 && sample_num < stream->n_samples) {
13289 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13299 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13301 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13305 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13309 /* Different length, updated */
13310 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13313 /* streams in list are sorted in track-id order */
13314 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13315 /* Different stream-id, updated */
13316 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13317 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13325 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13326 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13328 /* Connect old stream's srcpad to new stream */
13329 newstream->pad = oldstream->pad;
13330 oldstream->pad = NULL;
13332 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13333 * case we need to force one through */
13334 newstream->new_stream = GST_PAD_IS_EOS (newstream->pad);
13336 return gst_qtdemux_configure_stream (qtdemux, newstream);
13340 qtdemux_update_streams (GstQTDemux * qtdemux)
13343 g_assert (qtdemux->streams_aware);
13345 /* At below, figure out which stream in active_streams has identical stream-id
13346 * with that of in old_streams. If there is matching stream-id,
13347 * corresponding newstream will not be exposed again,
13348 * but demux will reuse srcpad of matched old stream
13350 * active_streams : newly created streams from the latest moov
13351 * old_streams : existing streams (belong to previous moov)
13354 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13355 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13356 QtDemuxStream *oldstream = NULL;
13359 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13360 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13362 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13363 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13364 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13366 /* null pad stream cannot be reused */
13367 if (oldstream->pad == NULL)
13372 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13374 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13377 /* we don't need to preserve order of old streams */
13378 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13382 /* now we have all info and can expose */
13383 list = stream->stream_tags;
13384 stream->stream_tags = NULL;
13385 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13393 /* Must be called with expose lock */
13394 static GstFlowReturn
13395 qtdemux_expose_streams (GstQTDemux * qtdemux)
13399 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13401 if (!qtdemux_is_streams_update (qtdemux)) {
13402 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13403 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13404 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13405 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13406 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13407 return GST_FLOW_ERROR;
13410 g_ptr_array_set_size (qtdemux->old_streams, 0);
13411 qtdemux->need_segment = TRUE;
13413 return GST_FLOW_OK;
13416 if (qtdemux->streams_aware) {
13417 if (!qtdemux_update_streams (qtdemux))
13418 return GST_FLOW_ERROR;
13420 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13421 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13424 /* now we have all info and can expose */
13425 list = stream->stream_tags;
13426 stream->stream_tags = NULL;
13427 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13428 return GST_FLOW_ERROR;
13433 gst_qtdemux_guess_bitrate (qtdemux);
13435 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13437 /* If we have still old_streams, it's no more used stream */
13438 for (i = 0; i < qtdemux->old_streams->len; i++) {
13439 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13444 event = gst_event_new_eos ();
13445 if (qtdemux->segment_seqnum)
13446 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13448 gst_pad_push_event (stream->pad, event);
13452 g_ptr_array_set_size (qtdemux->old_streams, 0);
13454 /* check if we should post a redirect in case there is a single trak
13455 * and it is a redirecting trak */
13456 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13457 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13460 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13461 "an external content");
13462 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13463 gst_structure_new ("redirect",
13464 "new-location", G_TYPE_STRING,
13465 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13466 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13467 g_free (qtdemux->redirect_location);
13468 qtdemux->redirect_location =
13469 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13472 g_ptr_array_foreach (qtdemux->active_streams,
13473 (GFunc) qtdemux_do_allocation, qtdemux);
13475 qtdemux->need_segment = TRUE;
13477 qtdemux->exposed = TRUE;
13478 return GST_FLOW_OK;
13483 GstStructure *structure; /* helper for sort function */
13485 guint min_req_bitrate;
13486 guint min_req_qt_version;
13490 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13492 GstQtReference *ref_a = (GstQtReference *) a;
13493 GstQtReference *ref_b = (GstQtReference *) b;
13495 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13496 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13498 /* known bitrates go before unknown; higher bitrates go first */
13499 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13502 /* sort the redirects and post a message for the application.
13505 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13507 GstQtReference *best;
13510 GValue list_val = { 0, };
13513 g_assert (references != NULL);
13515 references = g_list_sort (references, qtdemux_redirects_sort_func);
13517 best = (GstQtReference *) references->data;
13519 g_value_init (&list_val, GST_TYPE_LIST);
13521 for (l = references; l != NULL; l = l->next) {
13522 GstQtReference *ref = (GstQtReference *) l->data;
13523 GValue struct_val = { 0, };
13525 ref->structure = gst_structure_new ("redirect",
13526 "new-location", G_TYPE_STRING, ref->location, NULL);
13528 if (ref->min_req_bitrate > 0) {
13529 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13530 ref->min_req_bitrate, NULL);
13533 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13534 g_value_set_boxed (&struct_val, ref->structure);
13535 gst_value_list_append_value (&list_val, &struct_val);
13536 g_value_unset (&struct_val);
13537 /* don't free anything here yet, since we need best->structure below */
13540 g_assert (best != NULL);
13541 s = gst_structure_copy (best->structure);
13543 if (g_list_length (references) > 1) {
13544 gst_structure_set_value (s, "locations", &list_val);
13547 g_value_unset (&list_val);
13549 for (l = references; l != NULL; l = l->next) {
13550 GstQtReference *ref = (GstQtReference *) l->data;
13552 gst_structure_free (ref->structure);
13553 g_free (ref->location);
13556 g_list_free (references);
13558 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13559 g_free (qtdemux->redirect_location);
13560 qtdemux->redirect_location =
13561 g_strdup (gst_structure_get_string (s, "new-location"));
13562 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13563 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13566 /* look for redirect nodes, collect all redirect information and
13570 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13572 GNode *rmra, *rmda, *rdrf;
13574 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13576 GList *redirects = NULL;
13578 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13580 GstQtReference ref = { NULL, NULL, 0, 0 };
13581 GNode *rmdr, *rmvc;
13583 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13584 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13585 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13586 ref.min_req_bitrate);
13589 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13590 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13591 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13593 #ifndef GST_DISABLE_GST_DEBUG
13594 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13596 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13598 GST_LOG_OBJECT (qtdemux,
13599 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13600 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13601 bitmask, check_type);
13602 if (package == FOURCC_qtim && check_type == 0) {
13603 ref.min_req_qt_version = version;
13607 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13613 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13614 if (ref_len > 20) {
13615 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13616 ref_data = (guint8 *) rdrf->data + 20;
13617 if (ref_type == FOURCC_alis) {
13618 guint record_len, record_version, fn_len;
13620 if (ref_len > 70) {
13621 /* MacOSX alias record, google for alias-layout.txt */
13622 record_len = QT_UINT16 (ref_data + 4);
13623 record_version = QT_UINT16 (ref_data + 4 + 2);
13624 fn_len = QT_UINT8 (ref_data + 50);
13625 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13626 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13629 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13632 } else if (ref_type == FOURCC_url_) {
13633 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13635 GST_DEBUG_OBJECT (qtdemux,
13636 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13637 GST_FOURCC_ARGS (ref_type));
13639 if (ref.location != NULL) {
13640 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13642 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13644 GST_WARNING_OBJECT (qtdemux,
13645 "Failed to extract redirect location from rdrf atom");
13648 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13652 /* look for others */
13653 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13656 if (redirects != NULL) {
13657 qtdemux_process_redirects (qtdemux, redirects);
13663 static GstTagList *
13664 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13668 if (tags == NULL) {
13669 tags = gst_tag_list_new_empty ();
13670 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13673 if (qtdemux->major_brand == FOURCC_mjp2)
13674 fmt = "Motion JPEG 2000";
13675 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13677 else if (qtdemux->major_brand == FOURCC_qt__)
13679 else if (qtdemux->fragmented)
13682 fmt = "ISO MP4/M4A";
13684 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13685 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13687 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13693 /* we have read the complete moov node now.
13694 * This function parses all of the relevant info, creates the traks and
13695 * prepares all data structures for playback
13698 qtdemux_parse_tree (GstQTDemux * qtdemux)
13705 guint64 creation_time;
13706 GstDateTime *datetime = NULL;
13709 /* make sure we have a usable taglist */
13710 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13712 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13713 if (mvhd == NULL) {
13714 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13715 return qtdemux_parse_redirects (qtdemux);
13718 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13719 if (version == 1) {
13720 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13721 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13722 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13723 } else if (version == 0) {
13724 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13725 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13726 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13728 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13732 /* Moving qt creation time (secs since 1904) to unix time */
13733 if (creation_time != 0) {
13734 /* Try to use epoch first as it should be faster and more commonly found */
13735 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13738 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13739 /* some data cleansing sanity */
13740 now_s = g_get_real_time () / G_USEC_PER_SEC;
13741 if (now_s + 24 * 3600 < creation_time) {
13742 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13744 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13747 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13748 GDateTime *dt, *dt_local;
13750 dt = g_date_time_add_seconds (base_dt, creation_time);
13751 dt_local = g_date_time_to_local (dt);
13752 datetime = gst_date_time_new_from_g_date_time (dt_local);
13754 g_date_time_unref (base_dt);
13755 g_date_time_unref (dt);
13759 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13760 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13762 gst_date_time_unref (datetime);
13765 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13766 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13768 /* check for fragmented file and get some (default) data */
13769 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13772 GstByteReader mehd_data;
13774 /* let track parsing or anyone know weird stuff might happen ... */
13775 qtdemux->fragmented = TRUE;
13777 /* compensate for total duration */
13778 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13780 qtdemux_parse_mehd (qtdemux, &mehd_data);
13783 /* Update the movie segment duration, unless it was directly given to us
13784 * by upstream. Otherwise let it as is, as we don't want to mangle the
13785 * duration provided by upstream that may come e.g. from a MPD file. */
13786 if (!qtdemux->upstream_format_is_time) {
13787 GstClockTime duration;
13788 /* set duration in the segment info */
13789 gst_qtdemux_get_duration (qtdemux, &duration);
13790 qtdemux->segment.duration = duration;
13791 /* also do not exceed duration; stop is set that way post seek anyway,
13792 * and segment activation falls back to duration,
13793 * whereas loop only checks stop, so let's align this here as well */
13794 qtdemux->segment.stop = duration;
13797 /* parse all traks */
13798 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13800 qtdemux_parse_trak (qtdemux, trak);
13801 /* iterate all siblings */
13802 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13805 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13808 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13810 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13812 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13815 /* maybe also some tags in meta box */
13816 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13818 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13819 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13821 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13824 /* parse any protection system info */
13825 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13827 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13828 qtdemux_parse_pssh (qtdemux, pssh);
13829 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13832 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13837 /* taken from ffmpeg */
13839 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13851 len = (len << 7) | (c & 0x7f);
13860 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13861 gsize codec_data_size)
13863 GList *list = NULL;
13864 guint8 *p = codec_data;
13865 gint i, offset, num_packets;
13866 guint *length, last;
13868 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13870 if (codec_data == NULL || codec_data_size == 0)
13873 /* start of the stream and vorbis audio or theora video, need to
13874 * send the codec_priv data as first three packets */
13875 num_packets = p[0] + 1;
13876 GST_DEBUG_OBJECT (qtdemux,
13877 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13878 (guint) num_packets, codec_data_size);
13880 /* Let's put some limits, Don't think there even is a xiph codec
13881 * with more than 3-4 headers */
13882 if (G_UNLIKELY (num_packets > 16)) {
13883 GST_WARNING_OBJECT (qtdemux,
13884 "Unlikely number of xiph headers, most likely not valid");
13888 length = g_alloca (num_packets * sizeof (guint));
13892 /* first packets, read length values */
13893 for (i = 0; i < num_packets - 1; i++) {
13895 while (offset < codec_data_size) {
13896 length[i] += p[offset];
13897 if (p[offset++] != 0xff)
13902 if (offset + last > codec_data_size)
13905 /* last packet is the remaining size */
13906 length[i] = codec_data_size - offset - last;
13908 for (i = 0; i < num_packets; i++) {
13911 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
13913 if (offset + length[i] > codec_data_size)
13916 hdr = gst_buffer_new_memdup (p + offset, length[i]);
13917 list = g_list_append (list, hdr);
13919 offset += length[i];
13928 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
13934 /* this can change the codec originally present in @list */
13936 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13937 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13939 int len = QT_UINT32 (esds->data);
13940 guint8 *ptr = esds->data;
13941 guint8 *end = ptr + len;
13943 guint8 *data_ptr = NULL;
13945 guint8 object_type_id = 0;
13946 guint8 stream_type = 0;
13947 const char *codec_name = NULL;
13948 GstCaps *caps = NULL;
13950 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13952 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13954 while (ptr + 1 < end) {
13955 tag = QT_UINT8 (ptr);
13956 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13958 len = read_descr_size (ptr, end, &ptr);
13959 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13961 /* Check the stated amount of data is available for reading */
13962 if (len < 0 || ptr + len > end)
13966 case ES_DESCRIPTOR_TAG:
13967 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
13968 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
13971 case DECODER_CONFIG_DESC_TAG:{
13972 guint max_bitrate, avg_bitrate;
13974 object_type_id = QT_UINT8 (ptr);
13975 stream_type = QT_UINT8 (ptr + 1) >> 2;
13976 max_bitrate = QT_UINT32 (ptr + 5);
13977 avg_bitrate = QT_UINT32 (ptr + 9);
13978 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13979 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
13980 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13981 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13982 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13983 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13984 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13985 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13987 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13988 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13989 avg_bitrate, NULL);
13994 case DECODER_SPECIFIC_INFO_TAG:
13995 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13996 if (object_type_id == 0xe0 && len == 0x40) {
14002 GST_DEBUG_OBJECT (qtdemux,
14003 "Have VOBSUB palette. Creating palette event");
14004 /* move to decConfigDescr data and read palette */
14006 for (i = 0; i < 16; i++) {
14007 clut[i] = QT_UINT32 (data);
14011 s = gst_structure_new ("application/x-gst-dvd", "event",
14012 G_TYPE_STRING, "dvd-spu-clut-change",
14013 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14014 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14015 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14016 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14017 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14018 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14019 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14020 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14023 /* store event and trigger custom processing */
14024 stream->pending_event =
14025 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14027 /* Generic codec_data handler puts it on the caps */
14034 case SL_CONFIG_DESC_TAG:
14035 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14039 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14041 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14047 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14048 * in use, and should also be used to override some other parameters for some
14050 switch (object_type_id) {
14051 case 0x20: /* MPEG-4 */
14052 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14053 * profile_and_level_indication */
14054 if (data_ptr != NULL && data_len >= 5 &&
14055 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14056 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14057 data_ptr + 4, data_len - 4);
14059 break; /* Nothing special needed here */
14060 case 0x21: /* H.264 */
14061 codec_name = "H.264 / AVC";
14062 caps = gst_caps_new_simple ("video/x-h264",
14063 "stream-format", G_TYPE_STRING, "avc",
14064 "alignment", G_TYPE_STRING, "au", NULL);
14066 case 0x40: /* AAC (any) */
14067 case 0x66: /* AAC Main */
14068 case 0x67: /* AAC LC */
14069 case 0x68: /* AAC SSR */
14070 /* Override channels and rate based on the codec_data, as it's often
14072 /* Only do so for basic setup without HE-AAC extension */
14073 if (data_ptr && data_len == 2) {
14074 guint channels, rate;
14076 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14078 entry->n_channels = channels;
14080 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14082 entry->rate = rate;
14085 /* Set level and profile if possible */
14086 if (data_ptr != NULL && data_len >= 2) {
14087 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14088 data_ptr, data_len);
14090 const gchar *profile_str = NULL;
14093 guint8 *codec_data;
14094 gint rate_idx, profile;
14096 /* No codec_data, let's invent something.
14097 * FIXME: This is wrong for SBR! */
14099 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14101 buffer = gst_buffer_new_and_alloc (2);
14102 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14103 codec_data = map.data;
14106 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14109 switch (object_type_id) {
14111 profile_str = "main";
14115 profile_str = "lc";
14119 profile_str = "ssr";
14127 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14129 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14131 gst_buffer_unmap (buffer, &map);
14132 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14133 GST_TYPE_BUFFER, buffer, NULL);
14134 gst_buffer_unref (buffer);
14137 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14138 G_TYPE_STRING, profile_str, NULL);
14142 case 0x60: /* MPEG-2, various profiles */
14148 codec_name = "MPEG-2 video";
14149 caps = gst_caps_new_simple ("video/mpeg",
14150 "mpegversion", G_TYPE_INT, 2,
14151 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14153 case 0x69: /* MPEG-2 BC audio */
14154 case 0x6B: /* MPEG-1 audio */
14155 caps = gst_caps_new_simple ("audio/mpeg",
14156 "mpegversion", G_TYPE_INT, 1, NULL);
14157 codec_name = "MPEG-1 audio";
14159 case 0x6A: /* MPEG-1 */
14160 codec_name = "MPEG-1 video";
14161 caps = gst_caps_new_simple ("video/mpeg",
14162 "mpegversion", G_TYPE_INT, 1,
14163 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14165 case 0x6C: /* MJPEG */
14167 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14169 codec_name = "Motion-JPEG";
14171 case 0x6D: /* PNG */
14173 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14175 codec_name = "PNG still images";
14177 case 0x6E: /* JPEG2000 */
14178 codec_name = "JPEG-2000";
14179 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14181 case 0xA4: /* Dirac */
14182 codec_name = "Dirac";
14183 caps = gst_caps_new_empty_simple ("video/x-dirac");
14185 case 0xA5: /* AC3 */
14186 codec_name = "AC-3 audio";
14187 caps = gst_caps_new_simple ("audio/x-ac3",
14188 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14190 case 0xA9: /* AC3 */
14191 codec_name = "DTS audio";
14192 caps = gst_caps_new_simple ("audio/x-dts",
14193 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14196 if (stream_type == 0x05 && data_ptr) {
14198 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14201 GValue arr_val = G_VALUE_INIT;
14202 GValue buf_val = G_VALUE_INIT;
14205 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14206 codec_name = "Vorbis";
14207 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14208 g_value_init (&arr_val, GST_TYPE_ARRAY);
14209 g_value_init (&buf_val, GST_TYPE_BUFFER);
14210 for (tmp = headers; tmp; tmp = tmp->next) {
14211 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14212 gst_value_array_append_value (&arr_val, &buf_val);
14214 s = gst_caps_get_structure (caps, 0);
14215 gst_structure_take_value (s, "streamheader", &arr_val);
14216 g_value_unset (&buf_val);
14217 g_list_free (headers);
14224 case 0xE1: /* QCELP */
14225 /* QCELP, the codec_data is a riff tag (little endian) with
14226 * 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). */
14227 caps = gst_caps_new_empty_simple ("audio/qcelp");
14228 codec_name = "QCELP";
14234 /* If we have a replacement caps, then change our caps for this stream */
14236 gst_caps_unref (entry->caps);
14237 entry->caps = caps;
14240 if (codec_name && list)
14241 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14242 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14244 /* Add the codec_data attribute to caps, if we have it */
14248 buffer = gst_buffer_new_and_alloc (data_len);
14249 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14251 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14252 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14254 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14256 gst_buffer_unref (buffer);
14261 static inline GstCaps *
14262 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14266 char *s, fourstr[5];
14268 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14269 for (i = 0; i < 4; i++) {
14270 if (!g_ascii_isalnum (fourstr[i]))
14273 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14274 caps = gst_caps_new_empty_simple (s);
14279 #define _codec(name) \
14281 if (codec_name) { \
14282 *codec_name = g_strdup (name); \
14287 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14288 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14289 const guint8 * stsd_entry_data, gchar ** codec_name)
14291 GstCaps *caps = NULL;
14292 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14296 _codec ("PNG still images");
14297 caps = gst_caps_new_empty_simple ("image/png");
14300 _codec ("JPEG still images");
14302 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14305 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14306 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14307 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14308 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14309 _codec ("Motion-JPEG");
14311 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14314 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14315 _codec ("Motion-JPEG format B");
14316 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14319 _codec ("JPEG-2000");
14320 /* override to what it should be according to spec, avoid palette_data */
14321 entry->bits_per_sample = 24;
14322 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14325 _codec ("Sorensen video v.3");
14326 caps = gst_caps_new_simple ("video/x-svq",
14327 "svqversion", G_TYPE_INT, 3, NULL);
14329 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14330 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14331 _codec ("Sorensen video v.1");
14332 caps = gst_caps_new_simple ("video/x-svq",
14333 "svqversion", G_TYPE_INT, 1, NULL);
14335 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14336 caps = gst_caps_new_empty_simple ("video/x-raw");
14337 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14338 _codec ("Windows Raw RGB");
14339 stream->alignment = 32;
14345 bps = QT_UINT16 (stsd_entry_data + 82);
14348 format = GST_VIDEO_FORMAT_RGB15;
14351 format = GST_VIDEO_FORMAT_RGB16;
14354 format = GST_VIDEO_FORMAT_RGB;
14357 format = GST_VIDEO_FORMAT_ARGB;
14365 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14366 format = GST_VIDEO_FORMAT_I420;
14368 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14369 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14370 format = GST_VIDEO_FORMAT_I420;
14373 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14374 format = GST_VIDEO_FORMAT_UYVY;
14376 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14377 format = GST_VIDEO_FORMAT_v308;
14379 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14380 format = GST_VIDEO_FORMAT_v216;
14383 format = GST_VIDEO_FORMAT_v210;
14385 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14386 format = GST_VIDEO_FORMAT_r210;
14388 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14389 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14390 format = GST_VIDEO_FORMAT_v410;
14393 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14394 * but different order than AYUV
14395 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14396 format = GST_VIDEO_FORMAT_v408;
14399 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14400 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14401 _codec ("MPEG-1 video");
14402 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14403 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14405 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14406 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14407 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14408 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14409 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14410 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14411 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14412 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14413 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14414 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14415 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14416 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14417 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14418 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14419 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14420 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14421 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14422 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14423 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14424 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14425 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14426 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14427 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14428 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14429 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14430 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14431 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14432 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14433 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14434 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14435 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14436 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14437 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14438 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14439 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14440 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14441 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14442 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14443 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14444 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14445 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14446 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14447 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14448 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14449 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14450 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14451 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14452 _codec ("MPEG-2 video");
14453 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14454 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14456 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14457 _codec ("GIF still images");
14458 caps = gst_caps_new_empty_simple ("image/gif");
14461 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14463 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14465 /* ffmpeg uses the height/width props, don't know why */
14466 caps = gst_caps_new_simple ("video/x-h263",
14467 "variant", G_TYPE_STRING, "itu", NULL);
14471 _codec ("MPEG-4 video");
14472 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14473 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14475 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14476 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14477 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14478 caps = gst_caps_new_simple ("video/x-msmpeg",
14479 "msmpegversion", G_TYPE_INT, 43, NULL);
14481 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14483 caps = gst_caps_new_simple ("video/x-divx",
14484 "divxversion", G_TYPE_INT, 3, NULL);
14486 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14487 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14489 caps = gst_caps_new_simple ("video/x-divx",
14490 "divxversion", G_TYPE_INT, 4, NULL);
14492 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14494 caps = gst_caps_new_simple ("video/x-divx",
14495 "divxversion", G_TYPE_INT, 5, NULL);
14498 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14500 caps = gst_caps_new_simple ("video/x-ffv",
14501 "ffvversion", G_TYPE_INT, 1, NULL);
14504 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14505 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14510 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14511 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14512 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14516 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14517 _codec ("Cinepak");
14518 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14520 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14521 _codec ("Apple QuickDraw");
14522 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14524 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14525 _codec ("Apple video");
14526 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14531 _codec ("H.264 / AVC");
14532 caps = gst_caps_new_simple ("video/x-h264",
14533 "stream-format", G_TYPE_STRING, "avc",
14534 "alignment", G_TYPE_STRING, "au", NULL);
14538 _codec ("H.264 / AVC");
14539 caps = gst_caps_new_simple ("video/x-h264",
14540 "stream-format", G_TYPE_STRING, "avc3",
14541 "alignment", G_TYPE_STRING, "au", NULL);
14546 _codec ("H.265 / HEVC");
14547 caps = gst_caps_new_simple ("video/x-h265",
14548 "stream-format", G_TYPE_STRING, "hvc1",
14549 "alignment", G_TYPE_STRING, "au", NULL);
14553 _codec ("H.265 / HEVC");
14554 caps = gst_caps_new_simple ("video/x-h265",
14555 "stream-format", G_TYPE_STRING, "hev1",
14556 "alignment", G_TYPE_STRING, "au", NULL);
14559 _codec ("Run-length encoding");
14560 caps = gst_caps_new_simple ("video/x-rle",
14561 "layout", G_TYPE_STRING, "quicktime", NULL);
14564 _codec ("Run-length encoding");
14565 caps = gst_caps_new_simple ("video/x-rle",
14566 "layout", G_TYPE_STRING, "microsoft", NULL);
14568 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14569 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14570 _codec ("Indeo Video 3");
14571 caps = gst_caps_new_simple ("video/x-indeo",
14572 "indeoversion", G_TYPE_INT, 3, NULL);
14574 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14575 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14576 _codec ("Intel Video 4");
14577 caps = gst_caps_new_simple ("video/x-indeo",
14578 "indeoversion", G_TYPE_INT, 4, NULL);
14582 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14583 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14584 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14585 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14586 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14587 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14588 _codec ("DV Video");
14589 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14590 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14592 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14593 case FOURCC_dv5p: /* DVCPRO50 PAL */
14594 _codec ("DVCPro50 Video");
14595 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14596 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14598 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14599 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14600 _codec ("DVCProHD Video");
14601 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14602 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14604 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14605 _codec ("Apple Graphics (SMC)");
14606 caps = gst_caps_new_empty_simple ("video/x-smc");
14608 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14610 caps = gst_caps_new_empty_simple ("video/x-vp3");
14612 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14613 _codec ("VP6 Flash");
14614 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14618 caps = gst_caps_new_empty_simple ("video/x-theora");
14619 /* theora uses one byte of padding in the data stream because it does not
14620 * allow 0 sized packets while theora does */
14621 entry->padding = 1;
14625 caps = gst_caps_new_empty_simple ("video/x-dirac");
14627 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14628 _codec ("TIFF still images");
14629 caps = gst_caps_new_empty_simple ("image/tiff");
14631 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14632 _codec ("Apple Intermediate Codec");
14633 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14635 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14636 _codec ("AVID DNxHD");
14637 caps = gst_caps_from_string ("video/x-dnxhd");
14641 _codec ("On2 VP8");
14642 caps = gst_caps_from_string ("video/x-vp8");
14645 _codec ("Google VP9");
14646 caps = gst_caps_from_string ("video/x-vp9");
14649 _codec ("Apple ProRes LT");
14651 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14655 _codec ("Apple ProRes HQ");
14657 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14661 _codec ("Apple ProRes");
14663 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14667 _codec ("Apple ProRes Proxy");
14669 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14673 _codec ("Apple ProRes 4444");
14675 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14678 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14679 if (entry->bits_per_sample > 0) {
14680 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14685 _codec ("Apple ProRes 4444 XQ");
14687 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14690 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14691 if (entry->bits_per_sample > 0) {
14692 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14697 _codec ("GoPro CineForm");
14698 caps = gst_caps_from_string ("video/x-cineform");
14703 caps = gst_caps_new_simple ("video/x-wmv",
14704 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14708 caps = gst_caps_new_empty_simple ("video/x-av1");
14710 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14713 caps = _get_unknown_codec_name ("video", fourcc);
14718 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14721 gst_video_info_init (&info);
14722 gst_video_info_set_format (&info, format, entry->width, entry->height);
14724 caps = gst_video_info_to_caps (&info);
14725 *codec_name = gst_pb_utils_get_codec_description (caps);
14727 /* enable clipping for raw video streams */
14728 stream->need_clip = TRUE;
14729 stream->alignment = 32;
14736 round_up_pow2 (guint n)
14748 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14749 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14750 int len, gchar ** codec_name)
14753 const GstStructure *s;
14756 GstAudioFormat format = 0;
14759 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14761 depth = entry->bytes_per_packet * 8;
14764 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14766 /* 8-bit audio is unsigned */
14768 format = GST_AUDIO_FORMAT_U8;
14769 /* otherwise it's signed and big-endian just like 'twos' */
14771 endian = G_BIG_ENDIAN;
14778 endian = G_LITTLE_ENDIAN;
14781 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14783 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14787 caps = gst_caps_new_simple ("audio/x-raw",
14788 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14789 "layout", G_TYPE_STRING, "interleaved", NULL);
14790 stream->alignment = GST_ROUND_UP_8 (depth);
14791 stream->alignment = round_up_pow2 (stream->alignment);
14795 _codec ("Raw 64-bit floating-point audio");
14796 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14798 caps = gst_caps_new_simple ("audio/x-raw",
14799 "format", G_TYPE_STRING, "F64BE",
14800 "layout", G_TYPE_STRING, "interleaved", NULL);
14801 stream->alignment = 8;
14804 _codec ("Raw 32-bit floating-point audio");
14805 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14807 caps = gst_caps_new_simple ("audio/x-raw",
14808 "format", G_TYPE_STRING, "F32BE",
14809 "layout", G_TYPE_STRING, "interleaved", NULL);
14810 stream->alignment = 4;
14813 _codec ("Raw 24-bit PCM audio");
14814 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14816 caps = gst_caps_new_simple ("audio/x-raw",
14817 "format", G_TYPE_STRING, "S24BE",
14818 "layout", G_TYPE_STRING, "interleaved", NULL);
14819 stream->alignment = 4;
14822 _codec ("Raw 32-bit PCM audio");
14823 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14825 caps = gst_caps_new_simple ("audio/x-raw",
14826 "format", G_TYPE_STRING, "S32BE",
14827 "layout", G_TYPE_STRING, "interleaved", NULL);
14828 stream->alignment = 4;
14831 _codec ("Raw 16-bit PCM audio");
14832 caps = gst_caps_new_simple ("audio/x-raw",
14833 "format", G_TYPE_STRING, "S16LE",
14834 "layout", G_TYPE_STRING, "interleaved", NULL);
14835 stream->alignment = 2;
14838 _codec ("Mu-law audio");
14839 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14842 _codec ("A-law audio");
14843 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14847 _codec ("Microsoft ADPCM");
14848 /* Microsoft ADPCM-ACM code 2 */
14849 caps = gst_caps_new_simple ("audio/x-adpcm",
14850 "layout", G_TYPE_STRING, "microsoft", NULL);
14854 _codec ("DVI/IMA ADPCM");
14855 caps = gst_caps_new_simple ("audio/x-adpcm",
14856 "layout", G_TYPE_STRING, "dvi", NULL);
14860 _codec ("DVI/Intel IMA ADPCM");
14861 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14862 caps = gst_caps_new_simple ("audio/x-adpcm",
14863 "layout", G_TYPE_STRING, "quicktime", NULL);
14867 /* MPEG layer 3, CBR only (pre QT4.1) */
14870 _codec ("MPEG-1 layer 3");
14871 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14872 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14873 "mpegversion", G_TYPE_INT, 1, NULL);
14875 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14876 _codec ("MPEG-1 layer 2");
14878 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14879 "mpegversion", G_TYPE_INT, 1, NULL);
14882 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14883 _codec ("EAC-3 audio");
14884 caps = gst_caps_new_simple ("audio/x-eac3",
14885 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14886 entry->sampled = TRUE;
14888 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14890 _codec ("AC-3 audio");
14891 caps = gst_caps_new_simple ("audio/x-ac3",
14892 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14893 entry->sampled = TRUE;
14895 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14896 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14897 _codec ("DTS audio");
14898 caps = gst_caps_new_simple ("audio/x-dts",
14899 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14900 entry->sampled = TRUE;
14902 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14903 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14904 _codec ("DTS-HD audio");
14905 caps = gst_caps_new_simple ("audio/x-dts",
14906 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14907 entry->sampled = TRUE;
14911 caps = gst_caps_new_simple ("audio/x-mace",
14912 "maceversion", G_TYPE_INT, 3, NULL);
14916 caps = gst_caps_new_simple ("audio/x-mace",
14917 "maceversion", G_TYPE_INT, 6, NULL);
14919 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14921 caps = gst_caps_new_empty_simple ("application/ogg");
14923 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14924 _codec ("DV audio");
14925 caps = gst_caps_new_empty_simple ("audio/x-dv");
14928 _codec ("MPEG-4 AAC audio");
14929 caps = gst_caps_new_simple ("audio/mpeg",
14930 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14931 "stream-format", G_TYPE_STRING, "raw", NULL);
14933 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14934 _codec ("QDesign Music");
14935 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14938 _codec ("QDesign Music v.2");
14939 /* FIXME: QDesign music version 2 (no constant) */
14940 if (FALSE && data) {
14941 caps = gst_caps_new_simple ("audio/x-qdm2",
14942 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14943 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14944 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14946 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14950 _codec ("GSM audio");
14951 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14954 _codec ("AMR audio");
14955 caps = gst_caps_new_empty_simple ("audio/AMR");
14958 _codec ("AMR-WB audio");
14959 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14962 _codec ("Quicktime IMA ADPCM");
14963 caps = gst_caps_new_simple ("audio/x-adpcm",
14964 "layout", G_TYPE_STRING, "quicktime", NULL);
14967 _codec ("Apple lossless audio");
14968 caps = gst_caps_new_empty_simple ("audio/x-alac");
14971 _codec ("Free Lossless Audio Codec");
14972 caps = gst_caps_new_simple ("audio/x-flac",
14973 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14975 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14976 _codec ("QualComm PureVoice");
14977 caps = gst_caps_from_string ("audio/qcelp");
14982 caps = gst_caps_new_empty_simple ("audio/x-wma");
14986 caps = gst_caps_new_empty_simple ("audio/x-opus");
14993 GstAudioFormat format;
14996 FLAG_IS_FLOAT = 0x1,
14997 FLAG_IS_BIG_ENDIAN = 0x2,
14998 FLAG_IS_SIGNED = 0x4,
14999 FLAG_IS_PACKED = 0x8,
15000 FLAG_IS_ALIGNED_HIGH = 0x10,
15001 FLAG_IS_NON_INTERLEAVED = 0x20
15003 _codec ("Raw LPCM audio");
15005 if (data && len >= 36) {
15006 depth = QT_UINT32 (data + 24);
15007 flags = QT_UINT32 (data + 28);
15008 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15010 if ((flags & FLAG_IS_FLOAT) == 0) {
15015 if ((flags & FLAG_IS_ALIGNED_HIGH))
15018 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15019 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15020 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15021 caps = gst_caps_new_simple ("audio/x-raw",
15022 "format", G_TYPE_STRING,
15024 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15025 "UNKNOWN", "layout", G_TYPE_STRING,
15026 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15027 "interleaved", NULL);
15028 stream->alignment = GST_ROUND_UP_8 (depth);
15029 stream->alignment = round_up_pow2 (stream->alignment);
15034 if (flags & FLAG_IS_BIG_ENDIAN)
15035 format = GST_AUDIO_FORMAT_F64BE;
15037 format = GST_AUDIO_FORMAT_F64LE;
15039 if (flags & FLAG_IS_BIG_ENDIAN)
15040 format = GST_AUDIO_FORMAT_F32BE;
15042 format = GST_AUDIO_FORMAT_F32LE;
15044 caps = gst_caps_new_simple ("audio/x-raw",
15045 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15046 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15047 "non-interleaved" : "interleaved", NULL);
15048 stream->alignment = width / 8;
15052 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15055 caps = gst_caps_new_empty_simple ("audio/x-ac4");
15058 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15062 caps = _get_unknown_codec_name ("audio", fourcc);
15068 GstCaps *templ_caps =
15069 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15070 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15071 gst_caps_unref (caps);
15072 gst_caps_unref (templ_caps);
15073 caps = intersection;
15076 /* enable clipping for raw audio streams */
15077 s = gst_caps_get_structure (caps, 0);
15078 name = gst_structure_get_name (s);
15079 if (g_str_has_prefix (name, "audio/x-raw")) {
15080 stream->need_clip = TRUE;
15081 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15082 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15083 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15084 stream->max_buffer_size);
15090 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15091 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15092 const guint8 * stsd_entry_data, gchar ** codec_name)
15096 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15100 _codec ("DVD subtitle");
15101 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15102 stream->process_func = gst_qtdemux_process_buffer_dvd;
15105 _codec ("Quicktime timed text");
15108 _codec ("3GPP timed text");
15110 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15112 /* actual text piece needs to be extracted */
15113 stream->process_func = gst_qtdemux_process_buffer_text;
15116 _codec ("XML subtitles");
15117 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15122 const gchar *buf = "WEBVTT\n\n";
15124 _codec ("WebVTT subtitles");
15125 caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15126 stream->process_func = gst_qtdemux_process_buffer_wvtt;
15128 /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15129 buffer = gst_buffer_new_and_alloc (8);
15130 gst_buffer_fill (buffer, 0, buf, 8);
15131 stream->buffers = g_slist_append (stream->buffers, buffer);
15136 _codec ("CEA 608 Closed Caption");
15138 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15139 G_TYPE_STRING, "s334-1a", NULL);
15140 stream->process_func = gst_qtdemux_process_buffer_clcp;
15141 stream->need_split = TRUE;
15144 _codec ("CEA 708 Closed Caption");
15146 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15147 G_TYPE_STRING, "cdp", NULL);
15148 stream->process_func = gst_qtdemux_process_buffer_clcp;
15153 caps = _get_unknown_codec_name ("text", fourcc);
15161 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15162 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15163 const guint8 * stsd_entry_data, gchar ** codec_name)
15169 _codec ("MPEG 1 video");
15170 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15171 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15181 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15182 const gchar * system_id)
15186 if (!qtdemux->protection_system_ids)
15187 qtdemux->protection_system_ids =
15188 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15189 /* Check whether we already have an entry for this system ID. */
15190 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15191 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15192 if (g_ascii_strcasecmp (system_id, id) == 0) {
15196 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15197 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,