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 <glib/gi18n-lib.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 */
2675 guint32 minor_version;
2678 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2679 GST_DEBUG_OBJECT (qtdemux, "ftyp major brand: %" GST_FOURCC_FORMAT,
2680 GST_FOURCC_ARGS (qtdemux->major_brand));
2681 minor_version = QT_UINT32 (buffer + 12);
2682 GST_DEBUG_OBJECT (qtdemux, "ftyp minor version: %u", minor_version);
2683 if (qtdemux->comp_brands)
2684 gst_buffer_unref (qtdemux->comp_brands);
2685 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2686 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2689 length = length - 16;
2690 while (length > 0) {
2691 GST_DEBUG_OBJECT (qtdemux, "ftyp compatible brand: %" GST_FOURCC_FORMAT,
2692 GST_FOURCC_ARGS (QT_FOURCC (p)));
2700 qtdemux_parse_styp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2702 /* only consider at least a sufficiently complete styp atom */
2705 guint32 major_brand;
2706 guint32 minor_version;
2709 major_brand = QT_FOURCC (buffer + 8);
2710 GST_DEBUG_OBJECT (qtdemux, "styp major brand: %" GST_FOURCC_FORMAT,
2711 GST_FOURCC_ARGS (major_brand));
2712 minor_version = QT_UINT32 (buffer + 12);
2713 GST_DEBUG_OBJECT (qtdemux, "styp minor version: %u", minor_version);
2714 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2715 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2718 length = length - 16;
2719 while (length > 0) {
2720 GST_DEBUG_OBJECT (qtdemux, "styp compatible brand: %" GST_FOURCC_FORMAT,
2721 GST_FOURCC_ARGS (QT_FOURCC (p)));
2729 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2730 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2731 guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2732 guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2733 const guint8 * constant_iv)
2735 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2736 gst_buffer_fill (kid_buf, 0, kid, 16);
2737 if (info->default_properties)
2738 gst_structure_free (info->default_properties);
2739 info->default_properties =
2740 gst_structure_new ("application/x-cenc",
2741 "iv_size", G_TYPE_UINT, iv_size,
2742 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2743 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2744 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2745 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2746 gst_buffer_unref (kid_buf);
2747 if (protection_scheme_type == FOURCC_cbcs) {
2748 if (crypt_byte_block != 0 || skip_byte_block != 0) {
2749 gst_structure_set (info->default_properties, "crypt_byte_block",
2750 G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2751 skip_byte_block, NULL);
2753 if (constant_iv != NULL) {
2754 GstBuffer *constant_iv_buf =
2755 gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2756 gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2757 gst_structure_set (info->default_properties, "constant_iv_size",
2758 G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2760 gst_buffer_unref (constant_iv_buf);
2762 gst_structure_set (info->default_properties, "cipher-mode",
2763 G_TYPE_STRING, "cbcs", NULL);
2765 gst_structure_set (info->default_properties, "cipher-mode",
2766 G_TYPE_STRING, "cenc", NULL);
2771 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2772 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2774 guint32 algorithm_id = 0;
2776 gboolean is_encrypted = TRUE;
2779 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2780 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2785 if (algorithm_id == 0) {
2786 is_encrypted = FALSE;
2787 } else if (algorithm_id == 1) {
2788 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2789 } else if (algorithm_id == 2) {
2790 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2793 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2796 if (!gst_byte_reader_get_data (br, 16, &kid))
2799 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2800 is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2801 gst_structure_set (info->default_properties, "piff_algorithm_id",
2802 G_TYPE_UINT, algorithm_id, NULL);
2808 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2816 QtDemuxStream *stream;
2817 GstStructure *structure;
2818 QtDemuxCencSampleSetInfo *ss_info = NULL;
2819 const gchar *system_id;
2820 gboolean uses_sub_sample_encryption = FALSE;
2821 guint32 sample_count;
2823 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2826 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2828 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2829 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2830 GST_WARNING_OBJECT (qtdemux,
2831 "Attempting PIFF box parsing on an unencrypted stream.");
2835 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2836 G_TYPE_STRING, &system_id, NULL);
2837 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2839 stream->protected = TRUE;
2840 stream->protection_scheme_type = FOURCC_cenc;
2842 if (!stream->protection_scheme_info)
2843 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2845 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2846 if (!ss_info->default_properties) {
2847 ss_info->default_properties =
2848 gst_structure_new ("application/x-cenc",
2849 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2854 if (ss_info->crypto_info) {
2855 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2856 g_ptr_array_free (ss_info->crypto_info, TRUE);
2857 ss_info->crypto_info = NULL;
2861 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2863 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2864 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2868 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2869 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2873 if ((flags & 0x000001)) {
2874 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2877 } else if ((flags & 0x000002)) {
2878 uses_sub_sample_encryption = TRUE;
2881 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2883 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2887 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2888 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2892 ss_info->crypto_info =
2893 g_ptr_array_new_full (sample_count,
2894 (GDestroyNotify) qtdemux_gst_structure_free);
2896 for (i = 0; i < sample_count; ++i) {
2897 GstStructure *properties;
2901 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2902 if (properties == NULL) {
2903 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2904 qtdemux->cenc_aux_sample_count = i;
2908 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2909 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2910 gst_structure_free (properties);
2911 qtdemux->cenc_aux_sample_count = i;
2914 buf = gst_buffer_new_wrapped (data, iv_size);
2915 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2916 gst_buffer_unref (buf);
2918 if (uses_sub_sample_encryption) {
2919 guint16 n_subsamples;
2920 const GValue *kid_buf_value;
2922 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2923 || n_subsamples == 0) {
2924 GST_ERROR_OBJECT (qtdemux,
2925 "failed to get subsample count for sample %u", i);
2926 gst_structure_free (properties);
2927 qtdemux->cenc_aux_sample_count = i;
2930 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2931 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2932 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2934 gst_structure_free (properties);
2935 qtdemux->cenc_aux_sample_count = i;
2938 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2941 gst_structure_get_value (ss_info->default_properties, "kid");
2943 gst_structure_set (properties,
2944 "subsample_count", G_TYPE_UINT, n_subsamples,
2945 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2946 gst_structure_set_value (properties, "kid", kid_buf_value);
2947 gst_buffer_unref (buf);
2949 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2952 g_ptr_array_add (ss_info->crypto_info, properties);
2955 qtdemux->cenc_aux_sample_count = sample_count;
2959 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2961 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2962 0x97, 0xA9, 0x42, 0xE8,
2963 0x9C, 0x71, 0x99, 0x94,
2964 0x91, 0xE3, 0xAF, 0xAC
2966 static const guint8 playready_uuid[] = {
2967 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2968 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2971 static const guint8 piff_sample_encryption_uuid[] = {
2972 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2973 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2978 /* counts as header data */
2979 qtdemux->header_size += length;
2981 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2983 if (length <= offset + 16) {
2984 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2988 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2990 GstTagList *taglist;
2992 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2993 length - offset - 16, NULL);
2994 taglist = gst_tag_list_from_xmp_buffer (buf);
2995 gst_buffer_unref (buf);
2997 /* make sure we have a usable taglist */
2998 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3000 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3002 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3004 const gunichar2 *s_utf16;
3007 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3008 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3009 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3010 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3014 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3015 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3017 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3018 qtdemux_parse_piff (qtdemux, buffer, length, offset);
3020 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3021 GST_READ_UINT32_LE (buffer + offset),
3022 GST_READ_UINT32_LE (buffer + offset + 4),
3023 GST_READ_UINT32_LE (buffer + offset + 8),
3024 GST_READ_UINT32_LE (buffer + offset + 12));
3029 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3031 GstSidxParser sidx_parser;
3032 GstIsoffParserResult res;
3035 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3038 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3040 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3041 if (res == GST_ISOFF_QT_PARSER_DONE) {
3042 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3044 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3047 /* caller verifies at least 8 bytes in buf */
3049 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3050 guint64 * plength, guint32 * pfourcc)
3055 length = QT_UINT32 (data);
3056 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3057 fourcc = QT_FOURCC (data + 4);
3058 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3061 length = G_MAXUINT64;
3062 } else if (length == 1 && size >= 16) {
3063 /* this means we have an extended size, which is the 64 bit value of
3064 * the next 8 bytes */
3065 length = QT_UINT64 (data + 8);
3066 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3076 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3078 guint32 version = 0;
3079 GstClockTime duration = 0;
3081 if (!gst_byte_reader_get_uint32_be (br, &version))
3086 if (!gst_byte_reader_get_uint64_be (br, &duration))
3091 if (!gst_byte_reader_get_uint32_be (br, &dur))
3096 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3097 qtdemux->duration = duration;
3103 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3109 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3110 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3112 if (!stream->parsed_trex && qtdemux->moov_node) {
3114 GstByteReader trex_data;
3116 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3118 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3121 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3123 /* skip version/flags */
3124 if (!gst_byte_reader_skip (&trex_data, 4))
3126 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3128 if (id != stream->track_id)
3130 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3132 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3134 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3136 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3139 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3140 "duration %d, size %d, flags 0x%x", stream->track_id,
3143 stream->parsed_trex = TRUE;
3144 stream->def_sample_description_index = sdi;
3145 stream->def_sample_duration = dur;
3146 stream->def_sample_size = size;
3147 stream->def_sample_flags = flags;
3150 /* iterate all siblings */
3151 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3157 *ds_duration = stream->def_sample_duration;
3158 *ds_size = stream->def_sample_size;
3159 *ds_flags = stream->def_sample_flags;
3161 /* even then, above values are better than random ... */
3162 if (G_UNLIKELY (!stream->parsed_trex)) {
3163 GST_WARNING_OBJECT (qtdemux,
3164 "failed to find fragment defaults for stream %d", stream->track_id);
3171 /* This method should be called whenever a more accurate duration might
3172 * have been found. It will update all relevant variables if/where needed
3175 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3179 GstClockTime prevdur;
3181 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3183 if (movdur > qtdemux->duration) {
3184 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3185 GST_DEBUG_OBJECT (qtdemux,
3186 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3187 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3188 qtdemux->duration = movdur;
3189 GST_DEBUG_OBJECT (qtdemux,
3190 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3191 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3192 GST_TIME_ARGS (qtdemux->segment.stop));
3193 if (qtdemux->segment.duration == prevdur) {
3194 /* If the current segment has duration/stop identical to previous duration
3195 * update them also (because they were set at that point in time with
3196 * the wrong duration */
3197 /* We convert the value *from* the timescale version to avoid rounding errors */
3198 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3199 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3200 qtdemux->segment.duration = fixeddur;
3201 qtdemux->segment.stop = fixeddur;
3205 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3206 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3208 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3209 if (movdur > stream->duration) {
3210 GST_DEBUG_OBJECT (qtdemux,
3211 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3212 GST_TIME_ARGS (duration));
3213 stream->duration = movdur;
3214 /* internal duration tracking state has been updated above, so */
3215 /* preserve an open-ended dummy segment rather than repeatedly updating
3216 * it and spamming downstream accordingly with segment events */
3217 /* also mangle the edit list end time when fragmented with a single edit
3218 * list that may only cover any non-fragmented data */
3219 if ((stream->dummy_segment ||
3220 (qtdemux->fragmented && stream->n_segments == 1)) &&
3221 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3222 /* Update all dummy values to new duration */
3223 stream->segments[0].stop_time = duration;
3224 stream->segments[0].duration = duration;
3225 stream->segments[0].media_stop = duration;
3227 /* let downstream know we possibly have a new stop time */
3228 if (stream->segment_index != -1) {
3231 if (qtdemux->segment.rate >= 0) {
3232 pos = stream->segment.start;
3234 pos = stream->segment.stop;
3237 gst_qtdemux_stream_update_segment (qtdemux, stream,
3238 stream->segment_index, pos, NULL, NULL);
3246 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3247 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3248 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3249 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3252 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3254 gint32 data_offset = 0;
3256 guint32 flags = 0, first_flags = 0, samples_count = 0;
3259 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3260 QtDemuxSample *sample;
3261 gboolean ismv = FALSE;
3262 gint64 initial_offset;
3265 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3266 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3267 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3268 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3270 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3271 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3275 /* presence of stss or not can't really tell us much,
3276 * and flags and so on tend to be marginally reliable in these files */
3277 if (stream->subtype == FOURCC_soun) {
3278 GST_DEBUG_OBJECT (qtdemux,
3279 "sound track in fragmented file; marking all keyframes");
3280 stream->all_keyframe = TRUE;
3283 if (!gst_byte_reader_get_uint8 (trun, &version) ||
3284 !gst_byte_reader_get_uint24_be (trun, &flags))
3287 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3290 if (flags & TR_DATA_OFFSET) {
3291 /* note this is really signed */
3292 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3294 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3295 /* default base offset = first byte of moof */
3296 if (*base_offset == -1) {
3297 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3298 *base_offset = moof_offset;
3300 *running_offset = *base_offset + data_offset;
3302 /* if no offset at all, that would mean data starts at moof start,
3303 * which is a bit wrong and is ismv crappy way, so compensate
3304 * assuming data is in mdat following moof */
3305 if (*base_offset == -1) {
3306 *base_offset = moof_offset + moof_length + 8;
3307 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3310 if (*running_offset == -1)
3311 *running_offset = *base_offset;
3314 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3316 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3317 data_offset, flags, samples_count);
3319 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3320 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3321 GST_DEBUG_OBJECT (qtdemux,
3322 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3323 flags ^= TR_FIRST_SAMPLE_FLAGS;
3325 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3327 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3331 /* FIXME ? spec says other bits should also be checked to determine
3332 * entry size (and prefix size for that matter) */
3334 dur_offset = size_offset = 0;
3335 if (flags & TR_SAMPLE_DURATION) {
3336 GST_LOG_OBJECT (qtdemux, "entry duration present");
3337 dur_offset = entry_size;
3340 if (flags & TR_SAMPLE_SIZE) {
3341 GST_LOG_OBJECT (qtdemux, "entry size present");
3342 size_offset = entry_size;
3345 if (flags & TR_SAMPLE_FLAGS) {
3346 GST_LOG_OBJECT (qtdemux, "entry flags present");
3347 flags_offset = entry_size;
3350 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3351 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3352 ct_offset = entry_size;
3356 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3358 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3360 if (stream->n_samples + samples_count >=
3361 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3364 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3365 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3366 (stream->n_samples + samples_count) *
3367 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3369 /* create a new array of samples if it's the first sample parsed */
3370 if (stream->n_samples == 0) {
3371 g_assert (stream->samples == NULL);
3372 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3373 /* or try to reallocate it with space enough to insert the new samples */
3375 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3376 stream->n_samples + samples_count);
3377 if (stream->samples == NULL)
3380 if (qtdemux->fragment_start != -1) {
3381 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3382 qtdemux->fragment_start = -1;
3384 if (stream->n_samples == 0) {
3385 if (decode_ts > 0) {
3386 timestamp = decode_ts;
3387 } else if (stream->pending_seek != NULL) {
3388 /* if we don't have a timestamp from a tfdt box, we'll use the one
3389 * from the mfra seek table */
3390 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3391 GST_TIME_ARGS (stream->pending_seek->ts));
3393 /* FIXME: this is not fully correct, the timestamp refers to the random
3394 * access sample refered to in the tfra entry, which may not necessarily
3395 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3396 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3401 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3402 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3403 GST_TIME_ARGS (gst_ts));
3405 /* subsequent fragments extend stream */
3407 stream->samples[stream->n_samples - 1].timestamp +
3408 stream->samples[stream->n_samples - 1].duration;
3410 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3411 * difference (1 sec.) between decode_ts and timestamp, prefer the
3413 if (has_tfdt && !qtdemux->upstream_format_is_time
3414 && ABSDIFF (decode_ts, timestamp) >
3415 MAX (stream->duration_last_moof / 2,
3416 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3417 GST_INFO_OBJECT (qtdemux,
3418 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3419 ") are significantly different (more than %" GST_TIME_FORMAT
3420 "), using decode_ts",
3421 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3422 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3423 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3424 MAX (stream->duration_last_moof / 2,
3425 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3426 timestamp = decode_ts;
3429 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3430 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3431 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3435 initial_offset = *running_offset;
3437 sample = stream->samples + stream->n_samples;
3438 for (i = 0; i < samples_count; i++) {
3439 guint32 dur, size, sflags;
3442 /* first read sample data */
3443 if (flags & TR_SAMPLE_DURATION) {
3444 dur = QT_UINT32 (data + dur_offset);
3446 dur = d_sample_duration;
3448 if (flags & TR_SAMPLE_SIZE) {
3449 size = QT_UINT32 (data + size_offset);
3451 size = d_sample_size;
3453 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3455 sflags = first_flags;
3457 sflags = d_sample_flags;
3459 } else if (flags & TR_SAMPLE_FLAGS) {
3460 sflags = QT_UINT32 (data + flags_offset);
3462 sflags = d_sample_flags;
3465 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3466 /* Read offsets as signed numbers regardless of trun version as very
3467 * high offsets are unlikely and there are files out there that use
3468 * version=0 truns with negative offsets */
3469 ct = QT_UINT32 (data + ct_offset);
3471 /* FIXME: Set offset to 0 for "no decode samples". This needs
3472 * to be handled in a codec specific manner ideally. */
3473 if (ct == G_MININT32)
3480 /* fill the sample information */
3481 sample->offset = *running_offset;
3482 sample->pts_offset = ct;
3483 sample->size = size;
3484 sample->timestamp = timestamp;
3485 sample->duration = dur;
3486 /* sample-is-difference-sample */
3487 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3488 * now idea how it relates to bitfield other than massive LE/BE confusion */
3489 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3490 *running_offset += size;
3492 stream->duration_moof += dur;
3499 /* Shift PTS/DTS to allow for negative composition offsets while keeping
3500 * A/V sync in place. This is similar to the code handling ctts/cslg in the
3501 * non-fragmented case.
3504 stream->cslg_shift = -min_ct;
3506 stream->cslg_shift = 0;
3508 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
3509 stream->cslg_shift);
3511 /* Update total duration if needed */
3512 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3514 /* Pre-emptively figure out size of mdat based on trun information.
3515 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3516 * size, else we will still be able to use this when dealing with gap'ed
3518 qtdemux->mdatleft = *running_offset - initial_offset;
3519 qtdemux->mdatoffset = initial_offset;
3520 qtdemux->mdatsize = qtdemux->mdatleft;
3522 stream->n_samples += samples_count;
3523 stream->n_samples_moof += samples_count;
3525 if (stream->pending_seek != NULL)
3526 stream->pending_seek = NULL;
3532 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3537 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3543 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3544 "be larger than %uMB (broken file?)", stream->n_samples,
3545 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3550 /* find stream with @id */
3551 static inline QtDemuxStream *
3552 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3554 QtDemuxStream *stream;
3558 if (G_UNLIKELY (!id)) {
3559 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3563 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3564 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3565 if (stream->track_id == id)
3568 if (qtdemux->mss_mode) {
3569 /* mss should have only 1 stream anyway */
3570 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3577 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3578 guint32 * fragment_number)
3580 if (!gst_byte_reader_skip (mfhd, 4))
3582 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3587 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3593 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3594 QtDemuxStream ** stream, guint32 * default_sample_duration,
3595 guint32 * default_sample_size, guint32 * default_sample_flags,
3596 gint64 * base_offset)
3599 guint32 track_id = 0;
3601 if (!gst_byte_reader_skip (tfhd, 1) ||
3602 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3605 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3608 *stream = qtdemux_find_stream (qtdemux, track_id);
3609 if (G_UNLIKELY (!*stream))
3610 goto unknown_stream;
3612 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3613 *base_offset = qtdemux->moof_offset;
3615 if (flags & TF_BASE_DATA_OFFSET)
3616 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3619 /* obtain stream defaults */
3620 qtdemux_parse_trex (qtdemux, *stream,
3621 default_sample_duration, default_sample_size, default_sample_flags);
3623 (*stream)->stsd_sample_description_id =
3624 (*stream)->def_sample_description_index - 1;
3626 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3627 guint32 sample_description_index;
3628 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3630 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3633 if (qtdemux->mss_mode) {
3634 /* mss has no stsd entry */
3635 (*stream)->stsd_sample_description_id = 0;
3638 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3639 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3642 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3643 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3646 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3647 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3654 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3659 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3665 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3666 guint64 * decode_time)
3668 guint32 version = 0;
3670 if (!gst_byte_reader_get_uint32_be (br, &version))
3675 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3678 guint32 dec_time = 0;
3679 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3681 *decode_time = dec_time;
3684 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3691 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3696 /* Returns a pointer to a GstStructure containing the properties of
3697 * the stream sample identified by @sample_index. The caller must unref
3698 * the returned object after use. Returns NULL if unsuccessful. */
3699 static GstStructure *
3700 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3701 QtDemuxStream * stream, guint sample_index)
3703 QtDemuxCencSampleSetInfo *info = NULL;
3705 g_return_val_if_fail (stream != NULL, NULL);
3706 g_return_val_if_fail (stream->protected, NULL);
3707 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3709 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3711 /* Currently, cenc properties for groups of samples are not supported, so
3712 * simply return a copy of the default sample properties */
3713 return gst_structure_copy (info->default_properties);
3716 /* Parses the sizes of sample auxiliary information contained within a stream,
3717 * as given in a saiz box. Returns array of sample_count guint8 size values,
3718 * or NULL on failure */
3720 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3721 GstByteReader * br, guint32 * sample_count)
3725 guint8 default_info_size;
3727 g_return_val_if_fail (qtdemux != NULL, NULL);
3728 g_return_val_if_fail (stream != NULL, NULL);
3729 g_return_val_if_fail (br != NULL, NULL);
3730 g_return_val_if_fail (sample_count != NULL, NULL);
3732 if (!gst_byte_reader_get_uint32_be (br, &flags))
3736 /* aux_info_type and aux_info_type_parameter are ignored */
3737 if (!gst_byte_reader_skip (br, 8))
3741 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3743 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3745 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3747 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3750 if (default_info_size == 0) {
3751 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3755 info_sizes = g_new (guint8, *sample_count);
3756 memset (info_sizes, default_info_size, *sample_count);
3762 /* Parses the offset of sample auxiliary information contained within a stream,
3763 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3765 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3766 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3771 guint32 aux_info_type = 0;
3772 guint32 aux_info_type_parameter = 0;
3773 guint32 entry_count;
3776 const guint8 *aux_info_type_data = NULL;
3778 g_return_val_if_fail (qtdemux != NULL, FALSE);
3779 g_return_val_if_fail (stream != NULL, FALSE);
3780 g_return_val_if_fail (br != NULL, FALSE);
3781 g_return_val_if_fail (offset != NULL, FALSE);
3783 if (!gst_byte_reader_get_uint8 (br, &version))
3786 if (!gst_byte_reader_get_uint24_be (br, &flags))
3791 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3793 aux_info_type = QT_FOURCC (aux_info_type_data);
3795 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3797 } else if (stream->protected) {
3798 aux_info_type = stream->protection_scheme_type;
3800 aux_info_type = CUR_STREAM (stream)->fourcc;
3804 *info_type = aux_info_type;
3805 if (info_type_parameter)
3806 *info_type_parameter = aux_info_type_parameter;
3808 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3809 "aux_info_type_parameter: %#06x",
3810 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3812 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3815 if (entry_count != 1) {
3816 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3821 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3823 *offset = (guint64) off_32;
3825 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3830 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3835 qtdemux_gst_structure_free (GstStructure * gststructure)
3838 gst_structure_free (gststructure);
3842 /* Parses auxiliary information relating to samples protected using
3843 * Common Encryption (cenc); the format of this information
3844 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3847 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3848 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3850 QtDemuxCencSampleSetInfo *ss_info = NULL;
3853 GPtrArray *old_crypto_info = NULL;
3854 guint old_entries = 0;
3856 g_return_val_if_fail (qtdemux != NULL, FALSE);
3857 g_return_val_if_fail (stream != NULL, FALSE);
3858 g_return_val_if_fail (br != NULL, FALSE);
3859 g_return_val_if_fail (stream->protected, FALSE);
3860 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3862 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3864 if (ss_info->crypto_info) {
3865 old_crypto_info = ss_info->crypto_info;
3866 /* Count number of non-null entries remaining at the tail end */
3867 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3868 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3874 ss_info->crypto_info =
3875 g_ptr_array_new_full (sample_count + old_entries,
3876 (GDestroyNotify) qtdemux_gst_structure_free);
3878 /* We preserve old entries because we parse the next moof in advance
3879 * of consuming all samples from the previous moof, and otherwise
3880 * we'd discard the corresponding crypto info for the samples
3881 * from the previous fragment. */
3883 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3885 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3886 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3888 g_ptr_array_index (old_crypto_info, i) = NULL;
3892 if (old_crypto_info) {
3893 /* Everything now belongs to the new array */
3894 g_ptr_array_free (old_crypto_info, TRUE);
3897 for (i = 0; i < sample_count; ++i) {
3898 GstStructure *properties;
3899 guint16 n_subsamples = 0;
3903 gboolean could_read_iv;
3905 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3906 if (properties == NULL) {
3907 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3910 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3911 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3912 gst_structure_free (properties);
3916 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3917 if (could_read_iv) {
3918 buf = gst_buffer_new_wrapped (data, iv_size);
3919 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3920 gst_buffer_unref (buf);
3921 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3922 const GValue *constant_iv_size_value =
3923 gst_structure_get_value (properties, "constant_iv_size");
3924 const GValue *constant_iv_value =
3925 gst_structure_get_value (properties, "iv");
3926 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3927 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3928 gst_structure_free (properties);
3931 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3932 gst_structure_remove_field (properties, "constant_iv_size");
3933 } else if (stream->protection_scheme_type == FOURCC_cenc) {
3934 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3935 gst_structure_free (properties);
3938 size = info_sizes[i];
3939 if (size > iv_size) {
3940 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3941 || !(n_subsamples > 0)) {
3942 gst_structure_free (properties);
3943 GST_ERROR_OBJECT (qtdemux,
3944 "failed to get subsample count for sample %u", i);
3947 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3948 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3949 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3951 gst_structure_free (properties);
3954 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3956 gst_structure_free (properties);
3959 gst_structure_set (properties,
3960 "subsample_count", G_TYPE_UINT, n_subsamples,
3961 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3962 gst_buffer_unref (buf);
3964 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3966 g_ptr_array_add (ss_info->crypto_info, properties);
3971 /* Converts a UUID in raw byte form to a string representation, as defined in
3972 * RFC 4122. The caller takes ownership of the returned string and is
3973 * responsible for freeing it after use. */
3975 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3977 const guint8 *uuid = (const guint8 *) uuid_bytes;
3979 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3980 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3981 uuid[0], uuid[1], uuid[2], uuid[3],
3982 uuid[4], uuid[5], uuid[6], uuid[7],
3983 uuid[8], uuid[9], uuid[10], uuid[11],
3984 uuid[12], uuid[13], uuid[14], uuid[15]);
3987 /* Parses a Protection System Specific Header box (pssh), as defined in the
3988 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3989 * information needed by a specific content protection system in order to
3990 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3993 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3995 gchar *sysid_string;
3996 guint32 pssh_size = QT_UINT32 (node->data);
3997 GstBuffer *pssh = NULL;
3998 GstEvent *event = NULL;
3999 guint32 parent_box_type;
4002 if (G_UNLIKELY (pssh_size < 32U)) {
4003 GST_ERROR_OBJECT (qtdemux, "invalid box size");
4008 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4010 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4012 pssh = gst_buffer_new_memdup (node->data, pssh_size);
4013 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4014 gst_buffer_get_size (pssh));
4016 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4018 /* Push an event containing the pssh box onto the queues of all streams. */
4019 event = gst_event_new_protection (sysid_string, pssh,
4020 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4021 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4022 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4023 GST_TRACE_OBJECT (qtdemux,
4024 "adding protection event for stream %s and system %s",
4025 stream->stream_id, sysid_string);
4026 g_queue_push_tail (&stream->protection_scheme_event_queue,
4027 gst_event_ref (event));
4029 g_free (sysid_string);
4030 gst_event_unref (event);
4031 gst_buffer_unref (pssh);
4036 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4037 guint64 moof_offset, QtDemuxStream * stream)
4039 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4041 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4042 GNode *saiz_node, *saio_node, *pssh_node;
4043 GstByteReader saiz_data, saio_data;
4044 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4045 gint64 base_offset, running_offset;
4047 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4049 /* NOTE @stream ignored */
4051 moof_node = g_node_new ((guint8 *) buffer);
4052 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4053 qtdemux_node_dump (qtdemux, moof_node);
4055 /* Get fragment number from mfhd and check it's valid */
4057 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4058 if (mfhd_node == NULL)
4060 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4062 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4064 /* unknown base_offset to start with */
4065 base_offset = running_offset = -1;
4066 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4068 guint64 decode_time = 0;
4070 /* Fragment Header node */
4072 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4076 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4077 &ds_size, &ds_flags, &base_offset))
4080 /* The following code assumes at most a single set of sample auxiliary
4081 * data in the fragment (consisting of a saiz box and a corresponding saio
4082 * box); in theory, however, there could be multiple sets of sample
4083 * auxiliary data in a fragment. */
4085 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4088 guint32 info_type = 0;
4090 guint32 info_type_parameter = 0;
4092 g_free (qtdemux->cenc_aux_info_sizes);
4094 qtdemux->cenc_aux_info_sizes =
4095 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4096 &qtdemux->cenc_aux_sample_count);
4097 if (qtdemux->cenc_aux_info_sizes == NULL) {
4098 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4102 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4105 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4106 g_free (qtdemux->cenc_aux_info_sizes);
4107 qtdemux->cenc_aux_info_sizes = NULL;
4111 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4112 &info_type, &info_type_parameter, &offset))) {
4113 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4114 g_free (qtdemux->cenc_aux_info_sizes);
4115 qtdemux->cenc_aux_info_sizes = NULL;
4118 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4119 offset += (guint64) (base_offset - qtdemux->moof_offset);
4120 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4121 && info_type_parameter == 0U) {
4123 if (offset > length) {
4124 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4125 qtdemux->cenc_aux_info_offset = offset;
4127 gst_byte_reader_init (&br, buffer + offset, length - offset);
4128 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4129 qtdemux->cenc_aux_info_sizes,
4130 qtdemux->cenc_aux_sample_count)) {
4131 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4132 g_free (qtdemux->cenc_aux_info_sizes);
4133 qtdemux->cenc_aux_info_sizes = NULL;
4141 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4144 /* We'll use decode_time to interpolate timestamps
4145 * in case the input timestamps are missing */
4146 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4148 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4149 " (%" GST_TIME_FORMAT ")", decode_time,
4150 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4151 decode_time) : GST_CLOCK_TIME_NONE));
4153 /* Discard the fragment buffer timestamp info to avoid using it.
4154 * Rely on tfdt instead as it is more accurate than the timestamp
4155 * that is fetched from a manifest/playlist and is usually
4157 qtdemux->fragment_start = -1;
4160 if (G_UNLIKELY (!stream)) {
4161 /* we lost track of offset, we'll need to regain it,
4162 * but can delay complaining until later or avoid doing so altogether */
4166 if (G_UNLIKELY (base_offset < -1))
4169 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4171 if (!qtdemux->pullbased) {
4172 /* Sample tables can grow enough to be problematic if the system memory
4173 * is very low (e.g. embedded devices) and the videos very long
4174 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4175 * Fortunately, we can easily discard them for each new fragment when
4176 * we know qtdemux will not receive seeks outside of the current fragment.
4177 * adaptivedemux honors this assumption.
4178 * This optimization is also useful for applications that use qtdemux as
4179 * a push-based simple demuxer, like Media Source Extensions. */
4180 gst_qtdemux_stream_flush_samples_data (stream);
4183 /* initialise moof sample data */
4184 stream->n_samples_moof = 0;
4185 stream->duration_last_moof = stream->duration_moof;
4186 stream->duration_moof = 0;
4188 /* Track Run node */
4190 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4193 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4194 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4195 &running_offset, decode_time, (tfdt_node != NULL));
4196 /* iterate all siblings */
4197 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4199 /* don't use tfdt for subsequent trun as it only refers to the first */
4203 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4205 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4206 guint32 box_length = QT_UINT32 (uuid_buffer);
4208 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4211 /* if no new base_offset provided for next traf,
4212 * base is end of current traf */
4213 base_offset = running_offset;
4214 running_offset = -1;
4216 if (stream->n_samples_moof && stream->duration_moof)
4217 stream->new_caps = TRUE;
4220 /* iterate all siblings */
4221 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4224 /* parse any protection system info */
4225 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4227 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4228 qtdemux_parse_pssh (qtdemux, pssh_node);
4229 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4232 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4233 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4235 /* Unless the user has explicitly requested another seek, perform an
4236 * internal seek to the time specified in the tfdt.
4238 * This way if the user opens a file where the first tfdt is 1 hour
4239 * into the presentation, they will not have to wait 1 hour for run
4240 * time to catch up and actual playback to start. */
4243 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4244 "performing an internal seek to %" GST_TIME_FORMAT,
4245 GST_TIME_ARGS (min_dts));
4247 qtdemux->segment.start = min_dts;
4248 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4250 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4251 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4252 stream->time_position = min_dts;
4255 /* Before this code was run a segment was already sent when the moov was
4256 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4257 * be emitted after a moov, and we can emit a second segment anyway for
4258 * special cases like this. */
4259 qtdemux->need_segment = TRUE;
4262 qtdemux->first_moof_already_parsed = TRUE;
4264 g_node_destroy (moof_node);
4269 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4274 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4279 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4284 g_node_destroy (moof_node);
4285 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4286 (_("This file is corrupt and cannot be played.")), (NULL));
4292 /* might be used if some day we actually use mfra & co
4293 * for random access to fragments,
4294 * but that will require quite some modifications and much less relying
4295 * on a sample array */
4299 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4301 QtDemuxStream *stream;
4302 guint32 ver_flags, track_id, len, num_entries, i;
4303 guint value_size, traf_size, trun_size, sample_size;
4304 guint64 time = 0, moof_offset = 0;
4306 GstBuffer *buf = NULL;
4311 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4313 if (!gst_byte_reader_skip (&tfra, 8))
4316 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4319 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4320 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4321 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4324 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4326 stream = qtdemux_find_stream (qtdemux, track_id);
4328 goto unknown_trackid;
4330 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4331 sample_size = (len & 3) + 1;
4332 trun_size = ((len & 12) >> 2) + 1;
4333 traf_size = ((len & 48) >> 4) + 1;
4335 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4336 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4338 if (num_entries == 0)
4341 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4342 value_size + value_size + traf_size + trun_size + sample_size))
4345 g_free (stream->ra_entries);
4346 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4347 stream->n_ra_entries = num_entries;
4349 for (i = 0; i < num_entries; i++) {
4350 qt_atom_parser_get_offset (&tfra, value_size, &time);
4351 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4352 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4353 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4354 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4356 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4358 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4359 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4361 stream->ra_entries[i].ts = time;
4362 stream->ra_entries[i].moof_offset = moof_offset;
4364 /* don't want to go through the entire file and read all moofs at startup */
4366 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4367 if (ret != GST_FLOW_OK)
4369 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4370 moof_offset, stream);
4371 gst_buffer_unref (buf);
4375 check_update_duration (qtdemux, time);
4382 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4387 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4392 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4398 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4400 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4401 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4402 GstBuffer *mfro = NULL, *mfra = NULL;
4404 gboolean ret = FALSE;
4405 GNode *mfra_node, *tfra_node;
4406 guint64 mfra_offset = 0;
4407 guint32 fourcc, mfra_size;
4410 /* query upstream size in bytes */
4411 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4412 goto size_query_failed;
4414 /* mfro box should be at the very end of the file */
4415 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4416 if (flow != GST_FLOW_OK)
4419 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4421 fourcc = QT_FOURCC (mfro_map.data + 4);
4422 if (fourcc != FOURCC_mfro)
4425 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4426 if (mfro_map.size < 16)
4427 goto invalid_mfro_size;
4429 mfra_size = QT_UINT32 (mfro_map.data + 12);
4430 if (mfra_size >= len)
4431 goto invalid_mfra_size;
4433 mfra_offset = len - mfra_size;
4435 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4436 mfra_offset, mfra_size);
4438 /* now get and parse mfra box */
4439 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4440 if (flow != GST_FLOW_OK)
4443 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4445 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4446 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4448 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4451 qtdemux_parse_tfra (qtdemux, tfra_node);
4452 /* iterate all siblings */
4453 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4455 g_node_destroy (mfra_node);
4457 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4463 if (mfro_map.memory != NULL)
4464 gst_buffer_unmap (mfro, &mfro_map);
4465 gst_buffer_unref (mfro);
4468 if (mfra_map.memory != NULL)
4469 gst_buffer_unmap (mfra, &mfra_map);
4470 gst_buffer_unref (mfra);
4477 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4482 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4487 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4492 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4498 add_offset (guint64 offset, guint64 advance)
4500 /* Avoid 64-bit overflow by clamping */
4501 if (offset > G_MAXUINT64 - advance)
4503 return offset + advance;
4506 static GstFlowReturn
4507 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4511 GstBuffer *buf = NULL;
4512 GstFlowReturn ret = GST_FLOW_OK;
4513 guint64 cur_offset = qtdemux->offset;
4516 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4517 if (G_UNLIKELY (ret != GST_FLOW_OK))
4519 gst_buffer_map (buf, &map, GST_MAP_READ);
4520 if (G_LIKELY (map.size >= 8))
4521 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4522 gst_buffer_unmap (buf, &map);
4523 gst_buffer_unref (buf);
4525 /* maybe we already got most we needed, so only consider this eof */
4526 if (G_UNLIKELY (length == 0)) {
4527 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4528 (_("Invalid atom size.")),
4529 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4530 GST_FOURCC_ARGS (fourcc)));
4537 /* record for later parsing when needed */
4538 if (!qtdemux->moof_offset) {
4539 qtdemux->moof_offset = qtdemux->offset;
4541 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4544 qtdemux->offset += length; /* skip moof and keep going */
4546 if (qtdemux->got_moov) {
4547 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4559 GST_LOG_OBJECT (qtdemux,
4560 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4561 GST_FOURCC_ARGS (fourcc), cur_offset);
4562 qtdemux->offset = add_offset (qtdemux->offset, length);
4567 GstBuffer *moov = NULL;
4569 if (qtdemux->got_moov) {
4570 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4571 qtdemux->offset = add_offset (qtdemux->offset, length);
4575 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4576 if (ret != GST_FLOW_OK)
4578 gst_buffer_map (moov, &map, GST_MAP_READ);
4580 if (length != map.size) {
4581 /* Some files have a 'moov' atom at the end of the file which contains
4582 * a terminal 'free' atom where the body of the atom is missing.
4583 * Check for, and permit, this special case.
4585 if (map.size >= 8) {
4586 guint8 *final_data = map.data + (map.size - 8);
4587 guint32 final_length = QT_UINT32 (final_data);
4588 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4590 if (final_fourcc == FOURCC_free
4591 && map.size + final_length - 8 == length) {
4592 /* Ok, we've found that special case. Allocate a new buffer with
4593 * that free atom actually present. */
4594 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4595 gst_buffer_fill (newmoov, 0, map.data, map.size);
4596 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4597 gst_buffer_unmap (moov, &map);
4598 gst_buffer_unref (moov);
4600 gst_buffer_map (moov, &map, GST_MAP_READ);
4605 if (length != map.size) {
4606 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4607 (_("This file is incomplete and cannot be played.")),
4608 ("We got less than expected (received %" G_GSIZE_FORMAT
4609 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4610 (guint) length, cur_offset));
4611 gst_buffer_unmap (moov, &map);
4612 gst_buffer_unref (moov);
4613 ret = GST_FLOW_ERROR;
4616 qtdemux->offset += length;
4618 qtdemux_parse_moov (qtdemux, map.data, length);
4619 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4621 qtdemux_parse_tree (qtdemux);
4622 if (qtdemux->moov_node_compressed) {
4623 g_node_destroy (qtdemux->moov_node_compressed);
4624 g_free (qtdemux->moov_node->data);
4626 qtdemux->moov_node_compressed = NULL;
4627 g_node_destroy (qtdemux->moov_node);
4628 qtdemux->moov_node = NULL;
4629 gst_buffer_unmap (moov, &map);
4630 gst_buffer_unref (moov);
4631 qtdemux->got_moov = TRUE;
4637 GstBuffer *ftyp = NULL;
4639 /* extract major brand; might come in handy for ISO vs QT issues */
4640 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4641 if (ret != GST_FLOW_OK)
4643 qtdemux->offset += length;
4644 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4645 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4646 gst_buffer_unmap (ftyp, &map);
4647 gst_buffer_unref (ftyp);
4652 GstBuffer *styp = NULL;
4654 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &styp);
4655 if (ret != GST_FLOW_OK)
4657 qtdemux->offset += length;
4658 gst_buffer_map (styp, &map, GST_MAP_READ);
4659 qtdemux_parse_styp (qtdemux, map.data, map.size);
4660 gst_buffer_unmap (styp, &map);
4661 gst_buffer_unref (styp);
4666 GstBuffer *uuid = NULL;
4668 /* uuid are extension atoms */
4669 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4670 if (ret != GST_FLOW_OK)
4672 qtdemux->offset += length;
4673 gst_buffer_map (uuid, &map, GST_MAP_READ);
4674 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4675 gst_buffer_unmap (uuid, &map);
4676 gst_buffer_unref (uuid);
4681 GstBuffer *sidx = NULL;
4682 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4683 if (ret != GST_FLOW_OK)
4685 qtdemux->offset += length;
4686 gst_buffer_map (sidx, &map, GST_MAP_READ);
4687 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4688 gst_buffer_unmap (sidx, &map);
4689 gst_buffer_unref (sidx);
4694 GstBuffer *unknown = NULL;
4696 GST_LOG_OBJECT (qtdemux,
4697 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4698 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4700 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4701 if (ret != GST_FLOW_OK)
4703 gst_buffer_map (unknown, &map, GST_MAP_READ);
4704 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4705 gst_buffer_unmap (unknown, &map);
4706 gst_buffer_unref (unknown);
4707 qtdemux->offset += length;
4713 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4714 /* digested all data, show what we have */
4715 qtdemux_prepare_streams (qtdemux);
4716 QTDEMUX_EXPOSE_LOCK (qtdemux);
4717 ret = qtdemux_expose_streams (qtdemux);
4718 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4720 qtdemux->state = QTDEMUX_STATE_MOVIE;
4721 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4728 /* Seeks to the previous keyframe of the indexed stream and
4729 * aligns other streams with respect to the keyframe timestamp
4730 * of indexed stream. Only called in case of Reverse Playback
4732 static GstFlowReturn
4733 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4735 guint32 seg_idx = 0, k_index = 0;
4736 guint32 ref_seg_idx, ref_k_index;
4737 GstClockTime k_pos = 0, last_stop = 0;
4738 QtDemuxSegment *seg = NULL;
4739 QtDemuxStream *ref_str = NULL;
4740 guint64 seg_media_start_mov; /* segment media start time in mov format */
4744 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4745 * and finally align all the other streams on that timestamp with their
4746 * respective keyframes */
4747 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4748 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4750 /* No candidate yet, take the first stream */
4756 /* So that stream has a segment, we prefer video streams */
4757 if (str->subtype == FOURCC_vide) {
4763 if (G_UNLIKELY (!ref_str)) {
4764 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4768 if (G_UNLIKELY (!ref_str->from_sample)) {
4769 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4773 /* So that stream has been playing from from_sample to to_sample. We will
4774 * get the timestamp of the previous sample and search for a keyframe before
4775 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4776 if (ref_str->subtype == FOURCC_vide) {
4777 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4778 ref_str->from_sample - 1, FALSE);
4780 if (ref_str->from_sample >= 10)
4781 k_index = ref_str->from_sample - 10;
4787 ref_str->samples[k_index].timestamp +
4788 ref_str->samples[k_index].pts_offset;
4790 /* get current segment for that stream */
4791 seg = &ref_str->segments[ref_str->segment_index];
4792 /* Use segment start in original timescale for comparisons */
4793 seg_media_start_mov = seg->trak_media_start;
4795 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4796 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4797 k_index, target_ts, seg_media_start_mov,
4798 GST_TIME_ARGS (seg->media_start));
4800 /* Crawl back through segments to find the one containing this I frame */
4801 while (target_ts < seg_media_start_mov) {
4802 GST_DEBUG_OBJECT (qtdemux,
4803 "keyframe position (sample %u) is out of segment %u " " target %"
4804 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4805 ref_str->segment_index, target_ts, seg_media_start_mov);
4807 if (G_UNLIKELY (!ref_str->segment_index)) {
4808 /* Reached first segment, let's consider it's EOS */
4811 ref_str->segment_index--;
4812 seg = &ref_str->segments[ref_str->segment_index];
4813 /* Use segment start in original timescale for comparisons */
4814 seg_media_start_mov = seg->trak_media_start;
4816 /* Calculate time position of the keyframe and where we should stop */
4818 QTSTREAMTIME_TO_GSTTIME (ref_str,
4819 target_ts - seg->trak_media_start) + seg->time;
4821 QTSTREAMTIME_TO_GSTTIME (ref_str,
4822 ref_str->samples[ref_str->from_sample].timestamp -
4823 seg->trak_media_start) + seg->time;
4825 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4826 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4827 k_index, GST_TIME_ARGS (k_pos));
4829 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4830 qtdemux->segment.position = last_stop;
4831 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4832 GST_TIME_ARGS (last_stop));
4834 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4835 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4839 ref_seg_idx = ref_str->segment_index;
4840 ref_k_index = k_index;
4842 /* Align them all on this */
4843 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4845 GstClockTime seg_time = 0;
4846 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4848 /* aligning reference stream again might lead to backing up to yet another
4849 * keyframe (due to timestamp rounding issues),
4850 * potentially putting more load on downstream; so let's try to avoid */
4851 if (str == ref_str) {
4852 seg_idx = ref_seg_idx;
4853 seg = &str->segments[seg_idx];
4854 k_index = ref_k_index;
4855 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4856 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4858 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4859 GST_DEBUG_OBJECT (qtdemux,
4860 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4861 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4863 /* get segment and time in the segment */
4864 seg = &str->segments[seg_idx];
4865 seg_time = k_pos - seg->time;
4867 /* get the media time in the segment.
4868 * No adjustment for empty "filler" segments */
4869 if (seg->media_start != GST_CLOCK_TIME_NONE)
4870 seg_time += seg->media_start;
4872 /* get the index of the sample with media time */
4873 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4874 GST_DEBUG_OBJECT (qtdemux,
4875 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4876 GST_TIME_ARGS (seg_time), index);
4878 /* find previous keyframe */
4879 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4882 /* Remember until where we want to go */
4883 str->to_sample = str->from_sample - 1;
4884 /* Define our time position */
4886 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4887 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4888 if (seg->media_start != GST_CLOCK_TIME_NONE)
4889 str->time_position -= seg->media_start;
4891 /* Now seek back in time */
4892 gst_qtdemux_move_stream (qtdemux, str, k_index);
4893 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4894 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4895 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4901 return GST_FLOW_EOS;
4905 * Gets the current qt segment start, stop and position for the
4906 * given time offset. This is used in update_segment()
4909 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4910 QtDemuxStream * stream, GstClockTime offset,
4911 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4913 GstClockTime seg_time;
4914 GstClockTime start, stop, time;
4915 QtDemuxSegment *segment;
4917 segment = &stream->segments[stream->segment_index];
4919 /* get time in this segment */
4920 seg_time = (offset - segment->time) * segment->rate;
4922 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4923 GST_TIME_ARGS (seg_time));
4925 if (G_UNLIKELY (seg_time > segment->duration)) {
4926 GST_LOG_OBJECT (stream->pad,
4927 "seg_time > segment->duration %" GST_TIME_FORMAT,
4928 GST_TIME_ARGS (segment->duration));
4929 seg_time = segment->duration;
4932 /* qtdemux->segment.stop is in outside-time-realm, whereas
4933 * segment->media_stop is in track-time-realm.
4935 * In order to compare the two, we need to bring segment.stop
4936 * into the track-time-realm
4938 * FIXME - does this comment still hold? Don't see any conversion here */
4940 stop = qtdemux->segment.stop;
4941 if (stop == GST_CLOCK_TIME_NONE)
4942 stop = qtdemux->segment.duration;
4943 if (stop == GST_CLOCK_TIME_NONE)
4944 stop = segment->media_stop;
4947 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4949 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4950 start = segment->time + seg_time;
4952 stop = start - seg_time + segment->duration;
4953 } else if (qtdemux->segment.rate >= 0) {
4954 start = MIN (segment->media_start + seg_time, stop);
4957 if (segment->media_start >= qtdemux->segment.start) {
4958 time = segment->time;
4960 time = segment->time + (qtdemux->segment.start - segment->media_start);
4963 start = MAX (segment->media_start, qtdemux->segment.start);
4964 stop = MIN (segment->media_start + seg_time, stop);
4973 * Updates the qt segment used for the stream and pushes a new segment event
4974 * downstream on this stream's pad.
4977 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4978 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4979 GstClockTime * _stop)
4981 QtDemuxSegment *segment;
4982 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4986 /* update the current segment */
4987 stream->segment_index = seg_idx;
4989 /* get the segment */
4990 segment = &stream->segments[seg_idx];
4992 if (G_UNLIKELY (offset < segment->time)) {
4993 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4994 GST_TIME_ARGS (segment->time));
4998 /* segment lies beyond total indicated duration */
4999 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5000 segment->time > qtdemux->segment.duration)) {
5001 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5002 " < segment->time %" GST_TIME_FORMAT,
5003 GST_TIME_ARGS (qtdemux->segment.duration),
5004 GST_TIME_ARGS (segment->time));
5008 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5009 &start, &stop, &time);
5011 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5012 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5013 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5015 /* combine global rate with that of the segment */
5016 rate = segment->rate * qtdemux->segment.rate;
5018 /* Copy flags from main segment */
5019 stream->segment.flags = qtdemux->segment.flags;
5021 /* update the segment values used for clipping */
5022 stream->segment.offset = qtdemux->segment.offset;
5023 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5024 stream->segment.applied_rate = qtdemux->segment.applied_rate;
5025 stream->segment.rate = rate;
5026 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5027 stream->cslg_shift);
5029 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5030 stream->cslg_shift);
5032 stream->segment.stop = stop;
5033 stream->segment.time = time;
5034 stream->segment.position = stream->segment.start;
5036 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5039 /* now prepare and send the segment */
5041 event = gst_event_new_segment (&stream->segment);
5042 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5043 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5045 gst_pad_push_event (stream->pad, event);
5046 /* assume we can send more data now */
5047 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5048 /* clear to send tags on this pad now */
5049 gst_qtdemux_push_tags (qtdemux, stream);
5060 /* activate the given segment number @seg_idx of @stream at time @offset.
5061 * @offset is an absolute global position over all the segments.
5063 * This will push out a NEWSEGMENT event with the right values and
5064 * position the stream index to the first decodable sample before
5068 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5069 guint32 seg_idx, GstClockTime offset)
5071 QtDemuxSegment *segment;
5072 guint32 index, kf_index;
5073 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5075 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5076 seg_idx, GST_TIME_ARGS (offset));
5078 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5082 segment = &stream->segments[stream->segment_index];
5084 /* in the fragmented case, we pick a fragment that starts before our
5085 * desired position and rely on downstream to wait for a keyframe
5086 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5087 * tfra entries tells us which trun/sample the key unit is in, but we don't
5088 * make use of this additional information at the moment) */
5089 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5090 stream->to_sample = G_MAXUINT32;
5093 /* well, it will be taken care of below */
5094 qtdemux->fragmented_seek_pending = FALSE;
5095 /* FIXME ideally the do_fragmented_seek can be done right here,
5096 * rather than at loop level
5097 * (which might even allow handling edit lists in a fragmented file) */
5100 /* We don't need to look for a sample in push-based */
5101 if (!qtdemux->pullbased)
5104 /* and move to the keyframe before the indicated media time of the
5106 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5107 if (qtdemux->segment.rate >= 0) {
5108 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5109 stream->to_sample = G_MAXUINT32;
5110 GST_DEBUG_OBJECT (stream->pad,
5111 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5112 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5113 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5115 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5116 stream->to_sample = index;
5117 GST_DEBUG_OBJECT (stream->pad,
5118 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5119 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5120 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5123 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5124 "this is an empty segment");
5128 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5129 * encountered an error and printed a message so we return appropriately */
5133 /* we're at the right spot */
5134 if (index == stream->sample_index) {
5135 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5139 /* find keyframe of the target index */
5140 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5142 /* go back two frames to provide lead-in for non-raw audio decoders */
5143 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5144 guint32 lead_in = 2;
5145 guint32 old_index = kf_index;
5146 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5148 if (gst_structure_has_name (s, "audio/mpeg")) {
5150 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5151 && mpegversion == 1) {
5152 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5157 kf_index = MAX (kf_index, lead_in) - lead_in;
5158 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5159 GST_DEBUG_OBJECT (stream->pad,
5160 "Moving backwards %u frames to ensure sufficient sound lead-in",
5161 old_index - kf_index);
5163 kf_index = old_index;
5167 /* if we move forwards, we don't have to go back to the previous
5168 * keyframe since we already sent that. We can also just jump to
5169 * the keyframe right before the target index if there is one. */
5170 if (index > stream->sample_index) {
5171 /* moving forwards check if we move past a keyframe */
5172 if (kf_index > stream->sample_index) {
5173 GST_DEBUG_OBJECT (stream->pad,
5174 "moving forwards to keyframe at %u "
5175 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5177 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5178 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5179 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5181 GST_DEBUG_OBJECT (stream->pad,
5182 "moving forwards, keyframe at %u "
5183 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5185 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5186 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5189 GST_DEBUG_OBJECT (stream->pad,
5190 "moving backwards to %sframe at %u "
5191 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5192 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5193 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5194 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5195 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5201 /* prepare to get the current sample of @stream, getting essential values.
5203 * This function will also prepare and send the segment when needed.
5205 * Return FALSE if the stream is EOS.
5210 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5211 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5212 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5213 gboolean * keyframe)
5215 QtDemuxSample *sample;
5216 GstClockTime time_position;
5219 g_return_val_if_fail (stream != NULL, FALSE);
5221 time_position = stream->time_position;
5222 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5225 seg_idx = stream->segment_index;
5226 if (G_UNLIKELY (seg_idx == -1)) {
5227 /* find segment corresponding to time_position if we are looking
5229 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5232 /* different segment, activate it, sample_index will be set. */
5233 if (G_UNLIKELY (stream->segment_index != seg_idx))
5234 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5236 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5237 segments[stream->segment_index]))) {
5238 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5240 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5241 " prepare empty sample");
5244 *pts = *dts = time_position;
5245 *duration = seg->duration - (time_position - seg->time);
5252 if (stream->sample_index == -1)
5253 stream->sample_index = 0;
5255 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5256 stream->sample_index, stream->n_samples);
5258 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5259 if (!qtdemux->fragmented)
5262 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5266 GST_OBJECT_LOCK (qtdemux);
5267 flow = qtdemux_add_fragmented_samples (qtdemux);
5268 GST_OBJECT_UNLOCK (qtdemux);
5270 if (flow != GST_FLOW_OK)
5273 while (stream->sample_index >= stream->n_samples);
5276 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5277 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5278 stream->sample_index);
5282 /* now get the info for the sample we're at */
5283 sample = &stream->samples[stream->sample_index];
5285 *dts = QTSAMPLE_DTS (stream, sample);
5286 *pts = QTSAMPLE_PTS (stream, sample);
5287 *offset = sample->offset;
5288 *size = sample->size;
5289 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5290 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5297 stream->time_position = GST_CLOCK_TIME_NONE;
5302 /* move to the next sample in @stream.
5304 * Moves to the next segment when needed.
5307 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5309 QtDemuxSample *sample;
5310 QtDemuxSegment *segment;
5312 /* get current segment */
5313 segment = &stream->segments[stream->segment_index];
5315 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5316 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5320 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5321 /* Mark the stream as EOS */
5322 GST_DEBUG_OBJECT (qtdemux,
5323 "reached max allowed sample %u, mark EOS", stream->to_sample);
5324 stream->time_position = GST_CLOCK_TIME_NONE;
5328 /* move to next sample */
5329 stream->sample_index++;
5330 stream->offset_in_sample = 0;
5332 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5335 /* reached the last sample, we need the next segment */
5336 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5339 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5340 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5341 stream->sample_index);
5345 /* get next sample */
5346 sample = &stream->samples[stream->sample_index];
5348 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5349 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5350 GST_TIME_ARGS (segment->media_stop));
5352 /* see if we are past the segment */
5353 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5356 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5357 /* inside the segment, update time_position, looks very familiar to
5358 * GStreamer segments, doesn't it? */
5359 stream->time_position =
5360 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5362 /* not yet in segment, time does not yet increment. This means
5363 * that we are still prerolling keyframes to the decoder so it can
5364 * decode the first sample of the segment. */
5365 stream->time_position = segment->time;
5369 /* move to the next segment */
5372 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5374 if (stream->segment_index == stream->n_segments - 1) {
5375 /* are we at the end of the last segment, we're EOS */
5376 stream->time_position = GST_CLOCK_TIME_NONE;
5378 /* else we're only at the end of the current segment */
5379 stream->time_position = segment->stop_time;
5381 /* make sure we select a new segment */
5383 /* accumulate previous segments */
5384 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5385 stream->accumulated_base +=
5386 (stream->segment.stop -
5387 stream->segment.start) / ABS (stream->segment.rate);
5389 stream->segment_index = -1;
5394 gst_qtdemux_sync_streams (GstQTDemux * demux)
5398 if (QTDEMUX_N_STREAMS (demux) <= 1)
5401 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5402 QtDemuxStream *stream;
5403 GstClockTime end_time;
5405 stream = QTDEMUX_NTH_STREAM (demux, i);
5410 /* TODO advance time on subtitle streams here, if any some day */
5412 /* some clips/trailers may have unbalanced streams at the end,
5413 * so send EOS on shorter stream to prevent stalling others */
5415 /* do not mess with EOS if SEGMENT seeking */
5416 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5419 if (demux->pullbased) {
5420 /* loop mode is sample time based */
5421 if (!STREAM_IS_EOS (stream))
5424 /* push mode is byte position based */
5425 if (stream->n_samples &&
5426 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5430 if (stream->sent_eos)
5433 /* only act if some gap */
5434 end_time = stream->segments[stream->n_segments - 1].stop_time;
5435 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5436 ", stream end: %" GST_TIME_FORMAT,
5437 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5438 if (GST_CLOCK_TIME_IS_VALID (end_time)
5439 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5442 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5443 GST_PAD_NAME (stream->pad));
5444 stream->sent_eos = TRUE;
5445 event = gst_event_new_eos ();
5446 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5447 gst_event_set_seqnum (event, demux->segment_seqnum);
5448 gst_pad_push_event (stream->pad, event);
5453 /* EOS and NOT_LINKED need to be combined. This means that we return:
5455 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5456 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5458 static GstFlowReturn
5459 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5462 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5465 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5468 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5470 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5474 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5475 * completely clipped
5477 * Should be used only with raw buffers */
5479 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5482 guint64 start, stop, cstart, cstop, diff;
5483 GstClockTime pts, duration;
5485 gint num_rate, denom_rate;
5490 osize = size = gst_buffer_get_size (buf);
5493 /* depending on the type, setup the clip parameters */
5494 if (stream->subtype == FOURCC_soun) {
5495 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5496 num_rate = GST_SECOND;
5497 denom_rate = (gint) CUR_STREAM (stream)->rate;
5499 } else if (stream->subtype == FOURCC_vide) {
5501 num_rate = CUR_STREAM (stream)->fps_n;
5502 denom_rate = CUR_STREAM (stream)->fps_d;
5507 if (frame_size <= 0)
5508 goto bad_frame_size;
5510 /* we can only clip if we have a valid pts */
5511 pts = GST_BUFFER_PTS (buf);
5512 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5515 duration = GST_BUFFER_DURATION (buf);
5517 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5519 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5523 stop = start + duration;
5525 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5526 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5529 /* see if some clipping happened */
5530 diff = cstart - start;
5536 /* bring clipped time to samples and to bytes */
5537 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5540 GST_DEBUG_OBJECT (qtdemux,
5541 "clipping start to %" GST_TIME_FORMAT " %"
5542 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5548 diff = stop - cstop;
5553 /* bring clipped time to samples and then to bytes */
5554 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5556 GST_DEBUG_OBJECT (qtdemux,
5557 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5558 " bytes", GST_TIME_ARGS (cstop), diff);
5563 if (offset != 0 || size != osize)
5564 gst_buffer_resize (buf, offset, size);
5566 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5567 GST_BUFFER_PTS (buf) = pts;
5568 GST_BUFFER_DURATION (buf) = duration;
5572 /* dropped buffer */
5575 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5580 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5585 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5590 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5591 gst_buffer_unref (buf);
5597 gst_qtdemux_align_buffer (GstQTDemux * demux,
5598 GstBuffer * buffer, gsize alignment)
5602 gst_buffer_map (buffer, &map, GST_MAP_READ);
5604 if (map.size < sizeof (guintptr)) {
5605 gst_buffer_unmap (buffer, &map);
5609 if (((guintptr) map.data) & (alignment - 1)) {
5610 GstBuffer *new_buffer;
5611 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5613 new_buffer = gst_buffer_new_allocate (NULL,
5614 gst_buffer_get_size (buffer), ¶ms);
5616 /* Copy data "by hand", so ensure alignment is kept: */
5617 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5619 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5620 GST_DEBUG_OBJECT (demux,
5621 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5624 gst_buffer_unmap (buffer, &map);
5625 gst_buffer_unref (buffer);
5630 gst_buffer_unmap (buffer, &map);
5635 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5641 /* We are converting from pairs to triplets */
5642 *res = ccpair_size / 2 * 3;
5643 storage = g_malloc (*res);
5644 for (i = 0; i * 2 < ccpair_size; i += 1) {
5645 /* FIXME: Use line offset 0 as we simply can't know here */
5647 storage[i * 3] = 0x80 | 0x00;
5649 storage[i * 3] = 0x00 | 0x00;
5650 storage[i * 3 + 1] = ccpair[i * 2];
5651 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5658 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5662 guint32 atom_length, fourcc;
5663 QtDemuxStreamStsdEntry *stsd_entry;
5665 GST_MEMDUMP ("caption atom", data, size);
5667 /* There might be multiple atoms */
5672 atom_length = QT_UINT32 (data);
5673 fourcc = QT_FOURCC (data + 4);
5674 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5677 GST_DEBUG_OBJECT (stream->pad, "here");
5679 /* Check if we have something compatible */
5680 stsd_entry = CUR_STREAM (stream);
5681 switch (stsd_entry->fourcc) {
5683 guint8 *cdat = NULL, *cdt2 = NULL;
5684 gsize cdat_size = 0, cdt2_size = 0;
5685 /* Should be cdat or cdt2 */
5686 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5687 GST_WARNING_OBJECT (stream->pad,
5688 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5689 GST_FOURCC_ARGS (fourcc));
5693 /* Convert to S334-1 Annex A byte triplet */
5694 if (fourcc == FOURCC_cdat)
5695 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5697 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5698 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5701 /* Check for another atom ? */
5702 if (size > atom_length + 8) {
5703 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5704 if (size >= atom_length + new_atom_length) {
5705 fourcc = QT_FOURCC (data + atom_length + 4);
5706 if (fourcc == FOURCC_cdat) {
5709 convert_to_s334_1a (data + atom_length + 8,
5710 new_atom_length - 8, 1, &cdat_size);
5712 GST_WARNING_OBJECT (stream->pad,
5713 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5717 convert_to_s334_1a (data + atom_length + 8,
5718 new_atom_length - 8, 2, &cdt2_size);
5720 GST_WARNING_OBJECT (stream->pad,
5721 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5726 *cclen = cdat_size + cdt2_size;
5727 res = g_malloc (*cclen);
5729 memcpy (res, cdat, cdat_size);
5731 memcpy (res + cdat_size, cdt2, cdt2_size);
5737 if (fourcc != FOURCC_ccdp) {
5738 GST_WARNING_OBJECT (stream->pad,
5739 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5740 GST_FOURCC_ARGS (fourcc));
5743 *cclen = atom_length - 8;
5744 res = g_memdup2 (data + 8, *cclen);
5747 /* Keep this here in case other closed caption formats are added */
5748 g_assert_not_reached ();
5752 GST_MEMDUMP ("Output", res, *cclen);
5757 GST_WARNING ("[cdat] atom is too small or invalid");
5761 /* Handle Closed Caption sample buffers.
5762 * The input buffer metadata must be writable,
5763 * but time/duration etc not yet set and need not be preserved */
5765 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5768 GstBuffer *outbuf = NULL;
5773 gst_buffer_map (buf, &map, GST_MAP_READ);
5775 /* empty buffer is sent to terminate previous subtitle */
5776 if (map.size <= 2) {
5777 gst_buffer_unmap (buf, &map);
5778 gst_buffer_unref (buf);
5782 /* For closed caption, we need to extract the information from the
5783 * [cdat],[cdt2] or [ccdp] atom */
5784 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5785 gst_buffer_unmap (buf, &map);
5787 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5788 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5790 /* Conversion failed or there's nothing */
5792 gst_buffer_unref (buf);
5797 /* DVD subpicture specific sample handling.
5798 * the input buffer metadata must be writable,
5799 * but time/duration etc not yet set and need not be preserved */
5801 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5804 /* send a one time dvd clut event */
5805 if (stream->pending_event && stream->pad)
5806 gst_pad_push_event (stream->pad, stream->pending_event);
5807 stream->pending_event = NULL;
5809 /* empty buffer is sent to terminate previous subtitle */
5810 if (gst_buffer_get_size (buf) <= 2) {
5811 gst_buffer_unref (buf);
5815 /* That's all the processing needed for subpictures */
5819 /* Timed text formats
5820 * the input buffer metadata must be writable,
5821 * but time/duration etc not yet set and need not be preserved */
5823 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5826 GstBuffer *outbuf = NULL;
5831 /* not many cases for now */
5832 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5833 stream->subtype != FOURCC_sbtl)) {
5837 gst_buffer_map (buf, &map, GST_MAP_READ);
5839 /* empty buffer is sent to terminate previous subtitle */
5840 if (map.size <= 2) {
5841 gst_buffer_unmap (buf, &map);
5842 gst_buffer_unref (buf);
5846 nsize = GST_READ_UINT16_BE (map.data);
5847 nsize = MIN (nsize, map.size - 2);
5849 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5852 /* takes care of UTF-8 validation or UTF-16 recognition,
5853 * no other encoding expected */
5854 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5855 gst_buffer_unmap (buf, &map);
5858 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5859 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5861 /* this should not really happen unless the subtitle is corrupted */
5863 gst_buffer_unref (buf);
5865 /* FIXME ? convert optional subsequent style info to markup */
5870 /* WebVTT sample handling according to 14496-30 */
5872 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5875 GstBuffer *outbuf = NULL;
5878 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5879 g_assert_not_reached (); /* The buffer must be mappable */
5882 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5883 GstEvent *gap = NULL;
5884 /* Push a gap event */
5885 stream->segment.position = GST_BUFFER_PTS (buf);
5887 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5888 gst_pad_push_event (stream->pad, gap);
5890 if (GST_BUFFER_DURATION_IS_VALID (buf))
5891 stream->segment.position += GST_BUFFER_DURATION (buf);
5894 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5895 GST_BUFFER_DURATION (buf), map.data, map.size);
5896 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5899 gst_buffer_unmap (buf, &map);
5900 gst_buffer_unref (buf);
5905 static GstFlowReturn
5906 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5909 GstFlowReturn ret = GST_FLOW_OK;
5910 GstClockTime pts, duration;
5912 if (stream->need_clip)
5913 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5915 if (G_UNLIKELY (buf == NULL))
5918 if (G_UNLIKELY (stream->discont)) {
5919 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5920 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5921 stream->discont = FALSE;
5923 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5926 GST_LOG_OBJECT (qtdemux,
5927 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5928 ", duration %" GST_TIME_FORMAT " on pad %s",
5929 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5930 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5931 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5933 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5934 GstStructure *crypto_info;
5935 QtDemuxAavdEncryptionInfo *info =
5936 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5938 crypto_info = gst_structure_copy (info->default_properties);
5939 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5940 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5943 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
5944 || stream->protection_scheme_type == FOURCC_cbcs)) {
5945 GstStructure *crypto_info;
5946 QtDemuxCencSampleSetInfo *info =
5947 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5951 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5952 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5953 GST_PTR_FORMAT, event);
5954 gst_pad_push_event (stream->pad, event);
5957 if (info->crypto_info == NULL) {
5958 if (stream->protection_scheme_type == FOURCC_cbcs) {
5959 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
5960 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
5961 GST_ERROR_OBJECT (qtdemux,
5962 "failed to attach cbcs metadata to buffer");
5963 qtdemux_gst_structure_free (crypto_info);
5965 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
5968 GST_DEBUG_OBJECT (qtdemux,
5969 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5972 /* The end of the crypto_info array matches our n_samples position,
5973 * so count backward from there */
5974 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5975 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5976 /* steal structure from array */
5977 crypto_info = g_ptr_array_index (info->crypto_info, index);
5978 g_ptr_array_index (info->crypto_info, index) = NULL;
5979 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5980 info->crypto_info->len);
5981 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5982 GST_ERROR_OBJECT (qtdemux,
5983 "failed to attach cenc metadata to buffer");
5985 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5986 index, stream->sample_index);
5991 if (stream->alignment > 1)
5992 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5994 pts = GST_BUFFER_PTS (buf);
5995 duration = GST_BUFFER_DURATION (buf);
5997 ret = gst_pad_push (stream->pad, buf);
5999 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6000 /* mark position in stream, we'll need this to know when to send GAP event */
6001 stream->segment.position = pts + duration;
6009 static GstFlowReturn
6010 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6013 GstFlowReturn ret = GST_FLOW_OK;
6015 if (stream->subtype == FOURCC_clcp
6016 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6018 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6019 guint n_triplets, i;
6020 guint field1_off = 0, field2_off = 0;
6022 /* We have to split CEA608 buffers so that each outgoing buffer contains
6023 * one byte pair per field according to the framerate of the video track.
6025 * If there is only a single byte pair per field we don't have to do
6029 gst_buffer_map (buf, &map, GST_MAP_READ);
6031 n_triplets = map.size / 3;
6032 for (i = 0; i < n_triplets; i++) {
6033 if (map.data[3 * i] & 0x80)
6039 g_assert (n_field1 || n_field2);
6041 /* If there's more than 1 frame we have to split, otherwise we can just
6043 if (n_field1 > 1 || n_field2 > 1) {
6045 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6046 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6048 for (i = 0; i < n_output_buffers; i++) {
6050 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6054 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6055 outptr = outmap.data;
6058 gboolean found = FALSE;
6060 while (map.data + field1_off < map.data + map.size) {
6061 if (map.data[field1_off] & 0x80) {
6062 memcpy (outptr, &map.data[field1_off], 3);
6071 const guint8 empty[] = { 0x80, 0x80, 0x80 };
6073 memcpy (outptr, empty, 3);
6080 gboolean found = FALSE;
6082 while (map.data + field2_off < map.data + map.size) {
6083 if ((map.data[field2_off] & 0x80) == 0) {
6084 memcpy (outptr, &map.data[field2_off], 3);
6093 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6095 memcpy (outptr, empty, 3);
6101 gst_buffer_unmap (outbuf, &outmap);
6103 GST_BUFFER_PTS (outbuf) =
6104 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6105 GST_SECOND * CUR_STREAM (stream)->fps_d,
6106 CUR_STREAM (stream)->fps_n);
6107 GST_BUFFER_DURATION (outbuf) =
6108 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6109 CUR_STREAM (stream)->fps_n);
6110 GST_BUFFER_OFFSET (outbuf) = -1;
6111 GST_BUFFER_OFFSET_END (outbuf) = -1;
6113 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6115 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6118 gst_buffer_unmap (buf, &map);
6119 gst_buffer_unref (buf);
6121 gst_buffer_unmap (buf, &map);
6122 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6125 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6131 /* Sets a buffer's attributes properly and pushes it downstream.
6132 * Also checks for additional actions and custom processing that may
6133 * need to be done first.
6135 static GstFlowReturn
6136 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6137 QtDemuxStream * stream, GstBuffer * buf,
6138 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6139 gboolean keyframe, GstClockTime position, guint64 byte_position)
6141 GstFlowReturn ret = GST_FLOW_OK;
6143 /* offset the timestamps according to the edit list */
6145 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6149 gst_buffer_map (buf, &map, GST_MAP_READ);
6150 url = g_strndup ((gchar *) map.data, map.size);
6151 gst_buffer_unmap (buf, &map);
6152 if (url != NULL && strlen (url) != 0) {
6153 /* we have RTSP redirect now */
6154 g_free (qtdemux->redirect_location);
6155 qtdemux->redirect_location = g_strdup (url);
6156 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6157 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6158 gst_structure_new ("redirect",
6159 "new-location", G_TYPE_STRING, url, NULL)));
6161 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6167 /* position reporting */
6168 if (qtdemux->segment.rate >= 0) {
6169 qtdemux->segment.position = position;
6170 gst_qtdemux_sync_streams (qtdemux);
6173 if (G_UNLIKELY (!stream->pad)) {
6174 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6175 gst_buffer_unref (buf);
6179 /* send out pending buffers */
6180 while (stream->buffers) {
6181 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6183 if (G_UNLIKELY (stream->discont)) {
6184 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6185 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6186 stream->discont = FALSE;
6188 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6191 if (stream->alignment > 1)
6192 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6193 gst_pad_push (stream->pad, buffer);
6195 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6198 /* we're going to modify the metadata */
6199 buf = gst_buffer_make_writable (buf);
6201 GST_BUFFER_DTS (buf) = dts;
6202 GST_BUFFER_PTS (buf) = pts;
6203 GST_BUFFER_DURATION (buf) = duration;
6204 GST_BUFFER_OFFSET (buf) = -1;
6205 GST_BUFFER_OFFSET_END (buf) = -1;
6207 if (G_UNLIKELY (stream->process_func))
6208 buf = stream->process_func (qtdemux, stream, buf);
6215 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6216 stream->on_keyframe = FALSE;
6218 stream->on_keyframe = TRUE;
6221 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6222 gst_buffer_append_memory (buf,
6223 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6225 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6226 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6229 if (G_UNLIKELY (qtdemux->element_index)) {
6230 GstClockTime stream_time;
6233 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6235 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6236 GST_LOG_OBJECT (qtdemux,
6237 "adding association %" GST_TIME_FORMAT "-> %"
6238 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6239 gst_index_add_association (qtdemux->element_index,
6241 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6242 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6243 GST_FORMAT_BYTES, byte_position, NULL);
6248 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6254 static const QtDemuxRandomAccessEntry *
6255 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6256 GstClockTime pos, gboolean after)
6258 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6259 guint n_entries = stream->n_ra_entries;
6262 /* we assume the table is sorted */
6263 for (i = 0; i < n_entries; ++i) {
6264 if (entries[i].ts > pos)
6268 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6269 * probably okay to assume that the index lists the very first fragment */
6276 return &entries[i - 1];
6280 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6282 const QtDemuxRandomAccessEntry *best_entry = NULL;
6285 GST_OBJECT_LOCK (qtdemux);
6287 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6289 /* first see if we can determine where to go to using mfra,
6290 * before we start clearing things */
6291 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6292 const QtDemuxRandomAccessEntry *entry;
6293 QtDemuxStream *stream;
6294 gboolean is_audio_or_video;
6296 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6298 if (stream->ra_entries == NULL)
6301 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6302 is_audio_or_video = TRUE;
6304 is_audio_or_video = FALSE;
6307 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6308 stream->time_position, !is_audio_or_video);
6310 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6311 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6313 stream->pending_seek = entry;
6315 /* decide position to jump to just based on audio/video tracks, not subs */
6316 if (!is_audio_or_video)
6319 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6323 /* no luck, will handle seek otherwise */
6324 if (best_entry == NULL) {
6325 GST_OBJECT_UNLOCK (qtdemux);
6329 /* ok, now we can prepare for processing as of located moof */
6330 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6331 QtDemuxStream *stream;
6333 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6335 g_free (stream->samples);
6336 stream->samples = NULL;
6337 stream->n_samples = 0;
6338 stream->stbl_index = -1; /* no samples have yet been parsed */
6339 stream->sample_index = -1;
6341 if (stream->protection_scheme_info) {
6342 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6343 if (stream->protection_scheme_type == FOURCC_cenc
6344 || stream->protection_scheme_type == FOURCC_cbcs) {
6345 QtDemuxCencSampleSetInfo *info =
6346 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6347 if (info->crypto_info) {
6348 g_ptr_array_free (info->crypto_info, TRUE);
6349 info->crypto_info = NULL;
6355 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6356 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6357 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6358 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6360 qtdemux->moof_offset = best_entry->moof_offset;
6362 qtdemux_add_fragmented_samples (qtdemux);
6364 GST_OBJECT_UNLOCK (qtdemux);
6368 static GstFlowReturn
6369 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6371 GstFlowReturn ret = GST_FLOW_OK;
6372 GstBuffer *buf = NULL;
6373 QtDemuxStream *stream, *target_stream = NULL;
6374 GstClockTime min_time;
6376 GstClockTime dts = GST_CLOCK_TIME_NONE;
6377 GstClockTime pts = GST_CLOCK_TIME_NONE;
6378 GstClockTime duration = 0;
6379 gboolean keyframe = FALSE;
6380 guint sample_size = 0;
6381 guint num_samples = 1;
6386 if (qtdemux->fragmented_seek_pending) {
6387 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6388 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6389 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6390 qtdemux->fragmented_seek_pending = FALSE;
6392 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6396 /* Figure out the next stream sample to output, min_time is expressed in
6397 * global time and runs over the edit list segments. */
6398 min_time = G_MAXUINT64;
6399 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6400 GstClockTime position;
6402 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6403 position = stream->time_position;
6405 if (!GST_CLOCK_TIME_IS_VALID (position))
6408 if (stream->segment_index != -1) {
6409 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6410 position += segment->media_start;
6413 /* position of -1 is EOS */
6414 if (position < min_time) {
6415 min_time = position;
6416 target_stream = stream;
6420 if (G_UNLIKELY (target_stream == NULL)) {
6421 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6425 /* check for segment end */
6426 if (G_UNLIKELY (qtdemux->segment.stop != -1
6427 && qtdemux->segment.rate >= 0
6428 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6429 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6430 target_stream->time_position = GST_CLOCK_TIME_NONE;
6434 /* fetch info for the current sample of this stream */
6435 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, target_stream,
6436 &empty, &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6439 /* Send catche-up GAP event for each other stream if required.
6440 * This logic will be applied only for positive rate */
6441 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux) &&
6442 qtdemux->segment.rate >= 0; i++) {
6443 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6445 if (stream == target_stream ||
6446 !GST_CLOCK_TIME_IS_VALID (stream->segment.stop) ||
6447 !GST_CLOCK_TIME_IS_VALID (stream->segment.position))
6451 GstClockTime gap_threshold;
6452 /* kind of running time with offset segment.base and segment.start */
6453 GstClockTime pseudo_target_time = target_stream->segment.base;
6454 GstClockTime pseudo_cur_time = stream->segment.base;
6456 /* make sure positive offset, segment.position can be smallr than
6457 * segment.start for some reasons */
6458 if (target_stream->segment.position >= target_stream->segment.start) {
6459 pseudo_target_time +=
6460 (target_stream->segment.position - target_stream->segment.start);
6463 if (stream->segment.position >= stream->segment.start)
6464 pseudo_cur_time += (stream->segment.position - stream->segment.start);
6466 /* Only send gap events on non-subtitle streams if lagging way behind. */
6467 if (stream->subtype == FOURCC_subp
6468 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6469 stream->subtype == FOURCC_wvtt)
6470 gap_threshold = 1 * GST_SECOND;
6472 gap_threshold = 3 * GST_SECOND;
6474 /* send gap events until the stream catches up */
6475 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6476 while (GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6477 pseudo_cur_time + gap_threshold < pseudo_target_time) {
6479 gst_event_new_gap (stream->segment.position, gap_threshold);
6480 GST_LOG_OBJECT (stream->pad, "Sending %" GST_PTR_FORMAT, gap);
6482 gst_pad_push_event (stream->pad, gap);
6483 stream->segment.position += gap_threshold;
6484 pseudo_cur_time += gap_threshold;
6489 stream = target_stream;
6491 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6492 if (stream->new_caps) {
6493 gst_qtdemux_configure_stream (qtdemux, stream);
6494 qtdemux_do_allocation (stream, qtdemux);
6497 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6498 if (G_UNLIKELY (qtdemux->segment.
6499 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6500 if (stream->subtype == FOURCC_vide) {
6502 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6505 } else if (qtdemux->trickmode_interval > 0) {
6506 GstClockTimeDiff interval;
6508 if (qtdemux->segment.rate > 0)
6509 interval = stream->time_position - stream->last_keyframe_dts;
6511 interval = stream->last_keyframe_dts - stream->time_position;
6513 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6514 && interval < qtdemux->trickmode_interval) {
6515 GST_LOG_OBJECT (qtdemux,
6516 "Skipping keyframe within interval on track-id %u",
6520 stream->last_keyframe_dts = stream->time_position;
6526 GST_DEBUG_OBJECT (qtdemux,
6527 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6528 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6529 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6530 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6531 GST_TIME_ARGS (duration));
6533 if (G_UNLIKELY (empty)) {
6534 /* empty segment, push a gap if there's a second or more
6535 * difference and move to the next one */
6536 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6537 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6538 stream->segment.position = pts + duration;
6542 /* hmm, empty sample, skip and move to next sample */
6543 if (G_UNLIKELY (sample_size <= 0))
6546 /* last pushed sample was out of boundary, goto next sample */
6547 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6550 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6551 GST_DEBUG_OBJECT (qtdemux,
6552 "size %d larger than stream max_buffer_size %d, trimming",
6553 sample_size, stream->max_buffer_size);
6555 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6556 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6557 && sample_size < stream->min_buffer_size) {
6558 guint start_sample_index = stream->sample_index;
6559 guint accumulated_size = sample_size;
6560 guint64 expected_next_offset = offset + sample_size;
6562 GST_DEBUG_OBJECT (qtdemux,
6563 "size %d smaller than stream min_buffer_size %d, combining with the next",
6564 sample_size, stream->min_buffer_size);
6566 while (stream->sample_index < stream->to_sample
6567 && stream->sample_index + 1 < stream->n_samples) {
6568 const QtDemuxSample *next_sample;
6570 /* Increment temporarily */
6571 stream->sample_index++;
6573 /* Failed to parse sample so let's go back to the previous one that was
6574 * still successful */
6575 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6576 stream->sample_index--;
6580 next_sample = &stream->samples[stream->sample_index];
6582 /* Not contiguous with the previous sample so let's go back to the
6583 * previous one that was still successful */
6584 if (next_sample->offset != expected_next_offset) {
6585 stream->sample_index--;
6589 accumulated_size += next_sample->size;
6590 expected_next_offset += next_sample->size;
6591 if (accumulated_size >= stream->min_buffer_size)
6595 num_samples = stream->sample_index + 1 - start_sample_index;
6596 stream->sample_index = start_sample_index;
6597 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6598 num_samples, accumulated_size);
6599 size = accumulated_size;
6604 if (qtdemux->cenc_aux_info_offset > 0) {
6607 GstBuffer *aux_info = NULL;
6609 /* pull the data stored before the sample */
6611 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6612 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6613 if (G_UNLIKELY (ret != GST_FLOW_OK))
6615 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6616 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6617 gst_byte_reader_init (&br, map.data + 8, map.size);
6618 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6619 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6620 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6621 gst_buffer_unmap (aux_info, &map);
6622 gst_buffer_unref (aux_info);
6623 ret = GST_FLOW_ERROR;
6626 gst_buffer_unmap (aux_info, &map);
6627 gst_buffer_unref (aux_info);
6630 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6633 if (stream->use_allocator) {
6634 /* if we have a per-stream allocator, use it */
6635 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6638 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6640 if (G_UNLIKELY (ret != GST_FLOW_OK))
6643 /* Update for both splitting and combining of samples */
6644 if (size != sample_size) {
6645 pts += gst_util_uint64_scale_int (GST_SECOND,
6646 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6649 gst_util_uint64_scale_int (GST_SECOND,
6650 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6653 gst_util_uint64_scale_int (GST_SECOND,
6654 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6657 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6658 dts, pts, duration, keyframe, min_time, offset);
6660 if (size < sample_size) {
6661 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6662 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6664 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6666 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6667 if (time_position >= segment->media_start) {
6668 /* inside the segment, update time_position, looks very familiar to
6669 * GStreamer segments, doesn't it? */
6670 stream->time_position = (time_position - segment->media_start) +
6673 /* not yet in segment, time does not yet increment. This means
6674 * that we are still prerolling keyframes to the decoder so it can
6675 * decode the first sample of the segment. */
6676 stream->time_position = segment->time;
6678 } else if (size > sample_size) {
6679 /* Increase to the last sample we already pulled so that advancing
6680 * below brings us to the next sample we need to pull */
6681 stream->sample_index += num_samples - 1;
6685 GST_OBJECT_LOCK (qtdemux);
6686 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6687 GST_OBJECT_UNLOCK (qtdemux);
6688 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6689 * we have no more data for the pad to push */
6690 if (ret == GST_FLOW_EOS)
6693 stream->offset_in_sample += size;
6694 if (stream->offset_in_sample >= sample_size) {
6695 gst_qtdemux_advance_sample (qtdemux, stream);
6700 gst_qtdemux_advance_sample (qtdemux, stream);
6708 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6714 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6715 /* EOS will be raised if all are EOS */
6722 gst_qtdemux_loop (GstPad * pad)
6724 GstQTDemux *qtdemux;
6728 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6730 cur_offset = qtdemux->offset;
6731 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6732 cur_offset, qt_demux_state_string (qtdemux->state));
6734 switch (qtdemux->state) {
6735 case QTDEMUX_STATE_INITIAL:
6736 case QTDEMUX_STATE_HEADER:
6737 ret = gst_qtdemux_loop_state_header (qtdemux);
6739 case QTDEMUX_STATE_MOVIE:
6740 ret = gst_qtdemux_loop_state_movie (qtdemux);
6741 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6742 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6750 /* if something went wrong, pause */
6751 if (ret != GST_FLOW_OK)
6755 gst_object_unref (qtdemux);
6761 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6762 (NULL), ("streaming stopped, invalid state"));
6763 gst_pad_pause_task (pad);
6764 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6769 const gchar *reason = gst_flow_get_name (ret);
6771 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6773 gst_pad_pause_task (pad);
6775 /* fatal errors need special actions */
6777 if (ret == GST_FLOW_EOS) {
6778 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6779 /* we have no streams, post an error */
6780 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6782 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6785 if ((stop = qtdemux->segment.stop) == -1)
6786 stop = qtdemux->segment.duration;
6788 if (qtdemux->segment.rate >= 0) {
6789 GstMessage *message;
6792 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6793 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6794 GST_FORMAT_TIME, stop);
6795 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6796 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6797 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6798 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6800 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6801 gst_qtdemux_push_event (qtdemux, event);
6803 GstMessage *message;
6806 /* For Reverse Playback */
6807 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6808 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6809 GST_FORMAT_TIME, qtdemux->segment.start);
6810 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6811 qtdemux->segment.start);
6812 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6813 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6814 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6816 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6817 gst_qtdemux_push_event (qtdemux, event);
6822 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6823 event = gst_event_new_eos ();
6824 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6825 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6826 gst_qtdemux_push_event (qtdemux, event);
6828 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6829 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6830 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6839 * Returns if there are samples to be played.
6842 has_next_entry (GstQTDemux * demux)
6844 QtDemuxStream *stream;
6847 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6849 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6850 stream = QTDEMUX_NTH_STREAM (demux, i);
6852 if (stream->sample_index == -1) {
6853 stream->sample_index = 0;
6854 stream->offset_in_sample = 0;
6857 if (stream->sample_index >= stream->n_samples) {
6858 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6861 GST_DEBUG_OBJECT (demux, "Found a sample");
6865 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6872 * Returns the size of the first entry at the current offset.
6873 * If -1, there are none (which means EOS or empty file).
6876 next_entry_size (GstQTDemux * demux)
6878 QtDemuxStream *stream, *target_stream = NULL;
6879 guint64 smalloffs = (guint64) - 1;
6880 QtDemuxSample *sample;
6883 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6886 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6887 stream = QTDEMUX_NTH_STREAM (demux, i);
6889 if (stream->sample_index == -1) {
6890 stream->sample_index = 0;
6891 stream->offset_in_sample = 0;
6894 if (stream->sample_index >= stream->n_samples) {
6895 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6899 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6900 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6901 stream->sample_index);
6905 sample = &stream->samples[stream->sample_index];
6907 GST_LOG_OBJECT (demux,
6908 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6909 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6910 stream->sample_index, sample->offset, sample->size);
6912 if (((smalloffs == -1)
6913 || (sample->offset < smalloffs)) && (sample->size)) {
6914 smalloffs = sample->offset;
6915 target_stream = stream;
6922 GST_LOG_OBJECT (demux,
6923 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6924 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6926 stream = target_stream;
6927 sample = &stream->samples[stream->sample_index];
6929 if (sample->offset >= demux->offset) {
6930 demux->todrop = sample->offset - demux->offset;
6931 return sample->size + demux->todrop;
6934 GST_DEBUG_OBJECT (demux,
6935 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6940 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6942 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6944 gst_element_post_message (GST_ELEMENT_CAST (demux),
6945 gst_message_new_element (GST_OBJECT_CAST (demux),
6946 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6950 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6955 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6958 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6959 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6960 GST_SEEK_TYPE_NONE, -1);
6962 /* store seqnum to drop flush events, they don't need to reach downstream */
6963 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6964 res = gst_pad_push_event (demux->sinkpad, event);
6965 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6970 /* check for seekable upstream, above and beyond a mere query */
6972 gst_qtdemux_check_seekability (GstQTDemux * demux)
6975 gboolean seekable = FALSE;
6976 gint64 start = -1, stop = -1;
6978 if (demux->upstream_size)
6981 if (demux->upstream_format_is_time)
6984 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6985 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6986 GST_DEBUG_OBJECT (demux, "seeking query failed");
6990 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6992 /* try harder to query upstream size if we didn't get it the first time */
6993 if (seekable && stop == -1) {
6994 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6995 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6998 /* if upstream doesn't know the size, it's likely that it's not seekable in
6999 * practice even if it technically may be seekable */
7000 if (seekable && (start != 0 || stop <= start)) {
7001 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
7006 gst_query_unref (query);
7008 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
7009 G_GUINT64_FORMAT ")", seekable, start, stop);
7010 demux->upstream_seekable = seekable;
7011 demux->upstream_size = seekable ? stop : -1;
7015 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
7017 g_return_if_fail (bytes <= demux->todrop);
7019 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
7020 gst_adapter_flush (demux->adapter, bytes);
7021 demux->neededbytes -= bytes;
7022 demux->offset += bytes;
7023 demux->todrop -= bytes;
7026 /* PUSH-MODE only: Send a segment, if not done already. */
7028 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
7030 if (G_UNLIKELY (demux->need_segment)) {
7033 if (!demux->upstream_format_is_time) {
7034 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
7036 GstEvent *segment_event;
7037 segment_event = gst_event_new_segment (&demux->segment);
7038 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
7039 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
7040 gst_qtdemux_push_event (demux, segment_event);
7043 demux->need_segment = FALSE;
7045 /* clear to send tags on all streams */
7046 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7047 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7048 gst_qtdemux_push_tags (demux, stream);
7049 if (CUR_STREAM (stream)->sparse) {
7050 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
7051 gst_pad_push_event (stream->pad,
7052 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7058 /* Used for push mode only. */
7060 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7061 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7063 GstClockTime ts, dur;
7067 stream->segments[segment_index].duration - (pos -
7068 stream->segments[segment_index].time);
7069 stream->time_position += dur;
7071 /* Only gaps with a duration of at least one second are propagated.
7072 * Same workaround as in pull mode.
7073 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7074 if (dur >= GST_SECOND) {
7076 gap = gst_event_new_gap (ts, dur);
7078 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7079 "segment: %" GST_PTR_FORMAT, gap);
7080 gst_pad_push_event (stream->pad, gap);
7084 static GstFlowReturn
7085 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7089 demux = GST_QTDEMUX (parent);
7091 GST_DEBUG_OBJECT (demux,
7092 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7093 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7094 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7095 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7096 gst_buffer_get_size (inbuf), demux->offset);
7098 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7099 gboolean is_gap_input = FALSE;
7102 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7104 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7105 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7108 /* Check if we can land back on our feet in the case where upstream is
7109 * handling the seeking/pushing of samples with gaps in between (like
7110 * in the case of trick-mode DASH for example) */
7111 if (demux->upstream_format_is_time
7112 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7113 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7115 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7116 GST_LOG_OBJECT (demux,
7117 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7118 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7120 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7121 stream, GST_BUFFER_OFFSET (inbuf));
7123 QtDemuxSample *sample = &stream->samples[res];
7124 GST_LOG_OBJECT (demux,
7125 "Checking if sample %d from track-id %u is valid (offset:%"
7126 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7127 stream->track_id, sample->offset, sample->size);
7128 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7129 GST_LOG_OBJECT (demux,
7130 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7132 is_gap_input = TRUE;
7133 /* We can go back to standard playback mode */
7134 demux->state = QTDEMUX_STATE_MOVIE;
7135 /* Remember which sample this stream is at */
7136 stream->sample_index = res;
7137 /* Finally update all push-based values to the expected values */
7138 demux->neededbytes = stream->samples[res].size;
7139 demux->offset = GST_BUFFER_OFFSET (inbuf);
7141 demux->mdatsize - demux->offset + demux->mdatoffset;
7146 if (!is_gap_input) {
7147 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7148 /* Reset state if it's a real discont */
7149 demux->neededbytes = 16;
7150 demux->state = QTDEMUX_STATE_INITIAL;
7151 demux->offset = GST_BUFFER_OFFSET (inbuf);
7152 gst_adapter_clear (demux->adapter);
7155 /* Reverse fragmented playback, need to flush all we have before
7156 * consuming a new fragment.
7157 * The samples array have the timestamps calculated by accumulating the
7158 * durations but this won't work for reverse playback of fragments as
7159 * the timestamps of a subsequent fragment should be smaller than the
7160 * previously received one. */
7161 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7162 gst_qtdemux_process_adapter (demux, TRUE);
7163 g_ptr_array_foreach (demux->active_streams,
7164 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7168 gst_adapter_push (demux->adapter, inbuf);
7170 GST_DEBUG_OBJECT (demux,
7171 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7172 demux->neededbytes, gst_adapter_available (demux->adapter));
7174 return gst_qtdemux_process_adapter (demux, FALSE);
7177 static GstFlowReturn
7178 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7180 GstFlowReturn ret = GST_FLOW_OK;
7182 /* we never really mean to buffer that much */
7183 if (demux->neededbytes == -1) {
7187 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7188 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7190 #ifndef GST_DISABLE_GST_DEBUG
7192 guint64 discont_offset, distance_from_discont;
7194 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7195 distance_from_discont =
7196 gst_adapter_distance_from_discont (demux->adapter);
7198 GST_DEBUG_OBJECT (demux,
7199 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7200 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7201 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7202 demux->offset, discont_offset, distance_from_discont);
7206 switch (demux->state) {
7207 case QTDEMUX_STATE_INITIAL:{
7212 gst_qtdemux_check_seekability (demux);
7214 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7216 /* get fourcc/length, set neededbytes */
7217 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7219 gst_adapter_unmap (demux->adapter);
7221 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7222 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7224 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7225 (_("This file is invalid and cannot be played.")),
7226 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7227 GST_FOURCC_ARGS (fourcc)));
7228 ret = GST_FLOW_ERROR;
7231 if (fourcc == FOURCC_mdat) {
7232 gint next_entry = next_entry_size (demux);
7233 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7234 || !demux->fragmented)) {
7235 /* we have the headers, start playback */
7236 demux->state = QTDEMUX_STATE_MOVIE;
7237 demux->neededbytes = next_entry;
7238 demux->mdatleft = size;
7239 demux->mdatsize = demux->mdatleft;
7241 /* no headers yet, try to get them */
7244 guint64 old, target;
7247 old = demux->offset;
7248 target = old + size;
7250 /* try to jump over the atom with a seek */
7251 /* only bother if it seems worth doing so,
7252 * and avoids possible upstream/server problems */
7253 if (demux->upstream_seekable &&
7254 demux->upstream_size > 4 * (1 << 20)) {
7255 res = qtdemux_seek_offset (demux, target);
7257 GST_DEBUG_OBJECT (demux, "skipping seek");
7262 GST_DEBUG_OBJECT (demux, "seek success");
7263 /* remember the offset fo the first mdat so we can seek back to it
7264 * after we have the headers */
7265 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7266 demux->first_mdat = old;
7267 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7270 /* seek worked, continue reading */
7271 demux->offset = target;
7272 demux->neededbytes = 16;
7273 demux->state = QTDEMUX_STATE_INITIAL;
7275 /* seek failed, need to buffer */
7276 demux->offset = old;
7277 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7278 /* there may be multiple mdat (or alike) buffers */
7280 if (demux->mdatbuffer)
7281 bs = gst_buffer_get_size (demux->mdatbuffer);
7284 if (size + bs > 10 * (1 << 20))
7286 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7287 demux->neededbytes = size;
7288 if (!demux->mdatbuffer)
7289 demux->mdatoffset = demux->offset;
7292 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7293 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7294 (_("This file is invalid and cannot be played.")),
7295 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7296 GST_FOURCC_ARGS (fourcc), size));
7297 ret = GST_FLOW_ERROR;
7300 /* this means we already started buffering and still no moov header,
7301 * let's continue buffering everything till we get moov */
7302 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7303 || fourcc == FOURCC_moof))
7305 demux->neededbytes = size;
7306 demux->state = QTDEMUX_STATE_HEADER;
7310 case QTDEMUX_STATE_HEADER:{
7314 GST_DEBUG_OBJECT (demux, "In header");
7316 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7318 /* parse the header */
7319 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7321 if (fourcc == FOURCC_moov) {
7322 /* in usual fragmented setup we could try to scan for more
7323 * and end up at the the moov (after mdat) again */
7324 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7326 || demux->last_moov_offset == demux->offset)) {
7327 GST_DEBUG_OBJECT (demux,
7328 "Skipping moov atom as we have (this) one already");
7330 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7332 if (demux->got_moov && demux->fragmented) {
7333 GST_DEBUG_OBJECT (demux,
7334 "Got a second moov, clean up data from old one");
7335 if (demux->moov_node_compressed) {
7336 g_node_destroy (demux->moov_node_compressed);
7337 if (demux->moov_node)
7338 g_free (demux->moov_node->data);
7340 demux->moov_node_compressed = NULL;
7341 if (demux->moov_node)
7342 g_node_destroy (demux->moov_node);
7343 demux->moov_node = NULL;
7346 demux->last_moov_offset = demux->offset;
7348 /* Update streams with new moov */
7349 gst_qtdemux_stream_concat (demux,
7350 demux->old_streams, demux->active_streams);
7352 qtdemux_parse_moov (demux, data, demux->neededbytes);
7353 qtdemux_node_dump (demux, demux->moov_node);
7354 qtdemux_parse_tree (demux);
7355 qtdemux_prepare_streams (demux);
7356 QTDEMUX_EXPOSE_LOCK (demux);
7357 qtdemux_expose_streams (demux);
7358 QTDEMUX_EXPOSE_UNLOCK (demux);
7360 demux->got_moov = TRUE;
7362 gst_qtdemux_check_send_pending_segment (demux);
7364 if (demux->moov_node_compressed) {
7365 g_node_destroy (demux->moov_node_compressed);
7366 g_free (demux->moov_node->data);
7368 demux->moov_node_compressed = NULL;
7369 g_node_destroy (demux->moov_node);
7370 demux->moov_node = NULL;
7371 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7373 } else if (fourcc == FOURCC_moof) {
7374 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7376 GstClockTime prev_pts;
7377 guint64 prev_offset;
7378 guint64 adapter_discont_offset, adapter_discont_dist;
7380 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7383 * The timestamp of the moof buffer is relevant as some scenarios
7384 * won't have the initial timestamp in the atoms. Whenever a new
7385 * buffer has started, we get that buffer's PTS and use it as a base
7386 * timestamp for the trun entries.
7388 * To keep track of the current buffer timestamp and starting point
7389 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7390 * from the beginning of the buffer, with the distance and demux->offset
7391 * we know if it is still the same buffer or not.
7393 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7394 prev_offset = demux->offset - dist;
7395 if (demux->fragment_start_offset == -1
7396 || prev_offset > demux->fragment_start_offset) {
7397 demux->fragment_start_offset = prev_offset;
7398 demux->fragment_start = prev_pts;
7399 GST_DEBUG_OBJECT (demux,
7400 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7401 GST_TIME_FORMAT, demux->fragment_start_offset,
7402 GST_TIME_ARGS (demux->fragment_start));
7405 /* We can't use prev_offset() here because this would require
7406 * upstream to set consistent and correct offsets on all buffers
7407 * since the discont. Nothing ever did that in the past and we
7408 * would break backwards compatibility here then.
7409 * Instead take the offset we had at the last discont and count
7410 * the bytes from there. This works with old code as there would
7411 * be no discont between moov and moof, and also works with
7412 * adaptivedemux which correctly sets offset and will set the
7413 * DISCONT flag accordingly when needed.
7415 * We also only do this for upstream TIME segments as otherwise
7416 * there are potential backwards compatibility problems with
7417 * seeking in PUSH mode and upstream providing inconsistent
7419 adapter_discont_offset =
7420 gst_adapter_offset_at_discont (demux->adapter);
7421 adapter_discont_dist =
7422 gst_adapter_distance_from_discont (demux->adapter);
7424 GST_DEBUG_OBJECT (demux,
7425 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7426 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7427 demux->offset, adapter_discont_offset, adapter_discont_dist);
7429 if (demux->upstream_format_is_time) {
7430 demux->moof_offset = adapter_discont_offset;
7431 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7432 demux->moof_offset += adapter_discont_dist;
7433 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7434 demux->moof_offset = demux->offset;
7436 demux->moof_offset = demux->offset;
7439 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7440 demux->moof_offset, NULL)) {
7441 gst_adapter_unmap (demux->adapter);
7442 ret = GST_FLOW_ERROR;
7446 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7447 if (demux->mss_mode && !demux->exposed) {
7448 QTDEMUX_EXPOSE_LOCK (demux);
7449 qtdemux_expose_streams (demux);
7450 QTDEMUX_EXPOSE_UNLOCK (demux);
7453 gst_qtdemux_check_send_pending_segment (demux);
7455 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7457 } else if (fourcc == FOURCC_ftyp) {
7458 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7459 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7460 } else if (fourcc == FOURCC_uuid) {
7461 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7462 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7463 } else if (fourcc == FOURCC_sidx) {
7464 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7465 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7469 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7473 /* [free] and [skip] are padding atoms */
7474 GST_DEBUG_OBJECT (demux,
7475 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7476 GST_FOURCC_ARGS (fourcc));
7479 GST_WARNING_OBJECT (demux,
7480 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7481 GST_FOURCC_ARGS (fourcc));
7482 /* Let's jump that one and go back to initial state */
7486 gst_adapter_unmap (demux->adapter);
7489 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7490 gsize remaining_data_size = 0;
7492 /* the mdat was before the header */
7493 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7494 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7495 /* restore our adapter/offset view of things with upstream;
7496 * put preceding buffered data ahead of current moov data.
7497 * This should also handle evil mdat, moov, mdat cases and alike */
7498 gst_adapter_flush (demux->adapter, demux->neededbytes);
7500 /* Store any remaining data after the mdat for later usage */
7501 remaining_data_size = gst_adapter_available (demux->adapter);
7502 if (remaining_data_size > 0) {
7503 g_assert (demux->restoredata_buffer == NULL);
7504 demux->restoredata_buffer =
7505 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7506 demux->restoredata_offset = demux->offset + demux->neededbytes;
7507 GST_DEBUG_OBJECT (demux,
7508 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7509 G_GUINT64_FORMAT, remaining_data_size,
7510 demux->restoredata_offset);
7513 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7514 demux->mdatbuffer = NULL;
7515 demux->offset = demux->mdatoffset;
7516 demux->neededbytes = next_entry_size (demux);
7517 demux->state = QTDEMUX_STATE_MOVIE;
7518 demux->mdatleft = gst_adapter_available (demux->adapter);
7519 demux->mdatsize = demux->mdatleft;
7521 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7522 gst_adapter_flush (demux->adapter, demux->neededbytes);
7524 /* only go back to the mdat if there are samples to play */
7525 if (demux->got_moov && demux->first_mdat != -1
7526 && has_next_entry (demux)) {
7529 /* we need to seek back */
7530 res = qtdemux_seek_offset (demux, demux->first_mdat);
7532 demux->offset = demux->first_mdat;
7534 GST_DEBUG_OBJECT (demux, "Seek back failed");
7537 demux->offset += demux->neededbytes;
7539 demux->neededbytes = 16;
7540 demux->state = QTDEMUX_STATE_INITIAL;
7545 case QTDEMUX_STATE_BUFFER_MDAT:{
7549 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7551 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7552 gst_buffer_extract (buf, 0, fourcc, 4);
7553 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7554 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7555 if (demux->mdatbuffer)
7556 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7558 demux->mdatbuffer = buf;
7559 demux->offset += demux->neededbytes;
7560 demux->neededbytes = 16;
7561 demux->state = QTDEMUX_STATE_INITIAL;
7562 gst_qtdemux_post_progress (demux, 1, 1);
7566 case QTDEMUX_STATE_MOVIE:{
7567 QtDemuxStream *stream = NULL;
7568 QtDemuxSample *sample;
7569 GstClockTime dts, pts, duration;
7573 GST_DEBUG_OBJECT (demux,
7574 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7576 if (demux->fragmented) {
7577 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7579 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7580 /* if needed data starts within this atom,
7581 * then it should not exceed this atom */
7582 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7583 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7584 (_("This file is invalid and cannot be played.")),
7585 ("sample data crosses atom boundary"));
7586 ret = GST_FLOW_ERROR;
7589 demux->mdatleft -= demux->neededbytes;
7591 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7592 /* so we are dropping more than left in this atom */
7593 gst_qtdemux_drop_data (demux, demux->mdatleft);
7594 demux->mdatleft = 0;
7596 /* need to resume atom parsing so we do not miss any other pieces */
7597 demux->state = QTDEMUX_STATE_INITIAL;
7598 demux->neededbytes = 16;
7600 /* check if there was any stored post mdat data from previous buffers */
7601 if (demux->restoredata_buffer) {
7602 g_assert (gst_adapter_available (demux->adapter) == 0);
7604 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7605 demux->restoredata_buffer = NULL;
7606 demux->offset = demux->restoredata_offset;
7613 if (demux->todrop) {
7614 if (demux->cenc_aux_info_offset > 0) {
7618 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7619 data = gst_adapter_map (demux->adapter, demux->todrop);
7620 gst_byte_reader_init (&br, data + 8, demux->todrop);
7621 if (!qtdemux_parse_cenc_aux_info (demux,
7622 QTDEMUX_NTH_STREAM (demux, 0), &br,
7623 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7624 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7625 ret = GST_FLOW_ERROR;
7626 gst_adapter_unmap (demux->adapter);
7627 g_free (demux->cenc_aux_info_sizes);
7628 demux->cenc_aux_info_sizes = NULL;
7631 demux->cenc_aux_info_offset = 0;
7632 g_free (demux->cenc_aux_info_sizes);
7633 demux->cenc_aux_info_sizes = NULL;
7634 gst_adapter_unmap (demux->adapter);
7636 gst_qtdemux_drop_data (demux, demux->todrop);
7640 /* initial newsegment sent here after having added pads,
7641 * possible others in sink_event */
7642 gst_qtdemux_check_send_pending_segment (demux);
7644 /* Figure out which stream this packet belongs to */
7645 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7646 stream = QTDEMUX_NTH_STREAM (demux, i);
7647 if (stream->sample_index >= stream->n_samples) {
7648 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7652 GST_LOG_OBJECT (demux,
7653 "Checking track-id %u (sample_index:%d / offset:%"
7654 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7655 stream->sample_index,
7656 stream->samples[stream->sample_index].offset,
7657 stream->samples[stream->sample_index].size);
7659 if (stream->samples[stream->sample_index].offset == demux->offset)
7663 if (G_UNLIKELY (stream == NULL))
7664 goto unknown_stream;
7666 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7668 if (stream->new_caps) {
7669 gst_qtdemux_configure_stream (demux, stream);
7672 /* Put data in a buffer, set timestamps, caps, ... */
7673 sample = &stream->samples[stream->sample_index];
7675 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7676 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7677 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7679 dts = QTSAMPLE_DTS (stream, sample);
7680 pts = QTSAMPLE_PTS (stream, sample);
7681 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7682 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7684 /* check for segment end */
7685 if (G_UNLIKELY (demux->segment.stop != -1
7686 && demux->segment.stop <= pts && stream->on_keyframe)
7687 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7688 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7689 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7691 /* skip this data, stream is EOS */
7692 gst_adapter_flush (demux->adapter, demux->neededbytes);
7693 demux->offset += demux->neededbytes;
7695 /* check if all streams are eos */
7697 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7698 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7707 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7709 /* FIXME: should either be an assert or a plain check */
7710 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7712 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7713 dts, pts, duration, keyframe, dts, demux->offset);
7717 GST_OBJECT_LOCK (demux);
7718 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7719 GST_OBJECT_UNLOCK (demux);
7721 /* skip this data, stream is EOS */
7722 gst_adapter_flush (demux->adapter, demux->neededbytes);
7725 stream->sample_index++;
7726 stream->offset_in_sample = 0;
7728 /* update current offset and figure out size of next buffer */
7729 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7730 demux->offset, demux->neededbytes);
7731 demux->offset += demux->neededbytes;
7732 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7736 if (ret == GST_FLOW_EOS) {
7737 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7738 demux->neededbytes = -1;
7742 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7743 if (demux->fragmented) {
7744 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7745 /* there may be more to follow, only finish this atom */
7746 demux->todrop = demux->mdatleft;
7747 demux->neededbytes = demux->todrop;
7752 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7753 goto non_ok_unlinked_flow;
7762 /* when buffering movie data, at least show user something is happening */
7763 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7764 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7765 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7766 demux->neededbytes);
7773 non_ok_unlinked_flow:
7775 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7776 gst_flow_get_name (ret));
7781 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7782 ret = GST_FLOW_ERROR;
7787 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7793 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7794 (NULL), ("qtdemuxer invalid state %d", demux->state));
7795 ret = GST_FLOW_ERROR;
7800 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7801 (NULL), ("no 'moov' atom within the first 10 MB"));
7802 ret = GST_FLOW_ERROR;
7808 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7813 query = gst_query_new_scheduling ();
7815 if (!gst_pad_peer_query (sinkpad, query)) {
7816 gst_query_unref (query);
7820 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7821 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7822 gst_query_unref (query);
7827 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7828 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7832 GST_DEBUG_OBJECT (sinkpad, "activating push");
7833 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7838 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7839 GstPadMode mode, gboolean active)
7842 GstQTDemux *demux = GST_QTDEMUX (parent);
7845 case GST_PAD_MODE_PUSH:
7846 demux->pullbased = FALSE;
7849 case GST_PAD_MODE_PULL:
7851 demux->pullbased = TRUE;
7852 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7855 res = gst_pad_stop_task (sinkpad);
7867 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7873 memset (&z, 0, sizeof (z));
7878 if ((ret = inflateInit (&z)) != Z_OK) {
7879 GST_ERROR ("inflateInit() returned %d", ret);
7883 z.next_in = z_buffer;
7884 z.avail_in = z_length;
7886 buffer = (guint8 *) g_malloc (*length);
7887 z.avail_out = *length;
7888 z.next_out = (Bytef *) buffer;
7890 ret = inflate (&z, Z_NO_FLUSH);
7891 if (ret == Z_STREAM_END) {
7893 } else if (ret != Z_OK) {
7894 GST_WARNING ("inflate() returned %d", ret);
7899 buffer = (guint8 *) g_realloc (buffer, *length);
7900 z.next_out = (Bytef *) (buffer + z.total_out);
7901 z.avail_out += 4096;
7902 } while (z.avail_in > 0);
7904 if (ret != Z_STREAM_END) {
7909 *length = z.total_out;
7916 #endif /* HAVE_ZLIB */
7919 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7923 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7925 /* counts as header data */
7926 qtdemux->header_size += length;
7928 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7929 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7931 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7938 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7939 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7940 if (dcom == NULL || cmvd == NULL)
7941 goto invalid_compression;
7943 dcom_len = QT_UINT32 (dcom->data);
7945 goto invalid_compression;
7947 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7951 guint uncompressed_length;
7952 guint compressed_length;
7956 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7958 goto invalid_compression;
7960 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7961 compressed_length = cmvd_len - 12;
7962 GST_LOG ("length = %u", uncompressed_length);
7965 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7966 compressed_length, &uncompressed_length);
7969 qtdemux->moov_node_compressed = qtdemux->moov_node;
7970 qtdemux->moov_node = g_node_new (buf);
7972 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7973 uncompressed_length);
7977 #endif /* HAVE_ZLIB */
7979 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7980 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7987 invalid_compression:
7989 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7995 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7998 while (G_UNLIKELY (buf < end)) {
8002 if (G_UNLIKELY (buf + 4 > end)) {
8003 GST_LOG_OBJECT (qtdemux, "buffer overrun");
8006 len = QT_UINT32 (buf);
8007 if (G_UNLIKELY (len == 0)) {
8008 GST_LOG_OBJECT (qtdemux, "empty container");
8011 if (G_UNLIKELY (len < 8)) {
8012 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
8015 if (G_UNLIKELY (len > (end - buf))) {
8016 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
8017 (gint) (end - buf));
8021 child = g_node_new ((guint8 *) buf);
8022 g_node_append (node, child);
8023 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
8024 qtdemux_parse_node (qtdemux, child, buf, len);
8032 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
8035 int len = QT_UINT32 (xdxt->data);
8036 guint8 *buf = xdxt->data;
8037 guint8 *end = buf + len;
8040 /* skip size and type */
8048 size = QT_UINT32 (buf);
8049 type = QT_FOURCC (buf + 4);
8051 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
8053 if (buf + size > end || size <= 0)
8059 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8060 GST_FOURCC_ARGS (type));
8064 buffer = gst_buffer_new_and_alloc (size);
8065 gst_buffer_fill (buffer, 0, buf, size);
8066 stream->buffers = g_slist_append (stream->buffers, buffer);
8067 GST_LOG_OBJECT (qtdemux, "parsing theora header");
8070 buffer = gst_buffer_new_and_alloc (size);
8071 gst_buffer_fill (buffer, 0, buf, size);
8072 stream->buffers = g_slist_append (stream->buffers, buffer);
8073 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
8076 buffer = gst_buffer_new_and_alloc (size);
8077 gst_buffer_fill (buffer, 0, buf, size);
8078 stream->buffers = g_slist_append (stream->buffers, buffer);
8079 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
8082 GST_WARNING_OBJECT (qtdemux,
8083 "unknown theora cookie %" GST_FOURCC_FORMAT,
8084 GST_FOURCC_ARGS (type));
8093 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8097 guint32 node_length = 0;
8098 const QtNodeType *type;
8101 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8103 if (G_UNLIKELY (length < 8))
8104 goto not_enough_data;
8106 node_length = QT_UINT32 (buffer);
8107 fourcc = QT_FOURCC (buffer + 4);
8109 /* ignore empty nodes */
8110 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8113 type = qtdemux_type_get (fourcc);
8115 end = buffer + length;
8117 GST_LOG_OBJECT (qtdemux,
8118 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8119 GST_FOURCC_ARGS (fourcc), node_length, type->name);
8121 if (node_length > length)
8122 goto broken_atom_size;
8124 if (type->flags & QT_FLAG_CONTAINER) {
8125 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8130 if (node_length < 20) {
8131 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8134 GST_DEBUG_OBJECT (qtdemux,
8135 "parsing stsd (sample table, sample description) atom");
8136 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8137 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8149 /* also read alac (or whatever) in stead of mp4a in the following,
8150 * since a similar layout is used in other cases as well */
8151 if (fourcc == FOURCC_mp4a)
8153 else if (fourcc == FOURCC_fLaC)
8158 /* There are two things we might encounter here: a true mp4a atom, and
8159 an mp4a entry in an stsd atom. The latter is what we're interested
8160 in, and it looks like an atom, but isn't really one. The true mp4a
8161 atom is short, so we detect it based on length here. */
8162 if (length < min_size) {
8163 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8164 GST_FOURCC_ARGS (fourcc));
8168 /* 'version' here is the sound sample description version. Types 0 and
8169 1 are documented in the QTFF reference, but type 2 is not: it's
8170 described in Apple header files instead (struct SoundDescriptionV2
8172 version = QT_UINT16 (buffer + 16);
8174 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8175 GST_FOURCC_ARGS (fourcc), version);
8177 /* parse any esds descriptors */
8189 GST_WARNING_OBJECT (qtdemux,
8190 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8191 GST_FOURCC_ARGS (fourcc), version);
8196 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8224 /* codec_data is contained inside these atoms, which all have
8225 * the same format. */
8226 /* video sample description size is 86 bytes without extension.
8227 * node_length have to be bigger than 86 bytes because video sample
8228 * description can include extensions such as esds, fiel, glbl, etc. */
8229 if (node_length < 86) {
8230 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8231 " sample description length too short (%u < 86)",
8232 GST_FOURCC_ARGS (fourcc), node_length);
8236 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8237 GST_FOURCC_ARGS (fourcc));
8239 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8241 * revision level (2 bytes) : must be set to 0. */
8242 version = QT_UINT32 (buffer + 16);
8243 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8245 /* compressor name : PASCAL string and informative purposes
8246 * first byte : the number of bytes to be displayed.
8247 * it has to be less than 32 because it is reserved
8248 * space of 32 bytes total including itself. */
8249 str_len = QT_UINT8 (buffer + 50);
8251 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8252 (char *) buffer + 51);
8254 GST_WARNING_OBJECT (qtdemux,
8255 "compressorname length too big (%u > 31)", str_len);
8257 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8259 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8264 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8266 /* You are reading this correctly. QTFF specifies that the
8267 * metadata atom is a short atom, whereas ISO BMFF specifies
8268 * it's a full atom. But since so many people are doing things
8269 * differently, we actually peek into the atom to see which
8272 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8273 GST_FOURCC_ARGS (fourcc));
8276 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8277 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8278 * starts with a 'hdlr' atom */
8279 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8280 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8281 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8282 * with version/flags both set to zero */
8283 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8285 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8290 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8291 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8292 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8301 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8302 GST_FOURCC_ARGS (fourcc));
8306 version = QT_UINT32 (buffer + 12);
8307 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8314 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8319 if (length < offset) {
8320 GST_WARNING_OBJECT (qtdemux,
8321 "skipping too small %" GST_FOURCC_FORMAT " box",
8322 GST_FOURCC_ARGS (fourcc));
8325 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8331 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8336 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8341 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8345 if (!strcmp (type->name, "unknown"))
8346 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8350 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8351 GST_FOURCC_ARGS (fourcc));
8357 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8358 (_("This file is corrupt and cannot be played.")),
8359 ("Not enough data for an atom header, got only %u bytes", length));
8364 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8365 (_("This file is corrupt and cannot be played.")),
8366 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8367 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8374 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8376 /* FIXME: This can only reliably work if demuxers have a
8377 * separate streaming thread per srcpad. This should be
8378 * done in a demuxer base class, which integrates parts
8381 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8386 query = gst_query_new_allocation (stream->caps, FALSE);
8388 if (!gst_pad_peer_query (stream->pad, query)) {
8389 /* not a problem, just debug a little */
8390 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8393 if (stream->allocator)
8394 gst_object_unref (stream->allocator);
8396 if (gst_query_get_n_allocation_params (query) > 0) {
8397 /* try the allocator */
8398 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8400 stream->use_allocator = TRUE;
8402 stream->allocator = NULL;
8403 gst_allocation_params_init (&stream->params);
8404 stream->use_allocator = FALSE;
8406 gst_query_unref (query);
8411 pad_query (const GValue * item, GValue * value, gpointer user_data)
8413 GstPad *pad = g_value_get_object (item);
8414 GstQuery *query = user_data;
8417 res = gst_pad_peer_query (pad, query);
8420 g_value_set_boolean (value, TRUE);
8424 GST_INFO_OBJECT (pad, "pad peer query failed");
8429 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8430 GstPadDirection direction)
8433 GstIteratorFoldFunction func = pad_query;
8434 GValue res = { 0, };
8436 g_value_init (&res, G_TYPE_BOOLEAN);
8437 g_value_set_boolean (&res, FALSE);
8440 if (direction == GST_PAD_SRC)
8441 it = gst_element_iterate_src_pads (element);
8443 it = gst_element_iterate_sink_pads (element);
8445 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8446 gst_iterator_resync (it);
8448 gst_iterator_free (it);
8450 return g_value_get_boolean (&res);
8454 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8455 QtDemuxStream * stream)
8459 GstElement *element = GST_ELEMENT (qtdemux);
8461 gchar **filtered_sys_ids;
8462 GValue event_list = G_VALUE_INIT;
8465 /* 1. Check if we already have the context. */
8466 if (qtdemux->preferred_protection_system_id != NULL) {
8467 GST_LOG_OBJECT (element,
8468 "already have the protection context, no need to request it again");
8472 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8473 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8474 (const gchar **) qtdemux->protection_system_ids->pdata);
8476 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8477 qtdemux->protection_system_ids->len - 1);
8478 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8479 "decryptors for %u of them, running context request",
8480 qtdemux->protection_system_ids->len,
8481 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8484 if (stream->protection_scheme_event_queue.length) {
8485 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8486 stream->protection_scheme_event_queue.length);
8487 walk = stream->protection_scheme_event_queue.tail;
8489 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8490 qtdemux->protection_event_queue.length);
8491 walk = qtdemux->protection_event_queue.tail;
8494 g_value_init (&event_list, GST_TYPE_LIST);
8495 for (; walk; walk = g_list_previous (walk)) {
8496 GValue *event_value = g_new0 (GValue, 1);
8497 g_value_init (event_value, GST_TYPE_EVENT);
8498 g_value_set_boxed (event_value, walk->data);
8499 gst_value_list_append_and_take_value (&event_list, event_value);
8502 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8503 * check if downstream already has a context of the specific type
8504 * 2b) Query upstream as above.
8506 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8507 st = gst_query_writable_structure (query);
8508 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8509 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8511 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8512 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8513 gst_query_parse_context (query, &ctxt);
8514 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8515 gst_element_set_context (element, ctxt);
8516 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8517 gst_query_parse_context (query, &ctxt);
8518 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8519 gst_element_set_context (element, ctxt);
8521 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8522 * the required context type and afterwards check if a
8523 * usable context was set now as in 1). The message could
8524 * be handled by the parent bins of the element and the
8529 GST_INFO_OBJECT (element, "posting need context message");
8530 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8531 "drm-preferred-decryption-system-id");
8532 st = (GstStructure *) gst_message_get_structure (msg);
8533 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8534 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8537 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8538 gst_element_post_message (element, msg);
8541 g_strfreev (filtered_sys_ids);
8542 g_value_unset (&event_list);
8543 gst_query_unref (query);
8547 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8548 QtDemuxStream * stream)
8551 const gchar *selected_system = NULL;
8553 g_return_val_if_fail (qtdemux != NULL, FALSE);
8554 g_return_val_if_fail (stream != NULL, FALSE);
8555 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8558 if (stream->protection_scheme_type == FOURCC_aavd) {
8559 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8560 if (!gst_structure_has_name (s, "application/x-aavd")) {
8561 gst_structure_set (s,
8562 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8564 gst_structure_set_name (s, "application/x-aavd");
8569 if (stream->protection_scheme_type != FOURCC_cenc
8570 && stream->protection_scheme_type != FOURCC_cbcs) {
8571 GST_ERROR_OBJECT (qtdemux,
8572 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8573 GST_FOURCC_ARGS (stream->protection_scheme_type));
8577 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8578 if (!gst_structure_has_name (s, "application/x-cenc")) {
8579 gst_structure_set (s,
8580 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8581 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8582 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8584 gst_structure_set_name (s, "application/x-cenc");
8587 if (qtdemux->protection_system_ids == NULL) {
8588 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8589 "cenc protection system information has been found, not setting a "
8590 "protection system UUID");
8594 gst_qtdemux_request_protection_context (qtdemux, stream);
8595 if (qtdemux->preferred_protection_system_id != NULL) {
8596 const gchar *preferred_system_array[] =
8597 { qtdemux->preferred_protection_system_id, NULL };
8599 selected_system = gst_protection_select_system (preferred_system_array);
8601 if (selected_system) {
8602 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8603 qtdemux->preferred_protection_system_id);
8605 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8606 "because there is no available decryptor",
8607 qtdemux->preferred_protection_system_id);
8611 if (!selected_system) {
8612 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8613 selected_system = gst_protection_select_system ((const gchar **)
8614 qtdemux->protection_system_ids->pdata);
8615 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8616 qtdemux->protection_system_ids->len - 1);
8619 if (!selected_system) {
8620 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8621 "suitable decryptor element has been found");
8625 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8628 gst_structure_set (s,
8629 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8636 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8638 /* fps is calculated base on the duration of the average framerate since
8639 * qt does not have a fixed framerate. */
8640 gboolean fps_available = TRUE;
8641 guint32 first_duration = 0;
8643 if (stream->n_samples > 0)
8644 first_duration = stream->samples[0].duration;
8646 if ((stream->n_samples == 1 && first_duration == 0)
8647 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8649 CUR_STREAM (stream)->fps_n = 0;
8650 CUR_STREAM (stream)->fps_d = 1;
8652 if (stream->duration == 0 || stream->n_samples < 2) {
8653 CUR_STREAM (stream)->fps_n = stream->timescale;
8654 CUR_STREAM (stream)->fps_d = 1;
8655 fps_available = FALSE;
8657 GstClockTime avg_duration;
8661 /* duration and n_samples can be updated for fragmented format
8662 * so, framerate of fragmented format is calculated using data in a moof */
8663 if (qtdemux->fragmented && stream->n_samples_moof > 0
8664 && stream->duration_moof > 0) {
8665 n_samples = stream->n_samples_moof;
8666 duration = stream->duration_moof;
8668 n_samples = stream->n_samples;
8669 duration = stream->duration;
8672 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8673 /* stream->duration is guint64, timescale, n_samples are guint32 */
8675 gst_util_uint64_scale_round (duration -
8676 first_duration, GST_SECOND,
8677 (guint64) (stream->timescale) * (n_samples - 1));
8679 GST_LOG_OBJECT (qtdemux,
8680 "Calculating avg sample duration based on stream (or moof) duration %"
8682 " minus first sample %u, leaving %d samples gives %"
8683 GST_TIME_FORMAT, duration, first_duration,
8684 n_samples - 1, GST_TIME_ARGS (avg_duration));
8687 gst_video_guess_framerate (avg_duration,
8688 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8690 GST_DEBUG_OBJECT (qtdemux,
8691 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8692 stream->timescale, CUR_STREAM (stream)->fps_n,
8693 CUR_STREAM (stream)->fps_d);
8697 return fps_available;
8701 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8703 if (stream->subtype == FOURCC_vide) {
8704 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8706 if (CUR_STREAM (stream)->caps) {
8707 CUR_STREAM (stream)->caps =
8708 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8710 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8711 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8712 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8713 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8715 /* set framerate if calculated framerate is reliable */
8716 if (fps_available) {
8717 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8718 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8719 CUR_STREAM (stream)->fps_d, NULL);
8722 /* calculate pixel-aspect-ratio using display width and height */
8723 GST_DEBUG_OBJECT (qtdemux,
8724 "video size %dx%d, target display size %dx%d",
8725 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8726 stream->display_width, stream->display_height);
8727 /* qt file might have pasp atom */
8728 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8729 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8730 CUR_STREAM (stream)->par_h);
8731 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8732 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8733 CUR_STREAM (stream)->par_h, NULL);
8734 } else if (stream->display_width > 0 && stream->display_height > 0
8735 && CUR_STREAM (stream)->width > 0
8736 && CUR_STREAM (stream)->height > 0) {
8739 /* calculate the pixel aspect ratio using the display and pixel w/h */
8740 n = stream->display_width * CUR_STREAM (stream)->height;
8741 d = stream->display_height * CUR_STREAM (stream)->width;
8744 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8745 CUR_STREAM (stream)->par_w = n;
8746 CUR_STREAM (stream)->par_h = d;
8747 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8748 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8749 CUR_STREAM (stream)->par_h, NULL);
8752 if (CUR_STREAM (stream)->interlace_mode > 0) {
8753 if (CUR_STREAM (stream)->interlace_mode == 1) {
8754 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8755 G_TYPE_STRING, "progressive", NULL);
8756 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8757 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8758 G_TYPE_STRING, "interleaved", NULL);
8759 if (CUR_STREAM (stream)->field_order == 9) {
8760 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8761 G_TYPE_STRING, "top-field-first", NULL);
8762 } else if (CUR_STREAM (stream)->field_order == 14) {
8763 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8764 G_TYPE_STRING, "bottom-field-first", NULL);
8769 /* Create incomplete colorimetry here if needed */
8770 if (CUR_STREAM (stream)->colorimetry.range ||
8771 CUR_STREAM (stream)->colorimetry.matrix ||
8772 CUR_STREAM (stream)->colorimetry.transfer
8773 || CUR_STREAM (stream)->colorimetry.primaries) {
8774 gchar *colorimetry =
8775 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8776 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8777 G_TYPE_STRING, colorimetry, NULL);
8778 g_free (colorimetry);
8781 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8782 guint par_w = 1, par_h = 1;
8784 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8785 par_w = CUR_STREAM (stream)->par_w;
8786 par_h = CUR_STREAM (stream)->par_h;
8789 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8790 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8792 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8795 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8796 "multiview-mode", G_TYPE_STRING,
8797 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8798 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8799 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8804 else if (stream->subtype == FOURCC_soun) {
8805 if (CUR_STREAM (stream)->caps) {
8806 CUR_STREAM (stream)->caps =
8807 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8808 if (CUR_STREAM (stream)->rate > 0)
8809 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8810 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8811 if (CUR_STREAM (stream)->n_channels > 0)
8812 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8813 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8814 if (CUR_STREAM (stream)->n_channels > 2) {
8815 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8816 * correctly; this is just the minimum we can do - assume
8817 * we don't actually have any channel positions. */
8818 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8819 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8824 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8825 const GstStructure *s;
8826 QtDemuxStream *fps_stream = NULL;
8827 gboolean fps_available = FALSE;
8829 /* CEA608 closed caption tracks are a bit special in that each sample
8830 * can contain CCs for multiple frames, and CCs can be omitted and have to
8831 * be inferred from the duration of the sample then.
8833 * As such we take the framerate from the (first) video track here for
8834 * CEA608 as there must be one CC byte pair for every video frame
8835 * according to the spec.
8837 * For CEA708 all is fine and there is one sample per frame.
8840 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8841 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8844 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8845 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8847 if (tmp->subtype == FOURCC_vide) {
8854 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8855 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8856 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8859 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8860 fps_stream = stream;
8863 CUR_STREAM (stream)->caps =
8864 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8866 /* set framerate if calculated framerate is reliable */
8867 if (fps_available) {
8868 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8869 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8870 CUR_STREAM (stream)->fps_d, NULL);
8875 gboolean forward_collection = FALSE;
8876 GstCaps *prev_caps = NULL;
8878 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8879 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8880 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8881 gst_pad_set_active (stream->pad, TRUE);
8883 gst_pad_use_fixed_caps (stream->pad);
8885 if (stream->protected) {
8886 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8887 GST_ERROR_OBJECT (qtdemux,
8888 "Failed to configure protected stream caps.");
8893 if (stream->new_stream) {
8895 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8898 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8901 gst_event_parse_stream_flags (event, &stream_flags);
8902 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8903 qtdemux->have_group_id = TRUE;
8905 qtdemux->have_group_id = FALSE;
8906 gst_event_unref (event);
8907 } else if (!qtdemux->have_group_id) {
8908 qtdemux->have_group_id = TRUE;
8909 qtdemux->group_id = gst_util_group_id_next ();
8912 stream->new_stream = FALSE;
8913 event = gst_event_new_stream_start (stream->stream_id);
8914 if (qtdemux->have_group_id)
8915 gst_event_set_group_id (event, qtdemux->group_id);
8916 if (stream->disabled)
8917 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8918 if (CUR_STREAM (stream)->sparse) {
8919 stream_flags |= GST_STREAM_FLAG_SPARSE;
8921 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8923 gst_event_set_stream_flags (event, stream_flags);
8924 gst_pad_push_event (stream->pad, event);
8926 forward_collection = TRUE;
8929 prev_caps = gst_pad_get_current_caps (stream->pad);
8931 if (CUR_STREAM (stream)->caps) {
8933 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8934 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8935 CUR_STREAM (stream)->caps);
8936 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8938 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8941 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8945 gst_caps_unref (prev_caps);
8946 stream->new_caps = FALSE;
8948 if (forward_collection) {
8949 /* Forward upstream collection and selection if any */
8950 GstEvent *upstream_event = gst_pad_get_sticky_event (qtdemux->sinkpad,
8951 GST_EVENT_STREAM_COLLECTION, 0);
8953 gst_pad_push_event (stream->pad, upstream_event);
8960 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8961 QtDemuxStream * stream)
8963 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8966 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8967 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8968 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8969 stream->stsd_entries_length)) {
8970 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8971 (_("This file is invalid and cannot be played.")),
8972 ("New sample description id is out of bounds (%d >= %d)",
8973 stream->stsd_sample_description_id, stream->stsd_entries_length));
8975 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8976 stream->new_caps = TRUE;
8981 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8982 QtDemuxStream * stream, GstTagList * list)
8984 gboolean ret = TRUE;
8986 if (stream->subtype == FOURCC_vide) {
8987 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8990 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8993 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8994 gst_object_unref (stream->pad);
9000 qtdemux->n_video_streams++;
9001 } else if (stream->subtype == FOURCC_soun) {
9002 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
9005 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9007 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9008 gst_object_unref (stream->pad);
9013 qtdemux->n_audio_streams++;
9014 } else if (stream->subtype == FOURCC_strm) {
9015 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9016 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9017 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9018 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
9019 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9022 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9024 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9025 gst_object_unref (stream->pad);
9030 qtdemux->n_sub_streams++;
9031 } else if (CUR_STREAM (stream)->caps) {
9032 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9035 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9037 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9038 gst_object_unref (stream->pad);
9043 qtdemux->n_video_streams++;
9045 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9052 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9053 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9054 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9055 GST_OBJECT_LOCK (qtdemux);
9056 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9057 GST_OBJECT_UNLOCK (qtdemux);
9059 if (stream->stream_tags)
9060 gst_tag_list_unref (stream->stream_tags);
9061 stream->stream_tags = list;
9063 /* global tags go on each pad anyway */
9064 stream->send_global_tags = TRUE;
9065 /* send upstream GST_EVENT_PROTECTION events that were received before
9066 this source pad was created */
9067 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9068 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9072 gst_tag_list_unref (list);
9076 /* find next atom with @fourcc starting at @offset */
9077 static GstFlowReturn
9078 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9079 guint64 * length, guint32 fourcc)
9085 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9086 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9092 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9093 if (G_UNLIKELY (ret != GST_FLOW_OK))
9095 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9098 gst_buffer_unref (buf);
9101 gst_buffer_map (buf, &map, GST_MAP_READ);
9102 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9103 gst_buffer_unmap (buf, &map);
9104 gst_buffer_unref (buf);
9106 if (G_UNLIKELY (*length == 0)) {
9107 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9108 ret = GST_FLOW_ERROR;
9112 if (lfourcc == fourcc) {
9113 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9114 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9117 GST_LOG_OBJECT (qtdemux,
9118 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9119 GST_FOURCC_ARGS (lfourcc), *offset);
9120 if (*offset == G_MAXUINT64)
9130 /* might simply have had last one */
9131 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9136 /* should only do something in pull mode */
9137 /* call with OBJECT lock */
9138 static GstFlowReturn
9139 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9141 guint64 length, offset;
9142 GstBuffer *buf = NULL;
9143 GstFlowReturn ret = GST_FLOW_OK;
9144 GstFlowReturn res = GST_FLOW_OK;
9147 offset = qtdemux->moof_offset;
9148 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9151 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9152 return GST_FLOW_EOS;
9155 /* best not do pull etc with lock held */
9156 GST_OBJECT_UNLOCK (qtdemux);
9158 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9159 if (ret != GST_FLOW_OK)
9162 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9163 if (G_UNLIKELY (ret != GST_FLOW_OK))
9165 gst_buffer_map (buf, &map, GST_MAP_READ);
9166 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9167 gst_buffer_unmap (buf, &map);
9168 gst_buffer_unref (buf);
9173 gst_buffer_unmap (buf, &map);
9174 gst_buffer_unref (buf);
9178 /* look for next moof */
9179 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9180 if (G_UNLIKELY (ret != GST_FLOW_OK))
9184 GST_OBJECT_LOCK (qtdemux);
9186 qtdemux->moof_offset = offset;
9192 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9194 res = GST_FLOW_ERROR;
9199 /* maybe upstream temporarily flushing */
9200 if (ret != GST_FLOW_FLUSHING) {
9201 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9204 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9205 /* resume at current position next time */
9213 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9217 gint32 stts_duration;
9218 GstByteWriter stsc, stts, stsz;
9220 /* Each sample has a different size, which we don't support for merging */
9221 if (stream->sample_size == 0) {
9222 GST_DEBUG_OBJECT (qtdemux,
9223 "Not all samples have the same size, not merging");
9227 /* The stream has a ctts table, we don't support that */
9228 if (stream->ctts_present) {
9229 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9233 /* If there's a sync sample table also ignore this stream */
9234 if (stream->stps_present || stream->stss_present) {
9235 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9239 /* If chunks are considered samples already ignore this stream */
9240 if (stream->chunks_are_samples) {
9241 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9245 /* Require that all samples have the same duration */
9246 if (stream->n_sample_times > 1) {
9247 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9251 /* Parse the stts to get the sample duration and number of samples */
9252 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9253 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9255 /* Parse the number of chunks from the stco manually because the
9256 * reader is already behind that */
9257 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9259 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9262 /* Now parse stsc, convert chunks into single samples and generate a
9263 * new stsc, stts and stsz from this information */
9264 gst_byte_writer_init (&stsc);
9265 gst_byte_writer_init (&stts);
9266 gst_byte_writer_init (&stsz);
9268 /* Note: we skip fourccs, size, version, flags and other fields of the new
9269 * atoms as the byte readers with them are already behind that position
9270 * anyway and only update the values of those inside the stream directly.
9272 stream->n_sample_times = 0;
9273 stream->n_samples = 0;
9274 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9276 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9278 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9279 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9280 sample_description_id =
9281 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9283 if (i == stream->n_samples_per_chunk - 1) {
9284 /* +1 because first_chunk is 1-based */
9285 last_chunk = num_chunks + 1;
9287 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9290 GST_DEBUG_OBJECT (qtdemux,
9291 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9292 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9294 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9295 /* One sample in this chunk */
9296 gst_byte_writer_put_uint32_be (&stsc, 1);
9297 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9299 /* For each chunk write a stts and stsz entry now */
9300 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9301 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9302 for (j = first_chunk; j < last_chunk; j++) {
9303 gst_byte_writer_put_uint32_be (&stsz,
9304 stream->sample_size * samples_per_chunk);
9307 stream->n_sample_times += 1;
9308 stream->n_samples += last_chunk - first_chunk;
9311 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9313 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9314 stream->n_samples, stream->n_sample_times);
9316 /* We don't have a fixed sample size anymore */
9317 stream->sample_size = 0;
9319 /* Free old data for the atoms */
9320 g_free ((gpointer) stream->stsz.data);
9321 stream->stsz.data = NULL;
9322 g_free ((gpointer) stream->stsc.data);
9323 stream->stsc.data = NULL;
9324 g_free ((gpointer) stream->stts.data);
9325 stream->stts.data = NULL;
9327 /* Store new data and replace byte readers */
9328 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9329 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9330 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9331 stream->stts.size = gst_byte_writer_get_size (&stts);
9332 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9333 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9334 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9335 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9336 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9339 /* initialise bytereaders for stbl sub-atoms */
9341 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9343 stream->stbl_index = -1; /* no samples have yet been parsed */
9344 stream->sample_index = -1;
9346 /* time-to-sample atom */
9347 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9350 /* copy atom data into a new buffer for later use */
9351 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9353 /* skip version + flags */
9354 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9355 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9357 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9359 /* make sure there's enough data */
9360 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9361 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9362 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9363 stream->n_sample_times);
9364 if (!stream->n_sample_times)
9368 /* sync sample atom */
9369 stream->stps_present = FALSE;
9370 if ((stream->stss_present =
9371 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9372 &stream->stss) ? TRUE : FALSE) == TRUE) {
9373 /* copy atom data into a new buffer for later use */
9374 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9376 /* skip version + flags */
9377 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9378 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9381 if (stream->n_sample_syncs) {
9382 /* make sure there's enough data */
9383 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9387 /* partial sync sample atom */
9388 if ((stream->stps_present =
9389 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9390 &stream->stps) ? TRUE : FALSE) == TRUE) {
9391 /* copy atom data into a new buffer for later use */
9392 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9394 /* skip version + flags */
9395 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9396 !gst_byte_reader_get_uint32_be (&stream->stps,
9397 &stream->n_sample_partial_syncs))
9400 /* if there are no entries, the stss table contains the real
9402 if (stream->n_sample_partial_syncs) {
9403 /* make sure there's enough data */
9404 if (!qt_atom_parser_has_chunks (&stream->stps,
9405 stream->n_sample_partial_syncs, 4))
9412 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9415 /* copy atom data into a new buffer for later use */
9416 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9418 /* skip version + flags */
9419 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9420 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9423 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9426 if (!stream->n_samples)
9429 /* sample-to-chunk atom */
9430 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9433 /* copy atom data into a new buffer for later use */
9434 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9436 /* skip version + flags */
9437 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9438 !gst_byte_reader_get_uint32_be (&stream->stsc,
9439 &stream->n_samples_per_chunk))
9442 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9443 stream->n_samples_per_chunk);
9445 /* make sure there's enough data */
9446 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9452 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9453 stream->co_size = sizeof (guint32);
9454 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9456 stream->co_size = sizeof (guint64);
9460 /* copy atom data into a new buffer for later use */
9461 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9463 /* skip version + flags */
9464 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9467 /* chunks_are_samples == TRUE means treat chunks as samples */
9468 stream->chunks_are_samples = stream->sample_size
9469 && !CUR_STREAM (stream)->sampled;
9470 if (stream->chunks_are_samples) {
9471 /* treat chunks as samples */
9472 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9475 /* skip number of entries */
9476 if (!gst_byte_reader_skip (&stream->stco, 4))
9479 /* make sure there are enough data in the stsz atom */
9480 if (!stream->sample_size) {
9481 /* different sizes for each sample */
9482 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9487 /* composition time-to-sample */
9488 if ((stream->ctts_present =
9489 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9490 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9491 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9492 guint8 ctts_version;
9493 gboolean checked_ctts = FALSE;
9495 /* copy atom data into a new buffer for later use */
9496 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9498 /* version 1 has signed offsets */
9499 if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9503 if (!gst_byte_reader_skip (&stream->ctts, 3)
9504 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9505 &stream->n_composition_times))
9508 /* make sure there's enough data */
9509 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9513 /* This is optional, if missing we iterate the ctts */
9514 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9515 guint8 cslg_version;
9517 /* cslg version 1 has 64 bit fields */
9518 if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9522 if (!gst_byte_reader_skip (&cslg, 3))
9525 if (cslg_version == 0) {
9526 gint32 composition_to_dts_shift;
9528 if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9531 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9533 gint64 composition_to_dts_shift;
9535 if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9538 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9541 gint32 cslg_least = 0;
9542 guint num_entries, pos;
9545 pos = gst_byte_reader_get_pos (&stream->ctts);
9546 num_entries = stream->n_composition_times;
9548 checked_ctts = TRUE;
9550 stream->cslg_shift = 0;
9552 for (i = 0; i < num_entries; i++) {
9555 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9556 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9557 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9558 * slightly inaccurate PTS could be more usable than corrupted one */
9559 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9560 && ABS (offset) / 2 > stream->duration)) {
9561 GST_WARNING_OBJECT (qtdemux,
9562 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9563 " larger than duration %" G_GUINT64_FORMAT, offset,
9566 stream->cslg_shift = 0;
9567 stream->ctts_present = FALSE;
9571 /* Don't consider "no decode samples" with offset G_MININT32
9572 * for the DTS/PTS shift */
9573 if (offset != G_MININT32 && offset < cslg_least)
9574 cslg_least = offset;
9578 stream->cslg_shift = -cslg_least;
9580 stream->cslg_shift = 0;
9582 /* reset the reader so we can generate sample table */
9583 gst_byte_reader_set_pos (&stream->ctts, pos);
9586 /* Check if ctts values are looking reasonable if that didn't happen above */
9587 if (!checked_ctts) {
9588 guint num_entries, pos;
9591 pos = gst_byte_reader_get_pos (&stream->ctts);
9592 num_entries = stream->n_composition_times;
9594 for (i = 0; i < num_entries; i++) {
9597 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9598 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9599 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9600 * slightly inaccurate PTS could be more usable than corrupted one */
9601 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9602 && ABS (offset) / 2 > stream->duration)) {
9603 GST_WARNING_OBJECT (qtdemux,
9604 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9605 " larger than duration %" G_GUINT64_FORMAT, offset,
9608 stream->cslg_shift = 0;
9609 stream->ctts_present = FALSE;
9614 /* reset the reader so we can generate sample table */
9615 gst_byte_reader_set_pos (&stream->ctts, pos);
9618 /* Ensure the cslg_shift value is consistent so we can use it
9619 * unconditionally to produce TS and Segment */
9620 stream->cslg_shift = 0;
9623 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
9624 stream->cslg_shift);
9626 /* For raw audio streams especially we might want to merge the samples
9627 * to not output one audio sample per buffer. We're doing this here
9628 * before allocating the sample tables so that from this point onwards
9629 * the number of container samples are static */
9630 if (stream->min_buffer_size > 0) {
9631 qtdemux_merge_sample_table (qtdemux, stream);
9635 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9636 stream->n_samples, (guint) sizeof (QtDemuxSample),
9637 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9639 if (stream->n_samples >=
9640 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9641 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9642 "be larger than %uMB (broken file?)", stream->n_samples,
9643 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9647 g_assert (stream->samples == NULL);
9648 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9649 if (!stream->samples) {
9650 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9659 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9660 (_("This file is corrupt and cannot be played.")), (NULL));
9665 gst_qtdemux_stbl_free (stream);
9666 if (!qtdemux->fragmented) {
9667 /* not quite good */
9668 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9671 /* may pick up samples elsewhere */
9677 /* collect samples from the next sample to be parsed up to sample @n for @stream
9678 * by reading the info from @stbl
9680 * This code can be executed from both the streaming thread and the seeking
9681 * thread so it takes the object lock to protect itself
9684 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9687 QtDemuxSample *samples, *first, *cur, *last;
9688 guint32 n_samples_per_chunk;
9691 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9692 GST_FOURCC_FORMAT ", pad %s",
9693 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9694 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9696 n_samples = stream->n_samples;
9699 goto out_of_samples;
9701 GST_OBJECT_LOCK (qtdemux);
9702 if (n <= stream->stbl_index)
9703 goto already_parsed;
9705 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9707 if (!stream->stsz.data) {
9708 /* so we already parsed and passed all the moov samples;
9709 * onto fragmented ones */
9710 g_assert (qtdemux->fragmented);
9714 /* pointer to the sample table */
9715 samples = stream->samples;
9717 /* starts from -1, moves to the next sample index to parse */
9718 stream->stbl_index++;
9720 /* keep track of the first and last sample to fill */
9721 first = &samples[stream->stbl_index];
9724 if (!stream->chunks_are_samples) {
9725 /* set the sample sizes */
9726 if (stream->sample_size == 0) {
9727 /* different sizes for each sample */
9728 for (cur = first; cur <= last; cur++) {
9729 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9730 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9731 (guint) (cur - samples), cur->size);
9734 /* samples have the same size */
9735 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9736 for (cur = first; cur <= last; cur++)
9737 cur->size = stream->sample_size;
9741 n_samples_per_chunk = stream->n_samples_per_chunk;
9744 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9747 if (stream->stsc_chunk_index >= stream->last_chunk
9748 || stream->stsc_chunk_index < stream->first_chunk) {
9749 stream->first_chunk =
9750 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9751 stream->samples_per_chunk =
9752 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9754 stream->stsd_sample_description_id =
9755 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9757 /* chunk numbers are counted from 1 it seems */
9758 if (G_UNLIKELY (stream->first_chunk == 0))
9761 --stream->first_chunk;
9763 /* the last chunk of each entry is calculated by taking the first chunk
9764 * of the next entry; except if there is no next, where we fake it with
9766 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9767 stream->last_chunk = G_MAXUINT32;
9769 stream->last_chunk =
9770 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9771 if (G_UNLIKELY (stream->last_chunk == 0))
9774 --stream->last_chunk;
9777 GST_LOG_OBJECT (qtdemux,
9778 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9779 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9780 stream->samples_per_chunk, stream->stsd_sample_description_id);
9782 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9785 if (stream->last_chunk != G_MAXUINT32) {
9786 if (!qt_atom_parser_peek_sub (&stream->stco,
9787 stream->first_chunk * stream->co_size,
9788 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9793 stream->co_chunk = stream->stco;
9794 if (!gst_byte_reader_skip (&stream->co_chunk,
9795 stream->first_chunk * stream->co_size))
9799 stream->stsc_chunk_index = stream->first_chunk;
9802 last_chunk = stream->last_chunk;
9804 if (stream->chunks_are_samples) {
9805 cur = &samples[stream->stsc_chunk_index];
9807 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9810 stream->stsc_chunk_index = j;
9815 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9818 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9819 "%" G_GUINT64_FORMAT, j, cur->offset);
9821 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9822 CUR_STREAM (stream)->bytes_per_frame > 0) {
9824 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9825 CUR_STREAM (stream)->samples_per_frame *
9826 CUR_STREAM (stream)->bytes_per_frame;
9828 cur->size = stream->samples_per_chunk;
9831 GST_DEBUG_OBJECT (qtdemux,
9832 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9833 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9834 stream->stco_sample_index)), cur->size);
9836 cur->timestamp = stream->stco_sample_index;
9837 cur->duration = stream->samples_per_chunk;
9838 cur->keyframe = TRUE;
9841 stream->stco_sample_index += stream->samples_per_chunk;
9843 stream->stsc_chunk_index = j;
9845 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9846 guint32 samples_per_chunk;
9847 guint64 chunk_offset;
9849 if (!stream->stsc_sample_index
9850 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9851 &stream->chunk_offset))
9854 samples_per_chunk = stream->samples_per_chunk;
9855 chunk_offset = stream->chunk_offset;
9857 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9858 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9859 G_GUINT64_FORMAT " and size %d",
9860 (guint) (cur - samples), chunk_offset, cur->size);
9862 cur->offset = chunk_offset;
9863 chunk_offset += cur->size;
9866 if (G_UNLIKELY (cur > last)) {
9868 stream->stsc_sample_index = k + 1;
9869 stream->chunk_offset = chunk_offset;
9870 stream->stsc_chunk_index = j;
9874 stream->stsc_sample_index = 0;
9876 stream->stsc_chunk_index = j;
9878 stream->stsc_index++;
9881 if (stream->chunks_are_samples)
9885 guint32 n_sample_times;
9887 n_sample_times = stream->n_sample_times;
9890 for (i = stream->stts_index; i < n_sample_times; i++) {
9891 guint32 stts_samples;
9892 gint32 stts_duration;
9895 if (stream->stts_sample_index >= stream->stts_samples
9896 || !stream->stts_sample_index) {
9898 stream->stts_samples =
9899 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9900 stream->stts_duration =
9901 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9903 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9904 i, stream->stts_samples, stream->stts_duration);
9906 stream->stts_sample_index = 0;
9909 stts_samples = stream->stts_samples;
9910 stts_duration = stream->stts_duration;
9911 stts_time = stream->stts_time;
9913 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9914 GST_DEBUG_OBJECT (qtdemux,
9915 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9916 (guint) (cur - samples), j,
9917 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9919 cur->timestamp = stts_time;
9920 cur->duration = stts_duration;
9922 /* avoid 32-bit wrap-around,
9923 * but still mind possible 'negative' duration */
9924 stts_time += (gint64) stts_duration;
9927 if (G_UNLIKELY (cur > last)) {
9929 stream->stts_time = stts_time;
9930 stream->stts_sample_index = j + 1;
9931 if (stream->stts_sample_index >= stream->stts_samples)
9932 stream->stts_index++;
9936 stream->stts_sample_index = 0;
9937 stream->stts_time = stts_time;
9938 stream->stts_index++;
9940 /* fill up empty timestamps with the last timestamp, this can happen when
9941 * the last samples do not decode and so we don't have timestamps for them.
9942 * We however look at the last timestamp to estimate the track length so we
9943 * need something in here. */
9944 for (; cur < last; cur++) {
9945 GST_DEBUG_OBJECT (qtdemux,
9946 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9947 (guint) (cur - samples),
9948 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9949 cur->timestamp = stream->stts_time;
9955 /* sample sync, can be NULL */
9956 if (stream->stss_present == TRUE) {
9957 guint32 n_sample_syncs;
9959 n_sample_syncs = stream->n_sample_syncs;
9961 if (!n_sample_syncs) {
9962 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9963 stream->all_keyframe = TRUE;
9965 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9966 /* note that the first sample is index 1, not 0 */
9969 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9971 if (G_LIKELY (index > 0 && index <= n_samples)) {
9973 samples[index].keyframe = TRUE;
9974 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9975 /* and exit if we have enough samples */
9976 if (G_UNLIKELY (index >= n)) {
9983 stream->stss_index = i;
9986 /* stps marks partial sync frames like open GOP I-Frames */
9987 if (stream->stps_present == TRUE) {
9988 guint32 n_sample_partial_syncs;
9990 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9992 /* if there are no entries, the stss table contains the real
9994 if (n_sample_partial_syncs) {
9995 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9996 /* note that the first sample is index 1, not 0 */
9999 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
10001 if (G_LIKELY (index > 0 && index <= n_samples)) {
10003 samples[index].keyframe = TRUE;
10004 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10005 /* and exit if we have enough samples */
10006 if (G_UNLIKELY (index >= n)) {
10013 stream->stps_index = i;
10017 /* no stss, all samples are keyframes */
10018 stream->all_keyframe = TRUE;
10019 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10024 /* composition time to sample */
10025 if (stream->ctts_present == TRUE) {
10026 guint32 n_composition_times;
10027 guint32 ctts_count;
10028 gint32 ctts_soffset;
10030 /* Fill in the pts_offsets */
10032 n_composition_times = stream->n_composition_times;
10034 for (i = stream->ctts_index; i < n_composition_times; i++) {
10035 if (stream->ctts_sample_index >= stream->ctts_count
10036 || !stream->ctts_sample_index) {
10037 stream->ctts_count =
10038 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10039 stream->ctts_soffset =
10040 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10041 stream->ctts_sample_index = 0;
10044 ctts_count = stream->ctts_count;
10045 ctts_soffset = stream->ctts_soffset;
10047 /* FIXME: Set offset to 0 for "no decode samples". This needs
10048 * to be handled in a codec specific manner ideally. */
10049 if (ctts_soffset == G_MININT32)
10052 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10053 cur->pts_offset = ctts_soffset;
10056 if (G_UNLIKELY (cur > last)) {
10058 stream->ctts_sample_index = j + 1;
10062 stream->ctts_sample_index = 0;
10063 stream->ctts_index++;
10067 stream->stbl_index = n;
10068 /* if index has been completely parsed, free data that is no-longer needed */
10069 if (n + 1 == stream->n_samples) {
10070 gst_qtdemux_stbl_free (stream);
10071 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10072 if (qtdemux->pullbased) {
10073 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10074 while (n + 1 == stream->n_samples)
10075 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10079 GST_OBJECT_UNLOCK (qtdemux);
10086 GST_LOG_OBJECT (qtdemux,
10087 "Tried to parse up to sample %u but this sample has already been parsed",
10089 /* if fragmented, there may be more */
10090 if (qtdemux->fragmented && n == stream->stbl_index)
10092 GST_OBJECT_UNLOCK (qtdemux);
10098 GST_LOG_OBJECT (qtdemux,
10099 "Tried to parse up to sample %u but there are only %u samples", n + 1,
10100 stream->n_samples);
10101 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10102 (_("This file is corrupt and cannot be played.")), (NULL));
10107 GST_OBJECT_UNLOCK (qtdemux);
10108 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10109 (_("This file is corrupt and cannot be played.")), (NULL));
10114 /* collect all segment info for @stream.
10117 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10121 /* accept edts if they contain gaps at start and there is only
10122 * one media segment */
10123 gboolean allow_pushbased_edts = TRUE;
10124 gint media_segments_count = 0;
10126 /* parse and prepare segment info from the edit list */
10127 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10128 stream->n_segments = 0;
10129 stream->segments = NULL;
10130 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10133 gint segment_number, entry_size;
10135 GstClockTime stime;
10136 const guint8 *buffer;
10140 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10141 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10144 buffer = elst->data;
10146 size = QT_UINT32 (buffer);
10147 /* version, flags, n_segments */
10149 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10152 version = QT_UINT8 (buffer + 8);
10153 entry_size = (version == 1) ? 20 : 12;
10155 n_segments = QT_UINT32 (buffer + 12);
10157 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10158 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10162 /* we might allocate a bit too much, at least allocate 1 segment */
10163 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10165 /* segments always start from 0 */
10169 for (segment_number = 0; segment_number < n_segments; segment_number++) {
10171 guint64 media_time;
10172 gboolean empty_edit = FALSE;
10173 QtDemuxSegment *segment;
10175 GstClockTime media_start = GST_CLOCK_TIME_NONE;
10177 if (version == 1) {
10178 media_time = QT_UINT64 (buffer + 8);
10179 duration = QT_UINT64 (buffer);
10180 if (media_time == G_MAXUINT64)
10183 media_time = QT_UINT32 (buffer + 4);
10184 duration = QT_UINT32 (buffer);
10185 if (media_time == G_MAXUINT32)
10190 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10192 segment = &stream->segments[segment_number];
10194 /* time and duration expressed in global timescale */
10195 segment->time = stime;
10196 if (duration != 0 || empty_edit) {
10197 /* edge case: empty edits with duration=zero are treated here.
10198 * (files should not have these anyway). */
10200 /* add non scaled values so we don't cause roundoff errors */
10202 stime = QTTIME_TO_GSTTIME (qtdemux, time);
10203 segment->duration = stime - segment->time;
10205 /* zero duration does not imply media_start == media_stop
10206 * but, only specify media_start. The edit ends with the track. */
10207 stime = segment->duration = GST_CLOCK_TIME_NONE;
10208 /* Don't allow more edits after this one. */
10209 n_segments = segment_number + 1;
10211 segment->stop_time = stime;
10213 segment->trak_media_start = media_time;
10214 /* media_time expressed in stream timescale */
10216 segment->media_start = media_start;
10217 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10218 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10219 media_segments_count++;
10221 segment->media_start = GST_CLOCK_TIME_NONE;
10222 segment->media_stop = GST_CLOCK_TIME_NONE;
10224 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10226 if (rate_int <= 1) {
10227 /* 0 is not allowed, some programs write 1 instead of the floating point
10229 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10233 segment->rate = rate_int / 65536.0;
10236 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10237 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10238 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10239 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10240 segment_number, GST_TIME_ARGS (segment->time),
10241 GST_TIME_ARGS (segment->duration),
10242 GST_TIME_ARGS (segment->media_start), media_time,
10243 GST_TIME_ARGS (segment->media_stop),
10244 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10245 stream->timescale);
10246 if (segment->stop_time > qtdemux->segment.stop &&
10247 !qtdemux->upstream_format_is_time) {
10248 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10249 " extends to %" GST_TIME_FORMAT
10250 " past the end of the declared movie duration %" GST_TIME_FORMAT
10251 " movie segment will be extended", segment_number,
10252 GST_TIME_ARGS (segment->stop_time),
10253 GST_TIME_ARGS (qtdemux->segment.stop));
10254 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10257 buffer += entry_size;
10259 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10260 stream->n_segments = n_segments;
10261 if (media_segments_count != 1)
10262 allow_pushbased_edts = FALSE;
10266 /* push based does not handle segments, so act accordingly here,
10267 * and warn if applicable */
10268 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10269 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10270 /* remove and use default one below, we stream like it anyway */
10271 g_free (stream->segments);
10272 stream->segments = NULL;
10273 stream->n_segments = 0;
10276 /* no segments, create one to play the complete trak */
10277 if (stream->n_segments == 0) {
10278 GstClockTime stream_duration =
10279 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10281 if (stream->segments == NULL)
10282 stream->segments = g_new (QtDemuxSegment, 1);
10284 /* represent unknown our way */
10285 if (stream_duration == 0)
10286 stream_duration = GST_CLOCK_TIME_NONE;
10288 stream->segments[0].time = 0;
10289 stream->segments[0].stop_time = stream_duration;
10290 stream->segments[0].duration = stream_duration;
10291 stream->segments[0].media_start = 0;
10292 stream->segments[0].media_stop = stream_duration;
10293 stream->segments[0].rate = 1.0;
10294 stream->segments[0].trak_media_start = 0;
10296 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10297 GST_TIME_ARGS (stream_duration));
10298 stream->n_segments = 1;
10299 stream->dummy_segment = TRUE;
10301 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10307 * Parses the stsd atom of a svq3 trak looking for
10308 * the SMI and gama atoms.
10311 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10312 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10314 const guint8 *_gamma = NULL;
10315 GstBuffer *_seqh = NULL;
10316 const guint8 *stsd_data = stsd_entry_data;
10317 guint32 length = QT_UINT32 (stsd_data);
10321 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10327 version = QT_UINT16 (stsd_data);
10328 if (version == 3) {
10329 if (length >= 70) {
10332 while (length > 8) {
10333 guint32 fourcc, size;
10334 const guint8 *data;
10335 size = QT_UINT32 (stsd_data);
10336 fourcc = QT_FOURCC (stsd_data + 4);
10337 data = stsd_data + 8;
10340 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10341 "svq3 atom parsing");
10350 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10351 " for gama atom, expected 12", size);
10356 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10358 if (_seqh != NULL) {
10359 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10360 " found, ignoring");
10362 seqh_size = QT_UINT32 (data + 4);
10363 if (seqh_size > 0) {
10364 _seqh = gst_buffer_new_and_alloc (seqh_size);
10365 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10372 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10373 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10377 if (size <= length) {
10383 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10386 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10387 G_GUINT16_FORMAT, version);
10397 } else if (_seqh) {
10398 gst_buffer_unref (_seqh);
10403 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10406 GstByteReader dref;
10410 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10411 * atom that might contain a 'data' atom with the rtsp uri.
10412 * This case was reported in bug #597497, some info about
10413 * the hndl atom can be found in TN1195
10415 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10416 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10419 guint32 dref_num_entries = 0;
10420 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10421 gst_byte_reader_skip (&dref, 4) &&
10422 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10425 /* search dref entries for hndl atom */
10426 for (i = 0; i < dref_num_entries; i++) {
10427 guint32 size = 0, type;
10428 guint8 string_len = 0;
10429 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10430 qt_atom_parser_get_fourcc (&dref, &type)) {
10431 if (type == FOURCC_hndl) {
10432 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10434 /* skip data reference handle bytes and the
10435 * following pascal string and some extra 4
10436 * bytes I have no idea what are */
10437 if (!gst_byte_reader_skip (&dref, 4) ||
10438 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10439 !gst_byte_reader_skip (&dref, string_len + 4)) {
10440 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10444 /* iterate over the atoms to find the data atom */
10445 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10449 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10450 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10451 if (atom_type == FOURCC_data) {
10452 const guint8 *uri_aux = NULL;
10454 /* found the data atom that might contain the rtsp uri */
10455 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10456 "hndl atom, interpreting it as an URI");
10457 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10459 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10460 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10462 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10463 "didn't contain a rtsp address");
10465 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10470 /* skipping to the next entry */
10471 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10474 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10481 /* skip to the next entry */
10482 if (!gst_byte_reader_skip (&dref, size - 8))
10485 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10488 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10494 #define AMR_NB_ALL_MODES 0x81ff
10495 #define AMR_WB_ALL_MODES 0x83ff
10497 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10499 /* The 'damr' atom is of the form:
10501 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10502 * 32 b 8 b 16 b 8 b 8 b
10504 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10505 * represents the highest mode used in the stream (and thus the maximum
10506 * bitrate), with a couple of special cases as seen below.
10509 /* Map of frame type ID -> bitrate */
10510 static const guint nb_bitrates[] = {
10511 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10513 static const guint wb_bitrates[] = {
10514 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10520 gst_buffer_map (buf, &map, GST_MAP_READ);
10522 if (map.size != 0x11) {
10523 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10527 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10528 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10529 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10533 mode_set = QT_UINT16 (map.data + 13);
10535 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10536 max_mode = 7 + (wb ? 1 : 0);
10538 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10539 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10541 if (max_mode == -1) {
10542 GST_DEBUG ("No mode indication was found (mode set) = %x",
10547 gst_buffer_unmap (buf, &map);
10548 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10551 gst_buffer_unmap (buf, &map);
10556 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10557 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10560 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10566 if (gst_byte_reader_get_remaining (reader) < 36)
10569 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10570 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10571 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10572 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10573 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10574 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10575 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10576 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10577 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10579 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10580 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10581 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10583 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10584 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10586 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10587 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10594 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10595 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10602 * This macro will only compare value abdegh, it expects cfi to have already
10605 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10606 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10608 /* only handle the cases where the last column has standard values */
10609 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10610 const gchar *rotation_tag = NULL;
10612 /* no rotation needed */
10613 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10615 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10616 rotation_tag = "rotate-90";
10617 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10618 rotation_tag = "rotate-180";
10619 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10620 rotation_tag = "rotate-270";
10622 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10625 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10626 GST_STR_NULL (rotation_tag));
10627 if (rotation_tag != NULL) {
10628 if (*taglist == NULL)
10629 *taglist = gst_tag_list_new_empty ();
10630 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10631 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10634 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10639 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10640 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10644 GstBuffer *adrm_buf = NULL;
10645 QtDemuxAavdEncryptionInfo *info;
10647 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10648 if (G_UNLIKELY (!adrm)) {
10649 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10652 adrm_size = QT_UINT32 (adrm->data);
10653 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10655 stream->protection_scheme_type = FOURCC_aavd;
10657 if (!stream->protection_scheme_info)
10658 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10660 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10662 if (info->default_properties)
10663 gst_structure_free (info->default_properties);
10664 info->default_properties = gst_structure_new ("application/x-aavd",
10665 "encrypted", G_TYPE_BOOLEAN, TRUE,
10666 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10667 gst_buffer_unref (adrm_buf);
10669 *original_fmt = FOURCC_mp4a;
10673 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10674 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10675 * Common Encryption (cenc), the function will also parse the tenc box (defined
10676 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10677 * (typically an enc[v|a|t|s] sample entry); the function will set
10678 * @original_fmt to the fourcc of the original unencrypted stream format.
10679 * Returns TRUE if successful; FALSE otherwise. */
10681 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10682 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10688 QtDemuxCencSampleSetInfo *info;
10690 const guint8 *tenc_data;
10692 g_return_val_if_fail (qtdemux != NULL, FALSE);
10693 g_return_val_if_fail (stream != NULL, FALSE);
10694 g_return_val_if_fail (container != NULL, FALSE);
10695 g_return_val_if_fail (original_fmt != NULL, FALSE);
10697 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10698 if (G_UNLIKELY (!sinf)) {
10699 if (stream->protection_scheme_type == FOURCC_cenc
10700 || stream->protection_scheme_type == FOURCC_cbcs) {
10701 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10702 "mandatory for Common Encryption");
10708 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10709 if (G_UNLIKELY (!frma)) {
10710 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10714 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10715 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10716 GST_FOURCC_ARGS (*original_fmt));
10718 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10720 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10723 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10724 stream->protection_scheme_version =
10725 QT_UINT32 ((const guint8 *) schm->data + 16);
10727 GST_DEBUG_OBJECT (qtdemux,
10728 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10729 "protection_scheme_version: %#010x",
10730 GST_FOURCC_ARGS (stream->protection_scheme_type),
10731 stream->protection_scheme_version);
10733 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10735 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10738 if (stream->protection_scheme_type != FOURCC_cenc &&
10739 stream->protection_scheme_type != FOURCC_piff &&
10740 stream->protection_scheme_type != FOURCC_cbcs) {
10741 GST_ERROR_OBJECT (qtdemux,
10742 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10743 GST_FOURCC_ARGS (stream->protection_scheme_type));
10747 if (G_UNLIKELY (!stream->protection_scheme_info))
10748 stream->protection_scheme_info =
10749 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10751 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10753 if (stream->protection_scheme_type == FOURCC_cenc
10754 || stream->protection_scheme_type == FOURCC_cbcs) {
10755 guint8 is_encrypted;
10757 guint8 constant_iv_size = 0;
10758 const guint8 *default_kid;
10759 guint8 crypt_byte_block = 0;
10760 guint8 skip_byte_block = 0;
10761 const guint8 *constant_iv = NULL;
10763 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10765 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10766 "which is mandatory for Common Encryption");
10769 tenc_data = (const guint8 *) tenc->data + 12;
10770 is_encrypted = QT_UINT8 (tenc_data + 2);
10771 iv_size = QT_UINT8 (tenc_data + 3);
10772 default_kid = (tenc_data + 4);
10773 if (stream->protection_scheme_type == FOURCC_cbcs) {
10774 guint8 possible_pattern_info;
10775 if (iv_size == 0) {
10776 constant_iv_size = QT_UINT8 (tenc_data + 20);
10777 if (constant_iv_size != 8 && constant_iv_size != 16) {
10778 GST_ERROR_OBJECT (qtdemux,
10779 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10782 constant_iv = (tenc_data + 21);
10784 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10785 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10786 skip_byte_block = possible_pattern_info & 0x0f;
10788 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10789 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10790 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10791 } else if (stream->protection_scheme_type == FOURCC_piff) {
10793 static const guint8 piff_track_encryption_uuid[] = {
10794 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10795 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10798 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10800 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10801 "which is mandatory for Common Encryption");
10805 tenc_data = (const guint8 *) tenc->data + 8;
10806 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10807 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10808 GST_ERROR_OBJECT (qtdemux,
10809 "Unsupported track encryption box with uuid: %s", box_uuid);
10813 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10814 gst_byte_reader_init (&br, tenc_data, 20);
10815 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10816 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10819 stream->protection_scheme_type = FOURCC_cenc;
10826 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10827 QtDemuxStream ** stream2)
10829 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10833 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10838 /*parse svmi header if existing */
10839 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10841 guint len = QT_UINT32 ((guint8 *) svmi->data);
10842 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10844 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10845 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10846 guint8 frame_type, frame_layout;
10847 guint32 stereo_mono_change_count;
10852 /* MPEG-A stereo video */
10853 if (qtdemux->major_brand == FOURCC_ss02)
10854 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10856 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10857 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10858 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10860 switch (frame_type) {
10862 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10865 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10868 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10871 /* mode 3 is primary/secondary view sequence, ie
10872 * left/right views in separate tracks. See section 7.2
10873 * of ISO/IEC 23000-11:2009 */
10874 /* In the future this might be supported using related
10875 * streams, like an enhancement track - if files like this
10877 GST_FIXME_OBJECT (qtdemux,
10878 "Implement stereo video in separate streams");
10881 if ((frame_layout & 0x1) == 0)
10882 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10884 GST_LOG_OBJECT (qtdemux,
10885 "StereoVideo: composition type: %u, is_left_first: %u",
10886 frame_type, frame_layout);
10888 if (stereo_mono_change_count > 1) {
10889 GST_FIXME_OBJECT (qtdemux,
10890 "Mixed-mono flags are not yet supported in qtdemux.");
10893 stream->multiview_mode = mode;
10894 stream->multiview_flags = flags;
10901 /* parse the traks.
10902 * With each track we associate a new QtDemuxStream that contains all the info
10904 * traks that do not decode to something (like strm traks) will not have a pad.
10907 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10909 GstByteReader tkhd;
10923 QtDemuxStream *stream = NULL;
10924 const guint8 *stsd_data;
10925 const guint8 *stsd_entry_data;
10926 guint remaining_stsd_len;
10927 guint stsd_entry_count;
10929 guint16 lang_code; /* quicktime lang code or packed iso code */
10931 guint32 tkhd_flags = 0;
10932 guint8 tkhd_version = 0;
10933 guint32 w = 0, h = 0;
10934 guint value_size, stsd_len, len;
10938 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10940 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10941 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10942 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10945 /* pick between 64 or 32 bits */
10946 value_size = tkhd_version == 1 ? 8 : 4;
10947 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10948 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10951 /* Check if current moov has duplicated track_id */
10952 if (qtdemux_find_stream (qtdemux, track_id))
10953 goto existing_stream;
10955 stream = _create_stream (qtdemux, track_id);
10956 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10958 /* need defaults for fragments */
10959 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10961 if ((tkhd_flags & 1) == 0)
10962 stream->disabled = TRUE;
10964 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10965 tkhd_version, tkhd_flags, stream->track_id);
10967 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10970 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10971 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10972 if (qtdemux->major_brand != FOURCC_mjp2 ||
10973 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10977 len = QT_UINT32 ((guint8 *) mdhd->data);
10978 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10979 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10980 if (version == 0x01000000) {
10983 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10984 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10985 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
10989 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10990 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10991 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10994 if (lang_code < 0x400) {
10995 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10996 } else if (lang_code == 0x7fff) {
10997 stream->lang_id[0] = 0; /* unspecified */
10999 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11000 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11001 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11002 stream->lang_id[3] = 0;
11005 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11006 stream->timescale);
11007 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11009 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11010 lang_code, stream->lang_id);
11012 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11015 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11016 /* chapters track reference */
11017 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11019 gsize length = GST_READ_UINT32_BE (chap->data);
11020 if (qtdemux->chapters_track_id)
11021 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11023 if (length >= 12) {
11024 qtdemux->chapters_track_id =
11025 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11030 /* fragmented files may have bogus duration in moov */
11031 if (!qtdemux->fragmented &&
11032 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11033 guint64 tdur1, tdur2;
11035 /* don't overflow */
11036 tdur1 = stream->timescale * (guint64) qtdemux->duration;
11037 tdur2 = qtdemux->timescale * (guint64) stream->duration;
11040 * some of those trailers, nowadays, have prologue images that are
11041 * themselves video tracks as well. I haven't really found a way to
11042 * identify those yet, except for just looking at their duration. */
11043 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11044 GST_WARNING_OBJECT (qtdemux,
11045 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11046 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11047 "found, assuming preview image or something; skipping track",
11048 stream->duration, stream->timescale, qtdemux->duration,
11049 qtdemux->timescale);
11050 gst_qtdemux_stream_unref (stream);
11055 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11058 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11059 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11061 len = QT_UINT32 ((guint8 *) hdlr->data);
11063 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11064 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11065 GST_FOURCC_ARGS (stream->subtype));
11067 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11070 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11073 /* Parse out svmi (and later st3d/sv3d) atoms */
11074 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
11077 /* parse rest of tkhd */
11078 if (stream->subtype == FOURCC_vide) {
11081 /* version 1 uses some 64-bit ints */
11082 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11085 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11088 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11089 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11092 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11093 &stream->stream_tags);
11097 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11099 stsd_data = (const guint8 *) stsd->data;
11101 /* stsd should at least have one entry */
11102 stsd_len = QT_UINT32 (stsd_data);
11103 if (stsd_len < 24) {
11104 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11105 if (stream->subtype == FOURCC_vivo) {
11106 gst_qtdemux_stream_unref (stream);
11113 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11114 /* each stsd entry must contain at least 8 bytes */
11115 if (stream->stsd_entries_length == 0
11116 || stream->stsd_entries_length > stsd_len / 8) {
11117 stream->stsd_entries_length = 0;
11120 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11121 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
11122 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
11124 stsd_entry_data = stsd_data + 16;
11125 remaining_stsd_len = stsd_len - 16;
11126 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11128 gchar *codec = NULL;
11129 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11131 /* and that entry should fit within stsd */
11132 len = QT_UINT32 (stsd_entry_data);
11133 if (len > remaining_stsd_len)
11136 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11137 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
11138 GST_FOURCC_ARGS (entry->fourcc));
11139 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
11141 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11142 goto error_encrypted;
11144 if (fourcc == FOURCC_aavd) {
11145 if (stream->subtype != FOURCC_soun) {
11146 GST_ERROR_OBJECT (qtdemux,
11147 "Unexpeced stsd type 'aavd' outside 'soun' track");
11149 /* encrypted audio with sound sample description v0 */
11150 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11151 stream->protected = TRUE;
11152 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11153 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11157 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11158 /* FIXME this looks wrong, there might be multiple children
11159 * with the same type */
11160 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11161 stream->protected = TRUE;
11162 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11163 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11166 if (stream->subtype == FOURCC_vide) {
11171 gint depth, palette_size, palette_count;
11172 guint32 *palette_data = NULL;
11174 entry->sampled = TRUE;
11176 stream->display_width = w >> 16;
11177 stream->display_height = h >> 16;
11180 if (len < 86) /* TODO verify */
11183 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11184 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11185 entry->fps_n = 0; /* this is filled in later */
11186 entry->fps_d = 0; /* this is filled in later */
11187 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11188 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11190 /* if color_table_id is 0, ctab atom must follow; however some files
11191 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11192 * if color table is not present we'll correct the value */
11193 if (entry->color_table_id == 0 &&
11195 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11196 entry->color_table_id = -1;
11199 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11200 entry->width, entry->height, entry->bits_per_sample,
11201 entry->color_table_id);
11203 depth = entry->bits_per_sample;
11205 /* more than 32 bits means grayscale */
11206 gray = (depth > 32);
11207 /* low 32 bits specify the depth */
11210 /* different number of palette entries is determined by depth. */
11212 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11213 palette_count = (1 << depth);
11214 palette_size = palette_count * 4;
11216 if (entry->color_table_id) {
11217 switch (palette_count) {
11221 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11224 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11229 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11231 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11236 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11239 g_memdup2 (ff_qt_default_palette_256, palette_size);
11242 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11243 (_("The video in this file might not play correctly.")),
11244 ("unsupported palette depth %d", depth));
11248 gint i, j, start, end;
11254 start = QT_UINT32 (stsd_entry_data + offset + 70);
11255 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11256 end = QT_UINT16 (stsd_entry_data + offset + 76);
11258 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11259 start, end, palette_count);
11266 if (len < 94 + (end - start) * 8)
11269 /* palette is always the same size */
11270 palette_data = g_malloc0 (256 * 4);
11271 palette_size = 256 * 4;
11273 for (j = 0, i = start; i <= end; j++, i++) {
11274 guint32 a, r, g, b;
11276 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11277 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11278 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11279 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11281 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11282 (g & 0xff00) | (b >> 8);
11287 gst_caps_unref (entry->caps);
11290 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11292 if (G_UNLIKELY (!entry->caps)) {
11293 g_free (palette_data);
11294 goto unknown_stream;
11298 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11299 GST_TAG_VIDEO_CODEC, codec, NULL);
11304 if (palette_data) {
11307 if (entry->rgb8_palette)
11308 gst_memory_unref (entry->rgb8_palette);
11309 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11310 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11312 s = gst_caps_get_structure (entry->caps, 0);
11314 /* non-raw video has a palette_data property. raw video has the palette as
11315 * an extra plane that we append to the output buffers before we push
11317 if (!gst_structure_has_name (s, "video/x-raw")) {
11318 GstBuffer *palette;
11320 palette = gst_buffer_new ();
11321 gst_buffer_append_memory (palette, entry->rgb8_palette);
11322 entry->rgb8_palette = NULL;
11324 gst_caps_set_simple (entry->caps, "palette_data",
11325 GST_TYPE_BUFFER, palette, NULL);
11326 gst_buffer_unref (palette);
11328 } else if (palette_count != 0) {
11329 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11330 (NULL), ("Unsupported palette depth %d", depth));
11333 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11334 QT_UINT16 (stsd_entry_data + offset + 32));
11340 /* pick 'the' stsd child */
11341 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11342 // We should skip parsing the stsd for non-protected streams if
11343 // the entry doesn't match the fourcc, since they don't change
11344 // format. However, for protected streams we can have partial
11345 // encryption, where parts of the stream are encrypted and parts
11346 // not. For both parts of such streams, we should ensure the
11347 // esds overrides are parsed for both from the stsd.
11348 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11349 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11351 else if (!stream->protected)
11356 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11357 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11358 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11359 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11363 const guint8 *pasp_data = (const guint8 *) pasp->data;
11364 gint len = QT_UINT32 (pasp_data);
11367 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11368 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11370 CUR_STREAM (stream)->par_w = 0;
11371 CUR_STREAM (stream)->par_h = 0;
11374 CUR_STREAM (stream)->par_w = 0;
11375 CUR_STREAM (stream)->par_h = 0;
11379 const guint8 *fiel_data = (const guint8 *) fiel->data;
11380 gint len = QT_UINT32 (fiel_data);
11383 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11384 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11389 const guint8 *colr_data = (const guint8 *) colr->data;
11390 gint len = QT_UINT32 (colr_data);
11392 if (len == 19 || len == 18) {
11393 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11395 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11396 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11397 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11398 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11399 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11401 CUR_STREAM (stream)->colorimetry.primaries =
11402 gst_video_color_primaries_from_iso (primaries);
11403 CUR_STREAM (stream)->colorimetry.transfer =
11404 gst_video_transfer_function_from_iso (transfer_function);
11405 CUR_STREAM (stream)->colorimetry.matrix =
11406 gst_video_color_matrix_from_iso (matrix);
11407 CUR_STREAM (stream)->colorimetry.range =
11408 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11409 GST_VIDEO_COLOR_RANGE_16_235;
11411 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11414 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11419 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11420 stream->stream_tags);
11427 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11428 const guint8 *avc_data = stsd_entry_data + 0x56;
11431 while (len >= 0x8) {
11434 if (QT_UINT32 (avc_data) <= len)
11435 size = QT_UINT32 (avc_data) - 0x8;
11440 /* No real data, so break out */
11443 switch (QT_FOURCC (avc_data + 0x4)) {
11446 /* parse, if found */
11449 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11451 /* First 4 bytes are the length of the atom, the next 4 bytes
11452 * are the fourcc, the next 1 byte is the version, and the
11453 * subsequent bytes are profile_tier_level structure like data. */
11454 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11455 avc_data + 8 + 1, size - 1);
11456 buf = gst_buffer_new_and_alloc (size);
11457 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11458 gst_caps_set_simple (entry->caps,
11459 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11460 gst_buffer_unref (buf);
11468 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11470 /* First 4 bytes are the length of the atom, the next 4 bytes
11471 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11472 * next 1 byte is the version, and the
11473 * subsequent bytes are sequence parameter set like data. */
11475 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11477 gst_codec_utils_h264_caps_set_level_and_profile
11478 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11480 buf = gst_buffer_new_and_alloc (size);
11481 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11482 gst_caps_set_simple (entry->caps,
11483 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11484 gst_buffer_unref (buf);
11490 guint avg_bitrate, max_bitrate;
11492 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11496 max_bitrate = QT_UINT32 (avc_data + 0xc);
11497 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11499 if (!max_bitrate && !avg_bitrate)
11502 /* Some muxers seem to swap the average and maximum bitrates
11503 * (I'm looking at you, YouTube), so we swap for sanity. */
11504 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11505 guint temp = avg_bitrate;
11507 avg_bitrate = max_bitrate;
11508 max_bitrate = temp;
11511 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11512 gst_tag_list_add (stream->stream_tags,
11513 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11514 max_bitrate, NULL);
11516 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11517 gst_tag_list_add (stream->stream_tags,
11518 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11530 avc_data += size + 8;
11541 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11542 const guint8 *hevc_data = stsd_entry_data + 0x56;
11545 while (len >= 0x8) {
11548 if (QT_UINT32 (hevc_data) <= len)
11549 size = QT_UINT32 (hevc_data) - 0x8;
11554 /* No real data, so break out */
11557 switch (QT_FOURCC (hevc_data + 0x4)) {
11560 /* parse, if found */
11563 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11565 /* First 4 bytes are the length of the atom, the next 4 bytes
11566 * are the fourcc, the next 1 byte is the version, and the
11567 * subsequent bytes are sequence parameter set like data. */
11568 gst_codec_utils_h265_caps_set_level_tier_and_profile
11569 (entry->caps, hevc_data + 8 + 1, size - 1);
11571 buf = gst_buffer_new_and_alloc (size);
11572 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11573 gst_caps_set_simple (entry->caps,
11574 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11575 gst_buffer_unref (buf);
11582 hevc_data += size + 8;
11595 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11596 GST_FOURCC_ARGS (fourcc));
11598 /* codec data might be in glbl extension atom */
11600 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11606 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11608 len = QT_UINT32 (data);
11611 buf = gst_buffer_new_and_alloc (len);
11612 gst_buffer_fill (buf, 0, data + 8, len);
11613 gst_caps_set_simple (entry->caps,
11614 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11615 gst_buffer_unref (buf);
11622 /* see annex I of the jpeg2000 spec */
11623 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11624 const guint8 *data;
11625 const gchar *colorspace = NULL;
11627 guint32 ncomp_map = 0;
11628 gint32 *comp_map = NULL;
11629 guint32 nchan_def = 0;
11630 gint32 *chan_def = NULL;
11632 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11633 /* some required atoms */
11634 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11637 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11641 /* number of components; redundant with info in codestream, but useful
11643 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11644 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11646 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11648 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11651 GST_DEBUG_OBJECT (qtdemux, "found colr");
11652 /* extract colour space info */
11653 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11654 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11656 colorspace = "sRGB";
11659 colorspace = "GRAY";
11662 colorspace = "sYUV";
11670 /* colr is required, and only values 16, 17, and 18 are specified,
11671 so error if we have no colorspace */
11674 /* extract component mapping */
11675 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11677 guint32 cmap_len = 0;
11679 cmap_len = QT_UINT32 (cmap->data);
11680 if (cmap_len >= 8) {
11681 /* normal box, subtract off header */
11683 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11684 if (cmap_len % 4 == 0) {
11685 ncomp_map = (cmap_len / 4);
11686 comp_map = g_new0 (gint32, ncomp_map);
11687 for (i = 0; i < ncomp_map; i++) {
11690 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11691 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11692 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11693 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11698 /* extract channel definitions */
11699 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11701 guint32 cdef_len = 0;
11703 cdef_len = QT_UINT32 (cdef->data);
11704 if (cdef_len >= 10) {
11705 /* normal box, subtract off header and len */
11707 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11708 if (cdef_len % 6 == 0) {
11709 nchan_def = (cdef_len / 6);
11710 chan_def = g_new0 (gint32, nchan_def);
11711 for (i = 0; i < nchan_def; i++)
11713 for (i = 0; i < nchan_def; i++) {
11714 guint16 cn, typ, asoc;
11715 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11716 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11717 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11718 if (cn < nchan_def) {
11721 chan_def[cn] = asoc;
11724 chan_def[cn] = 0; /* alpha */
11727 chan_def[cn] = -typ;
11735 gst_caps_set_simple (entry->caps,
11736 "num-components", G_TYPE_INT, ncomp, NULL);
11737 gst_caps_set_simple (entry->caps,
11738 "colorspace", G_TYPE_STRING, colorspace, NULL);
11741 GValue arr = { 0, };
11742 GValue elt = { 0, };
11744 g_value_init (&arr, GST_TYPE_ARRAY);
11745 g_value_init (&elt, G_TYPE_INT);
11746 for (i = 0; i < ncomp_map; i++) {
11747 g_value_set_int (&elt, comp_map[i]);
11748 gst_value_array_append_value (&arr, &elt);
11750 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11751 "component-map", &arr);
11752 g_value_unset (&elt);
11753 g_value_unset (&arr);
11758 GValue arr = { 0, };
11759 GValue elt = { 0, };
11761 g_value_init (&arr, GST_TYPE_ARRAY);
11762 g_value_init (&elt, G_TYPE_INT);
11763 for (i = 0; i < nchan_def; i++) {
11764 g_value_set_int (&elt, chan_def[i]);
11765 gst_value_array_append_value (&arr, &elt);
11767 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11768 "channel-definitions", &arr);
11769 g_value_unset (&elt);
11770 g_value_unset (&arr);
11774 /* some optional atoms */
11775 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11776 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11778 /* indicate possible fields in caps */
11780 data = (guint8 *) field->data + 8;
11782 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11783 (gint) * data, NULL);
11785 /* add codec_data if provided */
11790 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11791 data = prefix->data;
11792 len = QT_UINT32 (data);
11795 buf = gst_buffer_new_and_alloc (len);
11796 gst_buffer_fill (buf, 0, data + 8, len);
11797 gst_caps_set_simple (entry->caps,
11798 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11799 gst_buffer_unref (buf);
11808 GstBuffer *seqh = NULL;
11809 const guint8 *gamma_data = NULL;
11810 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11812 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11815 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11816 QT_FP32 (gamma_data), NULL);
11819 /* sorry for the bad name, but we don't know what this is, other
11820 * than its own fourcc */
11821 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11823 gst_buffer_unref (seqh);
11826 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11827 buf = gst_buffer_new_and_alloc (len);
11828 gst_buffer_fill (buf, 0, stsd_data, len);
11829 gst_caps_set_simple (entry->caps,
11830 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11831 gst_buffer_unref (buf);
11836 /* https://developer.apple.com/standards/qtff-2001.pdf,
11837 * page 92, "Video Sample Description", under table 3.1 */
11840 const gint compressor_offset =
11841 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11842 const gint min_size = compressor_offset + 32 + 2 + 2;
11845 guint16 color_table_id = 0;
11848 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11850 /* recover information on interlaced/progressive */
11851 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11855 len = QT_UINT32 (jpeg->data);
11856 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11858 if (len >= min_size) {
11859 gst_byte_reader_init (&br, jpeg->data, len);
11861 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11862 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11863 if (color_table_id != 0) {
11864 /* the spec says there can be concatenated chunks in the data, and we want
11865 * to find one called field. Walk through them. */
11866 gint offset = min_size;
11867 while (offset + 8 < len) {
11868 guint32 size = 0, tag;
11869 ok = gst_byte_reader_get_uint32_le (&br, &size);
11870 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11871 if (!ok || size < 8) {
11872 GST_WARNING_OBJECT (qtdemux,
11873 "Failed to walk optional chunk list");
11876 GST_DEBUG_OBJECT (qtdemux,
11877 "Found optional %4.4s chunk, size %u",
11878 (const char *) &tag, size);
11879 if (tag == FOURCC_fiel) {
11880 guint8 n_fields = 0, ordering = 0;
11881 gst_byte_reader_get_uint8 (&br, &n_fields);
11882 gst_byte_reader_get_uint8 (&br, &ordering);
11883 if (n_fields == 1 || n_fields == 2) {
11884 GST_DEBUG_OBJECT (qtdemux,
11885 "Found fiel tag with %u fields, ordering %u",
11886 n_fields, ordering);
11888 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11889 "interlace-mode", G_TYPE_STRING, "interleaved",
11892 GST_WARNING_OBJECT (qtdemux,
11893 "Found fiel tag with invalid fields (%u)", n_fields);
11899 GST_DEBUG_OBJECT (qtdemux,
11900 "Color table ID is 0, not trying to get interlacedness");
11903 GST_WARNING_OBJECT (qtdemux,
11904 "Length of jpeg chunk is too small, not trying to get interlacedness");
11912 gst_caps_set_simple (entry->caps,
11913 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11919 GNode *xith, *xdxt;
11921 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11922 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11926 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11930 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11931 /* collect the headers and store them in a stream list so that we can
11932 * send them out first */
11933 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11943 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11944 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11947 ovc1_data = ovc1->data;
11948 ovc1_len = QT_UINT32 (ovc1_data);
11949 if (ovc1_len <= 198) {
11950 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11953 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11954 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11955 gst_caps_set_simple (entry->caps,
11956 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11957 gst_buffer_unref (buf);
11962 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11963 const guint8 *vc1_data = stsd_entry_data + 0x56;
11969 if (QT_UINT32 (vc1_data) <= len)
11970 size = QT_UINT32 (vc1_data) - 8;
11975 /* No real data, so break out */
11978 switch (QT_FOURCC (vc1_data + 0x4)) {
11979 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11983 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11984 buf = gst_buffer_new_and_alloc (size);
11985 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11986 gst_caps_set_simple (entry->caps,
11987 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11988 gst_buffer_unref (buf);
11995 vc1_data += size + 8;
12001 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12002 const guint8 *av1_data = stsd_entry_data + 0x56;
12005 while (len >= 0x8) {
12008 if (QT_UINT32 (av1_data) <= len)
12009 size = QT_UINT32 (av1_data) - 0x8;
12014 /* No real data, so break out */
12017 switch (QT_FOURCC (av1_data + 0x4)) {
12020 /* parse, if found */
12022 guint8 pres_delay_field;
12024 GST_DEBUG_OBJECT (qtdemux,
12025 "found av1C codec_data in stsd of size %d", size);
12027 /* not enough data, just ignore and hope for the best */
12032 * 4 bytes: atom length
12037 * 1 bits: initial_presentation_delay_present
12038 * 4 bits: initial_presentation_delay (if present else reserved
12042 if (av1_data[9] != 0) {
12043 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
12047 /* We skip initial_presentation_delay* for now */
12048 pres_delay_field = *(av1_data + 12);
12049 if (pres_delay_field & (1 << 5)) {
12050 gst_caps_set_simple (entry->caps,
12051 "presentation-delay", G_TYPE_INT,
12052 (gint) (pres_delay_field & 0x0F) + 1, NULL);
12055 buf = gst_buffer_new_and_alloc (size - 5);
12056 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12057 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12058 gst_caps_set_simple (entry->caps,
12059 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12060 gst_buffer_unref (buf);
12069 av1_data += size + 8;
12075 /* TODO: Need to parse vpcC for VP8 codec too.
12076 * Note that VPCodecConfigurationBox (vpcC) is defined for
12077 * vp08, vp09, and vp10 fourcc. */
12080 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12081 const guint8 *vpcc_data = stsd_entry_data + 0x56;
12084 while (len >= 0x8) {
12087 if (QT_UINT32 (vpcc_data) <= len)
12088 size = QT_UINT32 (vpcc_data) - 0x8;
12093 /* No real data, so break out */
12096 switch (QT_FOURCC (vpcc_data + 0x4)) {
12099 const gchar *profile_str = NULL;
12100 const gchar *chroma_format_str = NULL;
12103 guint8 chroma_format;
12104 GstVideoColorimetry cinfo;
12106 /* parse, if found */
12107 GST_DEBUG_OBJECT (qtdemux,
12108 "found vp codec_data in stsd of size %d", size);
12110 /* the meaning of "size" is length of the atom body, excluding
12111 * atom length and fourcc fields */
12116 * 4 bytes: atom length
12123 * 3 bits: chromaSubsampling
12124 * 1 bit: videoFullRangeFlag
12125 * 1 byte: colourPrimaries
12126 * 1 byte: transferCharacteristics
12127 * 1 byte: matrixCoefficients
12128 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
12129 * rest: codecIntializationData (not used for vp8 and vp9)
12132 if (vpcc_data[8] != 1) {
12133 GST_WARNING_OBJECT (qtdemux,
12134 "unknown vpcC version %d", vpcc_data[8]);
12138 profile = vpcc_data[12];
12157 gst_caps_set_simple (entry->caps,
12158 "profile", G_TYPE_STRING, profile_str, NULL);
12161 /* skip level, the VP9 spec v0.6 defines only one level atm,
12162 * but webm spec define various ones. Add level to caps
12163 * if we really need it then */
12165 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12166 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12167 gst_caps_set_simple (entry->caps,
12168 "bit-depth-luma", G_TYPE_UINT, bitdepth,
12169 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12172 chroma_format = (vpcc_data[14] & 0xe) >> 1;
12173 switch (chroma_format) {
12176 chroma_format_str = "4:2:0";
12179 chroma_format_str = "4:2:2";
12182 chroma_format_str = "4:4:4";
12188 if (chroma_format_str) {
12189 gst_caps_set_simple (entry->caps,
12190 "chroma-format", G_TYPE_STRING, chroma_format_str,
12194 if ((vpcc_data[14] & 0x1) != 0)
12195 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12197 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12199 gst_video_color_primaries_from_iso (vpcc_data[15]);
12201 gst_video_transfer_function_from_iso (vpcc_data[16]);
12203 gst_video_color_matrix_from_iso (vpcc_data[17]);
12205 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12206 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12207 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12208 /* set this only if all values are known, otherwise this
12209 * might overwrite valid ones parsed from other color box */
12210 CUR_STREAM (stream)->colorimetry = cinfo;
12219 vpcc_data += size + 8;
12229 GST_INFO_OBJECT (qtdemux,
12230 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12231 GST_FOURCC_ARGS (fourcc), entry->caps);
12233 } else if (stream->subtype == FOURCC_soun) {
12235 int version, samplesize;
12236 guint16 compression_id;
12237 gboolean amrwb = FALSE;
12240 /* sample description entry (16) + sound sample description v0 (20) */
12244 version = QT_UINT32 (stsd_entry_data + offset);
12245 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12246 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12247 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12248 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12250 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12251 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12252 QT_UINT32 (stsd_entry_data + offset + 4));
12253 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12254 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12255 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12256 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12257 QT_UINT16 (stsd_entry_data + offset + 14));
12258 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12260 if (compression_id == 0xfffe)
12261 entry->sampled = TRUE;
12263 /* first assume uncompressed audio */
12264 entry->bytes_per_sample = samplesize / 8;
12265 entry->samples_per_frame = entry->n_channels;
12266 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12267 entry->samples_per_packet = entry->samples_per_frame;
12268 entry->bytes_per_packet = entry->bytes_per_sample;
12272 if (version == 0x00010000) {
12273 /* sample description entry (16) + sound sample description v1 (20+16) */
12277 /* take information from here over the normal sample description */
12278 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12279 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12280 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12281 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12283 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12284 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12285 entry->samples_per_packet);
12286 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12287 entry->bytes_per_packet);
12288 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12289 entry->bytes_per_frame);
12290 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12291 entry->bytes_per_sample);
12293 if (!entry->sampled && entry->bytes_per_packet) {
12294 entry->samples_per_frame = (entry->bytes_per_frame /
12295 entry->bytes_per_packet) * entry->samples_per_packet;
12296 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12297 entry->samples_per_frame);
12299 } else if (version == 0x00020000) {
12300 /* sample description entry (16) + sound sample description v2 (56) */
12304 /* take information from here over the normal sample description */
12305 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12306 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12307 entry->samples_per_frame = entry->n_channels;
12308 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12309 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12310 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12311 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12313 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12314 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12315 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12316 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12317 entry->bytes_per_sample * 8);
12318 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12319 QT_UINT32 (stsd_entry_data + offset + 24));
12320 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12321 entry->bytes_per_packet);
12322 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12323 entry->samples_per_packet);
12324 } else if (version != 0x00000) {
12325 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12330 /* Yes, these have to be hard-coded */
12333 entry->samples_per_packet = 6;
12334 entry->bytes_per_packet = 1;
12335 entry->bytes_per_frame = 1 * entry->n_channels;
12336 entry->bytes_per_sample = 1;
12337 entry->samples_per_frame = 6 * entry->n_channels;
12342 entry->samples_per_packet = 3;
12343 entry->bytes_per_packet = 1;
12344 entry->bytes_per_frame = 1 * entry->n_channels;
12345 entry->bytes_per_sample = 1;
12346 entry->samples_per_frame = 3 * entry->n_channels;
12351 entry->samples_per_packet = 64;
12352 entry->bytes_per_packet = 34;
12353 entry->bytes_per_frame = 34 * entry->n_channels;
12354 entry->bytes_per_sample = 2;
12355 entry->samples_per_frame = 64 * entry->n_channels;
12361 entry->samples_per_packet = 1;
12362 entry->bytes_per_packet = 1;
12363 entry->bytes_per_frame = 1 * entry->n_channels;
12364 entry->bytes_per_sample = 1;
12365 entry->samples_per_frame = 1 * entry->n_channels;
12370 entry->samples_per_packet = 160;
12371 entry->bytes_per_packet = 33;
12372 entry->bytes_per_frame = 33 * entry->n_channels;
12373 entry->bytes_per_sample = 2;
12374 entry->samples_per_frame = 160 * entry->n_channels;
12377 /* fix up any invalid header information from above */
12382 /* Sometimes these are set to 0 in the sound sample descriptions so
12383 * let's try to infer useful values from the other information we
12384 * have available */
12385 if (entry->bytes_per_sample == 0)
12386 entry->bytes_per_sample =
12387 entry->bytes_per_frame / entry->n_channels;
12388 if (entry->bytes_per_sample == 0)
12389 entry->bytes_per_sample = samplesize / 8;
12391 if (entry->bytes_per_frame == 0)
12392 entry->bytes_per_frame =
12393 entry->bytes_per_sample * entry->n_channels;
12395 if (entry->bytes_per_packet == 0)
12396 entry->bytes_per_packet = entry->bytes_per_sample;
12398 if (entry->samples_per_frame == 0)
12399 entry->samples_per_frame = entry->n_channels;
12401 if (entry->samples_per_packet == 0)
12402 entry->samples_per_packet = entry->samples_per_frame;
12412 entry->bytes_per_sample = 3;
12416 entry->bytes_per_sample = 4;
12419 entry->bytes_per_sample = 8;
12422 entry->bytes_per_sample = 2;
12425 g_assert_not_reached ();
12428 entry->samples_per_frame = entry->n_channels;
12429 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12430 entry->samples_per_packet = entry->samples_per_frame;
12431 entry->bytes_per_packet = entry->bytes_per_sample;
12439 gst_caps_unref (entry->caps);
12441 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12442 stsd_entry_data + 32, len - 16, &codec);
12453 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12455 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12457 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12459 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12462 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12463 const gchar *format_str;
12467 format_str = (enda_value) ? "S24LE" : "S24BE";
12470 format_str = (enda_value) ? "S32LE" : "S32BE";
12473 format_str = (enda_value) ? "F32LE" : "F32BE";
12476 format_str = (enda_value) ? "F64LE" : "F64BE";
12479 g_assert_not_reached ();
12482 gst_caps_set_simple (entry->caps,
12483 "format", G_TYPE_STRING, format_str, NULL);
12489 const guint8 *owma_data;
12490 const gchar *codec_name = NULL;
12494 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12495 /* FIXME this should also be gst_riff_strf_auds,
12496 * but the latter one is actually missing bits-per-sample :( */
12501 gint32 nSamplesPerSec;
12502 gint32 nAvgBytesPerSec;
12503 gint16 nBlockAlign;
12504 gint16 wBitsPerSample;
12507 WAVEFORMATEX *wfex;
12509 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12510 owma_data = stsd_entry_data;
12511 owma_len = QT_UINT32 (owma_data);
12512 if (owma_len <= 54) {
12513 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12516 wfex = (WAVEFORMATEX *) (owma_data + 36);
12517 buf = gst_buffer_new_and_alloc (owma_len - 54);
12518 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12519 if (wfex->wFormatTag == 0x0161) {
12520 codec_name = "Windows Media Audio";
12522 } else if (wfex->wFormatTag == 0x0162) {
12523 codec_name = "Windows Media Audio 9 Pro";
12525 } else if (wfex->wFormatTag == 0x0163) {
12526 codec_name = "Windows Media Audio 9 Lossless";
12527 /* is that correct? gstffmpegcodecmap.c is missing it, but
12528 * fluendo codec seems to support it */
12532 gst_caps_set_simple (entry->caps,
12533 "codec_data", GST_TYPE_BUFFER, buf,
12534 "wmaversion", G_TYPE_INT, version,
12535 "block_align", G_TYPE_INT,
12536 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12537 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12538 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12539 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12540 gst_buffer_unref (buf);
12544 codec = g_strdup (codec_name);
12550 gint len = QT_UINT32 (stsd_entry_data) - offset;
12551 const guint8 *wfex_data = stsd_entry_data + offset;
12552 const gchar *codec_name = NULL;
12554 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12555 /* FIXME this should also be gst_riff_strf_auds,
12556 * but the latter one is actually missing bits-per-sample :( */
12561 gint32 nSamplesPerSec;
12562 gint32 nAvgBytesPerSec;
12563 gint16 nBlockAlign;
12564 gint16 wBitsPerSample;
12569 /* FIXME: unify with similar wavformatex parsing code above */
12570 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12576 if (QT_UINT32 (wfex_data) <= len)
12577 size = QT_UINT32 (wfex_data) - 8;
12582 /* No real data, so break out */
12585 switch (QT_FOURCC (wfex_data + 4)) {
12586 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12588 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12593 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12594 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12595 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12596 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12597 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12598 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12599 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12601 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12602 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12603 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12604 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12605 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12606 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12608 if (wfex.wFormatTag == 0x0161) {
12609 codec_name = "Windows Media Audio";
12611 } else if (wfex.wFormatTag == 0x0162) {
12612 codec_name = "Windows Media Audio 9 Pro";
12614 } else if (wfex.wFormatTag == 0x0163) {
12615 codec_name = "Windows Media Audio 9 Lossless";
12616 /* is that correct? gstffmpegcodecmap.c is missing it, but
12617 * fluendo codec seems to support it */
12621 gst_caps_set_simple (entry->caps,
12622 "wmaversion", G_TYPE_INT, version,
12623 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12624 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12625 "width", G_TYPE_INT, wfex.wBitsPerSample,
12626 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12628 if (size > wfex.cbSize) {
12631 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12632 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12633 size - wfex.cbSize);
12634 gst_caps_set_simple (entry->caps,
12635 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12636 gst_buffer_unref (buf);
12638 GST_WARNING_OBJECT (qtdemux, "no codec data");
12643 codec = g_strdup (codec_name);
12651 wfex_data += size + 8;
12657 const guint8 *dops_data;
12658 guint8 *channel_mapping = NULL;
12661 guint8 channel_mapping_family;
12662 guint8 stream_count;
12663 guint8 coupled_count;
12666 version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12668 dops_data = stsd_entry_data + 51;
12670 dops_data = stsd_entry_data + 35;
12672 channels = GST_READ_UINT8 (dops_data + 10);
12673 rate = GST_READ_UINT32_LE (dops_data + 13);
12674 channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12675 stream_count = GST_READ_UINT8 (dops_data + 20);
12676 coupled_count = GST_READ_UINT8 (dops_data + 21);
12678 if (channels > 0) {
12679 channel_mapping = g_malloc (channels * sizeof (guint8));
12680 for (i = 0; i < channels; i++)
12681 channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12684 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12685 channel_mapping_family, stream_count, coupled_count,
12687 g_free (channel_mapping);
12698 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12699 GST_TAG_AUDIO_CODEC, codec, NULL);
12703 /* some bitrate info may have ended up in caps */
12704 s = gst_caps_get_structure (entry->caps, 0);
12705 gst_structure_get_int (s, "bitrate", &bitrate);
12707 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12708 GST_TAG_BITRATE, bitrate, NULL);
12712 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12713 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12714 if (stream->protected) {
12715 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12716 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12718 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12728 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12730 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12732 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12736 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12737 16 bits is a byte-swapped wave-style codec identifier,
12738 and we can find a WAVE header internally to a 'wave' atom here.
12739 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12740 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12743 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12744 if (len < offset + 20) {
12745 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12747 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12748 const guint8 *data = stsd_entry_data + offset + 16;
12750 GNode *waveheadernode;
12752 wavenode = g_node_new ((guint8 *) data);
12753 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12754 const guint8 *waveheader;
12757 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12758 if (waveheadernode) {
12759 waveheader = (const guint8 *) waveheadernode->data;
12760 headerlen = QT_UINT32 (waveheader);
12762 if (headerlen > 8) {
12763 gst_riff_strf_auds *header = NULL;
12764 GstBuffer *headerbuf;
12770 headerbuf = gst_buffer_new_and_alloc (headerlen);
12771 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12773 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12774 headerbuf, &header, &extra)) {
12775 gst_caps_unref (entry->caps);
12776 /* FIXME: Need to do something with the channel reorder map */
12778 gst_riff_create_audio_caps (header->format, NULL, header,
12779 extra, NULL, NULL, NULL);
12782 gst_buffer_unref (extra);
12787 GST_DEBUG ("Didn't find waveheadernode for this codec");
12789 g_node_destroy (wavenode);
12792 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12793 stream->stream_tags);
12797 /* FIXME: what is in the chunk? */
12800 gint len = QT_UINT32 (stsd_data);
12802 /* seems to be always = 116 = 0x74 */
12808 gint len = QT_UINT32 (stsd_entry_data);
12811 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12813 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12814 gst_caps_set_simple (entry->caps,
12815 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12816 gst_buffer_unref (buf);
12818 gst_caps_set_simple (entry->caps,
12819 "samplesize", G_TYPE_INT, samplesize, NULL);
12824 GNode *alac, *wave = NULL;
12826 /* apparently, m4a has this atom appended directly in the stsd entry,
12827 * while mov has it in a wave atom */
12828 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12830 /* alac now refers to stsd entry atom */
12831 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12833 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12835 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12838 const guint8 *alac_data = alac->data;
12839 gint len = QT_UINT32 (alac->data);
12843 GST_DEBUG_OBJECT (qtdemux,
12844 "discarding alac atom with unexpected len %d", len);
12846 /* codec-data contains alac atom size and prefix,
12847 * ffmpeg likes it that way, not quite gst-ish though ...*/
12848 buf = gst_buffer_new_and_alloc (len);
12849 gst_buffer_fill (buf, 0, alac->data, len);
12850 gst_caps_set_simple (entry->caps,
12851 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12852 gst_buffer_unref (buf);
12854 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12855 entry->n_channels = QT_UINT8 (alac_data + 21);
12856 entry->rate = QT_UINT32 (alac_data + 32);
12857 samplesize = QT_UINT8 (alac_data + 16 + 1);
12860 gst_caps_set_simple (entry->caps,
12861 "samplesize", G_TYPE_INT, samplesize, NULL);
12866 /* The codingname of the sample entry is 'fLaC' */
12867 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12870 /* The 'dfLa' box is added to the sample entry to convey
12871 initializing information for the decoder. */
12872 const GNode *dfla =
12873 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12876 const guint32 len = QT_UINT32 (dfla->data);
12878 /* Must contain at least dfLa box header (12),
12879 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12881 GST_DEBUG_OBJECT (qtdemux,
12882 "discarding dfla atom with unexpected len %d", len);
12884 /* skip dfLa header to get the METADATA_BLOCKs */
12885 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12886 const guint32 metadata_blocks_len = len - 12;
12888 gchar *stream_marker = g_strdup ("fLaC");
12889 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12890 strlen (stream_marker));
12893 guint32 remainder = 0;
12894 guint32 block_size = 0;
12895 gboolean is_last = FALSE;
12897 GValue array = G_VALUE_INIT;
12898 GValue value = G_VALUE_INIT;
12900 g_value_init (&array, GST_TYPE_ARRAY);
12901 g_value_init (&value, GST_TYPE_BUFFER);
12903 gst_value_set_buffer (&value, block);
12904 gst_value_array_append_value (&array, &value);
12905 g_value_reset (&value);
12907 gst_buffer_unref (block);
12909 /* check there's at least one METADATA_BLOCK_HEADER's worth
12910 * of data, and we haven't already finished parsing */
12911 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12912 remainder = metadata_blocks_len - index;
12914 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12916 (metadata_blocks[index + 1] << 16) +
12917 (metadata_blocks[index + 2] << 8) +
12918 metadata_blocks[index + 3];
12920 /* be careful not to read off end of box */
12921 if (block_size > remainder) {
12925 is_last = metadata_blocks[index] >> 7;
12927 block = gst_buffer_new_and_alloc (block_size);
12929 gst_buffer_fill (block, 0, &metadata_blocks[index],
12932 gst_value_set_buffer (&value, block);
12933 gst_value_array_append_value (&array, &value);
12934 g_value_reset (&value);
12936 gst_buffer_unref (block);
12938 index += block_size;
12941 /* only append the metadata if we successfully read all of it */
12943 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12944 (stream)->caps, 0), "streamheader", &array);
12946 GST_WARNING_OBJECT (qtdemux,
12947 "discarding all METADATA_BLOCKs due to invalid "
12948 "block_size %d at idx %d, rem %d", block_size, index,
12952 g_value_unset (&value);
12953 g_value_unset (&array);
12955 /* The sample rate obtained from the stsd may not be accurate
12956 * since it cannot represent rates greater than 65535Hz, so
12957 * override that value with the sample rate from the
12958 * METADATA_BLOCK_STREAMINFO block */
12959 CUR_STREAM (stream)->rate =
12960 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12971 gint len = QT_UINT32 (stsd_entry_data);
12974 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12977 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12979 /* If we have enough data, let's try to get the 'damr' atom. See
12980 * the 3GPP container spec (26.244) for more details. */
12981 if ((len - 0x34) > 8 &&
12982 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12983 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12984 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12987 gst_caps_set_simple (entry->caps,
12988 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12989 gst_buffer_unref (buf);
12995 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12996 gint len = QT_UINT32 (stsd_entry_data);
12997 guint16 sound_version = 0;
12998 /* FIXME: Can this be determined somehow? There doesn't seem to be
12999 * anything in mp4a atom that specifis compression */
13001 guint16 channels = entry->n_channels;
13002 guint32 time_scale = (guint32) entry->rate;
13003 gint sample_rate_index = -1;
13006 sound_version = QT_UINT16 (stsd_entry_data + 16);
13008 if (sound_version == 1) {
13009 channels = QT_UINT16 (stsd_entry_data + 24);
13010 time_scale = QT_UINT32 (stsd_entry_data + 30);
13012 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
13016 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
13020 sample_rate_index =
13021 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
13022 if (sample_rate_index >= 0 && channels > 0) {
13023 guint8 codec_data[2];
13026 /* build AAC codec data */
13027 codec_data[0] = profile << 3;
13028 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
13029 codec_data[1] = (sample_rate_index & 0x01) << 7;
13030 codec_data[1] |= (channels & 0xF) << 3;
13032 buf = gst_buffer_new_and_alloc (2);
13033 gst_buffer_fill (buf, 0, codec_data, 2);
13034 gst_caps_set_simple (entry->caps,
13035 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13036 gst_buffer_unref (buf);
13046 /* Fully handled elsewhere */
13049 GST_INFO_OBJECT (qtdemux,
13050 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13054 GST_INFO_OBJECT (qtdemux,
13055 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13056 GST_FOURCC_ARGS (fourcc), entry->caps);
13058 } else if (stream->subtype == FOURCC_strm) {
13059 if (fourcc == FOURCC_rtsp) {
13060 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
13062 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
13063 GST_FOURCC_ARGS (fourcc));
13064 goto unknown_stream;
13066 entry->sampled = TRUE;
13067 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
13068 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
13069 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
13071 entry->sampled = TRUE;
13072 entry->sparse = TRUE;
13075 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13078 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13079 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13084 /* hunt for sort-of codec data */
13088 GNode *mp4s = NULL;
13089 GNode *esds = NULL;
13091 /* look for palette in a stsd->mp4s->esds sub-atom */
13092 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
13094 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
13095 if (esds == NULL) {
13097 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13101 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13102 stream->stream_tags);
13106 GST_INFO_OBJECT (qtdemux,
13107 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13110 GST_INFO_OBJECT (qtdemux,
13111 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13112 GST_FOURCC_ARGS (fourcc), entry->caps);
13114 /* everything in 1 sample */
13115 entry->sampled = TRUE;
13118 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13121 if (entry->caps == NULL)
13122 goto unknown_stream;
13125 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13126 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13132 /* promote to sampled format */
13133 if (entry->fourcc == FOURCC_samr) {
13134 /* force mono 8000 Hz for AMR */
13135 entry->sampled = TRUE;
13136 entry->n_channels = 1;
13137 entry->rate = 8000;
13138 } else if (entry->fourcc == FOURCC_sawb) {
13139 /* force mono 16000 Hz for AMR-WB */
13140 entry->sampled = TRUE;
13141 entry->n_channels = 1;
13142 entry->rate = 16000;
13143 } else if (entry->fourcc == FOURCC_mp4a) {
13144 entry->sampled = TRUE;
13148 stsd_entry_data += len;
13149 remaining_stsd_len -= len;
13153 /* collect sample information */
13154 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13155 goto samples_failed;
13157 if (qtdemux->fragmented) {
13160 /* need all moov samples as basis; probably not many if any at all */
13161 /* prevent moof parsing taking of at this time */
13162 offset = qtdemux->moof_offset;
13163 qtdemux->moof_offset = 0;
13164 if (stream->n_samples &&
13165 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13166 qtdemux->moof_offset = offset;
13167 goto samples_failed;
13169 qtdemux->moof_offset = offset;
13170 /* movie duration more reliable in this case (e.g. mehd) */
13171 if (qtdemux->segment.duration &&
13172 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13174 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13177 /* configure segments */
13178 if (!qtdemux_parse_segments (qtdemux, stream, trak))
13179 goto segments_failed;
13181 /* add some language tag, if useful */
13182 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13183 strcmp (stream->lang_id, "und")) {
13184 const gchar *lang_code;
13186 /* convert ISO 639-2 code to ISO 639-1 */
13187 lang_code = gst_tag_get_language_code (stream->lang_id);
13188 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13189 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13192 /* Check for UDTA tags */
13193 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13194 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13197 /* Insert and sort new stream in track-id order.
13198 * This will help in comparing old/new streams during stream update check */
13199 g_ptr_array_add (qtdemux->active_streams, stream);
13200 g_ptr_array_sort (qtdemux->active_streams,
13201 (GCompareFunc) qtdemux_track_id_compare_func);
13202 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13203 QTDEMUX_N_STREAMS (qtdemux));
13210 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13211 (_("This file is corrupt and cannot be played.")), (NULL));
13213 gst_qtdemux_stream_unref (stream);
13218 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13219 gst_qtdemux_stream_unref (stream);
13225 /* we posted an error already */
13226 /* free stbl sub-atoms */
13227 gst_qtdemux_stbl_free (stream);
13228 gst_qtdemux_stream_unref (stream);
13233 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13239 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13240 GST_FOURCC_ARGS (stream->subtype));
13241 gst_qtdemux_stream_unref (stream);
13246 /* If we can estimate the overall bitrate, and don't have information about the
13247 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13248 * the overall bitrate minus the sum of the bitrates of all other streams. This
13249 * should be useful for the common case where we have one audio and one video
13250 * stream and can estimate the bitrate of one, but not the other. */
13252 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13254 QtDemuxStream *stream = NULL;
13255 gint64 size, sys_bitrate, sum_bitrate = 0;
13256 GstClockTime duration;
13260 if (qtdemux->fragmented)
13263 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13265 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13267 GST_DEBUG_OBJECT (qtdemux,
13268 "Size in bytes of the stream not known - bailing");
13272 /* Subtract the header size */
13273 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13274 size, qtdemux->header_size);
13276 if (size < qtdemux->header_size)
13279 size = size - qtdemux->header_size;
13281 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13282 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13286 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13287 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13288 switch (str->subtype) {
13291 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13292 CUR_STREAM (str)->caps);
13293 /* retrieve bitrate, prefer avg then max */
13295 if (str->stream_tags) {
13296 if (gst_tag_list_get_uint (str->stream_tags,
13297 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13298 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13299 if (gst_tag_list_get_uint (str->stream_tags,
13300 GST_TAG_NOMINAL_BITRATE, &bitrate))
13301 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13302 if (gst_tag_list_get_uint (str->stream_tags,
13303 GST_TAG_BITRATE, &bitrate))
13304 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13307 sum_bitrate += bitrate;
13310 GST_DEBUG_OBJECT (qtdemux,
13311 ">1 stream with unknown bitrate - bailing");
13318 /* For other subtypes, we assume no significant impact on bitrate */
13324 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13328 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13330 if (sys_bitrate < sum_bitrate) {
13331 /* This can happen, since sum_bitrate might be derived from maximum
13332 * bitrates and not average bitrates */
13333 GST_DEBUG_OBJECT (qtdemux,
13334 "System bitrate less than sum bitrate - bailing");
13338 bitrate = sys_bitrate - sum_bitrate;
13339 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13340 ", Stream bitrate = %u", sys_bitrate, bitrate);
13342 if (!stream->stream_tags)
13343 stream->stream_tags = gst_tag_list_new_empty ();
13345 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13347 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13348 GST_TAG_BITRATE, bitrate, NULL);
13351 static GstFlowReturn
13352 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13354 GstFlowReturn ret = GST_FLOW_OK;
13357 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13359 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13360 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13361 guint32 sample_num = 0;
13363 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13364 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13366 if (qtdemux->fragmented && qtdemux->pullbased) {
13367 /* need all moov samples first */
13368 GST_OBJECT_LOCK (qtdemux);
13369 while (stream->n_samples == 0)
13370 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13372 GST_OBJECT_UNLOCK (qtdemux);
13374 /* discard any stray moof */
13375 qtdemux->moof_offset = 0;
13378 /* prepare braking */
13379 if (ret != GST_FLOW_ERROR)
13382 /* in pull mode, we should have parsed some sample info by now;
13383 * and quite some code will not handle no samples.
13384 * in push mode, we'll just have to deal with it */
13385 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13386 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13387 g_ptr_array_remove_index (qtdemux->active_streams, i);
13390 } else if (stream->track_id == qtdemux->chapters_track_id &&
13391 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13392 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13393 so that it doesn't look like a subtitle track */
13394 g_ptr_array_remove_index (qtdemux->active_streams, i);
13399 /* parse the initial sample for use in setting the frame rate cap */
13400 while (sample_num == 0 && sample_num < stream->n_samples) {
13401 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13411 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13413 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13417 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13421 /* Different length, updated */
13422 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13425 /* streams in list are sorted in track-id order */
13426 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13427 /* Different stream-id, updated */
13428 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13429 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13437 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13438 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13440 /* Connect old stream's srcpad to new stream */
13441 newstream->pad = oldstream->pad;
13442 oldstream->pad = NULL;
13444 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13445 * case we need to force one through */
13446 newstream->new_stream = GST_PAD_IS_EOS (newstream->pad);
13448 return gst_qtdemux_configure_stream (qtdemux, newstream);
13452 qtdemux_update_streams (GstQTDemux * qtdemux)
13455 g_assert (qtdemux->streams_aware);
13457 /* At below, figure out which stream in active_streams has identical stream-id
13458 * with that of in old_streams. If there is matching stream-id,
13459 * corresponding newstream will not be exposed again,
13460 * but demux will reuse srcpad of matched old stream
13462 * active_streams : newly created streams from the latest moov
13463 * old_streams : existing streams (belong to previous moov)
13466 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13467 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13468 QtDemuxStream *oldstream = NULL;
13471 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13472 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13474 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13475 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13476 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13478 /* null pad stream cannot be reused */
13479 if (oldstream->pad == NULL)
13484 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13486 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13489 /* we don't need to preserve order of old streams */
13490 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13494 /* now we have all info and can expose */
13495 list = stream->stream_tags;
13496 stream->stream_tags = NULL;
13497 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13505 /* Must be called with expose lock */
13506 static GstFlowReturn
13507 qtdemux_expose_streams (GstQTDemux * qtdemux)
13511 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13513 if (!qtdemux_is_streams_update (qtdemux)) {
13514 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13515 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13516 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13517 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13518 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13519 return GST_FLOW_ERROR;
13522 g_ptr_array_set_size (qtdemux->old_streams, 0);
13523 qtdemux->need_segment = TRUE;
13525 return GST_FLOW_OK;
13528 if (qtdemux->streams_aware) {
13529 if (!qtdemux_update_streams (qtdemux))
13530 return GST_FLOW_ERROR;
13532 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13533 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13536 /* now we have all info and can expose */
13537 list = stream->stream_tags;
13538 stream->stream_tags = NULL;
13539 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13540 return GST_FLOW_ERROR;
13545 gst_qtdemux_guess_bitrate (qtdemux);
13547 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13549 /* If we have still old_streams, it's no more used stream */
13550 for (i = 0; i < qtdemux->old_streams->len; i++) {
13551 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13556 event = gst_event_new_eos ();
13557 if (qtdemux->segment_seqnum)
13558 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13560 gst_pad_push_event (stream->pad, event);
13564 g_ptr_array_set_size (qtdemux->old_streams, 0);
13566 /* check if we should post a redirect in case there is a single trak
13567 * and it is a redirecting trak */
13568 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13569 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13572 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13573 "an external content");
13574 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13575 gst_structure_new ("redirect",
13576 "new-location", G_TYPE_STRING,
13577 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13578 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13579 g_free (qtdemux->redirect_location);
13580 qtdemux->redirect_location =
13581 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13584 g_ptr_array_foreach (qtdemux->active_streams,
13585 (GFunc) qtdemux_do_allocation, qtdemux);
13587 qtdemux->need_segment = TRUE;
13589 qtdemux->exposed = TRUE;
13590 return GST_FLOW_OK;
13595 GstStructure *structure; /* helper for sort function */
13597 guint min_req_bitrate;
13598 guint min_req_qt_version;
13602 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13604 GstQtReference *ref_a = (GstQtReference *) a;
13605 GstQtReference *ref_b = (GstQtReference *) b;
13607 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13608 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13610 /* known bitrates go before unknown; higher bitrates go first */
13611 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13614 /* sort the redirects and post a message for the application.
13617 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13619 GstQtReference *best;
13622 GValue list_val = { 0, };
13625 g_assert (references != NULL);
13627 references = g_list_sort (references, qtdemux_redirects_sort_func);
13629 best = (GstQtReference *) references->data;
13631 g_value_init (&list_val, GST_TYPE_LIST);
13633 for (l = references; l != NULL; l = l->next) {
13634 GstQtReference *ref = (GstQtReference *) l->data;
13635 GValue struct_val = { 0, };
13637 ref->structure = gst_structure_new ("redirect",
13638 "new-location", G_TYPE_STRING, ref->location, NULL);
13640 if (ref->min_req_bitrate > 0) {
13641 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13642 ref->min_req_bitrate, NULL);
13645 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13646 g_value_set_boxed (&struct_val, ref->structure);
13647 gst_value_list_append_value (&list_val, &struct_val);
13648 g_value_unset (&struct_val);
13649 /* don't free anything here yet, since we need best->structure below */
13652 g_assert (best != NULL);
13653 s = gst_structure_copy (best->structure);
13655 if (g_list_length (references) > 1) {
13656 gst_structure_set_value (s, "locations", &list_val);
13659 g_value_unset (&list_val);
13661 for (l = references; l != NULL; l = l->next) {
13662 GstQtReference *ref = (GstQtReference *) l->data;
13664 gst_structure_free (ref->structure);
13665 g_free (ref->location);
13668 g_list_free (references);
13670 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13671 g_free (qtdemux->redirect_location);
13672 qtdemux->redirect_location =
13673 g_strdup (gst_structure_get_string (s, "new-location"));
13674 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13675 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13678 /* look for redirect nodes, collect all redirect information and
13682 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13684 GNode *rmra, *rmda, *rdrf;
13686 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13688 GList *redirects = NULL;
13690 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13692 GstQtReference ref = { NULL, NULL, 0, 0 };
13693 GNode *rmdr, *rmvc;
13695 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13696 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13697 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13698 ref.min_req_bitrate);
13701 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13702 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13703 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13705 #ifndef GST_DISABLE_GST_DEBUG
13706 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13708 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13710 GST_LOG_OBJECT (qtdemux,
13711 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13712 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13713 bitmask, check_type);
13714 if (package == FOURCC_qtim && check_type == 0) {
13715 ref.min_req_qt_version = version;
13719 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13725 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13726 if (ref_len > 20) {
13727 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13728 ref_data = (guint8 *) rdrf->data + 20;
13729 if (ref_type == FOURCC_alis) {
13730 guint record_len, record_version, fn_len;
13732 if (ref_len > 70) {
13733 /* MacOSX alias record, google for alias-layout.txt */
13734 record_len = QT_UINT16 (ref_data + 4);
13735 record_version = QT_UINT16 (ref_data + 4 + 2);
13736 fn_len = QT_UINT8 (ref_data + 50);
13737 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13738 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13741 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13744 } else if (ref_type == FOURCC_url_) {
13745 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13747 GST_DEBUG_OBJECT (qtdemux,
13748 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13749 GST_FOURCC_ARGS (ref_type));
13751 if (ref.location != NULL) {
13752 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13754 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13756 GST_WARNING_OBJECT (qtdemux,
13757 "Failed to extract redirect location from rdrf atom");
13760 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13764 /* look for others */
13765 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13768 if (redirects != NULL) {
13769 qtdemux_process_redirects (qtdemux, redirects);
13775 static GstTagList *
13776 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13780 if (tags == NULL) {
13781 tags = gst_tag_list_new_empty ();
13782 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13785 if (qtdemux->major_brand == FOURCC_mjp2)
13786 fmt = "Motion JPEG 2000";
13787 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13789 else if (qtdemux->major_brand == FOURCC_qt__)
13791 else if (qtdemux->fragmented)
13794 fmt = "ISO MP4/M4A";
13796 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13797 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13799 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13805 /* we have read the complete moov node now.
13806 * This function parses all of the relevant info, creates the traks and
13807 * prepares all data structures for playback
13810 qtdemux_parse_tree (GstQTDemux * qtdemux)
13817 guint64 creation_time;
13818 GstDateTime *datetime = NULL;
13821 /* make sure we have a usable taglist */
13822 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13824 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13825 if (mvhd == NULL) {
13826 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13827 return qtdemux_parse_redirects (qtdemux);
13830 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13831 if (version == 1) {
13832 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13833 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13834 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13835 } else if (version == 0) {
13836 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13837 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13838 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13840 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13844 /* Moving qt creation time (secs since 1904) to unix time */
13845 if (creation_time != 0) {
13846 /* Try to use epoch first as it should be faster and more commonly found */
13847 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13850 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13851 /* some data cleansing sanity */
13852 now_s = g_get_real_time () / G_USEC_PER_SEC;
13853 if (now_s + 24 * 3600 < creation_time) {
13854 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13856 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13859 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13860 GDateTime *dt, *dt_local;
13862 dt = g_date_time_add_seconds (base_dt, creation_time);
13863 dt_local = g_date_time_to_local (dt);
13864 datetime = gst_date_time_new_from_g_date_time (dt_local);
13866 g_date_time_unref (base_dt);
13867 g_date_time_unref (dt);
13871 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13872 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13874 gst_date_time_unref (datetime);
13877 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13878 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13880 /* check for fragmented file and get some (default) data */
13881 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13884 GstByteReader mehd_data;
13886 /* let track parsing or anyone know weird stuff might happen ... */
13887 qtdemux->fragmented = TRUE;
13889 /* compensate for total duration */
13890 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13892 qtdemux_parse_mehd (qtdemux, &mehd_data);
13895 /* Update the movie segment duration, unless it was directly given to us
13896 * by upstream. Otherwise let it as is, as we don't want to mangle the
13897 * duration provided by upstream that may come e.g. from a MPD file. */
13898 if (!qtdemux->upstream_format_is_time) {
13899 GstClockTime duration;
13900 /* set duration in the segment info */
13901 gst_qtdemux_get_duration (qtdemux, &duration);
13902 qtdemux->segment.duration = duration;
13903 /* also do not exceed duration; stop is set that way post seek anyway,
13904 * and segment activation falls back to duration,
13905 * whereas loop only checks stop, so let's align this here as well */
13906 qtdemux->segment.stop = duration;
13909 /* parse all traks */
13910 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13912 qtdemux_parse_trak (qtdemux, trak);
13913 /* iterate all siblings */
13914 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13917 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13920 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13922 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13924 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13927 /* maybe also some tags in meta box */
13928 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13930 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13931 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13933 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13936 /* parse any protection system info */
13937 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13939 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13940 qtdemux_parse_pssh (qtdemux, pssh);
13941 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13944 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13949 /* taken from ffmpeg */
13951 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13963 len = (len << 7) | (c & 0x7f);
13972 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13973 gsize codec_data_size)
13975 GList *list = NULL;
13976 guint8 *p = codec_data;
13977 gint i, offset, num_packets;
13978 guint *length, last;
13980 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13982 if (codec_data == NULL || codec_data_size == 0)
13985 /* start of the stream and vorbis audio or theora video, need to
13986 * send the codec_priv data as first three packets */
13987 num_packets = p[0] + 1;
13988 GST_DEBUG_OBJECT (qtdemux,
13989 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13990 (guint) num_packets, codec_data_size);
13992 /* Let's put some limits, Don't think there even is a xiph codec
13993 * with more than 3-4 headers */
13994 if (G_UNLIKELY (num_packets > 16)) {
13995 GST_WARNING_OBJECT (qtdemux,
13996 "Unlikely number of xiph headers, most likely not valid");
14000 length = g_alloca (num_packets * sizeof (guint));
14004 /* first packets, read length values */
14005 for (i = 0; i < num_packets - 1; i++) {
14007 while (offset < codec_data_size) {
14008 length[i] += p[offset];
14009 if (p[offset++] != 0xff)
14014 if (offset + last > codec_data_size)
14017 /* last packet is the remaining size */
14018 length[i] = codec_data_size - offset - last;
14020 for (i = 0; i < num_packets; i++) {
14023 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14025 if (offset + length[i] > codec_data_size)
14028 hdr = gst_buffer_new_memdup (p + offset, length[i]);
14029 list = g_list_append (list, hdr);
14031 offset += length[i];
14040 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14046 /* this can change the codec originally present in @list */
14048 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14049 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14051 int len = QT_UINT32 (esds->data);
14052 guint8 *ptr = esds->data;
14053 guint8 *end = ptr + len;
14055 guint8 *data_ptr = NULL;
14057 guint8 object_type_id = 0;
14058 guint8 stream_type = 0;
14059 const char *codec_name = NULL;
14060 GstCaps *caps = NULL;
14062 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14064 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14066 while (ptr + 1 < end) {
14067 tag = QT_UINT8 (ptr);
14068 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14070 len = read_descr_size (ptr, end, &ptr);
14071 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14073 /* Check the stated amount of data is available for reading */
14074 if (len < 0 || ptr + len > end)
14078 case ES_DESCRIPTOR_TAG:
14079 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14080 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14083 case DECODER_CONFIG_DESC_TAG:{
14084 guint max_bitrate, avg_bitrate;
14086 object_type_id = QT_UINT8 (ptr);
14087 stream_type = QT_UINT8 (ptr + 1) >> 2;
14088 max_bitrate = QT_UINT32 (ptr + 5);
14089 avg_bitrate = QT_UINT32 (ptr + 9);
14090 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14091 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14092 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14093 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14094 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14095 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14096 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14097 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14099 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14100 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14101 avg_bitrate, NULL);
14106 case DECODER_SPECIFIC_INFO_TAG:
14107 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14108 if (object_type_id == 0xe0 && len == 0x40) {
14114 GST_DEBUG_OBJECT (qtdemux,
14115 "Have VOBSUB palette. Creating palette event");
14116 /* move to decConfigDescr data and read palette */
14118 for (i = 0; i < 16; i++) {
14119 clut[i] = QT_UINT32 (data);
14123 s = gst_structure_new ("application/x-gst-dvd", "event",
14124 G_TYPE_STRING, "dvd-spu-clut-change",
14125 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14126 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14127 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14128 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14129 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14130 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14131 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14132 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14135 /* store event and trigger custom processing */
14136 stream->pending_event =
14137 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14139 /* Generic codec_data handler puts it on the caps */
14146 case SL_CONFIG_DESC_TAG:
14147 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14151 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14153 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14159 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14160 * in use, and should also be used to override some other parameters for some
14162 switch (object_type_id) {
14163 case 0x20: /* MPEG-4 */
14164 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14165 * profile_and_level_indication */
14166 if (data_ptr != NULL && data_len >= 5 &&
14167 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14168 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14169 data_ptr + 4, data_len - 4);
14171 break; /* Nothing special needed here */
14172 case 0x21: /* H.264 */
14173 codec_name = "H.264 / AVC";
14174 caps = gst_caps_new_simple ("video/x-h264",
14175 "stream-format", G_TYPE_STRING, "avc",
14176 "alignment", G_TYPE_STRING, "au", NULL);
14178 case 0x40: /* AAC (any) */
14179 case 0x66: /* AAC Main */
14180 case 0x67: /* AAC LC */
14181 case 0x68: /* AAC SSR */
14182 /* Override channels and rate based on the codec_data, as it's often
14184 /* Only do so for basic setup without HE-AAC extension */
14185 if (data_ptr && data_len == 2) {
14186 guint channels, rate;
14188 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14190 entry->n_channels = channels;
14192 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14194 entry->rate = rate;
14197 /* Set level and profile if possible */
14198 if (data_ptr != NULL && data_len >= 2) {
14199 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14200 data_ptr, data_len);
14202 const gchar *profile_str = NULL;
14205 guint8 *codec_data;
14206 gint rate_idx, profile;
14208 /* No codec_data, let's invent something.
14209 * FIXME: This is wrong for SBR! */
14211 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14213 buffer = gst_buffer_new_and_alloc (2);
14214 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14215 codec_data = map.data;
14218 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14221 switch (object_type_id) {
14223 profile_str = "main";
14227 profile_str = "lc";
14231 profile_str = "ssr";
14239 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14241 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14243 gst_buffer_unmap (buffer, &map);
14244 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14245 GST_TYPE_BUFFER, buffer, NULL);
14246 gst_buffer_unref (buffer);
14249 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14250 G_TYPE_STRING, profile_str, NULL);
14254 case 0x60: /* MPEG-2, various profiles */
14260 codec_name = "MPEG-2 video";
14261 caps = gst_caps_new_simple ("video/mpeg",
14262 "mpegversion", G_TYPE_INT, 2,
14263 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14265 case 0x69: /* MPEG-2 BC audio */
14266 case 0x6B: /* MPEG-1 audio */
14267 caps = gst_caps_new_simple ("audio/mpeg",
14268 "mpegversion", G_TYPE_INT, 1, NULL);
14269 codec_name = "MPEG-1 audio";
14271 case 0x6A: /* MPEG-1 */
14272 codec_name = "MPEG-1 video";
14273 caps = gst_caps_new_simple ("video/mpeg",
14274 "mpegversion", G_TYPE_INT, 1,
14275 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14277 case 0x6C: /* MJPEG */
14279 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14281 codec_name = "Motion-JPEG";
14283 case 0x6D: /* PNG */
14285 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14287 codec_name = "PNG still images";
14289 case 0x6E: /* JPEG2000 */
14290 codec_name = "JPEG-2000";
14291 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14293 case 0xA4: /* Dirac */
14294 codec_name = "Dirac";
14295 caps = gst_caps_new_empty_simple ("video/x-dirac");
14297 case 0xA5: /* AC3 */
14298 codec_name = "AC-3 audio";
14299 caps = gst_caps_new_simple ("audio/x-ac3",
14300 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14302 case 0xA9: /* AC3 */
14303 codec_name = "DTS audio";
14304 caps = gst_caps_new_simple ("audio/x-dts",
14305 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14308 if (stream_type == 0x05 && data_ptr) {
14310 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14313 GValue arr_val = G_VALUE_INIT;
14314 GValue buf_val = G_VALUE_INIT;
14317 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14318 codec_name = "Vorbis";
14319 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14320 g_value_init (&arr_val, GST_TYPE_ARRAY);
14321 g_value_init (&buf_val, GST_TYPE_BUFFER);
14322 for (tmp = headers; tmp; tmp = tmp->next) {
14323 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14324 gst_value_array_append_value (&arr_val, &buf_val);
14326 s = gst_caps_get_structure (caps, 0);
14327 gst_structure_take_value (s, "streamheader", &arr_val);
14328 g_value_unset (&buf_val);
14329 g_list_free (headers);
14336 case 0xE1: /* QCELP */
14337 /* QCELP, the codec_data is a riff tag (little endian) with
14338 * 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). */
14339 caps = gst_caps_new_empty_simple ("audio/qcelp");
14340 codec_name = "QCELP";
14346 /* If we have a replacement caps, then change our caps for this stream */
14348 gst_caps_unref (entry->caps);
14349 entry->caps = caps;
14352 if (codec_name && list)
14353 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14354 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14356 /* Add the codec_data attribute to caps, if we have it */
14360 buffer = gst_buffer_new_and_alloc (data_len);
14361 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14363 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14364 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14366 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14368 gst_buffer_unref (buffer);
14373 static inline GstCaps *
14374 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14378 char *s, fourstr[5];
14380 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14381 for (i = 0; i < 4; i++) {
14382 if (!g_ascii_isalnum (fourstr[i]))
14385 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14386 caps = gst_caps_new_empty_simple (s);
14391 #define _codec(name) \
14393 if (codec_name) { \
14394 *codec_name = g_strdup (name); \
14399 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14400 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14401 const guint8 * stsd_entry_data, gchar ** codec_name)
14403 GstCaps *caps = NULL;
14404 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14408 _codec ("PNG still images");
14409 caps = gst_caps_new_empty_simple ("image/png");
14412 _codec ("JPEG still images");
14414 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14417 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14418 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14419 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14420 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14421 _codec ("Motion-JPEG");
14423 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14426 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14427 _codec ("Motion-JPEG format B");
14428 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14431 _codec ("JPEG-2000");
14432 /* override to what it should be according to spec, avoid palette_data */
14433 entry->bits_per_sample = 24;
14434 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14437 _codec ("Sorensen video v.3");
14438 caps = gst_caps_new_simple ("video/x-svq",
14439 "svqversion", G_TYPE_INT, 3, NULL);
14441 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14442 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14443 _codec ("Sorensen video v.1");
14444 caps = gst_caps_new_simple ("video/x-svq",
14445 "svqversion", G_TYPE_INT, 1, NULL);
14447 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14448 caps = gst_caps_new_empty_simple ("video/x-raw");
14449 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14450 _codec ("Windows Raw RGB");
14451 stream->alignment = 32;
14457 bps = QT_UINT16 (stsd_entry_data + 82);
14460 format = GST_VIDEO_FORMAT_RGB15;
14463 format = GST_VIDEO_FORMAT_RGB16;
14466 format = GST_VIDEO_FORMAT_RGB;
14469 format = GST_VIDEO_FORMAT_ARGB;
14477 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14478 format = GST_VIDEO_FORMAT_I420;
14480 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14481 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14482 format = GST_VIDEO_FORMAT_I420;
14485 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14486 format = GST_VIDEO_FORMAT_UYVY;
14488 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14489 format = GST_VIDEO_FORMAT_v308;
14491 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14492 format = GST_VIDEO_FORMAT_v216;
14495 format = GST_VIDEO_FORMAT_v210;
14497 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14498 format = GST_VIDEO_FORMAT_r210;
14500 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14501 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14502 format = GST_VIDEO_FORMAT_v410;
14505 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14506 * but different order than AYUV
14507 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14508 format = GST_VIDEO_FORMAT_v408;
14511 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14512 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14513 _codec ("MPEG-1 video");
14514 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14515 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14517 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14518 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14519 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14520 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14521 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14522 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14523 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14524 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14525 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14526 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14527 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14528 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14529 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14530 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14531 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14532 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14533 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14534 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14535 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14536 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14537 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14538 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14539 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14540 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14541 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14542 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14543 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14544 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14545 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14546 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14547 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14548 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14549 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14550 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14551 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14552 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14553 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14554 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14555 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14556 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14557 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14558 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14559 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14560 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14561 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14562 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14563 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14564 _codec ("MPEG-2 video");
14565 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14566 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14568 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14569 _codec ("GIF still images");
14570 caps = gst_caps_new_empty_simple ("image/gif");
14573 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14575 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14577 /* ffmpeg uses the height/width props, don't know why */
14578 caps = gst_caps_new_simple ("video/x-h263",
14579 "variant", G_TYPE_STRING, "itu", NULL);
14583 _codec ("MPEG-4 video");
14584 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14585 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14587 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14588 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14589 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14590 caps = gst_caps_new_simple ("video/x-msmpeg",
14591 "msmpegversion", G_TYPE_INT, 43, NULL);
14593 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14595 caps = gst_caps_new_simple ("video/x-divx",
14596 "divxversion", G_TYPE_INT, 3, NULL);
14598 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14599 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14601 caps = gst_caps_new_simple ("video/x-divx",
14602 "divxversion", G_TYPE_INT, 4, NULL);
14604 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14606 caps = gst_caps_new_simple ("video/x-divx",
14607 "divxversion", G_TYPE_INT, 5, NULL);
14610 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14612 caps = gst_caps_new_simple ("video/x-ffv",
14613 "ffvversion", G_TYPE_INT, 1, NULL);
14616 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14617 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14622 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14623 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14624 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14628 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14629 _codec ("Cinepak");
14630 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14632 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14633 _codec ("Apple QuickDraw");
14634 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14636 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14637 _codec ("Apple video");
14638 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14643 _codec ("H.264 / AVC");
14644 caps = gst_caps_new_simple ("video/x-h264",
14645 "stream-format", G_TYPE_STRING, "avc",
14646 "alignment", G_TYPE_STRING, "au", NULL);
14650 _codec ("H.264 / AVC");
14651 caps = gst_caps_new_simple ("video/x-h264",
14652 "stream-format", G_TYPE_STRING, "avc3",
14653 "alignment", G_TYPE_STRING, "au", NULL);
14658 _codec ("H.265 / HEVC");
14659 caps = gst_caps_new_simple ("video/x-h265",
14660 "stream-format", G_TYPE_STRING, "hvc1",
14661 "alignment", G_TYPE_STRING, "au", NULL);
14665 _codec ("H.265 / HEVC");
14666 caps = gst_caps_new_simple ("video/x-h265",
14667 "stream-format", G_TYPE_STRING, "hev1",
14668 "alignment", G_TYPE_STRING, "au", NULL);
14671 _codec ("Run-length encoding");
14672 caps = gst_caps_new_simple ("video/x-rle",
14673 "layout", G_TYPE_STRING, "quicktime", NULL);
14676 _codec ("Run-length encoding");
14677 caps = gst_caps_new_simple ("video/x-rle",
14678 "layout", G_TYPE_STRING, "microsoft", NULL);
14680 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14681 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14682 _codec ("Indeo Video 3");
14683 caps = gst_caps_new_simple ("video/x-indeo",
14684 "indeoversion", G_TYPE_INT, 3, NULL);
14686 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14687 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14688 _codec ("Intel Video 4");
14689 caps = gst_caps_new_simple ("video/x-indeo",
14690 "indeoversion", G_TYPE_INT, 4, NULL);
14694 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14695 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14696 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14697 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14698 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14699 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14700 _codec ("DV Video");
14701 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14702 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14704 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14705 case FOURCC_dv5p: /* DVCPRO50 PAL */
14706 _codec ("DVCPro50 Video");
14707 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14708 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14710 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14711 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14712 _codec ("DVCProHD Video");
14713 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14714 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14716 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14717 _codec ("Apple Graphics (SMC)");
14718 caps = gst_caps_new_empty_simple ("video/x-smc");
14720 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14722 caps = gst_caps_new_empty_simple ("video/x-vp3");
14724 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14725 _codec ("VP6 Flash");
14726 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14730 caps = gst_caps_new_empty_simple ("video/x-theora");
14731 /* theora uses one byte of padding in the data stream because it does not
14732 * allow 0 sized packets while theora does */
14733 entry->padding = 1;
14737 caps = gst_caps_new_empty_simple ("video/x-dirac");
14739 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14740 _codec ("TIFF still images");
14741 caps = gst_caps_new_empty_simple ("image/tiff");
14743 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14744 _codec ("Apple Intermediate Codec");
14745 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14747 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14748 _codec ("AVID DNxHD");
14749 caps = gst_caps_from_string ("video/x-dnxhd");
14753 _codec ("On2 VP8");
14754 caps = gst_caps_from_string ("video/x-vp8");
14757 _codec ("Google VP9");
14758 caps = gst_caps_from_string ("video/x-vp9");
14761 _codec ("Apple ProRes LT");
14763 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14767 _codec ("Apple ProRes HQ");
14769 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14773 _codec ("Apple ProRes");
14775 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14779 _codec ("Apple ProRes Proxy");
14781 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14785 _codec ("Apple ProRes 4444");
14787 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14790 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14791 if (entry->bits_per_sample > 0) {
14792 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14797 _codec ("Apple ProRes 4444 XQ");
14799 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14802 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14803 if (entry->bits_per_sample > 0) {
14804 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14809 _codec ("GoPro CineForm");
14810 caps = gst_caps_from_string ("video/x-cineform");
14815 caps = gst_caps_new_simple ("video/x-wmv",
14816 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14820 caps = gst_caps_new_simple ("video/x-av1",
14821 "alignment", G_TYPE_STRING, "tu", NULL);
14823 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14826 caps = _get_unknown_codec_name ("video", fourcc);
14831 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14834 gst_video_info_init (&info);
14835 gst_video_info_set_format (&info, format, entry->width, entry->height);
14837 caps = gst_video_info_to_caps (&info);
14838 *codec_name = gst_pb_utils_get_codec_description (caps);
14840 /* enable clipping for raw video streams */
14841 stream->need_clip = TRUE;
14842 stream->alignment = 32;
14849 round_up_pow2 (guint n)
14861 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14862 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14863 int len, gchar ** codec_name)
14866 const GstStructure *s;
14869 GstAudioFormat format = 0;
14872 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14874 depth = entry->bytes_per_packet * 8;
14877 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14879 /* 8-bit audio is unsigned */
14881 format = GST_AUDIO_FORMAT_U8;
14882 /* otherwise it's signed and big-endian just like 'twos' */
14884 endian = G_BIG_ENDIAN;
14891 endian = G_LITTLE_ENDIAN;
14894 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14896 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14900 caps = gst_caps_new_simple ("audio/x-raw",
14901 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14902 "layout", G_TYPE_STRING, "interleaved", NULL);
14903 stream->alignment = GST_ROUND_UP_8 (depth);
14904 stream->alignment = round_up_pow2 (stream->alignment);
14908 _codec ("Raw 64-bit floating-point audio");
14909 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14911 caps = gst_caps_new_simple ("audio/x-raw",
14912 "format", G_TYPE_STRING, "F64BE",
14913 "layout", G_TYPE_STRING, "interleaved", NULL);
14914 stream->alignment = 8;
14917 _codec ("Raw 32-bit floating-point audio");
14918 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14920 caps = gst_caps_new_simple ("audio/x-raw",
14921 "format", G_TYPE_STRING, "F32BE",
14922 "layout", G_TYPE_STRING, "interleaved", NULL);
14923 stream->alignment = 4;
14926 _codec ("Raw 24-bit PCM audio");
14927 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14929 caps = gst_caps_new_simple ("audio/x-raw",
14930 "format", G_TYPE_STRING, "S24BE",
14931 "layout", G_TYPE_STRING, "interleaved", NULL);
14932 stream->alignment = 4;
14935 _codec ("Raw 32-bit PCM audio");
14936 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14938 caps = gst_caps_new_simple ("audio/x-raw",
14939 "format", G_TYPE_STRING, "S32BE",
14940 "layout", G_TYPE_STRING, "interleaved", NULL);
14941 stream->alignment = 4;
14944 _codec ("Raw 16-bit PCM audio");
14945 caps = gst_caps_new_simple ("audio/x-raw",
14946 "format", G_TYPE_STRING, "S16LE",
14947 "layout", G_TYPE_STRING, "interleaved", NULL);
14948 stream->alignment = 2;
14951 _codec ("Mu-law audio");
14952 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14955 _codec ("A-law audio");
14956 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14960 _codec ("Microsoft ADPCM");
14961 /* Microsoft ADPCM-ACM code 2 */
14962 caps = gst_caps_new_simple ("audio/x-adpcm",
14963 "layout", G_TYPE_STRING, "microsoft", NULL);
14967 _codec ("DVI/IMA ADPCM");
14968 caps = gst_caps_new_simple ("audio/x-adpcm",
14969 "layout", G_TYPE_STRING, "dvi", NULL);
14973 _codec ("DVI/Intel IMA ADPCM");
14974 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14975 caps = gst_caps_new_simple ("audio/x-adpcm",
14976 "layout", G_TYPE_STRING, "quicktime", NULL);
14980 /* MPEG layer 3, CBR only (pre QT4.1) */
14983 _codec ("MPEG-1 layer 3");
14984 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14985 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14986 "mpegversion", G_TYPE_INT, 1, NULL);
14988 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14989 _codec ("MPEG-1 layer 2");
14991 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14992 "mpegversion", G_TYPE_INT, 1, NULL);
14995 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14996 _codec ("EAC-3 audio");
14997 caps = gst_caps_new_simple ("audio/x-eac3",
14998 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14999 entry->sampled = TRUE;
15001 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15003 _codec ("AC-3 audio");
15004 caps = gst_caps_new_simple ("audio/x-ac3",
15005 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15006 entry->sampled = TRUE;
15008 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15009 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15010 _codec ("DTS audio");
15011 caps = gst_caps_new_simple ("audio/x-dts",
15012 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15013 entry->sampled = TRUE;
15015 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15016 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15017 _codec ("DTS-HD audio");
15018 caps = gst_caps_new_simple ("audio/x-dts",
15019 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15020 entry->sampled = TRUE;
15024 caps = gst_caps_new_simple ("audio/x-mace",
15025 "maceversion", G_TYPE_INT, 3, NULL);
15029 caps = gst_caps_new_simple ("audio/x-mace",
15030 "maceversion", G_TYPE_INT, 6, NULL);
15032 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15034 caps = gst_caps_new_empty_simple ("application/ogg");
15036 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15037 _codec ("DV audio");
15038 caps = gst_caps_new_empty_simple ("audio/x-dv");
15041 _codec ("MPEG-4 AAC audio");
15042 caps = gst_caps_new_simple ("audio/mpeg",
15043 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15044 "stream-format", G_TYPE_STRING, "raw", NULL);
15046 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15047 _codec ("QDesign Music");
15048 caps = gst_caps_new_empty_simple ("audio/x-qdm");
15051 _codec ("QDesign Music v.2");
15052 /* FIXME: QDesign music version 2 (no constant) */
15053 if (FALSE && data) {
15054 caps = gst_caps_new_simple ("audio/x-qdm2",
15055 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15056 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15057 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15059 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15063 _codec ("GSM audio");
15064 caps = gst_caps_new_empty_simple ("audio/x-gsm");
15067 _codec ("AMR audio");
15068 caps = gst_caps_new_empty_simple ("audio/AMR");
15071 _codec ("AMR-WB audio");
15072 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15075 _codec ("Quicktime IMA ADPCM");
15076 caps = gst_caps_new_simple ("audio/x-adpcm",
15077 "layout", G_TYPE_STRING, "quicktime", NULL);
15080 _codec ("Apple lossless audio");
15081 caps = gst_caps_new_empty_simple ("audio/x-alac");
15084 _codec ("Free Lossless Audio Codec");
15085 caps = gst_caps_new_simple ("audio/x-flac",
15086 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15088 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15089 _codec ("QualComm PureVoice");
15090 caps = gst_caps_from_string ("audio/qcelp");
15095 caps = gst_caps_new_empty_simple ("audio/x-wma");
15099 caps = gst_caps_new_empty_simple ("audio/x-opus");
15106 GstAudioFormat format;
15109 FLAG_IS_FLOAT = 0x1,
15110 FLAG_IS_BIG_ENDIAN = 0x2,
15111 FLAG_IS_SIGNED = 0x4,
15112 FLAG_IS_PACKED = 0x8,
15113 FLAG_IS_ALIGNED_HIGH = 0x10,
15114 FLAG_IS_NON_INTERLEAVED = 0x20
15116 _codec ("Raw LPCM audio");
15118 if (data && len >= 36) {
15119 depth = QT_UINT32 (data + 24);
15120 flags = QT_UINT32 (data + 28);
15121 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15123 if ((flags & FLAG_IS_FLOAT) == 0) {
15128 if ((flags & FLAG_IS_ALIGNED_HIGH))
15131 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15132 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15133 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15134 caps = gst_caps_new_simple ("audio/x-raw",
15135 "format", G_TYPE_STRING,
15137 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15138 "UNKNOWN", "layout", G_TYPE_STRING,
15139 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15140 "interleaved", NULL);
15141 stream->alignment = GST_ROUND_UP_8 (depth);
15142 stream->alignment = round_up_pow2 (stream->alignment);
15147 if (flags & FLAG_IS_BIG_ENDIAN)
15148 format = GST_AUDIO_FORMAT_F64BE;
15150 format = GST_AUDIO_FORMAT_F64LE;
15152 if (flags & FLAG_IS_BIG_ENDIAN)
15153 format = GST_AUDIO_FORMAT_F32BE;
15155 format = GST_AUDIO_FORMAT_F32LE;
15157 caps = gst_caps_new_simple ("audio/x-raw",
15158 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15159 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15160 "non-interleaved" : "interleaved", NULL);
15161 stream->alignment = width / 8;
15165 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15168 caps = gst_caps_new_empty_simple ("audio/x-ac4");
15171 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15175 caps = _get_unknown_codec_name ("audio", fourcc);
15181 GstCaps *templ_caps =
15182 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15183 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15184 gst_caps_unref (caps);
15185 gst_caps_unref (templ_caps);
15186 caps = intersection;
15189 /* enable clipping for raw audio streams */
15190 s = gst_caps_get_structure (caps, 0);
15191 name = gst_structure_get_name (s);
15192 if (g_str_has_prefix (name, "audio/x-raw")) {
15193 stream->need_clip = TRUE;
15194 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15195 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15196 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15197 stream->max_buffer_size);
15203 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15204 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15205 const guint8 * stsd_entry_data, gchar ** codec_name)
15209 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15213 _codec ("DVD subtitle");
15214 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15215 stream->process_func = gst_qtdemux_process_buffer_dvd;
15218 _codec ("Quicktime timed text");
15221 _codec ("3GPP timed text");
15223 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15225 /* actual text piece needs to be extracted */
15226 stream->process_func = gst_qtdemux_process_buffer_text;
15229 _codec ("XML subtitles");
15230 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15235 const gchar *buf = "WEBVTT\n\n";
15237 _codec ("WebVTT subtitles");
15238 caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15239 stream->process_func = gst_qtdemux_process_buffer_wvtt;
15241 /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15242 buffer = gst_buffer_new_and_alloc (8);
15243 gst_buffer_fill (buffer, 0, buf, 8);
15244 stream->buffers = g_slist_append (stream->buffers, buffer);
15249 _codec ("CEA 608 Closed Caption");
15251 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15252 G_TYPE_STRING, "s334-1a", NULL);
15253 stream->process_func = gst_qtdemux_process_buffer_clcp;
15254 stream->need_split = TRUE;
15257 _codec ("CEA 708 Closed Caption");
15259 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15260 G_TYPE_STRING, "cdp", NULL);
15261 stream->process_func = gst_qtdemux_process_buffer_clcp;
15266 caps = _get_unknown_codec_name ("text", fourcc);
15274 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15275 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15276 const guint8 * stsd_entry_data, gchar ** codec_name)
15282 _codec ("MPEG 1 video");
15283 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15284 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15294 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15295 const gchar * system_id)
15299 if (!qtdemux->protection_system_ids)
15300 qtdemux->protection_system_ids =
15301 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15302 /* Check whether we already have an entry for this system ID. */
15303 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15304 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15305 if (g_ascii_strcasecmp (system_id, id) == 0) {
15309 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15310 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,