2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
12 * Copyright (C) <2016> British Broadcasting Corporation
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with this library; if not, write to the
26 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
31 * SECTION:element-qtdemux
34 * Demuxes a .mov file into raw or compressed audio and/or video streams.
36 * This element supports both push and pull-based scheduling, depending on the
37 * capabilities of the upstream elements.
39 * ## Example launch line
41 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
42 * ]| Play (parse and decode) a .mov file and try to output it to
43 * an automatically detected soundcard and videosink. If the MOV file contains
44 * compressed audio or video data, this will only work if you have the
45 * right decoder elements/plugins installed.
53 #include "gst/gst-i18n-plugin.h"
55 #include <glib/gprintf.h>
56 #include <gst/base/base.h>
57 #include <gst/tag/tag.h>
58 #include <gst/audio/audio.h>
59 #include <gst/riff/riff.h>
60 #include <gst/pbutils/pbutils.h>
62 #include "gstisomp4elements.h"
63 #include "qtatomparser.h"
64 #include "qtdemux_types.h"
65 #include "qtdemux_dump.h"
67 #include "descriptors.h"
68 #include "qtdemux_lang.h"
70 #include "qtpalette.h"
71 #include "qtdemux_tags.h"
72 #include "qtdemux_tree.h"
73 #include "qtdemux-webvtt.h"
79 #include <gst/math-compat.h>
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
97 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
99 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
101 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
103 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
104 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
105 #define QTDEMUX_NTH_STREAM(demux,idx) \
106 QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
107 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
108 QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
110 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
112 GST_DEBUG_CATEGORY (qtdemux_debug);
113 #define GST_CAT_DEFAULT qtdemux_debug
115 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
116 typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
118 /* Macros for converting to/from timescale */
119 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
120 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
122 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
123 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
125 /* timestamp is the DTS */
126 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
127 /* timestamp + offset + cslg_shift is the outgoing PTS */
128 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
129 /* timestamp + offset is the PTS used for internal seek calculations */
130 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
131 /* timestamp + duration - dts is the duration */
132 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
134 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
136 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
137 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
138 GST_TRACE("Locking from thread %p", g_thread_self()); \
139 g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
140 GST_TRACE("Locked from thread %p", g_thread_self()); \
143 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
144 GST_TRACE("Unlocking from thread %p", g_thread_self()); \
145 g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
149 * Quicktime has tracks and segments. A track is a continuous piece of
150 * multimedia content. The track is not always played from start to finish but
151 * instead, pieces of the track are 'cut out' and played in sequence. This is
152 * what the segments do.
154 * Inside the track we have keyframes (K) and delta frames. The track has its
155 * own timing, which starts from 0 and extends to end. The position in the track
156 * is called the media_time.
158 * The segments now describe the pieces that should be played from this track
159 * and are basically tuples of media_time/duration/rate entries. We can have
160 * multiple segments and they are all played after one another. An example:
162 * segment 1: media_time: 1 second, duration: 1 second, rate 1
163 * segment 2: media_time: 3 second, duration: 2 second, rate 2
165 * To correctly play back this track, one must play: 1 second of media starting
166 * from media_time 1 followed by 2 seconds of media starting from media_time 3
169 * Each of the segments will be played at a specific time, the first segment at
170 * time 0, the second one after the duration of the first one, etc.. Note that
171 * the time in resulting playback is not identical to the media_time of the
174 * Visually, assuming the track has 4 second of media_time:
177 * .-----------------------------------------------------------.
178 * track: | K.....K.........K........K.......K.......K...........K... |
179 * '-----------------------------------------------------------'
181 * .------------^ ^ .----------^ ^
182 * / .-------------' / .------------------'
184 * .--------------. .--------------.
185 * | segment 1 | | segment 2 |
186 * '--------------' '--------------'
188 * The challenge here is to cut out the right pieces of the track for each of
189 * the playback segments. This fortunately can easily be done with the SEGMENT
190 * events of GStreamer.
192 * For playback of segment 1, we need to provide the decoder with the keyframe
193 * (a), in the above figure, but we must instruct it only to output the decoded
194 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
195 * position set to the time of the segment: 0.
197 * We then proceed to push data from keyframe (a) to frame (b). The decoder
198 * decodes but clips all before media_time 1.
200 * After finishing a segment, we push out a new SEGMENT event with the clipping
201 * boundaries of the new data.
203 * This is a good usecase for the GStreamer accumulated SEGMENT events.
206 struct _QtDemuxSegment
208 /* global time and duration, all gst time */
210 GstClockTime stop_time;
211 GstClockTime duration;
212 /* media time of trak, all gst time */
213 GstClockTime media_start;
214 GstClockTime media_stop;
216 /* Media start time in trak timescale units */
217 guint32 trak_media_start;
220 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
222 /* Used with fragmented MP4 files (mfra atom) */
223 struct _QtDemuxRandomAccessEntry
230 /* Contains properties and cryptographic info for a set of samples from a
231 * track protected using Common Encryption (cenc) */
232 struct _QtDemuxCencSampleSetInfo
234 GstStructure *default_properties;
236 /* @crypto_info holds one GstStructure per sample */
237 GPtrArray *crypto_info;
240 struct _QtDemuxAavdEncryptionInfo
242 GstStructure *default_properties;
246 qt_demux_state_string (enum QtDemuxState state)
249 case QTDEMUX_STATE_INITIAL:
251 case QTDEMUX_STATE_HEADER:
253 case QTDEMUX_STATE_MOVIE:
255 case QTDEMUX_STATE_BUFFER_MDAT:
256 return "<BUFFER_MDAT>";
262 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
264 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
266 static GstStaticPadTemplate gst_qtdemux_sink_template =
267 GST_STATIC_PAD_TEMPLATE ("sink",
270 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
274 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
275 GST_STATIC_PAD_TEMPLATE ("video_%u",
278 GST_STATIC_CAPS_ANY);
280 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
281 GST_STATIC_PAD_TEMPLATE ("audio_%u",
284 GST_STATIC_CAPS_ANY);
286 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
287 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
290 GST_STATIC_CAPS_ANY);
292 #define gst_qtdemux_parent_class parent_class
293 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
294 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
295 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
297 static void gst_qtdemux_dispose (GObject * object);
298 static void gst_qtdemux_finalize (GObject * object);
301 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
302 GstClockTime media_time);
304 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
305 QtDemuxStream * str, gint64 media_offset);
308 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
309 static GstIndex *gst_qtdemux_get_index (GstElement * element);
311 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
312 GstStateChange transition);
313 static void gst_qtdemux_set_context (GstElement * element,
314 GstContext * context);
315 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
316 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
317 GstObject * parent, GstPadMode mode, gboolean active);
319 static void gst_qtdemux_loop (GstPad * pad);
320 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
322 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
324 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
326 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
327 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
328 QtDemuxStream * stream);
329 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
330 QtDemuxStream * stream);
331 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
334 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
336 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
337 const guint8 * buffer, guint length);
338 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
339 const guint8 * buffer, guint length);
340 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
342 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
343 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
345 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
346 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
347 const guint8 * stsd_entry_data, gchar ** codec_name);
348 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
349 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
350 const guint8 * data, int len, gchar ** codec_name);
351 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
352 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
353 gchar ** codec_name);
354 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
355 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
356 const guint8 * stsd_entry_data, gchar ** codec_name);
358 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
359 QtDemuxStream * stream, guint32 n);
360 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
361 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
362 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
363 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
364 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
365 static void qtdemux_do_allocation (QtDemuxStream * stream,
366 GstQTDemux * qtdemux);
367 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
368 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
369 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
370 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
371 GstClockTime * _start, GstClockTime * _stop);
372 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
373 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
375 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
376 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
378 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
380 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
381 QtDemuxStream * stream, guint sample_index);
382 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
384 static void qtdemux_gst_structure_free (GstStructure * gststructure);
385 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
388 gst_qtdemux_class_init (GstQTDemuxClass * klass)
390 GObjectClass *gobject_class;
391 GstElementClass *gstelement_class;
393 gobject_class = (GObjectClass *) klass;
394 gstelement_class = (GstElementClass *) klass;
396 parent_class = g_type_class_peek_parent (klass);
398 gobject_class->dispose = gst_qtdemux_dispose;
399 gobject_class->finalize = gst_qtdemux_finalize;
401 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
403 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
404 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
406 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
408 gst_tag_register_musicbrainz_tags ();
410 gst_element_class_add_static_pad_template (gstelement_class,
411 &gst_qtdemux_sink_template);
412 gst_element_class_add_static_pad_template (gstelement_class,
413 &gst_qtdemux_videosrc_template);
414 gst_element_class_add_static_pad_template (gstelement_class,
415 &gst_qtdemux_audiosrc_template);
416 gst_element_class_add_static_pad_template (gstelement_class,
417 &gst_qtdemux_subsrc_template);
418 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
420 "Demultiplex a QuickTime file into audio and video streams",
421 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
423 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
428 gst_qtdemux_init (GstQTDemux * qtdemux)
431 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
432 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
433 gst_pad_set_activatemode_function (qtdemux->sinkpad,
434 qtdemux_sink_activate_mode);
435 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
436 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
437 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
438 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
440 qtdemux->adapter = gst_adapter_new ();
441 g_queue_init (&qtdemux->protection_event_queue);
442 qtdemux->flowcombiner = gst_flow_combiner_new ();
443 g_mutex_init (&qtdemux->expose_lock);
445 qtdemux->active_streams = g_ptr_array_new_with_free_func
446 ((GDestroyNotify) gst_qtdemux_stream_unref);
447 qtdemux->old_streams = g_ptr_array_new_with_free_func
448 ((GDestroyNotify) gst_qtdemux_stream_unref);
450 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
452 gst_qtdemux_reset (qtdemux, TRUE);
456 gst_qtdemux_finalize (GObject * object)
458 GstQTDemux *qtdemux = GST_QTDEMUX (object);
460 g_free (qtdemux->redirect_location);
462 G_OBJECT_CLASS (parent_class)->finalize (object);
466 gst_qtdemux_dispose (GObject * object)
468 GstQTDemux *qtdemux = GST_QTDEMUX (object);
470 if (qtdemux->adapter) {
471 g_object_unref (G_OBJECT (qtdemux->adapter));
472 qtdemux->adapter = NULL;
474 gst_tag_list_unref (qtdemux->tag_list);
475 gst_flow_combiner_free (qtdemux->flowcombiner);
476 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
478 g_queue_clear (&qtdemux->protection_event_queue);
480 g_free (qtdemux->cenc_aux_info_sizes);
481 qtdemux->cenc_aux_info_sizes = NULL;
482 g_mutex_clear (&qtdemux->expose_lock);
484 g_ptr_array_free (qtdemux->active_streams, TRUE);
485 g_ptr_array_free (qtdemux->old_streams, TRUE);
487 G_OBJECT_CLASS (parent_class)->dispose (object);
491 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
493 if (qtdemux->redirect_location) {
494 GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
495 (_("This file contains no playable streams.")),
496 ("no known streams found, a redirect message has been posted"),
497 ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
499 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
500 (_("This file contains no playable streams.")),
501 ("no known streams found"));
506 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
508 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
509 mem, size, 0, size, mem, free_func);
513 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
520 if (G_UNLIKELY (size == 0)) {
522 GstBuffer *tmp = NULL;
524 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
525 if (ret != GST_FLOW_OK)
528 gst_buffer_map (tmp, &map, GST_MAP_READ);
529 size = QT_UINT32 (map.data);
530 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
532 gst_buffer_unmap (tmp, &map);
533 gst_buffer_unref (tmp);
536 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
537 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
538 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
539 /* we're pulling header but already got most interesting bits,
540 * so never mind the rest (e.g. tags) (that much) */
541 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
545 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
546 (_("This file is invalid and cannot be played.")),
547 ("atom has bogus size %" G_GUINT64_FORMAT, size));
548 return GST_FLOW_ERROR;
552 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
554 if (G_UNLIKELY (flow != GST_FLOW_OK))
557 bsize = gst_buffer_get_size (*buf);
558 /* Catch short reads - we don't want any partial atoms */
559 if (G_UNLIKELY (bsize < size)) {
560 GST_WARNING_OBJECT (qtdemux,
561 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
562 gst_buffer_unref (*buf);
572 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
573 GstFormat src_format, gint64 src_value, GstFormat dest_format,
577 QtDemuxStream *stream = gst_pad_get_element_private (pad);
580 if (stream->subtype != FOURCC_vide) {
585 switch (src_format) {
586 case GST_FORMAT_TIME:
587 switch (dest_format) {
588 case GST_FORMAT_BYTES:{
589 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
595 *dest_value = stream->samples[index].offset;
597 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
598 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
599 GST_TIME_ARGS (src_value), *dest_value);
607 case GST_FORMAT_BYTES:
608 switch (dest_format) {
609 case GST_FORMAT_TIME:{
611 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
620 QTSTREAMTIME_TO_GSTTIME (stream,
621 stream->samples[index].timestamp);
622 GST_DEBUG_OBJECT (qtdemux,
623 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
624 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
643 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
645 gboolean res = FALSE;
647 *duration = GST_CLOCK_TIME_NONE;
649 if (qtdemux->duration != 0 &&
650 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
651 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
654 *duration = GST_CLOCK_TIME_NONE;
661 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
664 gboolean res = FALSE;
665 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
667 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
669 switch (GST_QUERY_TYPE (query)) {
670 case GST_QUERY_POSITION:{
673 gst_query_parse_position (query, &fmt, NULL);
674 if (fmt == GST_FORMAT_TIME
675 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
676 gst_query_set_position (query, GST_FORMAT_TIME,
677 qtdemux->segment.position);
682 case GST_QUERY_DURATION:{
685 gst_query_parse_duration (query, &fmt, NULL);
686 if (fmt == GST_FORMAT_TIME) {
687 /* First try to query upstream */
688 res = gst_pad_query_default (pad, parent, query);
690 GstClockTime duration;
691 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
692 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
699 case GST_QUERY_CONVERT:{
700 GstFormat src_fmt, dest_fmt;
701 gint64 src_value, dest_value = 0;
703 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
705 res = gst_qtdemux_src_convert (qtdemux, pad,
706 src_fmt, src_value, dest_fmt, &dest_value);
708 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
712 case GST_QUERY_FORMATS:
713 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
716 case GST_QUERY_SEEKING:{
720 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
722 if (fmt == GST_FORMAT_BYTES) {
723 /* We always refuse BYTES seeks from downstream */
727 /* try upstream first */
728 res = gst_pad_query_default (pad, parent, query);
731 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
732 if (fmt == GST_FORMAT_TIME) {
733 GstClockTime duration;
735 gst_qtdemux_get_duration (qtdemux, &duration);
737 if (!qtdemux->pullbased) {
740 /* we might be able with help from upstream */
742 q = gst_query_new_seeking (GST_FORMAT_BYTES);
743 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
744 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
745 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
749 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
755 case GST_QUERY_SEGMENT:
760 format = qtdemux->segment.format;
763 gst_segment_to_stream_time (&qtdemux->segment, format,
764 qtdemux->segment.start);
765 if ((stop = qtdemux->segment.stop) == -1)
766 stop = qtdemux->segment.duration;
768 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
770 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
775 res = gst_pad_query_default (pad, parent, query);
783 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
785 if (G_LIKELY (stream->pad)) {
786 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
787 GST_DEBUG_PAD_NAME (stream->pad));
789 if (!gst_tag_list_is_empty (stream->stream_tags)) {
790 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
791 stream->stream_tags);
792 gst_pad_push_event (stream->pad,
793 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
796 if (G_UNLIKELY (stream->send_global_tags)) {
797 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
799 gst_pad_push_event (stream->pad,
800 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
801 stream->send_global_tags = FALSE;
806 /* push event on all source pads; takes ownership of the event */
808 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
810 gboolean has_valid_stream = FALSE;
811 GstEventType etype = GST_EVENT_TYPE (event);
814 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
815 GST_EVENT_TYPE_NAME (event));
817 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
819 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
820 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
822 if ((pad = stream->pad)) {
823 has_valid_stream = TRUE;
825 if (etype == GST_EVENT_EOS) {
826 /* let's not send twice */
827 if (stream->sent_eos)
829 stream->sent_eos = TRUE;
832 gst_pad_push_event (pad, gst_event_ref (event));
836 gst_event_unref (event);
838 /* if it is EOS and there are no pads, post an error */
839 if (!has_valid_stream && etype == GST_EVENT_EOS) {
840 gst_qtdemux_post_no_playable_stream_error (qtdemux);
850 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
852 if ((gint64) s1->timestamp > *media_time)
854 if ((gint64) s1->timestamp == *media_time)
860 /* find the index of the sample that includes the data for @media_time using a
861 * binary search. Only to be called in optimized cases of linear search below.
863 * Returns the index of the sample with the corresponding *DTS*.
866 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
869 QtDemuxSample *result;
872 /* convert media_time to mov format */
874 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
876 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
877 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
878 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
880 if (G_LIKELY (result))
881 index = result - str->samples;
890 /* find the index of the sample that includes the data for @media_offset using a
893 * Returns the index of the sample.
896 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
897 QtDemuxStream * str, gint64 media_offset)
899 QtDemuxSample *result = str->samples;
902 if (result == NULL || str->n_samples == 0)
905 if (media_offset == result->offset)
909 while (index < str->n_samples - 1) {
910 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
913 if (media_offset < result->offset)
924 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
929 /* find the index of the sample that includes the data for @media_time using a
930 * linear search, and keeping in mind that not all samples may have been parsed
931 * yet. If possible, it will delegate to binary search.
933 * Returns the index of the sample.
936 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
937 GstClockTime media_time)
941 QtDemuxSample *sample;
943 /* convert media_time to mov format */
945 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
947 sample = str->samples;
948 if (mov_time == sample->timestamp + sample->pts_offset)
951 /* use faster search if requested time in already parsed range */
952 sample = str->samples + str->stbl_index;
953 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
954 index = gst_qtdemux_find_index (qtdemux, str, media_time);
955 sample = str->samples + index;
957 while (index < str->n_samples - 1) {
958 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
961 sample = str->samples + index + 1;
962 if (mov_time < sample->timestamp) {
963 sample = str->samples + index;
971 /* sample->timestamp is now <= media_time, need to find the corresponding
972 * PTS now by looking backwards */
973 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
975 sample = str->samples + index;
983 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
988 /* find the index of the keyframe needed to decode the sample at @index
989 * of stream @str, or of a subsequent keyframe (depending on @next)
991 * Returns the index of the keyframe.
994 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
995 guint32 index, gboolean next)
997 guint32 new_index = index;
999 if (index >= str->n_samples) {
1000 new_index = str->n_samples;
1004 /* all keyframes, return index */
1005 if (str->all_keyframe) {
1010 /* else search until we have a keyframe */
1011 while (new_index < str->n_samples) {
1012 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1015 if (str->samples[new_index].keyframe)
1027 if (new_index == str->n_samples) {
1028 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1033 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1034 "gave %u", next ? "after" : "before", index, new_index);
1041 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1046 /* find the segment for @time_position for @stream
1048 * Returns the index of the segment containing @time_position.
1049 * Returns the last segment and sets the @eos variable to TRUE
1050 * if the time is beyond the end. @eos may be NULL
1053 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1054 GstClockTime time_position)
1059 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1060 GST_TIME_ARGS (time_position));
1063 for (i = 0; i < stream->n_segments; i++) {
1064 QtDemuxSegment *segment = &stream->segments[i];
1066 GST_LOG_OBJECT (stream->pad,
1067 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1068 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1070 /* For the last segment we include stop_time in the last segment */
1071 if (i < stream->n_segments - 1) {
1072 if (segment->time <= time_position && time_position < segment->stop_time) {
1073 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1078 /* Last segment always matches */
1086 /* move the stream @str to the sample position @index.
1088 * Updates @str->sample_index and marks discontinuity if needed.
1091 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1094 /* no change needed */
1095 if (index == str->sample_index)
1098 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1101 /* position changed, we have a discont */
1102 str->sample_index = index;
1103 str->offset_in_sample = 0;
1104 /* Each time we move in the stream we store the position where we are
1106 str->from_sample = index;
1107 str->discont = TRUE;
1111 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1112 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1115 gint64 min_byte_offset = -1;
1118 min_offset = desired_time;
1120 /* for each stream, find the index of the sample in the segment
1121 * and move back to the previous keyframe. */
1122 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1124 guint32 index, kindex;
1126 GstClockTime media_start;
1127 GstClockTime media_time;
1128 GstClockTime seg_time;
1129 QtDemuxSegment *seg;
1130 gboolean empty_segment = FALSE;
1132 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1134 if (CUR_STREAM (str)->sparse && !use_sparse)
1137 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1138 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1140 /* get segment and time in the segment */
1141 seg = &str->segments[seg_idx];
1142 seg_time = (desired_time - seg->time) * seg->rate;
1144 while (QTSEGMENT_IS_EMPTY (seg)) {
1146 empty_segment = TRUE;
1147 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1150 if (seg_idx == str->n_segments)
1152 seg = &str->segments[seg_idx];
1155 if (seg_idx == str->n_segments) {
1156 /* FIXME track shouldn't have the last segment as empty, but if it
1157 * happens we better handle it */
1161 /* get the media time in the segment */
1162 media_start = seg->media_start + seg_time;
1164 /* get the index of the sample with media time */
1165 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1166 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1167 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1168 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1171 /* shift to next frame if we are looking for next keyframe */
1172 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1173 && index < str->stbl_index)
1176 if (!empty_segment) {
1177 /* find previous keyframe */
1178 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1180 /* we will settle for one before if none found after */
1181 if (next && kindex == -1)
1182 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1184 /* Update the requested time whenever a keyframe was found, to make it
1185 * accurate and avoid having the first buffer fall outside of the segment
1190 /* get timestamp of keyframe */
1191 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1192 GST_DEBUG_OBJECT (qtdemux,
1193 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1194 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1195 str->samples[kindex].offset);
1197 /* keyframes in the segment get a chance to change the
1198 * desired_offset. keyframes out of the segment are
1200 if (media_time >= seg->media_start) {
1201 GstClockTime seg_time;
1203 /* this keyframe is inside the segment, convert back to
1205 seg_time = (media_time - seg->media_start) + seg->time;
1206 if ((!next && (seg_time < min_offset)) ||
1207 (next && (seg_time > min_offset)))
1208 min_offset = seg_time;
1213 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1214 min_byte_offset = str->samples[index].offset;
1218 *key_time = min_offset;
1220 *key_offset = min_byte_offset;
1224 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1225 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1229 g_return_val_if_fail (format != NULL, FALSE);
1230 g_return_val_if_fail (cur != NULL, FALSE);
1231 g_return_val_if_fail (stop != NULL, FALSE);
1233 if (*format == GST_FORMAT_TIME)
1237 if (cur_type != GST_SEEK_TYPE_NONE)
1238 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1239 if (res && stop_type != GST_SEEK_TYPE_NONE)
1240 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1243 *format = GST_FORMAT_TIME;
1248 /* perform seek in push based mode:
1249 find BYTE position to move to based on time and delegate to upstream
1252 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1257 GstSeekType cur_type, stop_type;
1258 gint64 cur, stop, key_cur;
1261 gint64 original_stop;
1264 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1266 gst_event_parse_seek (event, &rate, &format, &flags,
1267 &cur_type, &cur, &stop_type, &stop);
1268 seqnum = gst_event_get_seqnum (event);
1270 /* Directly send the instant-rate-change event here before taking the
1271 * stream-lock so that it can be applied as soon as possible */
1272 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1275 /* instant rate change only supported if direction does not change. All
1276 * other requirements are already checked before creating the seek event
1277 * but let's double-check here to be sure */
1278 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1279 (qtdemux->segment.rate < 0 && rate > 0) ||
1280 cur_type != GST_SEEK_TYPE_NONE ||
1281 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1282 GST_ERROR_OBJECT (qtdemux,
1283 "Instant rate change seeks only supported in the "
1284 "same direction, without flushing and position change");
1288 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1289 (GstSegmentFlags) flags);
1290 gst_event_set_seqnum (ev, seqnum);
1291 gst_qtdemux_push_event (qtdemux, ev);
1295 /* only forward streaming and seeking is possible */
1297 goto unsupported_seek;
1299 /* convert to TIME if needed and possible */
1300 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1304 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1305 * the original stop position to use when upstream pushes the new segment
1307 original_stop = stop;
1310 /* find reasonable corresponding BYTE position,
1311 * also try to mind about keyframes, since we can not go back a bit for them
1313 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1314 * mostly just work, but let's not yet boldly go there ... */
1315 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1320 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1321 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1324 GST_OBJECT_LOCK (qtdemux);
1325 qtdemux->seek_offset = byte_cur;
1326 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1327 qtdemux->push_seek_start = cur;
1329 qtdemux->push_seek_start = key_cur;
1332 if (stop_type == GST_SEEK_TYPE_NONE) {
1333 qtdemux->push_seek_stop = qtdemux->segment.stop;
1335 qtdemux->push_seek_stop = original_stop;
1337 GST_OBJECT_UNLOCK (qtdemux);
1339 qtdemux->segment_seqnum = seqnum;
1340 /* BYTE seek event */
1341 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1343 gst_event_set_seqnum (event, seqnum);
1344 res = gst_pad_push_event (qtdemux->sinkpad, event);
1351 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1357 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1362 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1367 /* perform the seek.
1369 * We set all segment_indexes in the streams to unknown and
1370 * adjust the time_position to the desired position. this is enough
1371 * to trigger a segment switch in the streaming thread to start
1372 * streaming from the desired position.
1374 * Keyframe seeking is a little more complicated when dealing with
1375 * segments. Ideally we want to move to the previous keyframe in
1376 * the segment but there might not be a keyframe in the segment. In
1377 * fact, none of the segments could contain a keyframe. We take a
1378 * practical approach: seek to the previous keyframe in the segment,
1379 * if there is none, seek to the beginning of the segment.
1381 * Called with STREAM_LOCK
1384 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1385 guint32 seqnum, GstSeekFlags flags)
1387 gint64 desired_offset;
1390 desired_offset = segment->position;
1392 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1393 GST_TIME_ARGS (desired_offset));
1395 /* may not have enough fragmented info to do this adjustment,
1396 * and we can't scan (and probably should not) at this time with
1397 * possibly flushing upstream */
1398 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1400 gboolean next, before, after;
1402 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1403 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1404 next = after && !before;
1405 if (segment->rate < 0)
1408 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1410 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1411 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1412 desired_offset = min_offset;
1415 /* and set all streams to the final position */
1416 GST_OBJECT_LOCK (qtdemux);
1417 gst_flow_combiner_reset (qtdemux->flowcombiner);
1418 GST_OBJECT_UNLOCK (qtdemux);
1419 qtdemux->segment_seqnum = seqnum;
1420 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1421 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1423 stream->time_position = desired_offset;
1424 stream->accumulated_base = 0;
1425 stream->sample_index = -1;
1426 stream->offset_in_sample = 0;
1427 stream->segment_index = -1;
1428 stream->sent_eos = FALSE;
1429 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1431 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1432 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1434 segment->position = desired_offset;
1435 if (segment->rate >= 0) {
1436 segment->start = desired_offset;
1437 /* We need to update time as we update start in that direction */
1438 segment->time = desired_offset;
1440 /* we stop at the end */
1441 if (segment->stop == -1)
1442 segment->stop = segment->duration;
1444 segment->stop = desired_offset;
1447 if (qtdemux->fragmented)
1448 qtdemux->fragmented_seek_pending = TRUE;
1453 /* do a seek in pull based mode */
1455 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1460 GstSeekType cur_type, stop_type;
1462 gboolean flush, instant_rate_change;
1464 GstSegment seeksegment;
1465 guint32 seqnum = GST_SEQNUM_INVALID;
1466 GstEvent *flush_event;
1469 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1471 gst_event_parse_seek (event, &rate, &format, &flags,
1472 &cur_type, &cur, &stop_type, &stop);
1473 seqnum = gst_event_get_seqnum (event);
1475 /* we have to have a format as the segment format. Try to convert
1477 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1481 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1483 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1484 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1486 /* Directly send the instant-rate-change event here before taking the
1487 * stream-lock so that it can be applied as soon as possible */
1488 if (instant_rate_change) {
1491 /* instant rate change only supported if direction does not change. All
1492 * other requirements are already checked before creating the seek event
1493 * but let's double-check here to be sure */
1494 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1495 (qtdemux->segment.rate < 0 && rate > 0) ||
1496 cur_type != GST_SEEK_TYPE_NONE ||
1497 stop_type != GST_SEEK_TYPE_NONE || flush) {
1498 GST_ERROR_OBJECT (qtdemux,
1499 "Instant rate change seeks only supported in the "
1500 "same direction, without flushing and position change");
1504 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1505 (GstSegmentFlags) flags);
1506 gst_event_set_seqnum (ev, seqnum);
1507 gst_qtdemux_push_event (qtdemux, ev);
1511 /* stop streaming, either by flushing or by pausing the task */
1513 flush_event = gst_event_new_flush_start ();
1514 if (seqnum != GST_SEQNUM_INVALID)
1515 gst_event_set_seqnum (flush_event, seqnum);
1516 /* unlock upstream pull_range */
1517 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1518 /* make sure out loop function exits */
1519 gst_qtdemux_push_event (qtdemux, flush_event);
1521 /* non flushing seek, pause the task */
1522 gst_pad_pause_task (qtdemux->sinkpad);
1525 /* wait for streaming to finish */
1526 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1528 /* copy segment, we need this because we still need the old
1529 * segment when we close the current segment. */
1530 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1532 /* configure the segment with the seek variables */
1533 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1534 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1535 cur_type, cur, stop_type, stop, &update)) {
1537 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1539 /* now do the seek */
1540 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1543 /* prepare for streaming again */
1545 flush_event = gst_event_new_flush_stop (TRUE);
1546 if (seqnum != GST_SEQNUM_INVALID)
1547 gst_event_set_seqnum (flush_event, seqnum);
1549 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1550 gst_qtdemux_push_event (qtdemux, flush_event);
1553 /* commit the new segment */
1554 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1556 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1557 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1558 qtdemux->segment.format, qtdemux->segment.position);
1559 if (seqnum != GST_SEQNUM_INVALID)
1560 gst_message_set_seqnum (msg, seqnum);
1561 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1564 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1565 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1566 qtdemux->sinkpad, NULL);
1568 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1575 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1581 qtdemux_ensure_index (GstQTDemux * qtdemux)
1585 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1587 /* Build complete index */
1588 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1589 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1591 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1592 GST_LOG_OBJECT (qtdemux,
1593 "Building complete index of track-id %u for seeking failed!",
1603 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1606 gboolean res = TRUE;
1607 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1609 switch (GST_EVENT_TYPE (event)) {
1610 case GST_EVENT_RECONFIGURE:
1611 GST_OBJECT_LOCK (qtdemux);
1612 gst_flow_combiner_reset (qtdemux->flowcombiner);
1613 GST_OBJECT_UNLOCK (qtdemux);
1614 res = gst_pad_event_default (pad, parent, event);
1616 case GST_EVENT_SEEK:
1618 GstSeekFlags flags = 0;
1619 GstFormat seek_format;
1620 gboolean instant_rate_change;
1622 #ifndef GST_DISABLE_GST_DEBUG
1623 GstClockTime ts = gst_util_get_timestamp ();
1625 guint32 seqnum = gst_event_get_seqnum (event);
1627 qtdemux->received_seek = TRUE;
1629 gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1631 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1633 if (seqnum == qtdemux->segment_seqnum) {
1634 GST_LOG_OBJECT (pad,
1635 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1636 gst_event_unref (event);
1640 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1641 /* seek should be handled by upstream, we might need to re-download fragments */
1642 GST_DEBUG_OBJECT (qtdemux,
1643 "let upstream handle seek for fragmented playback");
1647 if (seek_format == GST_FORMAT_BYTES) {
1648 GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1649 gst_event_unref (event);
1653 gst_event_parse_seek_trickmode_interval (event,
1654 &qtdemux->trickmode_interval);
1656 /* Build complete index for seeking;
1657 * if not a fragmented file at least and we're really doing a seek,
1658 * not just an instant-rate-change */
1659 if (!qtdemux->fragmented && !instant_rate_change) {
1660 if (!qtdemux_ensure_index (qtdemux))
1663 #ifndef GST_DISABLE_GST_DEBUG
1664 ts = gst_util_get_timestamp () - ts;
1665 GST_INFO_OBJECT (qtdemux,
1666 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1668 if (qtdemux->pullbased) {
1669 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1670 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1671 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1673 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1674 && QTDEMUX_N_STREAMS (qtdemux)
1675 && !qtdemux->fragmented) {
1676 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1678 GST_DEBUG_OBJECT (qtdemux,
1679 "ignoring seek in push mode in current state");
1682 gst_event_unref (event);
1687 res = gst_pad_event_default (pad, parent, event);
1697 GST_ERROR_OBJECT (qtdemux, "Index failed");
1698 gst_event_unref (event);
1704 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1706 * If @fw is false, the coding order is explored backwards.
1708 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1709 * sample is found for that track.
1711 * The stream and sample index of the sample with the minimum offset in the direction explored
1712 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1714 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1715 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1716 * @_stream and @_index. */
1718 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1719 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1722 gint64 time, min_time;
1723 QtDemuxStream *stream;
1730 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1733 gboolean set_sample;
1735 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1742 i = str->n_samples - 1;
1746 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1747 if (str->samples[i].size == 0)
1750 if (fw && (str->samples[i].offset < byte_pos))
1753 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1756 /* move stream to first available sample */
1758 gst_qtdemux_move_stream (qtdemux, str, i);
1762 /* avoid index from sparse streams since they might be far away */
1763 if (!CUR_STREAM (str)->sparse) {
1764 /* determine min/max time */
1765 time = QTSAMPLE_PTS (str, &str->samples[i]);
1766 if (min_time == -1 || (!fw && time > min_time) ||
1767 (fw && time < min_time)) {
1771 /* determine stream with leading sample, to get its position */
1773 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1774 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1782 /* no sample for this stream, mark eos */
1784 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1795 /* Copied from mpegtsbase code */
1796 /* FIXME: replace this function when we add new util function for stream-id creation */
1798 _get_upstream_id (GstQTDemux * demux)
1800 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1803 /* Try to create one from the upstream URI, else use a randome number */
1807 /* Try to generate one from the URI query and
1808 * if it fails take a random number instead */
1809 query = gst_query_new_uri ();
1810 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1811 gst_query_parse_uri (query, &uri);
1817 /* And then generate an SHA256 sum of the URI */
1818 cs = g_checksum_new (G_CHECKSUM_SHA256);
1819 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1821 upstream_id = g_strdup (g_checksum_get_string (cs));
1822 g_checksum_free (cs);
1824 /* Just get some random number if the URI query fails */
1825 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1826 "implementing a deterministic way of creating a stream-id");
1828 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1829 g_random_int (), g_random_int ());
1832 gst_query_unref (query);
1837 static QtDemuxStream *
1838 _create_stream (GstQTDemux * demux, guint32 track_id)
1840 QtDemuxStream *stream;
1843 stream = g_new0 (QtDemuxStream, 1);
1844 stream->demux = demux;
1845 stream->track_id = track_id;
1846 upstream_id = _get_upstream_id (demux);
1847 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1848 g_free (upstream_id);
1849 /* new streams always need a discont */
1850 stream->discont = TRUE;
1851 /* we enable clipping for raw audio/video streams */
1852 stream->need_clip = FALSE;
1853 stream->process_func = NULL;
1854 stream->segment_index = -1;
1855 stream->time_position = 0;
1856 stream->sample_index = -1;
1857 stream->offset_in_sample = 0;
1858 stream->new_stream = TRUE;
1859 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1860 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1861 stream->protected = FALSE;
1862 stream->protection_scheme_type = 0;
1863 stream->protection_scheme_version = 0;
1864 stream->protection_scheme_info = NULL;
1865 stream->n_samples_moof = 0;
1866 stream->duration_moof = 0;
1867 stream->duration_last_moof = 0;
1868 stream->alignment = 1;
1869 stream->stream_tags = gst_tag_list_new_empty ();
1870 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1871 g_queue_init (&stream->protection_scheme_event_queue);
1872 stream->ref_count = 1;
1873 /* consistent default for push based mode */
1874 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1879 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1881 GstStructure *structure;
1882 const gchar *variant;
1883 const GstCaps *mediacaps = NULL;
1885 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1887 structure = gst_caps_get_structure (caps, 0);
1888 variant = gst_structure_get_string (structure, "variant");
1890 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1891 QtDemuxStream *stream;
1892 const GValue *value;
1894 demux->fragmented = TRUE;
1895 demux->mss_mode = TRUE;
1897 if (QTDEMUX_N_STREAMS (demux) > 1) {
1898 /* can't do this, we can only renegotiate for another mss format */
1902 value = gst_structure_get_value (structure, "media-caps");
1905 const GValue *timescale_v;
1907 /* TODO update when stream changes during playback */
1909 if (QTDEMUX_N_STREAMS (demux) == 0) {
1910 stream = _create_stream (demux, 1);
1911 g_ptr_array_add (demux->active_streams, stream);
1912 /* mss has no stsd/stsd entry, use id 0 as default */
1913 stream->stsd_entries_length = 1;
1914 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1915 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1917 stream = QTDEMUX_NTH_STREAM (demux, 0);
1920 timescale_v = gst_structure_get_value (structure, "timescale");
1922 stream->timescale = g_value_get_uint64 (timescale_v);
1924 /* default mss timescale */
1925 stream->timescale = 10000000;
1927 demux->timescale = stream->timescale;
1929 mediacaps = gst_value_get_caps (value);
1930 if (!CUR_STREAM (stream)->caps
1931 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1932 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1934 stream->new_caps = TRUE;
1936 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1937 structure = gst_caps_get_structure (mediacaps, 0);
1938 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1939 stream->subtype = FOURCC_vide;
1941 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1942 gst_structure_get_int (structure, "height",
1943 &CUR_STREAM (stream)->height);
1944 gst_structure_get_fraction (structure, "framerate",
1945 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1946 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1948 stream->subtype = FOURCC_soun;
1949 gst_structure_get_int (structure, "channels",
1950 &CUR_STREAM (stream)->n_channels);
1951 gst_structure_get_int (structure, "rate", &rate);
1952 CUR_STREAM (stream)->rate = rate;
1953 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1954 if (gst_structure_has_field (structure, "original-media-type")) {
1955 const gchar *media_type =
1956 gst_structure_get_string (structure, "original-media-type");
1957 if (g_str_has_prefix (media_type, "video")) {
1958 stream->subtype = FOURCC_vide;
1959 } else if (g_str_has_prefix (media_type, "audio")) {
1960 stream->subtype = FOURCC_soun;
1965 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1967 demux->mss_mode = FALSE;
1974 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1978 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1979 gst_pad_stop_task (qtdemux->sinkpad);
1981 if (hard || qtdemux->upstream_format_is_time) {
1982 qtdemux->state = QTDEMUX_STATE_INITIAL;
1983 qtdemux->neededbytes = 16;
1984 qtdemux->todrop = 0;
1985 qtdemux->pullbased = FALSE;
1986 g_clear_pointer (&qtdemux->redirect_location, g_free);
1987 qtdemux->first_mdat = -1;
1988 qtdemux->header_size = 0;
1989 qtdemux->mdatoffset = -1;
1990 qtdemux->restoredata_offset = -1;
1991 if (qtdemux->mdatbuffer)
1992 gst_buffer_unref (qtdemux->mdatbuffer);
1993 if (qtdemux->restoredata_buffer)
1994 gst_buffer_unref (qtdemux->restoredata_buffer);
1995 qtdemux->mdatbuffer = NULL;
1996 qtdemux->restoredata_buffer = NULL;
1997 qtdemux->mdatleft = 0;
1998 qtdemux->mdatsize = 0;
1999 if (qtdemux->comp_brands)
2000 gst_buffer_unref (qtdemux->comp_brands);
2001 qtdemux->comp_brands = NULL;
2002 qtdemux->last_moov_offset = -1;
2003 if (qtdemux->moov_node_compressed) {
2004 g_node_destroy (qtdemux->moov_node_compressed);
2005 if (qtdemux->moov_node)
2006 g_free (qtdemux->moov_node->data);
2008 qtdemux->moov_node_compressed = NULL;
2009 if (qtdemux->moov_node)
2010 g_node_destroy (qtdemux->moov_node);
2011 qtdemux->moov_node = NULL;
2012 if (qtdemux->tag_list)
2013 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2014 qtdemux->tag_list = gst_tag_list_new_empty ();
2015 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2017 if (qtdemux->element_index)
2018 gst_object_unref (qtdemux->element_index);
2019 qtdemux->element_index = NULL;
2021 qtdemux->major_brand = 0;
2022 qtdemux->upstream_format_is_time = FALSE;
2023 qtdemux->upstream_seekable = FALSE;
2024 qtdemux->upstream_size = 0;
2026 qtdemux->fragment_start = -1;
2027 qtdemux->fragment_start_offset = -1;
2028 qtdemux->duration = 0;
2029 qtdemux->moof_offset = 0;
2030 qtdemux->chapters_track_id = 0;
2031 qtdemux->have_group_id = FALSE;
2032 qtdemux->group_id = G_MAXUINT;
2034 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2036 g_queue_clear (&qtdemux->protection_event_queue);
2038 qtdemux->received_seek = FALSE;
2039 qtdemux->first_moof_already_parsed = FALSE;
2041 qtdemux->offset = 0;
2042 gst_adapter_clear (qtdemux->adapter);
2043 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2044 qtdemux->need_segment = TRUE;
2047 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2048 qtdemux->trickmode_interval = 0;
2049 g_ptr_array_set_size (qtdemux->active_streams, 0);
2050 g_ptr_array_set_size (qtdemux->old_streams, 0);
2051 qtdemux->n_video_streams = 0;
2052 qtdemux->n_audio_streams = 0;
2053 qtdemux->n_sub_streams = 0;
2054 qtdemux->exposed = FALSE;
2055 qtdemux->fragmented = FALSE;
2056 qtdemux->mss_mode = FALSE;
2057 gst_caps_replace (&qtdemux->media_caps, NULL);
2058 qtdemux->timescale = 0;
2059 qtdemux->got_moov = FALSE;
2060 qtdemux->cenc_aux_info_offset = 0;
2061 qtdemux->cenc_aux_info_sizes = NULL;
2062 qtdemux->cenc_aux_sample_count = 0;
2063 if (qtdemux->protection_system_ids) {
2064 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2065 qtdemux->protection_system_ids = NULL;
2067 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2068 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2069 GST_BIN_FLAG_STREAMS_AWARE);
2071 if (qtdemux->preferred_protection_system_id) {
2072 g_free (qtdemux->preferred_protection_system_id);
2073 qtdemux->preferred_protection_system_id = NULL;
2075 } else if (qtdemux->mss_mode) {
2076 gst_flow_combiner_reset (qtdemux->flowcombiner);
2077 g_ptr_array_foreach (qtdemux->active_streams,
2078 (GFunc) gst_qtdemux_stream_clear, NULL);
2080 gst_flow_combiner_reset (qtdemux->flowcombiner);
2081 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2082 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2083 stream->sent_eos = FALSE;
2084 stream->time_position = 0;
2085 stream->accumulated_base = 0;
2086 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2092 /* Maps the @segment to the qt edts internal segments and pushes
2093 * the corresponding segment event.
2095 * If it ends up being at a empty segment, a gap will be pushed and the next
2096 * edts segment will be activated in sequence.
2098 * To be used in push-mode only */
2100 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2104 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2105 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2107 stream->time_position = segment->start;
2109 /* in push mode we should be guaranteed that we will have empty segments
2110 * at the beginning and then one segment after, other scenarios are not
2111 * supported and are discarded when parsing the edts */
2112 for (i = 0; i < stream->n_segments; i++) {
2113 if (stream->segments[i].stop_time > segment->start) {
2114 /* push the empty segment and move to the next one */
2115 gst_qtdemux_activate_segment (qtdemux, stream, i,
2116 stream->time_position);
2117 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2118 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2119 stream->time_position);
2121 /* accumulate previous segments */
2122 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2123 stream->accumulated_base +=
2124 (stream->segment.stop -
2125 stream->segment.start) / ABS (stream->segment.rate);
2129 g_assert (i == stream->n_segments - 1);
2136 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2147 for (i = 0; i < len; i++) {
2148 QtDemuxStream *stream = g_ptr_array_index (src, i);
2150 #ifndef GST_DISABLE_GST_DEBUG
2151 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2152 stream, GST_STR_NULL (stream->stream_id), dest);
2154 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2157 g_ptr_array_set_size (src, 0);
2161 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2164 GstQTDemux *demux = GST_QTDEMUX (parent);
2165 gboolean res = TRUE;
2167 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2169 switch (GST_EVENT_TYPE (event)) {
2170 case GST_EVENT_SEGMENT:
2173 QtDemuxStream *stream;
2177 /* some debug output */
2178 gst_event_copy_segment (event, &segment);
2179 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2182 if (segment.format == GST_FORMAT_TIME) {
2183 demux->upstream_format_is_time = TRUE;
2184 demux->segment_seqnum = gst_event_get_seqnum (event);
2186 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2187 "not in time format");
2189 /* chain will send initial newsegment after pads have been added */
2190 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2191 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2196 /* check if this matches a time seek we received previously
2197 * FIXME for backwards compatibility reasons we use the
2198 * seek_offset here to compare. In the future we might want to
2199 * change this to use the seqnum as it uniquely should identify
2200 * the segment that corresponds to the seek. */
2201 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2202 ", received segment offset %" G_GINT64_FORMAT,
2203 demux->seek_offset, segment.start);
2204 if (segment.format == GST_FORMAT_BYTES
2205 && demux->seek_offset == segment.start) {
2206 GST_OBJECT_LOCK (demux);
2207 offset = segment.start;
2209 segment.format = GST_FORMAT_TIME;
2210 segment.start = demux->push_seek_start;
2211 segment.stop = demux->push_seek_stop;
2212 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2213 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2214 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2215 GST_OBJECT_UNLOCK (demux);
2218 /* we only expect a BYTE segment, e.g. following a seek */
2219 if (segment.format == GST_FORMAT_BYTES) {
2220 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2221 offset = segment.start;
2223 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2224 NULL, (gint64 *) & segment.start);
2225 if ((gint64) segment.start < 0)
2228 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2229 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2230 NULL, (gint64 *) & segment.stop);
2231 /* keyframe seeking should already arrange for start >= stop,
2232 * but make sure in other rare cases */
2233 segment.stop = MAX (segment.stop, segment.start);
2235 } else if (segment.format == GST_FORMAT_TIME) {
2236 /* push all data on the adapter before starting this
2238 gst_qtdemux_process_adapter (demux, TRUE);
2240 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2244 /* We shouldn't modify upstream driven TIME FORMAT segment */
2245 if (!demux->upstream_format_is_time) {
2246 /* accept upstream's notion of segment and distribute along */
2247 segment.format = GST_FORMAT_TIME;
2248 segment.position = segment.time = segment.start;
2249 segment.duration = demux->segment.duration;
2250 segment.base = gst_segment_to_running_time (&demux->segment,
2251 GST_FORMAT_TIME, demux->segment.position);
2254 gst_segment_copy_into (&segment, &demux->segment);
2255 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2257 /* map segment to internal qt segments and push on each stream */
2258 if (QTDEMUX_N_STREAMS (demux)) {
2259 demux->need_segment = TRUE;
2260 gst_qtdemux_check_send_pending_segment (demux);
2263 /* clear leftover in current segment, if any */
2264 gst_adapter_clear (demux->adapter);
2266 /* set up streaming thread */
2267 demux->offset = offset;
2268 if (demux->upstream_format_is_time) {
2269 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2270 "set values to restart reading from a new atom");
2271 demux->neededbytes = 16;
2274 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2277 demux->todrop = stream->samples[idx].offset - offset;
2278 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2280 /* set up for EOS */
2281 demux->neededbytes = -1;
2286 gst_event_unref (event);
2290 case GST_EVENT_FLUSH_START:
2292 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2293 gst_event_unref (event);
2296 QTDEMUX_EXPOSE_LOCK (demux);
2297 res = gst_pad_event_default (demux->sinkpad, parent, event);
2298 QTDEMUX_EXPOSE_UNLOCK (demux);
2301 case GST_EVENT_FLUSH_STOP:
2305 dur = demux->segment.duration;
2306 gst_qtdemux_reset (demux, FALSE);
2307 demux->segment.duration = dur;
2309 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2310 gst_event_unref (event);
2316 /* If we are in push mode, and get an EOS before we've seen any streams,
2317 * then error out - we have nowhere to send the EOS */
2318 if (!demux->pullbased) {
2320 gboolean has_valid_stream = FALSE;
2321 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2322 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2323 has_valid_stream = TRUE;
2327 if (!has_valid_stream)
2328 gst_qtdemux_post_no_playable_stream_error (demux);
2330 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2331 (guint) gst_adapter_available (demux->adapter));
2332 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2338 case GST_EVENT_CAPS:{
2339 GstCaps *caps = NULL;
2341 gst_event_parse_caps (event, &caps);
2342 gst_qtdemux_setcaps (demux, caps);
2344 gst_event_unref (event);
2347 case GST_EVENT_PROTECTION:
2349 const gchar *system_id = NULL;
2351 gst_event_parse_protection (event, &system_id, NULL, NULL);
2352 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2354 gst_qtdemux_append_protection_system_id (demux, system_id);
2355 /* save the event for later, for source pads that have not been created */
2356 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2357 /* send it to all pads that already exist */
2358 gst_qtdemux_push_event (demux, event);
2362 case GST_EVENT_STREAM_START:
2365 gst_event_unref (event);
2367 /* Drain all the buffers */
2368 gst_qtdemux_process_adapter (demux, TRUE);
2369 gst_qtdemux_reset (demux, FALSE);
2370 /* We expect new moov box after new stream-start event */
2371 if (demux->exposed) {
2372 gst_qtdemux_stream_concat (demux,
2373 demux->old_streams, demux->active_streams);
2382 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2389 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2392 GstQTDemux *demux = GST_QTDEMUX (parent);
2393 gboolean res = FALSE;
2395 switch (GST_QUERY_TYPE (query)) {
2396 case GST_QUERY_BITRATE:
2398 GstClockTime duration;
2400 /* populate demux->upstream_size if not done yet */
2401 gst_qtdemux_check_seekability (demux);
2403 if (demux->upstream_size != -1
2404 && gst_qtdemux_get_duration (demux, &duration)) {
2406 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2409 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2410 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2411 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2413 /* TODO: better results based on ranges/index tables */
2414 gst_query_set_bitrate (query, bitrate);
2420 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2430 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2432 GstQTDemux *demux = GST_QTDEMUX (element);
2434 GST_OBJECT_LOCK (demux);
2435 if (demux->element_index)
2436 gst_object_unref (demux->element_index);
2438 demux->element_index = gst_object_ref (index);
2440 demux->element_index = NULL;
2442 GST_OBJECT_UNLOCK (demux);
2443 /* object lock might be taken again */
2445 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2446 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2447 demux->element_index, demux->index_id);
2451 gst_qtdemux_get_index (GstElement * element)
2453 GstIndex *result = NULL;
2454 GstQTDemux *demux = GST_QTDEMUX (element);
2456 GST_OBJECT_LOCK (demux);
2457 if (demux->element_index)
2458 result = gst_object_ref (demux->element_index);
2459 GST_OBJECT_UNLOCK (demux);
2461 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2468 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2470 g_free ((gpointer) stream->stco.data);
2471 stream->stco.data = NULL;
2472 g_free ((gpointer) stream->stsz.data);
2473 stream->stsz.data = NULL;
2474 g_free ((gpointer) stream->stsc.data);
2475 stream->stsc.data = NULL;
2476 g_free ((gpointer) stream->stts.data);
2477 stream->stts.data = NULL;
2478 g_free ((gpointer) stream->stss.data);
2479 stream->stss.data = NULL;
2480 g_free ((gpointer) stream->stps.data);
2481 stream->stps.data = NULL;
2482 g_free ((gpointer) stream->ctts.data);
2483 stream->ctts.data = NULL;
2487 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2489 g_free (stream->segments);
2490 stream->segments = NULL;
2491 stream->segment_index = -1;
2492 stream->accumulated_base = 0;
2496 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2498 g_free (stream->samples);
2499 stream->samples = NULL;
2500 gst_qtdemux_stbl_free (stream);
2503 g_free (stream->ra_entries);
2504 stream->ra_entries = NULL;
2505 stream->n_ra_entries = 0;
2507 stream->sample_index = -1;
2508 stream->stbl_index = -1;
2509 stream->n_samples = 0;
2510 stream->time_position = 0;
2512 stream->n_samples_moof = 0;
2513 stream->duration_moof = 0;
2514 stream->duration_last_moof = 0;
2518 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2521 if (stream->allocator)
2522 gst_object_unref (stream->allocator);
2523 while (stream->buffers) {
2524 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2525 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2527 for (i = 0; i < stream->stsd_entries_length; i++) {
2528 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2529 if (entry->rgb8_palette) {
2530 gst_memory_unref (entry->rgb8_palette);
2531 entry->rgb8_palette = NULL;
2533 entry->sparse = FALSE;
2536 if (stream->stream_tags)
2537 gst_tag_list_unref (stream->stream_tags);
2539 stream->stream_tags = gst_tag_list_new_empty ();
2540 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2541 g_free (stream->redirect_uri);
2542 stream->redirect_uri = NULL;
2543 stream->sent_eos = FALSE;
2544 stream->protected = FALSE;
2545 if (stream->protection_scheme_info) {
2546 if (stream->protection_scheme_type == FOURCC_cenc
2547 || stream->protection_scheme_type == FOURCC_cbcs) {
2548 QtDemuxCencSampleSetInfo *info =
2549 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2550 if (info->default_properties)
2551 gst_structure_free (info->default_properties);
2552 if (info->crypto_info)
2553 g_ptr_array_free (info->crypto_info, TRUE);
2555 if (stream->protection_scheme_type == FOURCC_aavd) {
2556 QtDemuxAavdEncryptionInfo *info =
2557 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2558 if (info->default_properties)
2559 gst_structure_free (info->default_properties);
2561 g_free (stream->protection_scheme_info);
2562 stream->protection_scheme_info = NULL;
2564 stream->protection_scheme_type = 0;
2565 stream->protection_scheme_version = 0;
2566 g_queue_foreach (&stream->protection_scheme_event_queue,
2567 (GFunc) gst_event_unref, NULL);
2568 g_queue_clear (&stream->protection_scheme_event_queue);
2569 gst_qtdemux_stream_flush_segments_data (stream);
2570 gst_qtdemux_stream_flush_samples_data (stream);
2574 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2577 gst_qtdemux_stream_clear (stream);
2578 for (i = 0; i < stream->stsd_entries_length; i++) {
2579 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2581 gst_caps_unref (entry->caps);
2585 g_free (stream->stsd_entries);
2586 stream->stsd_entries = NULL;
2587 stream->stsd_entries_length = 0;
2590 static QtDemuxStream *
2591 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2593 g_atomic_int_add (&stream->ref_count, 1);
2599 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2601 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2602 gst_qtdemux_stream_reset (stream);
2603 gst_tag_list_unref (stream->stream_tags);
2605 GstQTDemux *demux = stream->demux;
2606 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2607 GST_OBJECT_LOCK (demux);
2608 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2609 GST_OBJECT_UNLOCK (demux);
2611 g_free (stream->stream_id);
2616 static GstStateChangeReturn
2617 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2619 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2620 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2622 switch (transition) {
2623 case GST_STATE_CHANGE_READY_TO_PAUSED:
2624 gst_qtdemux_reset (qtdemux, TRUE);
2630 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2632 switch (transition) {
2633 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2634 gst_qtdemux_reset (qtdemux, TRUE);
2645 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2647 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2649 g_return_if_fail (GST_IS_CONTEXT (context));
2651 if (gst_context_has_context_type (context,
2652 "drm-preferred-decryption-system-id")) {
2653 const GstStructure *s;
2655 s = gst_context_get_structure (context);
2656 g_free (qtdemux->preferred_protection_system_id);
2657 qtdemux->preferred_protection_system_id =
2658 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2659 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2660 qtdemux->preferred_protection_system_id);
2663 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2667 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2669 /* counts as header data */
2670 qtdemux->header_size += length;
2672 /* only consider at least a sufficiently complete ftyp atom */
2676 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2677 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2678 GST_FOURCC_ARGS (qtdemux->major_brand));
2679 if (qtdemux->comp_brands)
2680 gst_buffer_unref (qtdemux->comp_brands);
2681 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2682 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2687 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2688 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2689 guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2690 guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2691 const guint8 * constant_iv)
2693 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2694 gst_buffer_fill (kid_buf, 0, kid, 16);
2695 if (info->default_properties)
2696 gst_structure_free (info->default_properties);
2697 info->default_properties =
2698 gst_structure_new ("application/x-cenc",
2699 "iv_size", G_TYPE_UINT, iv_size,
2700 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2701 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2702 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2703 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2704 gst_buffer_unref (kid_buf);
2705 if (protection_scheme_type == FOURCC_cbcs) {
2706 if (crypt_byte_block != 0 || skip_byte_block != 0) {
2707 gst_structure_set (info->default_properties, "crypt_byte_block",
2708 G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2709 skip_byte_block, NULL);
2711 if (constant_iv != NULL) {
2712 GstBuffer *constant_iv_buf =
2713 gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2714 gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2715 gst_structure_set (info->default_properties, "constant_iv_size",
2716 G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2718 gst_buffer_unref (constant_iv_buf);
2720 gst_structure_set (info->default_properties, "cipher-mode",
2721 G_TYPE_STRING, "cbcs", NULL);
2723 gst_structure_set (info->default_properties, "cipher-mode",
2724 G_TYPE_STRING, "cenc", NULL);
2729 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2730 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2732 guint32 algorithm_id = 0;
2734 gboolean is_encrypted = TRUE;
2737 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2738 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2743 if (algorithm_id == 0) {
2744 is_encrypted = FALSE;
2745 } else if (algorithm_id == 1) {
2746 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2747 } else if (algorithm_id == 2) {
2748 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2751 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2754 if (!gst_byte_reader_get_data (br, 16, &kid))
2757 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2758 is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2759 gst_structure_set (info->default_properties, "piff_algorithm_id",
2760 G_TYPE_UINT, algorithm_id, NULL);
2766 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2774 QtDemuxStream *stream;
2775 GstStructure *structure;
2776 QtDemuxCencSampleSetInfo *ss_info = NULL;
2777 const gchar *system_id;
2778 gboolean uses_sub_sample_encryption = FALSE;
2779 guint32 sample_count;
2781 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2784 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2786 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2787 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2788 GST_WARNING_OBJECT (qtdemux,
2789 "Attempting PIFF box parsing on an unencrypted stream.");
2793 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2794 G_TYPE_STRING, &system_id, NULL);
2795 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2797 stream->protected = TRUE;
2798 stream->protection_scheme_type = FOURCC_cenc;
2800 if (!stream->protection_scheme_info)
2801 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2803 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2804 if (!ss_info->default_properties) {
2805 ss_info->default_properties =
2806 gst_structure_new ("application/x-cenc",
2807 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2812 if (ss_info->crypto_info) {
2813 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2814 g_ptr_array_free (ss_info->crypto_info, TRUE);
2815 ss_info->crypto_info = NULL;
2819 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2821 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2822 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2826 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2827 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2831 if ((flags & 0x000001)) {
2832 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2835 } else if ((flags & 0x000002)) {
2836 uses_sub_sample_encryption = TRUE;
2839 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2841 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2845 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2846 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2850 ss_info->crypto_info =
2851 g_ptr_array_new_full (sample_count,
2852 (GDestroyNotify) qtdemux_gst_structure_free);
2854 for (i = 0; i < sample_count; ++i) {
2855 GstStructure *properties;
2859 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2860 if (properties == NULL) {
2861 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2862 qtdemux->cenc_aux_sample_count = i;
2866 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2867 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2868 gst_structure_free (properties);
2869 qtdemux->cenc_aux_sample_count = i;
2872 buf = gst_buffer_new_wrapped (data, iv_size);
2873 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2874 gst_buffer_unref (buf);
2876 if (uses_sub_sample_encryption) {
2877 guint16 n_subsamples;
2878 const GValue *kid_buf_value;
2880 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2881 || n_subsamples == 0) {
2882 GST_ERROR_OBJECT (qtdemux,
2883 "failed to get subsample count for sample %u", i);
2884 gst_structure_free (properties);
2885 qtdemux->cenc_aux_sample_count = i;
2888 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2889 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2890 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2892 gst_structure_free (properties);
2893 qtdemux->cenc_aux_sample_count = i;
2896 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2899 gst_structure_get_value (ss_info->default_properties, "kid");
2901 gst_structure_set (properties,
2902 "subsample_count", G_TYPE_UINT, n_subsamples,
2903 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2904 gst_structure_set_value (properties, "kid", kid_buf_value);
2905 gst_buffer_unref (buf);
2907 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2910 g_ptr_array_add (ss_info->crypto_info, properties);
2913 qtdemux->cenc_aux_sample_count = sample_count;
2917 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2919 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2920 0x97, 0xA9, 0x42, 0xE8,
2921 0x9C, 0x71, 0x99, 0x94,
2922 0x91, 0xE3, 0xAF, 0xAC
2924 static const guint8 playready_uuid[] = {
2925 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2926 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2929 static const guint8 piff_sample_encryption_uuid[] = {
2930 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2931 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2936 /* counts as header data */
2937 qtdemux->header_size += length;
2939 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2941 if (length <= offset + 16) {
2942 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2946 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2948 GstTagList *taglist;
2950 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2951 length - offset - 16, NULL);
2952 taglist = gst_tag_list_from_xmp_buffer (buf);
2953 gst_buffer_unref (buf);
2955 /* make sure we have a usable taglist */
2956 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2958 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2960 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2962 const gunichar2 *s_utf16;
2965 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2966 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2967 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2968 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2972 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2973 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2975 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2976 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2978 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2979 GST_READ_UINT32_LE (buffer + offset),
2980 GST_READ_UINT32_LE (buffer + offset + 4),
2981 GST_READ_UINT32_LE (buffer + offset + 8),
2982 GST_READ_UINT32_LE (buffer + offset + 12));
2987 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2989 GstSidxParser sidx_parser;
2990 GstIsoffParserResult res;
2993 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2996 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2998 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2999 if (res == GST_ISOFF_QT_PARSER_DONE) {
3000 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3002 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3005 /* caller verifies at least 8 bytes in buf */
3007 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3008 guint64 * plength, guint32 * pfourcc)
3013 length = QT_UINT32 (data);
3014 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3015 fourcc = QT_FOURCC (data + 4);
3016 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3019 length = G_MAXUINT64;
3020 } else if (length == 1 && size >= 16) {
3021 /* this means we have an extended size, which is the 64 bit value of
3022 * the next 8 bytes */
3023 length = QT_UINT64 (data + 8);
3024 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3034 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3036 guint32 version = 0;
3037 GstClockTime duration = 0;
3039 if (!gst_byte_reader_get_uint32_be (br, &version))
3044 if (!gst_byte_reader_get_uint64_be (br, &duration))
3049 if (!gst_byte_reader_get_uint32_be (br, &dur))
3054 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3055 qtdemux->duration = duration;
3061 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3067 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3068 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3070 if (!stream->parsed_trex && qtdemux->moov_node) {
3072 GstByteReader trex_data;
3074 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3076 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3079 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3081 /* skip version/flags */
3082 if (!gst_byte_reader_skip (&trex_data, 4))
3084 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3086 if (id != stream->track_id)
3088 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3090 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3092 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3094 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3097 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3098 "duration %d, size %d, flags 0x%x", stream->track_id,
3101 stream->parsed_trex = TRUE;
3102 stream->def_sample_description_index = sdi;
3103 stream->def_sample_duration = dur;
3104 stream->def_sample_size = size;
3105 stream->def_sample_flags = flags;
3108 /* iterate all siblings */
3109 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3115 *ds_duration = stream->def_sample_duration;
3116 *ds_size = stream->def_sample_size;
3117 *ds_flags = stream->def_sample_flags;
3119 /* even then, above values are better than random ... */
3120 if (G_UNLIKELY (!stream->parsed_trex)) {
3121 GST_WARNING_OBJECT (qtdemux,
3122 "failed to find fragment defaults for stream %d", stream->track_id);
3129 /* This method should be called whenever a more accurate duration might
3130 * have been found. It will update all relevant variables if/where needed
3133 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3137 GstClockTime prevdur;
3139 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3141 if (movdur > qtdemux->duration) {
3142 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3143 GST_DEBUG_OBJECT (qtdemux,
3144 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3145 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3146 qtdemux->duration = movdur;
3147 GST_DEBUG_OBJECT (qtdemux,
3148 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3149 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3150 GST_TIME_ARGS (qtdemux->segment.stop));
3151 if (qtdemux->segment.duration == prevdur) {
3152 /* If the current segment has duration/stop identical to previous duration
3153 * update them also (because they were set at that point in time with
3154 * the wrong duration */
3155 /* We convert the value *from* the timescale version to avoid rounding errors */
3156 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3157 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3158 qtdemux->segment.duration = fixeddur;
3159 qtdemux->segment.stop = fixeddur;
3163 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3164 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3166 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3167 if (movdur > stream->duration) {
3168 GST_DEBUG_OBJECT (qtdemux,
3169 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3170 GST_TIME_ARGS (duration));
3171 stream->duration = movdur;
3172 /* internal duration tracking state has been updated above, so */
3173 /* preserve an open-ended dummy segment rather than repeatedly updating
3174 * it and spamming downstream accordingly with segment events */
3175 /* also mangle the edit list end time when fragmented with a single edit
3176 * list that may only cover any non-fragmented data */
3177 if ((stream->dummy_segment ||
3178 (qtdemux->fragmented && stream->n_segments == 1)) &&
3179 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3180 /* Update all dummy values to new duration */
3181 stream->segments[0].stop_time = duration;
3182 stream->segments[0].duration = duration;
3183 stream->segments[0].media_stop = duration;
3185 /* let downstream know we possibly have a new stop time */
3186 if (stream->segment_index != -1) {
3189 if (qtdemux->segment.rate >= 0) {
3190 pos = stream->segment.start;
3192 pos = stream->segment.stop;
3195 gst_qtdemux_stream_update_segment (qtdemux, stream,
3196 stream->segment_index, pos, NULL, NULL);
3204 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3205 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3206 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3207 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3210 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3212 gint32 data_offset = 0;
3213 guint32 flags = 0, first_flags = 0, samples_count = 0;
3216 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3217 QtDemuxSample *sample;
3218 gboolean ismv = FALSE;
3219 gint64 initial_offset;
3221 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3222 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3223 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3224 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3226 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3227 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3231 /* presence of stss or not can't really tell us much,
3232 * and flags and so on tend to be marginally reliable in these files */
3233 if (stream->subtype == FOURCC_soun) {
3234 GST_DEBUG_OBJECT (qtdemux,
3235 "sound track in fragmented file; marking all keyframes");
3236 stream->all_keyframe = TRUE;
3239 if (!gst_byte_reader_skip (trun, 1) ||
3240 !gst_byte_reader_get_uint24_be (trun, &flags))
3243 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3246 if (flags & TR_DATA_OFFSET) {
3247 /* note this is really signed */
3248 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3250 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3251 /* default base offset = first byte of moof */
3252 if (*base_offset == -1) {
3253 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3254 *base_offset = moof_offset;
3256 *running_offset = *base_offset + data_offset;
3258 /* if no offset at all, that would mean data starts at moof start,
3259 * which is a bit wrong and is ismv crappy way, so compensate
3260 * assuming data is in mdat following moof */
3261 if (*base_offset == -1) {
3262 *base_offset = moof_offset + moof_length + 8;
3263 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3266 if (*running_offset == -1)
3267 *running_offset = *base_offset;
3270 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3272 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3273 data_offset, flags, samples_count);
3275 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3276 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3277 GST_DEBUG_OBJECT (qtdemux,
3278 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3279 flags ^= TR_FIRST_SAMPLE_FLAGS;
3281 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3283 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3287 /* FIXME ? spec says other bits should also be checked to determine
3288 * entry size (and prefix size for that matter) */
3290 dur_offset = size_offset = 0;
3291 if (flags & TR_SAMPLE_DURATION) {
3292 GST_LOG_OBJECT (qtdemux, "entry duration present");
3293 dur_offset = entry_size;
3296 if (flags & TR_SAMPLE_SIZE) {
3297 GST_LOG_OBJECT (qtdemux, "entry size present");
3298 size_offset = entry_size;
3301 if (flags & TR_SAMPLE_FLAGS) {
3302 GST_LOG_OBJECT (qtdemux, "entry flags present");
3303 flags_offset = entry_size;
3306 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3307 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3308 ct_offset = entry_size;
3312 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3314 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3316 if (stream->n_samples + samples_count >=
3317 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3320 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3321 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3322 (stream->n_samples + samples_count) *
3323 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3325 /* create a new array of samples if it's the first sample parsed */
3326 if (stream->n_samples == 0) {
3327 g_assert (stream->samples == NULL);
3328 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3329 /* or try to reallocate it with space enough to insert the new samples */
3331 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3332 stream->n_samples + samples_count);
3333 if (stream->samples == NULL)
3336 if (qtdemux->fragment_start != -1) {
3337 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3338 qtdemux->fragment_start = -1;
3340 if (stream->n_samples == 0) {
3341 if (decode_ts > 0) {
3342 timestamp = decode_ts;
3343 } else if (stream->pending_seek != NULL) {
3344 /* if we don't have a timestamp from a tfdt box, we'll use the one
3345 * from the mfra seek table */
3346 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3347 GST_TIME_ARGS (stream->pending_seek->ts));
3349 /* FIXME: this is not fully correct, the timestamp refers to the random
3350 * access sample refered to in the tfra entry, which may not necessarily
3351 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3352 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3357 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3358 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3359 GST_TIME_ARGS (gst_ts));
3361 /* subsequent fragments extend stream */
3363 stream->samples[stream->n_samples - 1].timestamp +
3364 stream->samples[stream->n_samples - 1].duration;
3366 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3367 * difference (1 sec.) between decode_ts and timestamp, prefer the
3369 if (has_tfdt && !qtdemux->upstream_format_is_time
3370 && ABSDIFF (decode_ts, timestamp) >
3371 MAX (stream->duration_last_moof / 2,
3372 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3373 GST_INFO_OBJECT (qtdemux,
3374 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3375 ") are significantly different (more than %" GST_TIME_FORMAT
3376 "), using decode_ts",
3377 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3378 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3379 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3380 MAX (stream->duration_last_moof / 2,
3381 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3382 timestamp = decode_ts;
3385 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3386 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3387 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3391 initial_offset = *running_offset;
3393 sample = stream->samples + stream->n_samples;
3394 for (i = 0; i < samples_count; i++) {
3395 guint32 dur, size, sflags, ct;
3397 /* first read sample data */
3398 if (flags & TR_SAMPLE_DURATION) {
3399 dur = QT_UINT32 (data + dur_offset);
3401 dur = d_sample_duration;
3403 if (flags & TR_SAMPLE_SIZE) {
3404 size = QT_UINT32 (data + size_offset);
3406 size = d_sample_size;
3408 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3410 sflags = first_flags;
3412 sflags = d_sample_flags;
3414 } else if (flags & TR_SAMPLE_FLAGS) {
3415 sflags = QT_UINT32 (data + flags_offset);
3417 sflags = d_sample_flags;
3419 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3420 ct = QT_UINT32 (data + ct_offset);
3426 /* fill the sample information */
3427 sample->offset = *running_offset;
3428 sample->pts_offset = ct;
3429 sample->size = size;
3430 sample->timestamp = timestamp;
3431 sample->duration = dur;
3432 /* sample-is-difference-sample */
3433 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3434 * now idea how it relates to bitfield other than massive LE/BE confusion */
3435 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3436 *running_offset += size;
3438 stream->duration_moof += dur;
3442 /* Update total duration if needed */
3443 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3445 /* Pre-emptively figure out size of mdat based on trun information.
3446 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3447 * size, else we will still be able to use this when dealing with gap'ed
3449 qtdemux->mdatleft = *running_offset - initial_offset;
3450 qtdemux->mdatoffset = initial_offset;
3451 qtdemux->mdatsize = qtdemux->mdatleft;
3453 stream->n_samples += samples_count;
3454 stream->n_samples_moof += samples_count;
3456 if (stream->pending_seek != NULL)
3457 stream->pending_seek = NULL;
3463 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3468 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3474 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3475 "be larger than %uMB (broken file?)", stream->n_samples,
3476 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3481 /* find stream with @id */
3482 static inline QtDemuxStream *
3483 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3485 QtDemuxStream *stream;
3489 if (G_UNLIKELY (!id)) {
3490 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3494 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3495 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3496 if (stream->track_id == id)
3499 if (qtdemux->mss_mode) {
3500 /* mss should have only 1 stream anyway */
3501 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3508 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3509 guint32 * fragment_number)
3511 if (!gst_byte_reader_skip (mfhd, 4))
3513 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3518 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3524 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3525 QtDemuxStream ** stream, guint32 * default_sample_duration,
3526 guint32 * default_sample_size, guint32 * default_sample_flags,
3527 gint64 * base_offset)
3530 guint32 track_id = 0;
3532 if (!gst_byte_reader_skip (tfhd, 1) ||
3533 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3536 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3539 *stream = qtdemux_find_stream (qtdemux, track_id);
3540 if (G_UNLIKELY (!*stream))
3541 goto unknown_stream;
3543 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3544 *base_offset = qtdemux->moof_offset;
3546 if (flags & TF_BASE_DATA_OFFSET)
3547 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3550 /* obtain stream defaults */
3551 qtdemux_parse_trex (qtdemux, *stream,
3552 default_sample_duration, default_sample_size, default_sample_flags);
3554 (*stream)->stsd_sample_description_id =
3555 (*stream)->def_sample_description_index - 1;
3557 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3558 guint32 sample_description_index;
3559 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3561 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3564 if (qtdemux->mss_mode) {
3565 /* mss has no stsd entry */
3566 (*stream)->stsd_sample_description_id = 0;
3569 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3570 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3573 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3574 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3577 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3578 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3585 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3590 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3596 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3597 guint64 * decode_time)
3599 guint32 version = 0;
3601 if (!gst_byte_reader_get_uint32_be (br, &version))
3606 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3609 guint32 dec_time = 0;
3610 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3612 *decode_time = dec_time;
3615 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3622 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3627 /* Returns a pointer to a GstStructure containing the properties of
3628 * the stream sample identified by @sample_index. The caller must unref
3629 * the returned object after use. Returns NULL if unsuccessful. */
3630 static GstStructure *
3631 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3632 QtDemuxStream * stream, guint sample_index)
3634 QtDemuxCencSampleSetInfo *info = NULL;
3636 g_return_val_if_fail (stream != NULL, NULL);
3637 g_return_val_if_fail (stream->protected, NULL);
3638 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3640 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3642 /* Currently, cenc properties for groups of samples are not supported, so
3643 * simply return a copy of the default sample properties */
3644 return gst_structure_copy (info->default_properties);
3647 /* Parses the sizes of sample auxiliary information contained within a stream,
3648 * as given in a saiz box. Returns array of sample_count guint8 size values,
3649 * or NULL on failure */
3651 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3652 GstByteReader * br, guint32 * sample_count)
3656 guint8 default_info_size;
3658 g_return_val_if_fail (qtdemux != NULL, NULL);
3659 g_return_val_if_fail (stream != NULL, NULL);
3660 g_return_val_if_fail (br != NULL, NULL);
3661 g_return_val_if_fail (sample_count != NULL, NULL);
3663 if (!gst_byte_reader_get_uint32_be (br, &flags))
3667 /* aux_info_type and aux_info_type_parameter are ignored */
3668 if (!gst_byte_reader_skip (br, 8))
3672 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3674 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3676 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3678 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3681 if (default_info_size == 0) {
3682 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3686 info_sizes = g_new (guint8, *sample_count);
3687 memset (info_sizes, default_info_size, *sample_count);
3693 /* Parses the offset of sample auxiliary information contained within a stream,
3694 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3696 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3697 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3702 guint32 aux_info_type = 0;
3703 guint32 aux_info_type_parameter = 0;
3704 guint32 entry_count;
3707 const guint8 *aux_info_type_data = NULL;
3709 g_return_val_if_fail (qtdemux != NULL, FALSE);
3710 g_return_val_if_fail (stream != NULL, FALSE);
3711 g_return_val_if_fail (br != NULL, FALSE);
3712 g_return_val_if_fail (offset != NULL, FALSE);
3714 if (!gst_byte_reader_get_uint8 (br, &version))
3717 if (!gst_byte_reader_get_uint24_be (br, &flags))
3722 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3724 aux_info_type = QT_FOURCC (aux_info_type_data);
3726 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3728 } else if (stream->protected) {
3729 aux_info_type = stream->protection_scheme_type;
3731 aux_info_type = CUR_STREAM (stream)->fourcc;
3735 *info_type = aux_info_type;
3736 if (info_type_parameter)
3737 *info_type_parameter = aux_info_type_parameter;
3739 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3740 "aux_info_type_parameter: %#06x",
3741 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3743 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3746 if (entry_count != 1) {
3747 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3752 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3754 *offset = (guint64) off_32;
3756 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3761 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3766 qtdemux_gst_structure_free (GstStructure * gststructure)
3769 gst_structure_free (gststructure);
3773 /* Parses auxiliary information relating to samples protected using
3774 * Common Encryption (cenc); the format of this information
3775 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3778 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3779 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3781 QtDemuxCencSampleSetInfo *ss_info = NULL;
3784 GPtrArray *old_crypto_info = NULL;
3785 guint old_entries = 0;
3787 g_return_val_if_fail (qtdemux != NULL, FALSE);
3788 g_return_val_if_fail (stream != NULL, FALSE);
3789 g_return_val_if_fail (br != NULL, FALSE);
3790 g_return_val_if_fail (stream->protected, FALSE);
3791 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3793 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3795 if (ss_info->crypto_info) {
3796 old_crypto_info = ss_info->crypto_info;
3797 /* Count number of non-null entries remaining at the tail end */
3798 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3799 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3805 ss_info->crypto_info =
3806 g_ptr_array_new_full (sample_count + old_entries,
3807 (GDestroyNotify) qtdemux_gst_structure_free);
3809 /* We preserve old entries because we parse the next moof in advance
3810 * of consuming all samples from the previous moof, and otherwise
3811 * we'd discard the corresponding crypto info for the samples
3812 * from the previous fragment. */
3814 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3816 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3817 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3819 g_ptr_array_index (old_crypto_info, i) = NULL;
3823 if (old_crypto_info) {
3824 /* Everything now belongs to the new array */
3825 g_ptr_array_free (old_crypto_info, TRUE);
3828 for (i = 0; i < sample_count; ++i) {
3829 GstStructure *properties;
3830 guint16 n_subsamples = 0;
3834 gboolean could_read_iv;
3836 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3837 if (properties == NULL) {
3838 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3841 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3842 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3843 gst_structure_free (properties);
3847 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3848 if (could_read_iv) {
3849 buf = gst_buffer_new_wrapped (data, iv_size);
3850 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3851 gst_buffer_unref (buf);
3852 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3853 const GValue *constant_iv_size_value =
3854 gst_structure_get_value (properties, "constant_iv_size");
3855 const GValue *constant_iv_value =
3856 gst_structure_get_value (properties, "iv");
3857 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3858 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3859 gst_structure_free (properties);
3862 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3863 gst_structure_remove_field (properties, "constant_iv_size");
3864 } else if (stream->protection_scheme_type == FOURCC_cenc) {
3865 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3866 gst_structure_free (properties);
3869 size = info_sizes[i];
3870 if (size > iv_size) {
3871 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3872 || !(n_subsamples > 0)) {
3873 gst_structure_free (properties);
3874 GST_ERROR_OBJECT (qtdemux,
3875 "failed to get subsample count for sample %u", i);
3878 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3879 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3880 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3882 gst_structure_free (properties);
3885 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3887 gst_structure_free (properties);
3890 gst_structure_set (properties,
3891 "subsample_count", G_TYPE_UINT, n_subsamples,
3892 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3893 gst_buffer_unref (buf);
3895 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3897 g_ptr_array_add (ss_info->crypto_info, properties);
3902 /* Converts a UUID in raw byte form to a string representation, as defined in
3903 * RFC 4122. The caller takes ownership of the returned string and is
3904 * responsible for freeing it after use. */
3906 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3908 const guint8 *uuid = (const guint8 *) uuid_bytes;
3910 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3911 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3912 uuid[0], uuid[1], uuid[2], uuid[3],
3913 uuid[4], uuid[5], uuid[6], uuid[7],
3914 uuid[8], uuid[9], uuid[10], uuid[11],
3915 uuid[12], uuid[13], uuid[14], uuid[15]);
3918 /* Parses a Protection System Specific Header box (pssh), as defined in the
3919 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3920 * information needed by a specific content protection system in order to
3921 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3924 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3926 gchar *sysid_string;
3927 guint32 pssh_size = QT_UINT32 (node->data);
3928 GstBuffer *pssh = NULL;
3929 GstEvent *event = NULL;
3930 guint32 parent_box_type;
3933 if (G_UNLIKELY (pssh_size < 32U)) {
3934 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3939 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3941 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3943 pssh = gst_buffer_new_memdup (node->data, pssh_size);
3944 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3945 gst_buffer_get_size (pssh));
3947 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3949 /* Push an event containing the pssh box onto the queues of all streams. */
3950 event = gst_event_new_protection (sysid_string, pssh,
3951 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3952 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3953 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3954 GST_TRACE_OBJECT (qtdemux,
3955 "adding protection event for stream %s and system %s",
3956 stream->stream_id, sysid_string);
3957 g_queue_push_tail (&stream->protection_scheme_event_queue,
3958 gst_event_ref (event));
3960 g_free (sysid_string);
3961 gst_event_unref (event);
3962 gst_buffer_unref (pssh);
3967 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3968 guint64 moof_offset, QtDemuxStream * stream)
3970 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3972 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3973 GNode *saiz_node, *saio_node, *pssh_node;
3974 GstByteReader saiz_data, saio_data;
3975 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3976 gint64 base_offset, running_offset;
3978 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
3980 /* NOTE @stream ignored */
3982 moof_node = g_node_new ((guint8 *) buffer);
3983 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3984 qtdemux_node_dump (qtdemux, moof_node);
3986 /* Get fragment number from mfhd and check it's valid */
3988 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3989 if (mfhd_node == NULL)
3991 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3993 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3995 /* unknown base_offset to start with */
3996 base_offset = running_offset = -1;
3997 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3999 guint64 decode_time = 0;
4001 /* Fragment Header node */
4003 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4007 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4008 &ds_size, &ds_flags, &base_offset))
4011 /* The following code assumes at most a single set of sample auxiliary
4012 * data in the fragment (consisting of a saiz box and a corresponding saio
4013 * box); in theory, however, there could be multiple sets of sample
4014 * auxiliary data in a fragment. */
4016 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4019 guint32 info_type = 0;
4021 guint32 info_type_parameter = 0;
4023 g_free (qtdemux->cenc_aux_info_sizes);
4025 qtdemux->cenc_aux_info_sizes =
4026 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4027 &qtdemux->cenc_aux_sample_count);
4028 if (qtdemux->cenc_aux_info_sizes == NULL) {
4029 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4033 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4036 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4037 g_free (qtdemux->cenc_aux_info_sizes);
4038 qtdemux->cenc_aux_info_sizes = NULL;
4042 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4043 &info_type, &info_type_parameter, &offset))) {
4044 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4045 g_free (qtdemux->cenc_aux_info_sizes);
4046 qtdemux->cenc_aux_info_sizes = NULL;
4049 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4050 offset += (guint64) (base_offset - qtdemux->moof_offset);
4051 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4052 && info_type_parameter == 0U) {
4054 if (offset > length) {
4055 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4056 qtdemux->cenc_aux_info_offset = offset;
4058 gst_byte_reader_init (&br, buffer + offset, length - offset);
4059 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4060 qtdemux->cenc_aux_info_sizes,
4061 qtdemux->cenc_aux_sample_count)) {
4062 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4063 g_free (qtdemux->cenc_aux_info_sizes);
4064 qtdemux->cenc_aux_info_sizes = NULL;
4072 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4075 /* We'll use decode_time to interpolate timestamps
4076 * in case the input timestamps are missing */
4077 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4079 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4080 " (%" GST_TIME_FORMAT ")", decode_time,
4081 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4082 decode_time) : GST_CLOCK_TIME_NONE));
4084 /* Discard the fragment buffer timestamp info to avoid using it.
4085 * Rely on tfdt instead as it is more accurate than the timestamp
4086 * that is fetched from a manifest/playlist and is usually
4088 qtdemux->fragment_start = -1;
4091 if (G_UNLIKELY (!stream)) {
4092 /* we lost track of offset, we'll need to regain it,
4093 * but can delay complaining until later or avoid doing so altogether */
4097 if (G_UNLIKELY (base_offset < -1))
4100 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4102 if (!qtdemux->pullbased) {
4103 /* Sample tables can grow enough to be problematic if the system memory
4104 * is very low (e.g. embedded devices) and the videos very long
4105 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4106 * Fortunately, we can easily discard them for each new fragment when
4107 * we know qtdemux will not receive seeks outside of the current fragment.
4108 * adaptivedemux honors this assumption.
4109 * This optimization is also useful for applications that use qtdemux as
4110 * a push-based simple demuxer, like Media Source Extensions. */
4111 gst_qtdemux_stream_flush_samples_data (stream);
4114 /* initialise moof sample data */
4115 stream->n_samples_moof = 0;
4116 stream->duration_last_moof = stream->duration_moof;
4117 stream->duration_moof = 0;
4119 /* Track Run node */
4121 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4124 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4125 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4126 &running_offset, decode_time, (tfdt_node != NULL));
4127 /* iterate all siblings */
4128 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4132 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4134 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4135 guint32 box_length = QT_UINT32 (uuid_buffer);
4137 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4140 /* if no new base_offset provided for next traf,
4141 * base is end of current traf */
4142 base_offset = running_offset;
4143 running_offset = -1;
4145 if (stream->n_samples_moof && stream->duration_moof)
4146 stream->new_caps = TRUE;
4149 /* iterate all siblings */
4150 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4153 /* parse any protection system info */
4154 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4156 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4157 qtdemux_parse_pssh (qtdemux, pssh_node);
4158 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4161 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4162 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4164 /* Unless the user has explicitly requested another seek, perform an
4165 * internal seek to the time specified in the tfdt.
4167 * This way if the user opens a file where the first tfdt is 1 hour
4168 * into the presentation, they will not have to wait 1 hour for run
4169 * time to catch up and actual playback to start. */
4172 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4173 "performing an internal seek to %" GST_TIME_FORMAT,
4174 GST_TIME_ARGS (min_dts));
4176 qtdemux->segment.start = min_dts;
4177 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4179 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4180 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4181 stream->time_position = min_dts;
4184 /* Before this code was run a segment was already sent when the moov was
4185 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4186 * be emitted after a moov, and we can emit a second segment anyway for
4187 * special cases like this. */
4188 qtdemux->need_segment = TRUE;
4191 qtdemux->first_moof_already_parsed = TRUE;
4193 g_node_destroy (moof_node);
4198 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4203 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4208 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4213 g_node_destroy (moof_node);
4214 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4215 (_("This file is corrupt and cannot be played.")), (NULL));
4221 /* might be used if some day we actually use mfra & co
4222 * for random access to fragments,
4223 * but that will require quite some modifications and much less relying
4224 * on a sample array */
4228 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4230 QtDemuxStream *stream;
4231 guint32 ver_flags, track_id, len, num_entries, i;
4232 guint value_size, traf_size, trun_size, sample_size;
4233 guint64 time = 0, moof_offset = 0;
4235 GstBuffer *buf = NULL;
4240 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4242 if (!gst_byte_reader_skip (&tfra, 8))
4245 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4248 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4249 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4250 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4253 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4255 stream = qtdemux_find_stream (qtdemux, track_id);
4257 goto unknown_trackid;
4259 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4260 sample_size = (len & 3) + 1;
4261 trun_size = ((len & 12) >> 2) + 1;
4262 traf_size = ((len & 48) >> 4) + 1;
4264 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4265 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4267 if (num_entries == 0)
4270 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4271 value_size + value_size + traf_size + trun_size + sample_size))
4274 g_free (stream->ra_entries);
4275 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4276 stream->n_ra_entries = num_entries;
4278 for (i = 0; i < num_entries; i++) {
4279 qt_atom_parser_get_offset (&tfra, value_size, &time);
4280 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4281 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4282 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4283 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4285 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4287 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4288 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4290 stream->ra_entries[i].ts = time;
4291 stream->ra_entries[i].moof_offset = moof_offset;
4293 /* don't want to go through the entire file and read all moofs at startup */
4295 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4296 if (ret != GST_FLOW_OK)
4298 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4299 moof_offset, stream);
4300 gst_buffer_unref (buf);
4304 check_update_duration (qtdemux, time);
4311 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4316 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4321 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4327 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4329 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4330 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4331 GstBuffer *mfro = NULL, *mfra = NULL;
4333 gboolean ret = FALSE;
4334 GNode *mfra_node, *tfra_node;
4335 guint64 mfra_offset = 0;
4336 guint32 fourcc, mfra_size;
4339 /* query upstream size in bytes */
4340 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4341 goto size_query_failed;
4343 /* mfro box should be at the very end of the file */
4344 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4345 if (flow != GST_FLOW_OK)
4348 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4350 fourcc = QT_FOURCC (mfro_map.data + 4);
4351 if (fourcc != FOURCC_mfro)
4354 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4355 if (mfro_map.size < 16)
4356 goto invalid_mfro_size;
4358 mfra_size = QT_UINT32 (mfro_map.data + 12);
4359 if (mfra_size >= len)
4360 goto invalid_mfra_size;
4362 mfra_offset = len - mfra_size;
4364 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4365 mfra_offset, mfra_size);
4367 /* now get and parse mfra box */
4368 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4369 if (flow != GST_FLOW_OK)
4372 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4374 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4375 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4377 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4380 qtdemux_parse_tfra (qtdemux, tfra_node);
4381 /* iterate all siblings */
4382 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4384 g_node_destroy (mfra_node);
4386 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4392 if (mfro_map.memory != NULL)
4393 gst_buffer_unmap (mfro, &mfro_map);
4394 gst_buffer_unref (mfro);
4397 if (mfra_map.memory != NULL)
4398 gst_buffer_unmap (mfra, &mfra_map);
4399 gst_buffer_unref (mfra);
4406 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4411 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4416 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4421 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4427 add_offset (guint64 offset, guint64 advance)
4429 /* Avoid 64-bit overflow by clamping */
4430 if (offset > G_MAXUINT64 - advance)
4432 return offset + advance;
4435 static GstFlowReturn
4436 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4440 GstBuffer *buf = NULL;
4441 GstFlowReturn ret = GST_FLOW_OK;
4442 guint64 cur_offset = qtdemux->offset;
4445 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4446 if (G_UNLIKELY (ret != GST_FLOW_OK))
4448 gst_buffer_map (buf, &map, GST_MAP_READ);
4449 if (G_LIKELY (map.size >= 8))
4450 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4451 gst_buffer_unmap (buf, &map);
4452 gst_buffer_unref (buf);
4454 /* maybe we already got most we needed, so only consider this eof */
4455 if (G_UNLIKELY (length == 0)) {
4456 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4457 (_("Invalid atom size.")),
4458 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4459 GST_FOURCC_ARGS (fourcc)));
4466 /* record for later parsing when needed */
4467 if (!qtdemux->moof_offset) {
4468 qtdemux->moof_offset = qtdemux->offset;
4470 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4473 qtdemux->offset += length; /* skip moof and keep going */
4475 if (qtdemux->got_moov) {
4476 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4488 GST_LOG_OBJECT (qtdemux,
4489 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4490 GST_FOURCC_ARGS (fourcc), cur_offset);
4491 qtdemux->offset = add_offset (qtdemux->offset, length);
4496 GstBuffer *moov = NULL;
4498 if (qtdemux->got_moov) {
4499 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4500 qtdemux->offset = add_offset (qtdemux->offset, length);
4504 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4505 if (ret != GST_FLOW_OK)
4507 gst_buffer_map (moov, &map, GST_MAP_READ);
4509 if (length != map.size) {
4510 /* Some files have a 'moov' atom at the end of the file which contains
4511 * a terminal 'free' atom where the body of the atom is missing.
4512 * Check for, and permit, this special case.
4514 if (map.size >= 8) {
4515 guint8 *final_data = map.data + (map.size - 8);
4516 guint32 final_length = QT_UINT32 (final_data);
4517 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4519 if (final_fourcc == FOURCC_free
4520 && map.size + final_length - 8 == length) {
4521 /* Ok, we've found that special case. Allocate a new buffer with
4522 * that free atom actually present. */
4523 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4524 gst_buffer_fill (newmoov, 0, map.data, map.size);
4525 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4526 gst_buffer_unmap (moov, &map);
4527 gst_buffer_unref (moov);
4529 gst_buffer_map (moov, &map, GST_MAP_READ);
4534 if (length != map.size) {
4535 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4536 (_("This file is incomplete and cannot be played.")),
4537 ("We got less than expected (received %" G_GSIZE_FORMAT
4538 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4539 (guint) length, cur_offset));
4540 gst_buffer_unmap (moov, &map);
4541 gst_buffer_unref (moov);
4542 ret = GST_FLOW_ERROR;
4545 qtdemux->offset += length;
4547 qtdemux_parse_moov (qtdemux, map.data, length);
4548 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4550 qtdemux_parse_tree (qtdemux);
4551 if (qtdemux->moov_node_compressed) {
4552 g_node_destroy (qtdemux->moov_node_compressed);
4553 g_free (qtdemux->moov_node->data);
4555 qtdemux->moov_node_compressed = NULL;
4556 g_node_destroy (qtdemux->moov_node);
4557 qtdemux->moov_node = NULL;
4558 gst_buffer_unmap (moov, &map);
4559 gst_buffer_unref (moov);
4560 qtdemux->got_moov = TRUE;
4566 GstBuffer *ftyp = NULL;
4568 /* extract major brand; might come in handy for ISO vs QT issues */
4569 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4570 if (ret != GST_FLOW_OK)
4572 qtdemux->offset += length;
4573 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4574 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4575 gst_buffer_unmap (ftyp, &map);
4576 gst_buffer_unref (ftyp);
4581 GstBuffer *uuid = NULL;
4583 /* uuid are extension atoms */
4584 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4585 if (ret != GST_FLOW_OK)
4587 qtdemux->offset += length;
4588 gst_buffer_map (uuid, &map, GST_MAP_READ);
4589 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4590 gst_buffer_unmap (uuid, &map);
4591 gst_buffer_unref (uuid);
4596 GstBuffer *sidx = NULL;
4597 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4598 if (ret != GST_FLOW_OK)
4600 qtdemux->offset += length;
4601 gst_buffer_map (sidx, &map, GST_MAP_READ);
4602 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4603 gst_buffer_unmap (sidx, &map);
4604 gst_buffer_unref (sidx);
4609 GstBuffer *unknown = NULL;
4611 GST_LOG_OBJECT (qtdemux,
4612 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4613 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4615 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4616 if (ret != GST_FLOW_OK)
4618 gst_buffer_map (unknown, &map, GST_MAP_READ);
4619 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4620 gst_buffer_unmap (unknown, &map);
4621 gst_buffer_unref (unknown);
4622 qtdemux->offset += length;
4628 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4629 /* digested all data, show what we have */
4630 qtdemux_prepare_streams (qtdemux);
4631 QTDEMUX_EXPOSE_LOCK (qtdemux);
4632 ret = qtdemux_expose_streams (qtdemux);
4633 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4635 qtdemux->state = QTDEMUX_STATE_MOVIE;
4636 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4643 /* Seeks to the previous keyframe of the indexed stream and
4644 * aligns other streams with respect to the keyframe timestamp
4645 * of indexed stream. Only called in case of Reverse Playback
4647 static GstFlowReturn
4648 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4650 guint32 seg_idx = 0, k_index = 0;
4651 guint32 ref_seg_idx, ref_k_index;
4652 GstClockTime k_pos = 0, last_stop = 0;
4653 QtDemuxSegment *seg = NULL;
4654 QtDemuxStream *ref_str = NULL;
4655 guint64 seg_media_start_mov; /* segment media start time in mov format */
4659 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4660 * and finally align all the other streams on that timestamp with their
4661 * respective keyframes */
4662 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4663 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4665 /* No candidate yet, take the first stream */
4671 /* So that stream has a segment, we prefer video streams */
4672 if (str->subtype == FOURCC_vide) {
4678 if (G_UNLIKELY (!ref_str)) {
4679 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4683 if (G_UNLIKELY (!ref_str->from_sample)) {
4684 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4688 /* So that stream has been playing from from_sample to to_sample. We will
4689 * get the timestamp of the previous sample and search for a keyframe before
4690 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4691 if (ref_str->subtype == FOURCC_vide) {
4692 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4693 ref_str->from_sample - 1, FALSE);
4695 if (ref_str->from_sample >= 10)
4696 k_index = ref_str->from_sample - 10;
4702 ref_str->samples[k_index].timestamp +
4703 ref_str->samples[k_index].pts_offset;
4705 /* get current segment for that stream */
4706 seg = &ref_str->segments[ref_str->segment_index];
4707 /* Use segment start in original timescale for comparisons */
4708 seg_media_start_mov = seg->trak_media_start;
4710 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4711 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4712 k_index, target_ts, seg_media_start_mov,
4713 GST_TIME_ARGS (seg->media_start));
4715 /* Crawl back through segments to find the one containing this I frame */
4716 while (target_ts < seg_media_start_mov) {
4717 GST_DEBUG_OBJECT (qtdemux,
4718 "keyframe position (sample %u) is out of segment %u " " target %"
4719 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4720 ref_str->segment_index, target_ts, seg_media_start_mov);
4722 if (G_UNLIKELY (!ref_str->segment_index)) {
4723 /* Reached first segment, let's consider it's EOS */
4726 ref_str->segment_index--;
4727 seg = &ref_str->segments[ref_str->segment_index];
4728 /* Use segment start in original timescale for comparisons */
4729 seg_media_start_mov = seg->trak_media_start;
4731 /* Calculate time position of the keyframe and where we should stop */
4733 QTSTREAMTIME_TO_GSTTIME (ref_str,
4734 target_ts - seg->trak_media_start) + seg->time;
4736 QTSTREAMTIME_TO_GSTTIME (ref_str,
4737 ref_str->samples[ref_str->from_sample].timestamp -
4738 seg->trak_media_start) + seg->time;
4740 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4741 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4742 k_index, GST_TIME_ARGS (k_pos));
4744 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4745 qtdemux->segment.position = last_stop;
4746 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4747 GST_TIME_ARGS (last_stop));
4749 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4750 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4754 ref_seg_idx = ref_str->segment_index;
4755 ref_k_index = k_index;
4757 /* Align them all on this */
4758 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4760 GstClockTime seg_time = 0;
4761 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4763 /* aligning reference stream again might lead to backing up to yet another
4764 * keyframe (due to timestamp rounding issues),
4765 * potentially putting more load on downstream; so let's try to avoid */
4766 if (str == ref_str) {
4767 seg_idx = ref_seg_idx;
4768 seg = &str->segments[seg_idx];
4769 k_index = ref_k_index;
4770 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4771 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4773 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4774 GST_DEBUG_OBJECT (qtdemux,
4775 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4776 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4778 /* get segment and time in the segment */
4779 seg = &str->segments[seg_idx];
4780 seg_time = k_pos - seg->time;
4782 /* get the media time in the segment.
4783 * No adjustment for empty "filler" segments */
4784 if (seg->media_start != GST_CLOCK_TIME_NONE)
4785 seg_time += seg->media_start;
4787 /* get the index of the sample with media time */
4788 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4789 GST_DEBUG_OBJECT (qtdemux,
4790 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4791 GST_TIME_ARGS (seg_time), index);
4793 /* find previous keyframe */
4794 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4797 /* Remember until where we want to go */
4798 str->to_sample = str->from_sample - 1;
4799 /* Define our time position */
4801 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4802 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4803 if (seg->media_start != GST_CLOCK_TIME_NONE)
4804 str->time_position -= seg->media_start;
4806 /* Now seek back in time */
4807 gst_qtdemux_move_stream (qtdemux, str, k_index);
4808 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4809 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4810 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4816 return GST_FLOW_EOS;
4820 * Gets the current qt segment start, stop and position for the
4821 * given time offset. This is used in update_segment()
4824 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4825 QtDemuxStream * stream, GstClockTime offset,
4826 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4828 GstClockTime seg_time;
4829 GstClockTime start, stop, time;
4830 QtDemuxSegment *segment;
4832 segment = &stream->segments[stream->segment_index];
4834 /* get time in this segment */
4835 seg_time = (offset - segment->time) * segment->rate;
4837 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4838 GST_TIME_ARGS (seg_time));
4840 if (G_UNLIKELY (seg_time > segment->duration)) {
4841 GST_LOG_OBJECT (stream->pad,
4842 "seg_time > segment->duration %" GST_TIME_FORMAT,
4843 GST_TIME_ARGS (segment->duration));
4844 seg_time = segment->duration;
4847 /* qtdemux->segment.stop is in outside-time-realm, whereas
4848 * segment->media_stop is in track-time-realm.
4850 * In order to compare the two, we need to bring segment.stop
4851 * into the track-time-realm
4853 * FIXME - does this comment still hold? Don't see any conversion here */
4855 stop = qtdemux->segment.stop;
4856 if (stop == GST_CLOCK_TIME_NONE)
4857 stop = qtdemux->segment.duration;
4858 if (stop == GST_CLOCK_TIME_NONE)
4859 stop = segment->media_stop;
4862 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4864 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4865 start = segment->time + seg_time;
4867 stop = start - seg_time + segment->duration;
4868 } else if (qtdemux->segment.rate >= 0) {
4869 start = MIN (segment->media_start + seg_time, stop);
4872 if (segment->media_start >= qtdemux->segment.start) {
4873 time = segment->time;
4875 time = segment->time + (qtdemux->segment.start - segment->media_start);
4878 start = MAX (segment->media_start, qtdemux->segment.start);
4879 stop = MIN (segment->media_start + seg_time, stop);
4888 * Updates the qt segment used for the stream and pushes a new segment event
4889 * downstream on this stream's pad.
4892 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4893 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4894 GstClockTime * _stop)
4896 QtDemuxSegment *segment;
4897 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4901 /* update the current segment */
4902 stream->segment_index = seg_idx;
4904 /* get the segment */
4905 segment = &stream->segments[seg_idx];
4907 if (G_UNLIKELY (offset < segment->time)) {
4908 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4909 GST_TIME_ARGS (segment->time));
4913 /* segment lies beyond total indicated duration */
4914 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4915 segment->time > qtdemux->segment.duration)) {
4916 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4917 " < segment->time %" GST_TIME_FORMAT,
4918 GST_TIME_ARGS (qtdemux->segment.duration),
4919 GST_TIME_ARGS (segment->time));
4923 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4924 &start, &stop, &time);
4926 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4927 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4928 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4930 /* combine global rate with that of the segment */
4931 rate = segment->rate * qtdemux->segment.rate;
4933 /* Copy flags from main segment */
4934 stream->segment.flags = qtdemux->segment.flags;
4936 /* update the segment values used for clipping */
4937 stream->segment.offset = qtdemux->segment.offset;
4938 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4939 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4940 stream->segment.rate = rate;
4941 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4942 stream->cslg_shift);
4943 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4944 stream->cslg_shift);
4945 stream->segment.time = time;
4946 stream->segment.position = stream->segment.start;
4948 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4951 /* now prepare and send the segment */
4953 event = gst_event_new_segment (&stream->segment);
4954 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4955 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4957 gst_pad_push_event (stream->pad, event);
4958 /* assume we can send more data now */
4959 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4960 /* clear to send tags on this pad now */
4961 gst_qtdemux_push_tags (qtdemux, stream);
4972 /* activate the given segment number @seg_idx of @stream at time @offset.
4973 * @offset is an absolute global position over all the segments.
4975 * This will push out a NEWSEGMENT event with the right values and
4976 * position the stream index to the first decodable sample before
4980 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4981 guint32 seg_idx, GstClockTime offset)
4983 QtDemuxSegment *segment;
4984 guint32 index, kf_index;
4985 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4987 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4988 seg_idx, GST_TIME_ARGS (offset));
4990 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4994 segment = &stream->segments[stream->segment_index];
4996 /* in the fragmented case, we pick a fragment that starts before our
4997 * desired position and rely on downstream to wait for a keyframe
4998 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4999 * tfra entries tells us which trun/sample the key unit is in, but we don't
5000 * make use of this additional information at the moment) */
5001 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5002 stream->to_sample = G_MAXUINT32;
5005 /* well, it will be taken care of below */
5006 qtdemux->fragmented_seek_pending = FALSE;
5007 /* FIXME ideally the do_fragmented_seek can be done right here,
5008 * rather than at loop level
5009 * (which might even allow handling edit lists in a fragmented file) */
5012 /* We don't need to look for a sample in push-based */
5013 if (!qtdemux->pullbased)
5016 /* and move to the keyframe before the indicated media time of the
5018 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5019 if (qtdemux->segment.rate >= 0) {
5020 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5021 stream->to_sample = G_MAXUINT32;
5022 GST_DEBUG_OBJECT (stream->pad,
5023 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5024 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5025 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5027 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5028 stream->to_sample = index;
5029 GST_DEBUG_OBJECT (stream->pad,
5030 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5031 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5032 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5035 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5036 "this is an empty segment");
5040 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5041 * encountered an error and printed a message so we return appropriately */
5045 /* we're at the right spot */
5046 if (index == stream->sample_index) {
5047 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5051 /* find keyframe of the target index */
5052 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5054 /* go back two frames to provide lead-in for non-raw audio decoders */
5055 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5056 guint32 lead_in = 2;
5057 guint32 old_index = kf_index;
5058 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5060 if (gst_structure_has_name (s, "audio/mpeg")) {
5062 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5063 && mpegversion == 1) {
5064 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5069 kf_index = MAX (kf_index, lead_in) - lead_in;
5070 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5071 GST_DEBUG_OBJECT (stream->pad,
5072 "Moving backwards %u frames to ensure sufficient sound lead-in",
5073 old_index - kf_index);
5075 kf_index = old_index;
5079 /* if we move forwards, we don't have to go back to the previous
5080 * keyframe since we already sent that. We can also just jump to
5081 * the keyframe right before the target index if there is one. */
5082 if (index > stream->sample_index) {
5083 /* moving forwards check if we move past a keyframe */
5084 if (kf_index > stream->sample_index) {
5085 GST_DEBUG_OBJECT (stream->pad,
5086 "moving forwards to keyframe at %u "
5087 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5089 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5090 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5091 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5093 GST_DEBUG_OBJECT (stream->pad,
5094 "moving forwards, keyframe at %u "
5095 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5097 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5098 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5101 GST_DEBUG_OBJECT (stream->pad,
5102 "moving backwards to %sframe at %u "
5103 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5104 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5105 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5106 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5107 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5113 /* prepare to get the current sample of @stream, getting essential values.
5115 * This function will also prepare and send the segment when needed.
5117 * Return FALSE if the stream is EOS.
5122 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5123 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5124 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5125 gboolean * keyframe)
5127 QtDemuxSample *sample;
5128 GstClockTime time_position;
5131 g_return_val_if_fail (stream != NULL, FALSE);
5133 time_position = stream->time_position;
5134 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5137 seg_idx = stream->segment_index;
5138 if (G_UNLIKELY (seg_idx == -1)) {
5139 /* find segment corresponding to time_position if we are looking
5141 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5144 /* different segment, activate it, sample_index will be set. */
5145 if (G_UNLIKELY (stream->segment_index != seg_idx))
5146 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5148 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5149 segments[stream->segment_index]))) {
5150 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5152 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5153 " prepare empty sample");
5156 *pts = *dts = time_position;
5157 *duration = seg->duration - (time_position - seg->time);
5164 if (stream->sample_index == -1)
5165 stream->sample_index = 0;
5167 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5168 stream->sample_index, stream->n_samples);
5170 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5171 if (!qtdemux->fragmented)
5174 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5178 GST_OBJECT_LOCK (qtdemux);
5179 flow = qtdemux_add_fragmented_samples (qtdemux);
5180 GST_OBJECT_UNLOCK (qtdemux);
5182 if (flow != GST_FLOW_OK)
5185 while (stream->sample_index >= stream->n_samples);
5188 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5189 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5190 stream->sample_index);
5194 /* now get the info for the sample we're at */
5195 sample = &stream->samples[stream->sample_index];
5197 *dts = QTSAMPLE_DTS (stream, sample);
5198 *pts = QTSAMPLE_PTS (stream, sample);
5199 *offset = sample->offset;
5200 *size = sample->size;
5201 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5202 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5209 stream->time_position = GST_CLOCK_TIME_NONE;
5214 /* move to the next sample in @stream.
5216 * Moves to the next segment when needed.
5219 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5221 QtDemuxSample *sample;
5222 QtDemuxSegment *segment;
5224 /* get current segment */
5225 segment = &stream->segments[stream->segment_index];
5227 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5228 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5232 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5233 /* Mark the stream as EOS */
5234 GST_DEBUG_OBJECT (qtdemux,
5235 "reached max allowed sample %u, mark EOS", stream->to_sample);
5236 stream->time_position = GST_CLOCK_TIME_NONE;
5240 /* move to next sample */
5241 stream->sample_index++;
5242 stream->offset_in_sample = 0;
5244 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5247 /* reached the last sample, we need the next segment */
5248 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5251 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5252 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5253 stream->sample_index);
5257 /* get next sample */
5258 sample = &stream->samples[stream->sample_index];
5260 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5261 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5262 GST_TIME_ARGS (segment->media_stop));
5264 /* see if we are past the segment */
5265 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5268 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5269 /* inside the segment, update time_position, looks very familiar to
5270 * GStreamer segments, doesn't it? */
5271 stream->time_position =
5272 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5274 /* not yet in segment, time does not yet increment. This means
5275 * that we are still prerolling keyframes to the decoder so it can
5276 * decode the first sample of the segment. */
5277 stream->time_position = segment->time;
5281 /* move to the next segment */
5284 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5286 if (stream->segment_index == stream->n_segments - 1) {
5287 /* are we at the end of the last segment, we're EOS */
5288 stream->time_position = GST_CLOCK_TIME_NONE;
5290 /* else we're only at the end of the current segment */
5291 stream->time_position = segment->stop_time;
5293 /* make sure we select a new segment */
5295 /* accumulate previous segments */
5296 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5297 stream->accumulated_base +=
5298 (stream->segment.stop -
5299 stream->segment.start) / ABS (stream->segment.rate);
5301 stream->segment_index = -1;
5306 gst_qtdemux_sync_streams (GstQTDemux * demux)
5310 if (QTDEMUX_N_STREAMS (demux) <= 1)
5313 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5314 QtDemuxStream *stream;
5315 GstClockTime end_time;
5317 stream = QTDEMUX_NTH_STREAM (demux, i);
5322 /* TODO advance time on subtitle streams here, if any some day */
5324 /* some clips/trailers may have unbalanced streams at the end,
5325 * so send EOS on shorter stream to prevent stalling others */
5327 /* do not mess with EOS if SEGMENT seeking */
5328 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5331 if (demux->pullbased) {
5332 /* loop mode is sample time based */
5333 if (!STREAM_IS_EOS (stream))
5336 /* push mode is byte position based */
5337 if (stream->n_samples &&
5338 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5342 if (stream->sent_eos)
5345 /* only act if some gap */
5346 end_time = stream->segments[stream->n_segments - 1].stop_time;
5347 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5348 ", stream end: %" GST_TIME_FORMAT,
5349 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5350 if (GST_CLOCK_TIME_IS_VALID (end_time)
5351 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5354 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5355 GST_PAD_NAME (stream->pad));
5356 stream->sent_eos = TRUE;
5357 event = gst_event_new_eos ();
5358 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5359 gst_event_set_seqnum (event, demux->segment_seqnum);
5360 gst_pad_push_event (stream->pad, event);
5365 /* EOS and NOT_LINKED need to be combined. This means that we return:
5367 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5368 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5370 static GstFlowReturn
5371 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5374 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5377 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5380 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5382 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5386 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5387 * completely clipped
5389 * Should be used only with raw buffers */
5391 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5394 guint64 start, stop, cstart, cstop, diff;
5395 GstClockTime pts, duration;
5397 gint num_rate, denom_rate;
5402 osize = size = gst_buffer_get_size (buf);
5405 /* depending on the type, setup the clip parameters */
5406 if (stream->subtype == FOURCC_soun) {
5407 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5408 num_rate = GST_SECOND;
5409 denom_rate = (gint) CUR_STREAM (stream)->rate;
5411 } else if (stream->subtype == FOURCC_vide) {
5413 num_rate = CUR_STREAM (stream)->fps_n;
5414 denom_rate = CUR_STREAM (stream)->fps_d;
5419 if (frame_size <= 0)
5420 goto bad_frame_size;
5422 /* we can only clip if we have a valid pts */
5423 pts = GST_BUFFER_PTS (buf);
5424 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5427 duration = GST_BUFFER_DURATION (buf);
5429 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5431 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5435 stop = start + duration;
5437 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5438 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5441 /* see if some clipping happened */
5442 diff = cstart - start;
5448 /* bring clipped time to samples and to bytes */
5449 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5452 GST_DEBUG_OBJECT (qtdemux,
5453 "clipping start to %" GST_TIME_FORMAT " %"
5454 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5460 diff = stop - cstop;
5465 /* bring clipped time to samples and then to bytes */
5466 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5468 GST_DEBUG_OBJECT (qtdemux,
5469 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5470 " bytes", GST_TIME_ARGS (cstop), diff);
5475 if (offset != 0 || size != osize)
5476 gst_buffer_resize (buf, offset, size);
5478 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5479 GST_BUFFER_PTS (buf) = pts;
5480 GST_BUFFER_DURATION (buf) = duration;
5484 /* dropped buffer */
5487 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5492 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5497 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5502 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5503 gst_buffer_unref (buf);
5509 gst_qtdemux_align_buffer (GstQTDemux * demux,
5510 GstBuffer * buffer, gsize alignment)
5514 gst_buffer_map (buffer, &map, GST_MAP_READ);
5516 if (map.size < sizeof (guintptr)) {
5517 gst_buffer_unmap (buffer, &map);
5521 if (((guintptr) map.data) & (alignment - 1)) {
5522 GstBuffer *new_buffer;
5523 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5525 new_buffer = gst_buffer_new_allocate (NULL,
5526 gst_buffer_get_size (buffer), ¶ms);
5528 /* Copy data "by hand", so ensure alignment is kept: */
5529 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5531 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5532 GST_DEBUG_OBJECT (demux,
5533 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5536 gst_buffer_unmap (buffer, &map);
5537 gst_buffer_unref (buffer);
5542 gst_buffer_unmap (buffer, &map);
5547 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5553 /* We are converting from pairs to triplets */
5554 *res = ccpair_size / 2 * 3;
5555 storage = g_malloc (*res);
5556 for (i = 0; i * 2 < ccpair_size; i += 1) {
5557 /* FIXME: Use line offset 0 as we simply can't know here */
5559 storage[i * 3] = 0x80 | 0x00;
5561 storage[i * 3] = 0x00 | 0x00;
5562 storage[i * 3 + 1] = ccpair[i * 2];
5563 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5570 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5574 guint32 atom_length, fourcc;
5575 QtDemuxStreamStsdEntry *stsd_entry;
5577 GST_MEMDUMP ("caption atom", data, size);
5579 /* There might be multiple atoms */
5584 atom_length = QT_UINT32 (data);
5585 fourcc = QT_FOURCC (data + 4);
5586 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5589 GST_DEBUG_OBJECT (stream->pad, "here");
5591 /* Check if we have something compatible */
5592 stsd_entry = CUR_STREAM (stream);
5593 switch (stsd_entry->fourcc) {
5595 guint8 *cdat = NULL, *cdt2 = NULL;
5596 gsize cdat_size = 0, cdt2_size = 0;
5597 /* Should be cdat or cdt2 */
5598 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5599 GST_WARNING_OBJECT (stream->pad,
5600 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5601 GST_FOURCC_ARGS (fourcc));
5605 /* Convert to S334-1 Annex A byte triplet */
5606 if (fourcc == FOURCC_cdat)
5607 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5609 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5610 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5613 /* Check for another atom ? */
5614 if (size > atom_length + 8) {
5615 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5616 if (size >= atom_length + new_atom_length) {
5617 fourcc = QT_FOURCC (data + atom_length + 4);
5618 if (fourcc == FOURCC_cdat) {
5621 convert_to_s334_1a (data + atom_length + 8,
5622 new_atom_length - 8, 1, &cdat_size);
5624 GST_WARNING_OBJECT (stream->pad,
5625 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5629 convert_to_s334_1a (data + atom_length + 8,
5630 new_atom_length - 8, 2, &cdt2_size);
5632 GST_WARNING_OBJECT (stream->pad,
5633 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5638 *cclen = cdat_size + cdt2_size;
5639 res = g_malloc (*cclen);
5641 memcpy (res, cdat, cdat_size);
5643 memcpy (res + cdat_size, cdt2, cdt2_size);
5649 if (fourcc != FOURCC_ccdp) {
5650 GST_WARNING_OBJECT (stream->pad,
5651 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5652 GST_FOURCC_ARGS (fourcc));
5655 *cclen = atom_length - 8;
5656 res = g_memdup2 (data + 8, *cclen);
5659 /* Keep this here in case other closed caption formats are added */
5660 g_assert_not_reached ();
5664 GST_MEMDUMP ("Output", res, *cclen);
5669 GST_WARNING ("[cdat] atom is too small or invalid");
5673 /* Handle Closed Caption sample buffers.
5674 * The input buffer metadata must be writable,
5675 * but time/duration etc not yet set and need not be preserved */
5677 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5680 GstBuffer *outbuf = NULL;
5685 gst_buffer_map (buf, &map, GST_MAP_READ);
5687 /* empty buffer is sent to terminate previous subtitle */
5688 if (map.size <= 2) {
5689 gst_buffer_unmap (buf, &map);
5690 gst_buffer_unref (buf);
5694 /* For closed caption, we need to extract the information from the
5695 * [cdat],[cdt2] or [ccdp] atom */
5696 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5697 gst_buffer_unmap (buf, &map);
5699 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5700 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5702 /* Conversion failed or there's nothing */
5704 gst_buffer_unref (buf);
5709 /* DVD subpicture specific sample handling.
5710 * the input buffer metadata must be writable,
5711 * but time/duration etc not yet set and need not be preserved */
5713 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5716 /* send a one time dvd clut event */
5717 if (stream->pending_event && stream->pad)
5718 gst_pad_push_event (stream->pad, stream->pending_event);
5719 stream->pending_event = NULL;
5721 /* empty buffer is sent to terminate previous subtitle */
5722 if (gst_buffer_get_size (buf) <= 2) {
5723 gst_buffer_unref (buf);
5727 /* That's all the processing needed for subpictures */
5731 /* Timed text formats
5732 * the input buffer metadata must be writable,
5733 * but time/duration etc not yet set and need not be preserved */
5735 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5738 GstBuffer *outbuf = NULL;
5743 /* not many cases for now */
5744 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5745 stream->subtype != FOURCC_sbtl)) {
5749 gst_buffer_map (buf, &map, GST_MAP_READ);
5751 /* empty buffer is sent to terminate previous subtitle */
5752 if (map.size <= 2) {
5753 gst_buffer_unmap (buf, &map);
5754 gst_buffer_unref (buf);
5758 nsize = GST_READ_UINT16_BE (map.data);
5759 nsize = MIN (nsize, map.size - 2);
5761 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5764 /* takes care of UTF-8 validation or UTF-16 recognition,
5765 * no other encoding expected */
5766 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5767 gst_buffer_unmap (buf, &map);
5770 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5771 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5773 /* this should not really happen unless the subtitle is corrupted */
5775 gst_buffer_unref (buf);
5777 /* FIXME ? convert optional subsequent style info to markup */
5782 /* WebVTT sample handling according to 14496-30 */
5784 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5787 GstBuffer *outbuf = NULL;
5790 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5791 g_assert_not_reached (); /* The buffer must be mappable */
5794 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5795 GstEvent *gap = NULL;
5796 /* Push a gap event */
5797 stream->segment.position = GST_BUFFER_PTS (buf);
5799 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5800 gst_pad_push_event (stream->pad, gap);
5802 if (GST_BUFFER_DURATION_IS_VALID (buf))
5803 stream->segment.position += GST_BUFFER_DURATION (buf);
5806 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5807 GST_BUFFER_DURATION (buf), map.data, map.size);
5808 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5811 gst_buffer_unmap (buf, &map);
5812 gst_buffer_unref (buf);
5817 static GstFlowReturn
5818 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5821 GstFlowReturn ret = GST_FLOW_OK;
5822 GstClockTime pts, duration;
5824 if (stream->need_clip)
5825 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5827 if (G_UNLIKELY (buf == NULL))
5830 if (G_UNLIKELY (stream->discont)) {
5831 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5832 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5833 stream->discont = FALSE;
5835 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5838 GST_LOG_OBJECT (qtdemux,
5839 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5840 ", duration %" GST_TIME_FORMAT " on pad %s",
5841 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5842 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5843 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5845 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5846 GstStructure *crypto_info;
5847 QtDemuxAavdEncryptionInfo *info =
5848 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5850 crypto_info = gst_structure_copy (info->default_properties);
5851 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5852 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5855 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
5856 || stream->protection_scheme_type == FOURCC_cbcs)) {
5857 GstStructure *crypto_info;
5858 QtDemuxCencSampleSetInfo *info =
5859 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5863 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5864 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5865 GST_PTR_FORMAT, event);
5866 gst_pad_push_event (stream->pad, event);
5869 if (info->crypto_info == NULL) {
5870 if (stream->protection_scheme_type == FOURCC_cbcs) {
5871 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
5872 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
5873 GST_ERROR_OBJECT (qtdemux,
5874 "failed to attach cbcs metadata to buffer");
5875 qtdemux_gst_structure_free (crypto_info);
5877 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
5880 GST_DEBUG_OBJECT (qtdemux,
5881 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5884 /* The end of the crypto_info array matches our n_samples position,
5885 * so count backward from there */
5886 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5887 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5888 /* steal structure from array */
5889 crypto_info = g_ptr_array_index (info->crypto_info, index);
5890 g_ptr_array_index (info->crypto_info, index) = NULL;
5891 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5892 info->crypto_info->len);
5893 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5894 GST_ERROR_OBJECT (qtdemux,
5895 "failed to attach cenc metadata to buffer");
5897 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5898 index, stream->sample_index);
5903 if (stream->alignment > 1)
5904 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5906 pts = GST_BUFFER_PTS (buf);
5907 duration = GST_BUFFER_DURATION (buf);
5909 ret = gst_pad_push (stream->pad, buf);
5911 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5912 /* mark position in stream, we'll need this to know when to send GAP event */
5913 stream->segment.position = pts + duration;
5921 static GstFlowReturn
5922 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5925 GstFlowReturn ret = GST_FLOW_OK;
5927 if (stream->subtype == FOURCC_clcp
5928 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
5930 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
5931 guint n_triplets, i;
5932 guint field1_off = 0, field2_off = 0;
5934 /* We have to split CEA608 buffers so that each outgoing buffer contains
5935 * one byte pair per field according to the framerate of the video track.
5937 * If there is only a single byte pair per field we don't have to do
5941 gst_buffer_map (buf, &map, GST_MAP_READ);
5943 n_triplets = map.size / 3;
5944 for (i = 0; i < n_triplets; i++) {
5945 if (map.data[3 * i] & 0x80)
5951 g_assert (n_field1 || n_field2);
5953 /* If there's more than 1 frame we have to split, otherwise we can just
5955 if (n_field1 > 1 || n_field2 > 1) {
5957 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
5958 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
5960 for (i = 0; i < n_output_buffers; i++) {
5962 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
5966 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
5967 outptr = outmap.data;
5970 gboolean found = FALSE;
5972 while (map.data + field1_off < map.data + map.size) {
5973 if (map.data[field1_off] & 0x80) {
5974 memcpy (outptr, &map.data[field1_off], 3);
5983 const guint8 empty[] = { 0x80, 0x80, 0x80 };
5985 memcpy (outptr, empty, 3);
5992 gboolean found = FALSE;
5994 while (map.data + field2_off < map.data + map.size) {
5995 if ((map.data[field2_off] & 0x80) == 0) {
5996 memcpy (outptr, &map.data[field2_off], 3);
6005 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6007 memcpy (outptr, empty, 3);
6013 gst_buffer_unmap (outbuf, &outmap);
6015 GST_BUFFER_PTS (outbuf) =
6016 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6017 GST_SECOND * CUR_STREAM (stream)->fps_d,
6018 CUR_STREAM (stream)->fps_n);
6019 GST_BUFFER_DURATION (outbuf) =
6020 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6021 CUR_STREAM (stream)->fps_n);
6022 GST_BUFFER_OFFSET (outbuf) = -1;
6023 GST_BUFFER_OFFSET_END (outbuf) = -1;
6025 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6027 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6030 gst_buffer_unmap (buf, &map);
6031 gst_buffer_unref (buf);
6033 gst_buffer_unmap (buf, &map);
6034 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6037 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6043 /* Sets a buffer's attributes properly and pushes it downstream.
6044 * Also checks for additional actions and custom processing that may
6045 * need to be done first.
6047 static GstFlowReturn
6048 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6049 QtDemuxStream * stream, GstBuffer * buf,
6050 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6051 gboolean keyframe, GstClockTime position, guint64 byte_position)
6053 GstFlowReturn ret = GST_FLOW_OK;
6055 /* offset the timestamps according to the edit list */
6057 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6061 gst_buffer_map (buf, &map, GST_MAP_READ);
6062 url = g_strndup ((gchar *) map.data, map.size);
6063 gst_buffer_unmap (buf, &map);
6064 if (url != NULL && strlen (url) != 0) {
6065 /* we have RTSP redirect now */
6066 g_free (qtdemux->redirect_location);
6067 qtdemux->redirect_location = g_strdup (url);
6068 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6069 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6070 gst_structure_new ("redirect",
6071 "new-location", G_TYPE_STRING, url, NULL)));
6073 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6079 /* position reporting */
6080 if (qtdemux->segment.rate >= 0) {
6081 qtdemux->segment.position = position;
6082 gst_qtdemux_sync_streams (qtdemux);
6085 if (G_UNLIKELY (!stream->pad)) {
6086 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6087 gst_buffer_unref (buf);
6091 /* send out pending buffers */
6092 while (stream->buffers) {
6093 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6095 if (G_UNLIKELY (stream->discont)) {
6096 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6097 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6098 stream->discont = FALSE;
6100 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6103 if (stream->alignment > 1)
6104 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6105 gst_pad_push (stream->pad, buffer);
6107 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6110 /* we're going to modify the metadata */
6111 buf = gst_buffer_make_writable (buf);
6113 GST_BUFFER_DTS (buf) = dts;
6114 GST_BUFFER_PTS (buf) = pts;
6115 GST_BUFFER_DURATION (buf) = duration;
6116 GST_BUFFER_OFFSET (buf) = -1;
6117 GST_BUFFER_OFFSET_END (buf) = -1;
6119 if (G_UNLIKELY (stream->process_func))
6120 buf = stream->process_func (qtdemux, stream, buf);
6127 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6128 stream->on_keyframe = FALSE;
6130 stream->on_keyframe = TRUE;
6133 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6134 gst_buffer_append_memory (buf,
6135 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6137 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6138 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6141 if (G_UNLIKELY (qtdemux->element_index)) {
6142 GstClockTime stream_time;
6145 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6147 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6148 GST_LOG_OBJECT (qtdemux,
6149 "adding association %" GST_TIME_FORMAT "-> %"
6150 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6151 gst_index_add_association (qtdemux->element_index,
6153 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6154 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6155 GST_FORMAT_BYTES, byte_position, NULL);
6160 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6166 static const QtDemuxRandomAccessEntry *
6167 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6168 GstClockTime pos, gboolean after)
6170 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6171 guint n_entries = stream->n_ra_entries;
6174 /* we assume the table is sorted */
6175 for (i = 0; i < n_entries; ++i) {
6176 if (entries[i].ts > pos)
6180 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6181 * probably okay to assume that the index lists the very first fragment */
6188 return &entries[i - 1];
6192 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6194 const QtDemuxRandomAccessEntry *best_entry = NULL;
6197 GST_OBJECT_LOCK (qtdemux);
6199 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6201 /* first see if we can determine where to go to using mfra,
6202 * before we start clearing things */
6203 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6204 const QtDemuxRandomAccessEntry *entry;
6205 QtDemuxStream *stream;
6206 gboolean is_audio_or_video;
6208 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6210 if (stream->ra_entries == NULL)
6213 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6214 is_audio_or_video = TRUE;
6216 is_audio_or_video = FALSE;
6219 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6220 stream->time_position, !is_audio_or_video);
6222 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6223 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6225 stream->pending_seek = entry;
6227 /* decide position to jump to just based on audio/video tracks, not subs */
6228 if (!is_audio_or_video)
6231 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6235 /* no luck, will handle seek otherwise */
6236 if (best_entry == NULL) {
6237 GST_OBJECT_UNLOCK (qtdemux);
6241 /* ok, now we can prepare for processing as of located moof */
6242 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6243 QtDemuxStream *stream;
6245 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6247 g_free (stream->samples);
6248 stream->samples = NULL;
6249 stream->n_samples = 0;
6250 stream->stbl_index = -1; /* no samples have yet been parsed */
6251 stream->sample_index = -1;
6253 if (stream->protection_scheme_info) {
6254 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6255 if (stream->protection_scheme_type == FOURCC_cenc
6256 || stream->protection_scheme_type == FOURCC_cbcs) {
6257 QtDemuxCencSampleSetInfo *info =
6258 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6259 if (info->crypto_info) {
6260 g_ptr_array_free (info->crypto_info, TRUE);
6261 info->crypto_info = NULL;
6267 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6268 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6269 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6270 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6272 qtdemux->moof_offset = best_entry->moof_offset;
6274 qtdemux_add_fragmented_samples (qtdemux);
6276 GST_OBJECT_UNLOCK (qtdemux);
6280 static GstFlowReturn
6281 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6283 GstFlowReturn ret = GST_FLOW_OK;
6284 GstBuffer *buf = NULL;
6285 QtDemuxStream *stream, *target_stream = NULL;
6286 GstClockTime min_time;
6288 GstClockTime dts = GST_CLOCK_TIME_NONE;
6289 GstClockTime pts = GST_CLOCK_TIME_NONE;
6290 GstClockTime duration = 0;
6291 gboolean keyframe = FALSE;
6292 guint sample_size = 0;
6293 guint num_samples = 1;
6298 if (qtdemux->fragmented_seek_pending) {
6299 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6300 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6301 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6302 qtdemux->fragmented_seek_pending = FALSE;
6304 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6308 /* Figure out the next stream sample to output, min_time is expressed in
6309 * global time and runs over the edit list segments. */
6310 min_time = G_MAXUINT64;
6311 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6312 GstClockTime position;
6314 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6315 position = stream->time_position;
6317 if (!GST_CLOCK_TIME_IS_VALID (position))
6320 if (stream->segment_index != -1) {
6321 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6322 position += segment->media_start;
6325 /* position of -1 is EOS */
6326 if (position < min_time) {
6327 min_time = position;
6328 target_stream = stream;
6332 if (G_UNLIKELY (target_stream == NULL)) {
6333 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6337 /* check for segment end */
6338 if (G_UNLIKELY (qtdemux->segment.stop != -1
6339 && qtdemux->segment.rate >= 0
6340 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6341 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6342 target_stream->time_position = GST_CLOCK_TIME_NONE;
6346 /* gap events for subtitle streams */
6347 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6348 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6350 GstClockTime gap_threshold;
6352 /* Only send gap events on non-subtitle streams if lagging way behind. */
6353 if (stream->subtype == FOURCC_subp
6354 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6355 stream->subtype == FOURCC_wvtt)
6356 gap_threshold = 1 * GST_SECOND;
6358 gap_threshold = 3 * GST_SECOND;
6360 /* send gap events until the stream catches up */
6361 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6362 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6363 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6364 stream->segment.position + gap_threshold < min_time) {
6366 gst_event_new_gap (stream->segment.position, gap_threshold);
6367 gst_pad_push_event (stream->pad, gap);
6368 stream->segment.position += gap_threshold;
6373 stream = target_stream;
6374 /* fetch info for the current sample of this stream */
6375 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6376 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6379 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6380 if (stream->new_caps) {
6381 gst_qtdemux_configure_stream (qtdemux, stream);
6382 qtdemux_do_allocation (stream, qtdemux);
6385 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6386 if (G_UNLIKELY (qtdemux->segment.
6387 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6388 if (stream->subtype == FOURCC_vide) {
6390 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6393 } else if (qtdemux->trickmode_interval > 0) {
6394 GstClockTimeDiff interval;
6396 if (qtdemux->segment.rate > 0)
6397 interval = stream->time_position - stream->last_keyframe_dts;
6399 interval = stream->last_keyframe_dts - stream->time_position;
6401 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6402 && interval < qtdemux->trickmode_interval) {
6403 GST_LOG_OBJECT (qtdemux,
6404 "Skipping keyframe within interval on track-id %u",
6408 stream->last_keyframe_dts = stream->time_position;
6414 GST_DEBUG_OBJECT (qtdemux,
6415 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6416 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6417 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6418 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6419 GST_TIME_ARGS (duration));
6421 if (G_UNLIKELY (empty)) {
6422 /* empty segment, push a gap if there's a second or more
6423 * difference and move to the next one */
6424 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6425 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6426 stream->segment.position = pts + duration;
6430 /* hmm, empty sample, skip and move to next sample */
6431 if (G_UNLIKELY (sample_size <= 0))
6434 /* last pushed sample was out of boundary, goto next sample */
6435 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6438 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6439 GST_DEBUG_OBJECT (qtdemux,
6440 "size %d larger than stream max_buffer_size %d, trimming",
6441 sample_size, stream->max_buffer_size);
6443 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6444 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6445 && sample_size < stream->min_buffer_size) {
6446 guint start_sample_index = stream->sample_index;
6447 guint accumulated_size = sample_size;
6448 guint64 expected_next_offset = offset + sample_size;
6450 GST_DEBUG_OBJECT (qtdemux,
6451 "size %d smaller than stream min_buffer_size %d, combining with the next",
6452 sample_size, stream->min_buffer_size);
6454 while (stream->sample_index < stream->to_sample
6455 && stream->sample_index + 1 < stream->n_samples) {
6456 const QtDemuxSample *next_sample;
6458 /* Increment temporarily */
6459 stream->sample_index++;
6461 /* Failed to parse sample so let's go back to the previous one that was
6462 * still successful */
6463 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6464 stream->sample_index--;
6468 next_sample = &stream->samples[stream->sample_index];
6470 /* Not contiguous with the previous sample so let's go back to the
6471 * previous one that was still successful */
6472 if (next_sample->offset != expected_next_offset) {
6473 stream->sample_index--;
6477 accumulated_size += next_sample->size;
6478 expected_next_offset += next_sample->size;
6479 if (accumulated_size >= stream->min_buffer_size)
6483 num_samples = stream->sample_index + 1 - start_sample_index;
6484 stream->sample_index = start_sample_index;
6485 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6486 num_samples, accumulated_size);
6487 size = accumulated_size;
6492 if (qtdemux->cenc_aux_info_offset > 0) {
6495 GstBuffer *aux_info = NULL;
6497 /* pull the data stored before the sample */
6499 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6500 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6501 if (G_UNLIKELY (ret != GST_FLOW_OK))
6503 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6504 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6505 gst_byte_reader_init (&br, map.data + 8, map.size);
6506 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6507 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6508 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6509 gst_buffer_unmap (aux_info, &map);
6510 gst_buffer_unref (aux_info);
6511 ret = GST_FLOW_ERROR;
6514 gst_buffer_unmap (aux_info, &map);
6515 gst_buffer_unref (aux_info);
6518 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6521 if (stream->use_allocator) {
6522 /* if we have a per-stream allocator, use it */
6523 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6526 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6528 if (G_UNLIKELY (ret != GST_FLOW_OK))
6531 /* Update for both splitting and combining of samples */
6532 if (size != sample_size) {
6533 pts += gst_util_uint64_scale_int (GST_SECOND,
6534 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6537 gst_util_uint64_scale_int (GST_SECOND,
6538 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6541 gst_util_uint64_scale_int (GST_SECOND,
6542 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6545 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6546 dts, pts, duration, keyframe, min_time, offset);
6548 if (size < sample_size) {
6549 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6550 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6552 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6554 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6555 if (time_position >= segment->media_start) {
6556 /* inside the segment, update time_position, looks very familiar to
6557 * GStreamer segments, doesn't it? */
6558 stream->time_position = (time_position - segment->media_start) +
6561 /* not yet in segment, time does not yet increment. This means
6562 * that we are still prerolling keyframes to the decoder so it can
6563 * decode the first sample of the segment. */
6564 stream->time_position = segment->time;
6566 } else if (size > sample_size) {
6567 /* Increase to the last sample we already pulled so that advancing
6568 * below brings us to the next sample we need to pull */
6569 stream->sample_index += num_samples - 1;
6573 GST_OBJECT_LOCK (qtdemux);
6574 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6575 GST_OBJECT_UNLOCK (qtdemux);
6576 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6577 * we have no more data for the pad to push */
6578 if (ret == GST_FLOW_EOS)
6581 stream->offset_in_sample += size;
6582 if (stream->offset_in_sample >= sample_size) {
6583 gst_qtdemux_advance_sample (qtdemux, stream);
6588 gst_qtdemux_advance_sample (qtdemux, stream);
6596 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6602 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6603 /* EOS will be raised if all are EOS */
6610 gst_qtdemux_loop (GstPad * pad)
6612 GstQTDemux *qtdemux;
6616 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6618 cur_offset = qtdemux->offset;
6619 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6620 cur_offset, qt_demux_state_string (qtdemux->state));
6622 switch (qtdemux->state) {
6623 case QTDEMUX_STATE_INITIAL:
6624 case QTDEMUX_STATE_HEADER:
6625 ret = gst_qtdemux_loop_state_header (qtdemux);
6627 case QTDEMUX_STATE_MOVIE:
6628 ret = gst_qtdemux_loop_state_movie (qtdemux);
6629 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6630 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6638 /* if something went wrong, pause */
6639 if (ret != GST_FLOW_OK)
6643 gst_object_unref (qtdemux);
6649 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6650 (NULL), ("streaming stopped, invalid state"));
6651 gst_pad_pause_task (pad);
6652 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6657 const gchar *reason = gst_flow_get_name (ret);
6659 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6661 gst_pad_pause_task (pad);
6663 /* fatal errors need special actions */
6665 if (ret == GST_FLOW_EOS) {
6666 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6667 /* we have no streams, post an error */
6668 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6670 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6673 if ((stop = qtdemux->segment.stop) == -1)
6674 stop = qtdemux->segment.duration;
6676 if (qtdemux->segment.rate >= 0) {
6677 GstMessage *message;
6680 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6681 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6682 GST_FORMAT_TIME, stop);
6683 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6684 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6685 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6686 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6688 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6689 gst_qtdemux_push_event (qtdemux, event);
6691 GstMessage *message;
6694 /* For Reverse Playback */
6695 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6696 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6697 GST_FORMAT_TIME, qtdemux->segment.start);
6698 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6699 qtdemux->segment.start);
6700 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6701 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6702 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6704 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6705 gst_qtdemux_push_event (qtdemux, event);
6710 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6711 event = gst_event_new_eos ();
6712 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6713 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6714 gst_qtdemux_push_event (qtdemux, event);
6716 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6717 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6718 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6727 * Returns if there are samples to be played.
6730 has_next_entry (GstQTDemux * demux)
6732 QtDemuxStream *stream;
6735 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6737 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6738 stream = QTDEMUX_NTH_STREAM (demux, i);
6740 if (stream->sample_index == -1) {
6741 stream->sample_index = 0;
6742 stream->offset_in_sample = 0;
6745 if (stream->sample_index >= stream->n_samples) {
6746 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6749 GST_DEBUG_OBJECT (demux, "Found a sample");
6753 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6760 * Returns the size of the first entry at the current offset.
6761 * If -1, there are none (which means EOS or empty file).
6764 next_entry_size (GstQTDemux * demux)
6766 QtDemuxStream *stream, *target_stream = NULL;
6767 guint64 smalloffs = (guint64) - 1;
6768 QtDemuxSample *sample;
6771 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6774 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6775 stream = QTDEMUX_NTH_STREAM (demux, i);
6777 if (stream->sample_index == -1) {
6778 stream->sample_index = 0;
6779 stream->offset_in_sample = 0;
6782 if (stream->sample_index >= stream->n_samples) {
6783 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6787 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6788 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6789 stream->sample_index);
6793 sample = &stream->samples[stream->sample_index];
6795 GST_LOG_OBJECT (demux,
6796 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6797 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6798 stream->sample_index, sample->offset, sample->size);
6800 if (((smalloffs == -1)
6801 || (sample->offset < smalloffs)) && (sample->size)) {
6802 smalloffs = sample->offset;
6803 target_stream = stream;
6810 GST_LOG_OBJECT (demux,
6811 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6812 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6814 stream = target_stream;
6815 sample = &stream->samples[stream->sample_index];
6817 if (sample->offset >= demux->offset) {
6818 demux->todrop = sample->offset - demux->offset;
6819 return sample->size + demux->todrop;
6822 GST_DEBUG_OBJECT (demux,
6823 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6828 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6830 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6832 gst_element_post_message (GST_ELEMENT_CAST (demux),
6833 gst_message_new_element (GST_OBJECT_CAST (demux),
6834 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6838 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6843 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6846 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6847 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6848 GST_SEEK_TYPE_NONE, -1);
6850 /* store seqnum to drop flush events, they don't need to reach downstream */
6851 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6852 res = gst_pad_push_event (demux->sinkpad, event);
6853 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6858 /* check for seekable upstream, above and beyond a mere query */
6860 gst_qtdemux_check_seekability (GstQTDemux * demux)
6863 gboolean seekable = FALSE;
6864 gint64 start = -1, stop = -1;
6866 if (demux->upstream_size)
6869 if (demux->upstream_format_is_time)
6872 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6873 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6874 GST_DEBUG_OBJECT (demux, "seeking query failed");
6878 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6880 /* try harder to query upstream size if we didn't get it the first time */
6881 if (seekable && stop == -1) {
6882 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6883 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6886 /* if upstream doesn't know the size, it's likely that it's not seekable in
6887 * practice even if it technically may be seekable */
6888 if (seekable && (start != 0 || stop <= start)) {
6889 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6894 gst_query_unref (query);
6896 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6897 G_GUINT64_FORMAT ")", seekable, start, stop);
6898 demux->upstream_seekable = seekable;
6899 demux->upstream_size = seekable ? stop : -1;
6903 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6905 g_return_if_fail (bytes <= demux->todrop);
6907 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6908 gst_adapter_flush (demux->adapter, bytes);
6909 demux->neededbytes -= bytes;
6910 demux->offset += bytes;
6911 demux->todrop -= bytes;
6914 /* PUSH-MODE only: Send a segment, if not done already. */
6916 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6918 if (G_UNLIKELY (demux->need_segment)) {
6921 if (!demux->upstream_format_is_time) {
6922 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6924 GstEvent *segment_event;
6925 segment_event = gst_event_new_segment (&demux->segment);
6926 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6927 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6928 gst_qtdemux_push_event (demux, segment_event);
6931 demux->need_segment = FALSE;
6933 /* clear to send tags on all streams */
6934 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6935 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6936 gst_qtdemux_push_tags (demux, stream);
6937 if (CUR_STREAM (stream)->sparse) {
6938 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6939 gst_pad_push_event (stream->pad,
6940 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6946 /* Used for push mode only. */
6948 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6949 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6951 GstClockTime ts, dur;
6955 stream->segments[segment_index].duration - (pos -
6956 stream->segments[segment_index].time);
6957 stream->time_position += dur;
6959 /* Only gaps with a duration of at least one second are propagated.
6960 * Same workaround as in pull mode.
6961 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6962 if (dur >= GST_SECOND) {
6964 gap = gst_event_new_gap (ts, dur);
6966 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6967 "segment: %" GST_PTR_FORMAT, gap);
6968 gst_pad_push_event (stream->pad, gap);
6972 static GstFlowReturn
6973 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6977 demux = GST_QTDEMUX (parent);
6979 GST_DEBUG_OBJECT (demux,
6980 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6981 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6982 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6983 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6984 gst_buffer_get_size (inbuf), demux->offset);
6986 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6987 gboolean is_gap_input = FALSE;
6990 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6992 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6993 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
6996 /* Check if we can land back on our feet in the case where upstream is
6997 * handling the seeking/pushing of samples with gaps in between (like
6998 * in the case of trick-mode DASH for example) */
6999 if (demux->upstream_format_is_time
7000 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7001 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7003 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7004 GST_LOG_OBJECT (demux,
7005 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7006 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7008 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7009 stream, GST_BUFFER_OFFSET (inbuf));
7011 QtDemuxSample *sample = &stream->samples[res];
7012 GST_LOG_OBJECT (demux,
7013 "Checking if sample %d from track-id %u is valid (offset:%"
7014 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7015 stream->track_id, sample->offset, sample->size);
7016 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7017 GST_LOG_OBJECT (demux,
7018 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7020 is_gap_input = TRUE;
7021 /* We can go back to standard playback mode */
7022 demux->state = QTDEMUX_STATE_MOVIE;
7023 /* Remember which sample this stream is at */
7024 stream->sample_index = res;
7025 /* Finally update all push-based values to the expected values */
7026 demux->neededbytes = stream->samples[res].size;
7027 demux->offset = GST_BUFFER_OFFSET (inbuf);
7029 demux->mdatsize - demux->offset + demux->mdatoffset;
7034 if (!is_gap_input) {
7035 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7036 /* Reset state if it's a real discont */
7037 demux->neededbytes = 16;
7038 demux->state = QTDEMUX_STATE_INITIAL;
7039 demux->offset = GST_BUFFER_OFFSET (inbuf);
7040 gst_adapter_clear (demux->adapter);
7043 /* Reverse fragmented playback, need to flush all we have before
7044 * consuming a new fragment.
7045 * The samples array have the timestamps calculated by accumulating the
7046 * durations but this won't work for reverse playback of fragments as
7047 * the timestamps of a subsequent fragment should be smaller than the
7048 * previously received one. */
7049 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7050 gst_qtdemux_process_adapter (demux, TRUE);
7051 g_ptr_array_foreach (demux->active_streams,
7052 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7056 gst_adapter_push (demux->adapter, inbuf);
7058 GST_DEBUG_OBJECT (demux,
7059 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7060 demux->neededbytes, gst_adapter_available (demux->adapter));
7062 return gst_qtdemux_process_adapter (demux, FALSE);
7065 static GstFlowReturn
7066 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7068 GstFlowReturn ret = GST_FLOW_OK;
7070 /* we never really mean to buffer that much */
7071 if (demux->neededbytes == -1) {
7075 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7076 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7078 #ifndef GST_DISABLE_GST_DEBUG
7080 guint64 discont_offset, distance_from_discont;
7082 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7083 distance_from_discont =
7084 gst_adapter_distance_from_discont (demux->adapter);
7086 GST_DEBUG_OBJECT (demux,
7087 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7088 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7089 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7090 demux->offset, discont_offset, distance_from_discont);
7094 switch (demux->state) {
7095 case QTDEMUX_STATE_INITIAL:{
7100 gst_qtdemux_check_seekability (demux);
7102 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7104 /* get fourcc/length, set neededbytes */
7105 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7107 gst_adapter_unmap (demux->adapter);
7109 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7110 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7112 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7113 (_("This file is invalid and cannot be played.")),
7114 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7115 GST_FOURCC_ARGS (fourcc)));
7116 ret = GST_FLOW_ERROR;
7119 if (fourcc == FOURCC_mdat) {
7120 gint next_entry = next_entry_size (demux);
7121 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7122 || !demux->fragmented)) {
7123 /* we have the headers, start playback */
7124 demux->state = QTDEMUX_STATE_MOVIE;
7125 demux->neededbytes = next_entry;
7126 demux->mdatleft = size;
7127 demux->mdatsize = demux->mdatleft;
7129 /* no headers yet, try to get them */
7132 guint64 old, target;
7135 old = demux->offset;
7136 target = old + size;
7138 /* try to jump over the atom with a seek */
7139 /* only bother if it seems worth doing so,
7140 * and avoids possible upstream/server problems */
7141 if (demux->upstream_seekable &&
7142 demux->upstream_size > 4 * (1 << 20)) {
7143 res = qtdemux_seek_offset (demux, target);
7145 GST_DEBUG_OBJECT (demux, "skipping seek");
7150 GST_DEBUG_OBJECT (demux, "seek success");
7151 /* remember the offset fo the first mdat so we can seek back to it
7152 * after we have the headers */
7153 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7154 demux->first_mdat = old;
7155 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7158 /* seek worked, continue reading */
7159 demux->offset = target;
7160 demux->neededbytes = 16;
7161 demux->state = QTDEMUX_STATE_INITIAL;
7163 /* seek failed, need to buffer */
7164 demux->offset = old;
7165 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7166 /* there may be multiple mdat (or alike) buffers */
7168 if (demux->mdatbuffer)
7169 bs = gst_buffer_get_size (demux->mdatbuffer);
7172 if (size + bs > 10 * (1 << 20))
7174 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7175 demux->neededbytes = size;
7176 if (!demux->mdatbuffer)
7177 demux->mdatoffset = demux->offset;
7180 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7181 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7182 (_("This file is invalid and cannot be played.")),
7183 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7184 GST_FOURCC_ARGS (fourcc), size));
7185 ret = GST_FLOW_ERROR;
7188 /* this means we already started buffering and still no moov header,
7189 * let's continue buffering everything till we get moov */
7190 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7191 || fourcc == FOURCC_moof))
7193 demux->neededbytes = size;
7194 demux->state = QTDEMUX_STATE_HEADER;
7198 case QTDEMUX_STATE_HEADER:{
7202 GST_DEBUG_OBJECT (demux, "In header");
7204 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7206 /* parse the header */
7207 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7209 if (fourcc == FOURCC_moov) {
7210 /* in usual fragmented setup we could try to scan for more
7211 * and end up at the the moov (after mdat) again */
7212 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7214 || demux->last_moov_offset == demux->offset)) {
7215 GST_DEBUG_OBJECT (demux,
7216 "Skipping moov atom as we have (this) one already");
7218 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7220 if (demux->got_moov && demux->fragmented) {
7221 GST_DEBUG_OBJECT (demux,
7222 "Got a second moov, clean up data from old one");
7223 if (demux->moov_node_compressed) {
7224 g_node_destroy (demux->moov_node_compressed);
7225 if (demux->moov_node)
7226 g_free (demux->moov_node->data);
7228 demux->moov_node_compressed = NULL;
7229 if (demux->moov_node)
7230 g_node_destroy (demux->moov_node);
7231 demux->moov_node = NULL;
7234 demux->last_moov_offset = demux->offset;
7236 /* Update streams with new moov */
7237 gst_qtdemux_stream_concat (demux,
7238 demux->old_streams, demux->active_streams);
7240 qtdemux_parse_moov (demux, data, demux->neededbytes);
7241 qtdemux_node_dump (demux, demux->moov_node);
7242 qtdemux_parse_tree (demux);
7243 qtdemux_prepare_streams (demux);
7244 QTDEMUX_EXPOSE_LOCK (demux);
7245 qtdemux_expose_streams (demux);
7246 QTDEMUX_EXPOSE_UNLOCK (demux);
7248 demux->got_moov = TRUE;
7250 gst_qtdemux_check_send_pending_segment (demux);
7252 if (demux->moov_node_compressed) {
7253 g_node_destroy (demux->moov_node_compressed);
7254 g_free (demux->moov_node->data);
7256 demux->moov_node_compressed = NULL;
7257 g_node_destroy (demux->moov_node);
7258 demux->moov_node = NULL;
7259 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7261 } else if (fourcc == FOURCC_moof) {
7262 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7264 GstClockTime prev_pts;
7265 guint64 prev_offset;
7266 guint64 adapter_discont_offset, adapter_discont_dist;
7268 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7271 * The timestamp of the moof buffer is relevant as some scenarios
7272 * won't have the initial timestamp in the atoms. Whenever a new
7273 * buffer has started, we get that buffer's PTS and use it as a base
7274 * timestamp for the trun entries.
7276 * To keep track of the current buffer timestamp and starting point
7277 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7278 * from the beginning of the buffer, with the distance and demux->offset
7279 * we know if it is still the same buffer or not.
7281 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7282 prev_offset = demux->offset - dist;
7283 if (demux->fragment_start_offset == -1
7284 || prev_offset > demux->fragment_start_offset) {
7285 demux->fragment_start_offset = prev_offset;
7286 demux->fragment_start = prev_pts;
7287 GST_DEBUG_OBJECT (demux,
7288 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7289 GST_TIME_FORMAT, demux->fragment_start_offset,
7290 GST_TIME_ARGS (demux->fragment_start));
7293 /* We can't use prev_offset() here because this would require
7294 * upstream to set consistent and correct offsets on all buffers
7295 * since the discont. Nothing ever did that in the past and we
7296 * would break backwards compatibility here then.
7297 * Instead take the offset we had at the last discont and count
7298 * the bytes from there. This works with old code as there would
7299 * be no discont between moov and moof, and also works with
7300 * adaptivedemux which correctly sets offset and will set the
7301 * DISCONT flag accordingly when needed.
7303 * We also only do this for upstream TIME segments as otherwise
7304 * there are potential backwards compatibility problems with
7305 * seeking in PUSH mode and upstream providing inconsistent
7307 adapter_discont_offset =
7308 gst_adapter_offset_at_discont (demux->adapter);
7309 adapter_discont_dist =
7310 gst_adapter_distance_from_discont (demux->adapter);
7312 GST_DEBUG_OBJECT (demux,
7313 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7314 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7315 demux->offset, adapter_discont_offset, adapter_discont_dist);
7317 if (demux->upstream_format_is_time) {
7318 demux->moof_offset = adapter_discont_offset;
7319 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7320 demux->moof_offset += adapter_discont_dist;
7321 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7322 demux->moof_offset = demux->offset;
7324 demux->moof_offset = demux->offset;
7327 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7328 demux->moof_offset, NULL)) {
7329 gst_adapter_unmap (demux->adapter);
7330 ret = GST_FLOW_ERROR;
7334 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7335 if (demux->mss_mode && !demux->exposed) {
7336 QTDEMUX_EXPOSE_LOCK (demux);
7337 qtdemux_expose_streams (demux);
7338 QTDEMUX_EXPOSE_UNLOCK (demux);
7341 gst_qtdemux_check_send_pending_segment (demux);
7343 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7345 } else if (fourcc == FOURCC_ftyp) {
7346 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7347 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7348 } else if (fourcc == FOURCC_uuid) {
7349 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7350 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7351 } else if (fourcc == FOURCC_sidx) {
7352 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7353 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7357 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7361 /* [free] and [skip] are padding atoms */
7362 GST_DEBUG_OBJECT (demux,
7363 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7364 GST_FOURCC_ARGS (fourcc));
7367 GST_WARNING_OBJECT (demux,
7368 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7369 GST_FOURCC_ARGS (fourcc));
7370 /* Let's jump that one and go back to initial state */
7374 gst_adapter_unmap (demux->adapter);
7377 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7378 gsize remaining_data_size = 0;
7380 /* the mdat was before the header */
7381 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7382 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7383 /* restore our adapter/offset view of things with upstream;
7384 * put preceding buffered data ahead of current moov data.
7385 * This should also handle evil mdat, moov, mdat cases and alike */
7386 gst_adapter_flush (demux->adapter, demux->neededbytes);
7388 /* Store any remaining data after the mdat for later usage */
7389 remaining_data_size = gst_adapter_available (demux->adapter);
7390 if (remaining_data_size > 0) {
7391 g_assert (demux->restoredata_buffer == NULL);
7392 demux->restoredata_buffer =
7393 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7394 demux->restoredata_offset = demux->offset + demux->neededbytes;
7395 GST_DEBUG_OBJECT (demux,
7396 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7397 G_GUINT64_FORMAT, remaining_data_size,
7398 demux->restoredata_offset);
7401 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7402 demux->mdatbuffer = NULL;
7403 demux->offset = demux->mdatoffset;
7404 demux->neededbytes = next_entry_size (demux);
7405 demux->state = QTDEMUX_STATE_MOVIE;
7406 demux->mdatleft = gst_adapter_available (demux->adapter);
7407 demux->mdatsize = demux->mdatleft;
7409 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7410 gst_adapter_flush (demux->adapter, demux->neededbytes);
7412 /* only go back to the mdat if there are samples to play */
7413 if (demux->got_moov && demux->first_mdat != -1
7414 && has_next_entry (demux)) {
7417 /* we need to seek back */
7418 res = qtdemux_seek_offset (demux, demux->first_mdat);
7420 demux->offset = demux->first_mdat;
7422 GST_DEBUG_OBJECT (demux, "Seek back failed");
7425 demux->offset += demux->neededbytes;
7427 demux->neededbytes = 16;
7428 demux->state = QTDEMUX_STATE_INITIAL;
7433 case QTDEMUX_STATE_BUFFER_MDAT:{
7437 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7439 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7440 gst_buffer_extract (buf, 0, fourcc, 4);
7441 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7442 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7443 if (demux->mdatbuffer)
7444 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7446 demux->mdatbuffer = buf;
7447 demux->offset += demux->neededbytes;
7448 demux->neededbytes = 16;
7449 demux->state = QTDEMUX_STATE_INITIAL;
7450 gst_qtdemux_post_progress (demux, 1, 1);
7454 case QTDEMUX_STATE_MOVIE:{
7455 QtDemuxStream *stream = NULL;
7456 QtDemuxSample *sample;
7457 GstClockTime dts, pts, duration;
7461 GST_DEBUG_OBJECT (demux,
7462 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7464 if (demux->fragmented) {
7465 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7467 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7468 /* if needed data starts within this atom,
7469 * then it should not exceed this atom */
7470 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7471 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7472 (_("This file is invalid and cannot be played.")),
7473 ("sample data crosses atom boundary"));
7474 ret = GST_FLOW_ERROR;
7477 demux->mdatleft -= demux->neededbytes;
7479 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7480 /* so we are dropping more than left in this atom */
7481 gst_qtdemux_drop_data (demux, demux->mdatleft);
7482 demux->mdatleft = 0;
7484 /* need to resume atom parsing so we do not miss any other pieces */
7485 demux->state = QTDEMUX_STATE_INITIAL;
7486 demux->neededbytes = 16;
7488 /* check if there was any stored post mdat data from previous buffers */
7489 if (demux->restoredata_buffer) {
7490 g_assert (gst_adapter_available (demux->adapter) == 0);
7492 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7493 demux->restoredata_buffer = NULL;
7494 demux->offset = demux->restoredata_offset;
7501 if (demux->todrop) {
7502 if (demux->cenc_aux_info_offset > 0) {
7506 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7507 data = gst_adapter_map (demux->adapter, demux->todrop);
7508 gst_byte_reader_init (&br, data + 8, demux->todrop);
7509 if (!qtdemux_parse_cenc_aux_info (demux,
7510 QTDEMUX_NTH_STREAM (demux, 0), &br,
7511 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7512 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7513 ret = GST_FLOW_ERROR;
7514 gst_adapter_unmap (demux->adapter);
7515 g_free (demux->cenc_aux_info_sizes);
7516 demux->cenc_aux_info_sizes = NULL;
7519 demux->cenc_aux_info_offset = 0;
7520 g_free (demux->cenc_aux_info_sizes);
7521 demux->cenc_aux_info_sizes = NULL;
7522 gst_adapter_unmap (demux->adapter);
7524 gst_qtdemux_drop_data (demux, demux->todrop);
7528 /* initial newsegment sent here after having added pads,
7529 * possible others in sink_event */
7530 gst_qtdemux_check_send_pending_segment (demux);
7532 /* Figure out which stream this packet belongs to */
7533 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7534 stream = QTDEMUX_NTH_STREAM (demux, i);
7535 if (stream->sample_index >= stream->n_samples) {
7536 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7540 GST_LOG_OBJECT (demux,
7541 "Checking track-id %u (sample_index:%d / offset:%"
7542 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7543 stream->sample_index,
7544 stream->samples[stream->sample_index].offset,
7545 stream->samples[stream->sample_index].size);
7547 if (stream->samples[stream->sample_index].offset == demux->offset)
7551 if (G_UNLIKELY (stream == NULL))
7552 goto unknown_stream;
7554 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7556 if (stream->new_caps) {
7557 gst_qtdemux_configure_stream (demux, stream);
7560 /* Put data in a buffer, set timestamps, caps, ... */
7561 sample = &stream->samples[stream->sample_index];
7563 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7564 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7565 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7567 dts = QTSAMPLE_DTS (stream, sample);
7568 pts = QTSAMPLE_PTS (stream, sample);
7569 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7570 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7572 /* check for segment end */
7573 if (G_UNLIKELY (demux->segment.stop != -1
7574 && demux->segment.stop <= pts && stream->on_keyframe)
7575 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7576 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7577 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7579 /* skip this data, stream is EOS */
7580 gst_adapter_flush (demux->adapter, demux->neededbytes);
7581 demux->offset += demux->neededbytes;
7583 /* check if all streams are eos */
7585 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7586 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7595 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7597 /* FIXME: should either be an assert or a plain check */
7598 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7600 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7601 dts, pts, duration, keyframe, dts, demux->offset);
7605 GST_OBJECT_LOCK (demux);
7606 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7607 GST_OBJECT_UNLOCK (demux);
7609 /* skip this data, stream is EOS */
7610 gst_adapter_flush (demux->adapter, demux->neededbytes);
7613 stream->sample_index++;
7614 stream->offset_in_sample = 0;
7616 /* update current offset and figure out size of next buffer */
7617 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7618 demux->offset, demux->neededbytes);
7619 demux->offset += demux->neededbytes;
7620 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7624 if (ret == GST_FLOW_EOS) {
7625 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7626 demux->neededbytes = -1;
7630 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7631 if (demux->fragmented) {
7632 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7633 /* there may be more to follow, only finish this atom */
7634 demux->todrop = demux->mdatleft;
7635 demux->neededbytes = demux->todrop;
7640 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7641 goto non_ok_unlinked_flow;
7650 /* when buffering movie data, at least show user something is happening */
7651 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7652 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7653 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7654 demux->neededbytes);
7661 non_ok_unlinked_flow:
7663 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7664 gst_flow_get_name (ret));
7669 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7670 ret = GST_FLOW_ERROR;
7675 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7681 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7682 (NULL), ("qtdemuxer invalid state %d", demux->state));
7683 ret = GST_FLOW_ERROR;
7688 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7689 (NULL), ("no 'moov' atom within the first 10 MB"));
7690 ret = GST_FLOW_ERROR;
7696 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7701 query = gst_query_new_scheduling ();
7703 if (!gst_pad_peer_query (sinkpad, query)) {
7704 gst_query_unref (query);
7708 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7709 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7710 gst_query_unref (query);
7715 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7716 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7720 GST_DEBUG_OBJECT (sinkpad, "activating push");
7721 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7726 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7727 GstPadMode mode, gboolean active)
7730 GstQTDemux *demux = GST_QTDEMUX (parent);
7733 case GST_PAD_MODE_PUSH:
7734 demux->pullbased = FALSE;
7737 case GST_PAD_MODE_PULL:
7739 demux->pullbased = TRUE;
7740 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7743 res = gst_pad_stop_task (sinkpad);
7755 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7761 memset (&z, 0, sizeof (z));
7766 if ((ret = inflateInit (&z)) != Z_OK) {
7767 GST_ERROR ("inflateInit() returned %d", ret);
7771 z.next_in = z_buffer;
7772 z.avail_in = z_length;
7774 buffer = (guint8 *) g_malloc (*length);
7775 z.avail_out = *length;
7776 z.next_out = (Bytef *) buffer;
7778 ret = inflate (&z, Z_NO_FLUSH);
7779 if (ret == Z_STREAM_END) {
7781 } else if (ret != Z_OK) {
7782 GST_WARNING ("inflate() returned %d", ret);
7787 buffer = (guint8 *) g_realloc (buffer, *length);
7788 z.next_out = (Bytef *) (buffer + z.total_out);
7789 z.avail_out += 4096;
7790 } while (z.avail_in > 0);
7792 if (ret != Z_STREAM_END) {
7797 *length = z.total_out;
7804 #endif /* HAVE_ZLIB */
7807 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7811 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7813 /* counts as header data */
7814 qtdemux->header_size += length;
7816 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7817 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7819 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7826 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7827 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7828 if (dcom == NULL || cmvd == NULL)
7829 goto invalid_compression;
7831 dcom_len = QT_UINT32 (dcom->data);
7833 goto invalid_compression;
7835 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7839 guint uncompressed_length;
7840 guint compressed_length;
7844 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7846 goto invalid_compression;
7848 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7849 compressed_length = cmvd_len - 12;
7850 GST_LOG ("length = %u", uncompressed_length);
7853 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7854 compressed_length, &uncompressed_length);
7857 qtdemux->moov_node_compressed = qtdemux->moov_node;
7858 qtdemux->moov_node = g_node_new (buf);
7860 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7861 uncompressed_length);
7865 #endif /* HAVE_ZLIB */
7867 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7868 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7875 invalid_compression:
7877 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7883 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7886 while (G_UNLIKELY (buf < end)) {
7890 if (G_UNLIKELY (buf + 4 > end)) {
7891 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7894 len = QT_UINT32 (buf);
7895 if (G_UNLIKELY (len == 0)) {
7896 GST_LOG_OBJECT (qtdemux, "empty container");
7899 if (G_UNLIKELY (len < 8)) {
7900 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7903 if (G_UNLIKELY (len > (end - buf))) {
7904 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7905 (gint) (end - buf));
7909 child = g_node_new ((guint8 *) buf);
7910 g_node_append (node, child);
7911 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7912 qtdemux_parse_node (qtdemux, child, buf, len);
7920 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7923 int len = QT_UINT32 (xdxt->data);
7924 guint8 *buf = xdxt->data;
7925 guint8 *end = buf + len;
7928 /* skip size and type */
7936 size = QT_UINT32 (buf);
7937 type = QT_FOURCC (buf + 4);
7939 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7941 if (buf + size > end || size <= 0)
7947 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7948 GST_FOURCC_ARGS (type));
7952 buffer = gst_buffer_new_and_alloc (size);
7953 gst_buffer_fill (buffer, 0, buf, size);
7954 stream->buffers = g_slist_append (stream->buffers, buffer);
7955 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7958 buffer = gst_buffer_new_and_alloc (size);
7959 gst_buffer_fill (buffer, 0, buf, size);
7960 stream->buffers = g_slist_append (stream->buffers, buffer);
7961 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7964 buffer = gst_buffer_new_and_alloc (size);
7965 gst_buffer_fill (buffer, 0, buf, size);
7966 stream->buffers = g_slist_append (stream->buffers, buffer);
7967 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7970 GST_WARNING_OBJECT (qtdemux,
7971 "unknown theora cookie %" GST_FOURCC_FORMAT,
7972 GST_FOURCC_ARGS (type));
7981 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7985 guint32 node_length = 0;
7986 const QtNodeType *type;
7989 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7991 if (G_UNLIKELY (length < 8))
7992 goto not_enough_data;
7994 node_length = QT_UINT32 (buffer);
7995 fourcc = QT_FOURCC (buffer + 4);
7997 /* ignore empty nodes */
7998 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8001 type = qtdemux_type_get (fourcc);
8003 end = buffer + length;
8005 GST_LOG_OBJECT (qtdemux,
8006 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8007 GST_FOURCC_ARGS (fourcc), node_length, type->name);
8009 if (node_length > length)
8010 goto broken_atom_size;
8012 if (type->flags & QT_FLAG_CONTAINER) {
8013 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8018 if (node_length < 20) {
8019 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8022 GST_DEBUG_OBJECT (qtdemux,
8023 "parsing stsd (sample table, sample description) atom");
8024 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8025 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8037 /* also read alac (or whatever) in stead of mp4a in the following,
8038 * since a similar layout is used in other cases as well */
8039 if (fourcc == FOURCC_mp4a)
8041 else if (fourcc == FOURCC_fLaC)
8046 /* There are two things we might encounter here: a true mp4a atom, and
8047 an mp4a entry in an stsd atom. The latter is what we're interested
8048 in, and it looks like an atom, but isn't really one. The true mp4a
8049 atom is short, so we detect it based on length here. */
8050 if (length < min_size) {
8051 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8052 GST_FOURCC_ARGS (fourcc));
8056 /* 'version' here is the sound sample description version. Types 0 and
8057 1 are documented in the QTFF reference, but type 2 is not: it's
8058 described in Apple header files instead (struct SoundDescriptionV2
8060 version = QT_UINT16 (buffer + 16);
8062 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8063 GST_FOURCC_ARGS (fourcc), version);
8065 /* parse any esds descriptors */
8077 GST_WARNING_OBJECT (qtdemux,
8078 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8079 GST_FOURCC_ARGS (fourcc), version);
8084 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8112 /* codec_data is contained inside these atoms, which all have
8113 * the same format. */
8114 /* video sample description size is 86 bytes without extension.
8115 * node_length have to be bigger than 86 bytes because video sample
8116 * description can include extensions such as esds, fiel, glbl, etc. */
8117 if (node_length < 86) {
8118 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8119 " sample description length too short (%u < 86)",
8120 GST_FOURCC_ARGS (fourcc), node_length);
8124 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8125 GST_FOURCC_ARGS (fourcc));
8127 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8129 * revision level (2 bytes) : must be set to 0. */
8130 version = QT_UINT32 (buffer + 16);
8131 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8133 /* compressor name : PASCAL string and informative purposes
8134 * first byte : the number of bytes to be displayed.
8135 * it has to be less than 32 because it is reserved
8136 * space of 32 bytes total including itself. */
8137 str_len = QT_UINT8 (buffer + 50);
8139 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8140 (char *) buffer + 51);
8142 GST_WARNING_OBJECT (qtdemux,
8143 "compressorname length too big (%u > 31)", str_len);
8145 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8147 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8152 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8154 /* You are reading this correctly. QTFF specifies that the
8155 * metadata atom is a short atom, whereas ISO BMFF specifies
8156 * it's a full atom. But since so many people are doing things
8157 * differently, we actually peek into the atom to see which
8160 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8161 GST_FOURCC_ARGS (fourcc));
8164 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8165 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8166 * starts with a 'hdlr' atom */
8167 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8168 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8169 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8170 * with version/flags both set to zero */
8171 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8173 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8178 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8179 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8180 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8189 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8190 GST_FOURCC_ARGS (fourcc));
8194 version = QT_UINT32 (buffer + 12);
8195 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8202 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8207 if (length < offset) {
8208 GST_WARNING_OBJECT (qtdemux,
8209 "skipping too small %" GST_FOURCC_FORMAT " box",
8210 GST_FOURCC_ARGS (fourcc));
8213 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8219 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8224 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8229 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8233 if (!strcmp (type->name, "unknown"))
8234 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8238 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8239 GST_FOURCC_ARGS (fourcc));
8245 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8246 (_("This file is corrupt and cannot be played.")),
8247 ("Not enough data for an atom header, got only %u bytes", length));
8252 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8253 (_("This file is corrupt and cannot be played.")),
8254 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8255 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8262 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8264 /* FIXME: This can only reliably work if demuxers have a
8265 * separate streaming thread per srcpad. This should be
8266 * done in a demuxer base class, which integrates parts
8269 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8274 query = gst_query_new_allocation (stream->caps, FALSE);
8276 if (!gst_pad_peer_query (stream->pad, query)) {
8277 /* not a problem, just debug a little */
8278 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8281 if (stream->allocator)
8282 gst_object_unref (stream->allocator);
8284 if (gst_query_get_n_allocation_params (query) > 0) {
8285 /* try the allocator */
8286 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8288 stream->use_allocator = TRUE;
8290 stream->allocator = NULL;
8291 gst_allocation_params_init (&stream->params);
8292 stream->use_allocator = FALSE;
8294 gst_query_unref (query);
8299 pad_query (const GValue * item, GValue * value, gpointer user_data)
8301 GstPad *pad = g_value_get_object (item);
8302 GstQuery *query = user_data;
8305 res = gst_pad_peer_query (pad, query);
8308 g_value_set_boolean (value, TRUE);
8312 GST_INFO_OBJECT (pad, "pad peer query failed");
8317 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8318 GstPadDirection direction)
8321 GstIteratorFoldFunction func = pad_query;
8322 GValue res = { 0, };
8324 g_value_init (&res, G_TYPE_BOOLEAN);
8325 g_value_set_boolean (&res, FALSE);
8328 if (direction == GST_PAD_SRC)
8329 it = gst_element_iterate_src_pads (element);
8331 it = gst_element_iterate_sink_pads (element);
8333 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8334 gst_iterator_resync (it);
8336 gst_iterator_free (it);
8338 return g_value_get_boolean (&res);
8342 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8343 QtDemuxStream * stream)
8347 GstElement *element = GST_ELEMENT (qtdemux);
8349 gchar **filtered_sys_ids;
8350 GValue event_list = G_VALUE_INIT;
8353 /* 1. Check if we already have the context. */
8354 if (qtdemux->preferred_protection_system_id != NULL) {
8355 GST_LOG_OBJECT (element,
8356 "already have the protection context, no need to request it again");
8360 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8361 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8362 (const gchar **) qtdemux->protection_system_ids->pdata);
8364 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8365 qtdemux->protection_system_ids->len - 1);
8366 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8367 "decryptors for %u of them, running context request",
8368 qtdemux->protection_system_ids->len,
8369 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8372 if (stream->protection_scheme_event_queue.length) {
8373 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8374 stream->protection_scheme_event_queue.length);
8375 walk = stream->protection_scheme_event_queue.tail;
8377 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8378 qtdemux->protection_event_queue.length);
8379 walk = qtdemux->protection_event_queue.tail;
8382 g_value_init (&event_list, GST_TYPE_LIST);
8383 for (; walk; walk = g_list_previous (walk)) {
8384 GValue *event_value = g_new0 (GValue, 1);
8385 g_value_init (event_value, GST_TYPE_EVENT);
8386 g_value_set_boxed (event_value, walk->data);
8387 gst_value_list_append_and_take_value (&event_list, event_value);
8390 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8391 * check if downstream already has a context of the specific type
8392 * 2b) Query upstream as above.
8394 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8395 st = gst_query_writable_structure (query);
8396 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8397 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8399 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8400 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8401 gst_query_parse_context (query, &ctxt);
8402 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8403 gst_element_set_context (element, ctxt);
8404 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8405 gst_query_parse_context (query, &ctxt);
8406 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8407 gst_element_set_context (element, ctxt);
8409 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8410 * the required context type and afterwards check if a
8411 * usable context was set now as in 1). The message could
8412 * be handled by the parent bins of the element and the
8417 GST_INFO_OBJECT (element, "posting need context message");
8418 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8419 "drm-preferred-decryption-system-id");
8420 st = (GstStructure *) gst_message_get_structure (msg);
8421 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8422 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8425 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8426 gst_element_post_message (element, msg);
8429 g_strfreev (filtered_sys_ids);
8430 g_value_unset (&event_list);
8431 gst_query_unref (query);
8435 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8436 QtDemuxStream * stream)
8439 const gchar *selected_system = NULL;
8441 g_return_val_if_fail (qtdemux != NULL, FALSE);
8442 g_return_val_if_fail (stream != NULL, FALSE);
8443 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8446 if (stream->protection_scheme_type == FOURCC_aavd) {
8447 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8448 if (!gst_structure_has_name (s, "application/x-aavd")) {
8449 gst_structure_set (s,
8450 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8452 gst_structure_set_name (s, "application/x-aavd");
8457 if (stream->protection_scheme_type != FOURCC_cenc
8458 && stream->protection_scheme_type != FOURCC_cbcs) {
8459 GST_ERROR_OBJECT (qtdemux,
8460 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8461 GST_FOURCC_ARGS (stream->protection_scheme_type));
8465 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8466 if (!gst_structure_has_name (s, "application/x-cenc")) {
8467 gst_structure_set (s,
8468 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8469 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8470 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8472 gst_structure_set_name (s, "application/x-cenc");
8475 if (qtdemux->protection_system_ids == NULL) {
8476 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8477 "cenc protection system information has been found, not setting a "
8478 "protection system UUID");
8482 gst_qtdemux_request_protection_context (qtdemux, stream);
8483 if (qtdemux->preferred_protection_system_id != NULL) {
8484 const gchar *preferred_system_array[] =
8485 { qtdemux->preferred_protection_system_id, NULL };
8487 selected_system = gst_protection_select_system (preferred_system_array);
8489 if (selected_system) {
8490 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8491 qtdemux->preferred_protection_system_id);
8493 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8494 "because there is no available decryptor",
8495 qtdemux->preferred_protection_system_id);
8499 if (!selected_system) {
8500 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8501 selected_system = gst_protection_select_system ((const gchar **)
8502 qtdemux->protection_system_ids->pdata);
8503 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8504 qtdemux->protection_system_ids->len - 1);
8507 if (!selected_system) {
8508 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8509 "suitable decryptor element has been found");
8513 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8516 gst_structure_set (s,
8517 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8524 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8526 /* fps is calculated base on the duration of the average framerate since
8527 * qt does not have a fixed framerate. */
8528 gboolean fps_available = TRUE;
8529 guint32 first_duration = 0;
8531 if (stream->n_samples > 0)
8532 first_duration = stream->samples[0].duration;
8534 if ((stream->n_samples == 1 && first_duration == 0)
8535 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8537 CUR_STREAM (stream)->fps_n = 0;
8538 CUR_STREAM (stream)->fps_d = 1;
8540 if (stream->duration == 0 || stream->n_samples < 2) {
8541 CUR_STREAM (stream)->fps_n = stream->timescale;
8542 CUR_STREAM (stream)->fps_d = 1;
8543 fps_available = FALSE;
8545 GstClockTime avg_duration;
8549 /* duration and n_samples can be updated for fragmented format
8550 * so, framerate of fragmented format is calculated using data in a moof */
8551 if (qtdemux->fragmented && stream->n_samples_moof > 0
8552 && stream->duration_moof > 0) {
8553 n_samples = stream->n_samples_moof;
8554 duration = stream->duration_moof;
8556 n_samples = stream->n_samples;
8557 duration = stream->duration;
8560 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8561 /* stream->duration is guint64, timescale, n_samples are guint32 */
8563 gst_util_uint64_scale_round (duration -
8564 first_duration, GST_SECOND,
8565 (guint64) (stream->timescale) * (n_samples - 1));
8567 GST_LOG_OBJECT (qtdemux,
8568 "Calculating avg sample duration based on stream (or moof) duration %"
8570 " minus first sample %u, leaving %d samples gives %"
8571 GST_TIME_FORMAT, duration, first_duration,
8572 n_samples - 1, GST_TIME_ARGS (avg_duration));
8575 gst_video_guess_framerate (avg_duration,
8576 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8578 GST_DEBUG_OBJECT (qtdemux,
8579 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8580 stream->timescale, CUR_STREAM (stream)->fps_n,
8581 CUR_STREAM (stream)->fps_d);
8585 return fps_available;
8589 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8591 if (stream->subtype == FOURCC_vide) {
8592 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8594 if (CUR_STREAM (stream)->caps) {
8595 CUR_STREAM (stream)->caps =
8596 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8598 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8599 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8600 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8601 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8603 /* set framerate if calculated framerate is reliable */
8604 if (fps_available) {
8605 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8606 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8607 CUR_STREAM (stream)->fps_d, NULL);
8610 /* calculate pixel-aspect-ratio using display width and height */
8611 GST_DEBUG_OBJECT (qtdemux,
8612 "video size %dx%d, target display size %dx%d",
8613 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8614 stream->display_width, stream->display_height);
8615 /* qt file might have pasp atom */
8616 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8617 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8618 CUR_STREAM (stream)->par_h);
8619 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8620 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8621 CUR_STREAM (stream)->par_h, NULL);
8622 } else if (stream->display_width > 0 && stream->display_height > 0
8623 && CUR_STREAM (stream)->width > 0
8624 && CUR_STREAM (stream)->height > 0) {
8627 /* calculate the pixel aspect ratio using the display and pixel w/h */
8628 n = stream->display_width * CUR_STREAM (stream)->height;
8629 d = stream->display_height * CUR_STREAM (stream)->width;
8632 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8633 CUR_STREAM (stream)->par_w = n;
8634 CUR_STREAM (stream)->par_h = d;
8635 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8636 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8637 CUR_STREAM (stream)->par_h, NULL);
8640 if (CUR_STREAM (stream)->interlace_mode > 0) {
8641 if (CUR_STREAM (stream)->interlace_mode == 1) {
8642 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8643 G_TYPE_STRING, "progressive", NULL);
8644 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8645 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8646 G_TYPE_STRING, "interleaved", NULL);
8647 if (CUR_STREAM (stream)->field_order == 9) {
8648 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8649 G_TYPE_STRING, "top-field-first", NULL);
8650 } else if (CUR_STREAM (stream)->field_order == 14) {
8651 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8652 G_TYPE_STRING, "bottom-field-first", NULL);
8657 /* Create incomplete colorimetry here if needed */
8658 if (CUR_STREAM (stream)->colorimetry.range ||
8659 CUR_STREAM (stream)->colorimetry.matrix ||
8660 CUR_STREAM (stream)->colorimetry.transfer
8661 || CUR_STREAM (stream)->colorimetry.primaries) {
8662 gchar *colorimetry =
8663 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8664 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8665 G_TYPE_STRING, colorimetry, NULL);
8666 g_free (colorimetry);
8669 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8670 guint par_w = 1, par_h = 1;
8672 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8673 par_w = CUR_STREAM (stream)->par_w;
8674 par_h = CUR_STREAM (stream)->par_h;
8677 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8678 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8680 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8683 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8684 "multiview-mode", G_TYPE_STRING,
8685 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8686 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8687 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8692 else if (stream->subtype == FOURCC_soun) {
8693 if (CUR_STREAM (stream)->caps) {
8694 CUR_STREAM (stream)->caps =
8695 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8696 if (CUR_STREAM (stream)->rate > 0)
8697 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8698 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8699 if (CUR_STREAM (stream)->n_channels > 0)
8700 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8701 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8702 if (CUR_STREAM (stream)->n_channels > 2) {
8703 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8704 * correctly; this is just the minimum we can do - assume
8705 * we don't actually have any channel positions. */
8706 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8707 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8712 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8713 const GstStructure *s;
8714 QtDemuxStream *fps_stream = NULL;
8715 gboolean fps_available = FALSE;
8717 /* CEA608 closed caption tracks are a bit special in that each sample
8718 * can contain CCs for multiple frames, and CCs can be omitted and have to
8719 * be inferred from the duration of the sample then.
8721 * As such we take the framerate from the (first) video track here for
8722 * CEA608 as there must be one CC byte pair for every video frame
8723 * according to the spec.
8725 * For CEA708 all is fine and there is one sample per frame.
8728 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8729 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8732 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8733 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8735 if (tmp->subtype == FOURCC_vide) {
8742 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8743 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8744 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8747 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8748 fps_stream = stream;
8751 CUR_STREAM (stream)->caps =
8752 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8754 /* set framerate if calculated framerate is reliable */
8755 if (fps_available) {
8756 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8757 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8758 CUR_STREAM (stream)->fps_d, NULL);
8763 GstCaps *prev_caps = NULL;
8765 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8766 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8767 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8768 gst_pad_set_active (stream->pad, TRUE);
8770 gst_pad_use_fixed_caps (stream->pad);
8772 if (stream->protected) {
8773 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8774 GST_ERROR_OBJECT (qtdemux,
8775 "Failed to configure protected stream caps.");
8780 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8781 CUR_STREAM (stream)->caps);
8782 if (stream->new_stream) {
8784 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8787 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8790 gst_event_parse_stream_flags (event, &stream_flags);
8791 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8792 qtdemux->have_group_id = TRUE;
8794 qtdemux->have_group_id = FALSE;
8795 gst_event_unref (event);
8796 } else if (!qtdemux->have_group_id) {
8797 qtdemux->have_group_id = TRUE;
8798 qtdemux->group_id = gst_util_group_id_next ();
8801 stream->new_stream = FALSE;
8802 event = gst_event_new_stream_start (stream->stream_id);
8803 if (qtdemux->have_group_id)
8804 gst_event_set_group_id (event, qtdemux->group_id);
8805 if (stream->disabled)
8806 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8807 if (CUR_STREAM (stream)->sparse) {
8808 stream_flags |= GST_STREAM_FLAG_SPARSE;
8810 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8812 gst_event_set_stream_flags (event, stream_flags);
8813 gst_pad_push_event (stream->pad, event);
8816 prev_caps = gst_pad_get_current_caps (stream->pad);
8818 if (CUR_STREAM (stream)->caps) {
8820 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8821 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8822 CUR_STREAM (stream)->caps);
8823 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8825 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8828 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8832 gst_caps_unref (prev_caps);
8833 stream->new_caps = FALSE;
8839 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8840 QtDemuxStream * stream)
8842 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8845 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8846 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8847 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8848 stream->stsd_entries_length)) {
8849 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8850 (_("This file is invalid and cannot be played.")),
8851 ("New sample description id is out of bounds (%d >= %d)",
8852 stream->stsd_sample_description_id, stream->stsd_entries_length));
8854 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8855 stream->new_caps = TRUE;
8860 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8861 QtDemuxStream * stream, GstTagList * list)
8863 gboolean ret = TRUE;
8865 if (stream->subtype == FOURCC_vide) {
8866 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8869 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8872 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8873 gst_object_unref (stream->pad);
8879 qtdemux->n_video_streams++;
8880 } else if (stream->subtype == FOURCC_soun) {
8881 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8884 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8886 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8887 gst_object_unref (stream->pad);
8892 qtdemux->n_audio_streams++;
8893 } else if (stream->subtype == FOURCC_strm) {
8894 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8895 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8896 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8897 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
8898 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8901 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8903 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8904 gst_object_unref (stream->pad);
8909 qtdemux->n_sub_streams++;
8910 } else if (CUR_STREAM (stream)->caps) {
8911 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8914 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8916 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8917 gst_object_unref (stream->pad);
8922 qtdemux->n_video_streams++;
8924 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8931 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8932 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8933 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8934 GST_OBJECT_LOCK (qtdemux);
8935 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8936 GST_OBJECT_UNLOCK (qtdemux);
8938 if (stream->stream_tags)
8939 gst_tag_list_unref (stream->stream_tags);
8940 stream->stream_tags = list;
8942 /* global tags go on each pad anyway */
8943 stream->send_global_tags = TRUE;
8944 /* send upstream GST_EVENT_PROTECTION events that were received before
8945 this source pad was created */
8946 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8947 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8951 gst_tag_list_unref (list);
8955 /* find next atom with @fourcc starting at @offset */
8956 static GstFlowReturn
8957 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8958 guint64 * length, guint32 fourcc)
8964 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8965 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8971 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8972 if (G_UNLIKELY (ret != GST_FLOW_OK))
8974 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8977 gst_buffer_unref (buf);
8980 gst_buffer_map (buf, &map, GST_MAP_READ);
8981 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8982 gst_buffer_unmap (buf, &map);
8983 gst_buffer_unref (buf);
8985 if (G_UNLIKELY (*length == 0)) {
8986 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8987 ret = GST_FLOW_ERROR;
8991 if (lfourcc == fourcc) {
8992 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
8993 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8996 GST_LOG_OBJECT (qtdemux,
8997 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8998 GST_FOURCC_ARGS (lfourcc), *offset);
8999 if (*offset == G_MAXUINT64)
9009 /* might simply have had last one */
9010 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9015 /* should only do something in pull mode */
9016 /* call with OBJECT lock */
9017 static GstFlowReturn
9018 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9020 guint64 length, offset;
9021 GstBuffer *buf = NULL;
9022 GstFlowReturn ret = GST_FLOW_OK;
9023 GstFlowReturn res = GST_FLOW_OK;
9026 offset = qtdemux->moof_offset;
9027 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9030 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9031 return GST_FLOW_EOS;
9034 /* best not do pull etc with lock held */
9035 GST_OBJECT_UNLOCK (qtdemux);
9037 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9038 if (ret != GST_FLOW_OK)
9041 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9042 if (G_UNLIKELY (ret != GST_FLOW_OK))
9044 gst_buffer_map (buf, &map, GST_MAP_READ);
9045 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9046 gst_buffer_unmap (buf, &map);
9047 gst_buffer_unref (buf);
9052 gst_buffer_unmap (buf, &map);
9053 gst_buffer_unref (buf);
9057 /* look for next moof */
9058 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9059 if (G_UNLIKELY (ret != GST_FLOW_OK))
9063 GST_OBJECT_LOCK (qtdemux);
9065 qtdemux->moof_offset = offset;
9071 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9073 res = GST_FLOW_ERROR;
9078 /* maybe upstream temporarily flushing */
9079 if (ret != GST_FLOW_FLUSHING) {
9080 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9083 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9084 /* resume at current position next time */
9092 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9096 gint32 stts_duration;
9097 GstByteWriter stsc, stts, stsz;
9099 /* Each sample has a different size, which we don't support for merging */
9100 if (stream->sample_size == 0) {
9101 GST_DEBUG_OBJECT (qtdemux,
9102 "Not all samples have the same size, not merging");
9106 /* The stream has a ctts table, we don't support that */
9107 if (stream->ctts_present) {
9108 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9112 /* If there's a sync sample table also ignore this stream */
9113 if (stream->stps_present || stream->stss_present) {
9114 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9118 /* If chunks are considered samples already ignore this stream */
9119 if (stream->chunks_are_samples) {
9120 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9124 /* Require that all samples have the same duration */
9125 if (stream->n_sample_times > 1) {
9126 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9130 /* Parse the stts to get the sample duration and number of samples */
9131 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9132 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9134 /* Parse the number of chunks from the stco manually because the
9135 * reader is already behind that */
9136 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9138 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9141 /* Now parse stsc, convert chunks into single samples and generate a
9142 * new stsc, stts and stsz from this information */
9143 gst_byte_writer_init (&stsc);
9144 gst_byte_writer_init (&stts);
9145 gst_byte_writer_init (&stsz);
9147 /* Note: we skip fourccs, size, version, flags and other fields of the new
9148 * atoms as the byte readers with them are already behind that position
9149 * anyway and only update the values of those inside the stream directly.
9151 stream->n_sample_times = 0;
9152 stream->n_samples = 0;
9153 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9155 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9157 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9158 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9159 sample_description_id =
9160 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9162 if (i == stream->n_samples_per_chunk - 1) {
9163 /* +1 because first_chunk is 1-based */
9164 last_chunk = num_chunks + 1;
9166 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9169 GST_DEBUG_OBJECT (qtdemux,
9170 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9171 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9173 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9174 /* One sample in this chunk */
9175 gst_byte_writer_put_uint32_be (&stsc, 1);
9176 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9178 /* For each chunk write a stts and stsz entry now */
9179 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9180 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9181 for (j = first_chunk; j < last_chunk; j++) {
9182 gst_byte_writer_put_uint32_be (&stsz,
9183 stream->sample_size * samples_per_chunk);
9186 stream->n_sample_times += 1;
9187 stream->n_samples += last_chunk - first_chunk;
9190 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9192 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9193 stream->n_samples, stream->n_sample_times);
9195 /* We don't have a fixed sample size anymore */
9196 stream->sample_size = 0;
9198 /* Free old data for the atoms */
9199 g_free ((gpointer) stream->stsz.data);
9200 stream->stsz.data = NULL;
9201 g_free ((gpointer) stream->stsc.data);
9202 stream->stsc.data = NULL;
9203 g_free ((gpointer) stream->stts.data);
9204 stream->stts.data = NULL;
9206 /* Store new data and replace byte readers */
9207 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9208 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9209 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9210 stream->stts.size = gst_byte_writer_get_size (&stts);
9211 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9212 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9213 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9214 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9215 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9218 /* initialise bytereaders for stbl sub-atoms */
9220 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9222 stream->stbl_index = -1; /* no samples have yet been parsed */
9223 stream->sample_index = -1;
9225 /* time-to-sample atom */
9226 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9229 /* copy atom data into a new buffer for later use */
9230 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9232 /* skip version + flags */
9233 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9234 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9236 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9238 /* make sure there's enough data */
9239 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9240 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9241 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9242 stream->n_sample_times);
9243 if (!stream->n_sample_times)
9247 /* sync sample atom */
9248 stream->stps_present = FALSE;
9249 if ((stream->stss_present =
9250 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9251 &stream->stss) ? TRUE : FALSE) == TRUE) {
9252 /* copy atom data into a new buffer for later use */
9253 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9255 /* skip version + flags */
9256 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9257 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9260 if (stream->n_sample_syncs) {
9261 /* make sure there's enough data */
9262 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9266 /* partial sync sample atom */
9267 if ((stream->stps_present =
9268 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9269 &stream->stps) ? TRUE : FALSE) == TRUE) {
9270 /* copy atom data into a new buffer for later use */
9271 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9273 /* skip version + flags */
9274 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9275 !gst_byte_reader_get_uint32_be (&stream->stps,
9276 &stream->n_sample_partial_syncs))
9279 /* if there are no entries, the stss table contains the real
9281 if (stream->n_sample_partial_syncs) {
9282 /* make sure there's enough data */
9283 if (!qt_atom_parser_has_chunks (&stream->stps,
9284 stream->n_sample_partial_syncs, 4))
9291 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9294 /* copy atom data into a new buffer for later use */
9295 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9297 /* skip version + flags */
9298 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9299 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9302 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9305 if (!stream->n_samples)
9308 /* sample-to-chunk atom */
9309 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9312 /* copy atom data into a new buffer for later use */
9313 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9315 /* skip version + flags */
9316 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9317 !gst_byte_reader_get_uint32_be (&stream->stsc,
9318 &stream->n_samples_per_chunk))
9321 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9322 stream->n_samples_per_chunk);
9324 /* make sure there's enough data */
9325 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9331 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9332 stream->co_size = sizeof (guint32);
9333 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9335 stream->co_size = sizeof (guint64);
9339 /* copy atom data into a new buffer for later use */
9340 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9342 /* skip version + flags */
9343 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9346 /* chunks_are_samples == TRUE means treat chunks as samples */
9347 stream->chunks_are_samples = stream->sample_size
9348 && !CUR_STREAM (stream)->sampled;
9349 if (stream->chunks_are_samples) {
9350 /* treat chunks as samples */
9351 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9354 /* skip number of entries */
9355 if (!gst_byte_reader_skip (&stream->stco, 4))
9358 /* make sure there are enough data in the stsz atom */
9359 if (!stream->sample_size) {
9360 /* different sizes for each sample */
9361 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9366 /* composition time-to-sample */
9367 if ((stream->ctts_present =
9368 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9369 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9370 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9372 /* copy atom data into a new buffer for later use */
9373 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9375 /* skip version + flags */
9376 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
9377 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9378 &stream->n_composition_times))
9381 /* make sure there's enough data */
9382 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9386 /* This is optional, if missing we iterate the ctts */
9387 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9388 guint8 cslg_version;
9390 /* cslg version 1 has 64 bit fields */
9391 if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9395 if (!gst_byte_reader_skip (&cslg, 3))
9398 if (cslg_version == 0) {
9399 gint32 composition_to_dts_shift;
9401 if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9404 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9406 gint64 composition_to_dts_shift;
9408 if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9411 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9414 gint32 cslg_least = 0;
9415 guint num_entries, pos;
9418 pos = gst_byte_reader_get_pos (&stream->ctts);
9419 num_entries = stream->n_composition_times;
9421 stream->cslg_shift = 0;
9423 for (i = 0; i < num_entries; i++) {
9426 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9427 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9428 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9429 * slightly inaccurate PTS could be more usable than corrupted one */
9430 if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
9431 GST_WARNING_OBJECT (qtdemux,
9432 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9433 " larger than duration %" G_GUINT64_FORMAT,
9434 offset, stream->duration);
9436 stream->cslg_shift = 0;
9437 stream->ctts_present = FALSE;
9441 if (offset < cslg_least)
9442 cslg_least = offset;
9446 stream->cslg_shift = ABS (cslg_least);
9448 stream->cslg_shift = 0;
9450 /* reset the reader so we can generate sample table */
9451 gst_byte_reader_set_pos (&stream->ctts, pos);
9454 /* Ensure the cslg_shift value is consistent so we can use it
9455 * unconditionally to produce TS and Segment */
9456 stream->cslg_shift = 0;
9459 /* For raw audio streams especially we might want to merge the samples
9460 * to not output one audio sample per buffer. We're doing this here
9461 * before allocating the sample tables so that from this point onwards
9462 * the number of container samples are static */
9463 if (stream->min_buffer_size > 0) {
9464 qtdemux_merge_sample_table (qtdemux, stream);
9468 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9469 stream->n_samples, (guint) sizeof (QtDemuxSample),
9470 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9472 if (stream->n_samples >=
9473 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9474 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9475 "be larger than %uMB (broken file?)", stream->n_samples,
9476 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9480 g_assert (stream->samples == NULL);
9481 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9482 if (!stream->samples) {
9483 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9492 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9493 (_("This file is corrupt and cannot be played.")), (NULL));
9498 gst_qtdemux_stbl_free (stream);
9499 if (!qtdemux->fragmented) {
9500 /* not quite good */
9501 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9504 /* may pick up samples elsewhere */
9510 /* collect samples from the next sample to be parsed up to sample @n for @stream
9511 * by reading the info from @stbl
9513 * This code can be executed from both the streaming thread and the seeking
9514 * thread so it takes the object lock to protect itself
9517 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9520 QtDemuxSample *samples, *first, *cur, *last;
9521 guint32 n_samples_per_chunk;
9524 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9525 GST_FOURCC_FORMAT ", pad %s",
9526 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9527 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9529 n_samples = stream->n_samples;
9532 goto out_of_samples;
9534 GST_OBJECT_LOCK (qtdemux);
9535 if (n <= stream->stbl_index)
9536 goto already_parsed;
9538 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9540 if (!stream->stsz.data) {
9541 /* so we already parsed and passed all the moov samples;
9542 * onto fragmented ones */
9543 g_assert (qtdemux->fragmented);
9547 /* pointer to the sample table */
9548 samples = stream->samples;
9550 /* starts from -1, moves to the next sample index to parse */
9551 stream->stbl_index++;
9553 /* keep track of the first and last sample to fill */
9554 first = &samples[stream->stbl_index];
9557 if (!stream->chunks_are_samples) {
9558 /* set the sample sizes */
9559 if (stream->sample_size == 0) {
9560 /* different sizes for each sample */
9561 for (cur = first; cur <= last; cur++) {
9562 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9563 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9564 (guint) (cur - samples), cur->size);
9567 /* samples have the same size */
9568 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9569 for (cur = first; cur <= last; cur++)
9570 cur->size = stream->sample_size;
9574 n_samples_per_chunk = stream->n_samples_per_chunk;
9577 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9580 if (stream->stsc_chunk_index >= stream->last_chunk
9581 || stream->stsc_chunk_index < stream->first_chunk) {
9582 stream->first_chunk =
9583 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9584 stream->samples_per_chunk =
9585 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9587 stream->stsd_sample_description_id =
9588 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9590 /* chunk numbers are counted from 1 it seems */
9591 if (G_UNLIKELY (stream->first_chunk == 0))
9594 --stream->first_chunk;
9596 /* the last chunk of each entry is calculated by taking the first chunk
9597 * of the next entry; except if there is no next, where we fake it with
9599 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9600 stream->last_chunk = G_MAXUINT32;
9602 stream->last_chunk =
9603 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9604 if (G_UNLIKELY (stream->last_chunk == 0))
9607 --stream->last_chunk;
9610 GST_LOG_OBJECT (qtdemux,
9611 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9612 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9613 stream->samples_per_chunk, stream->stsd_sample_description_id);
9615 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9618 if (stream->last_chunk != G_MAXUINT32) {
9619 if (!qt_atom_parser_peek_sub (&stream->stco,
9620 stream->first_chunk * stream->co_size,
9621 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9626 stream->co_chunk = stream->stco;
9627 if (!gst_byte_reader_skip (&stream->co_chunk,
9628 stream->first_chunk * stream->co_size))
9632 stream->stsc_chunk_index = stream->first_chunk;
9635 last_chunk = stream->last_chunk;
9637 if (stream->chunks_are_samples) {
9638 cur = &samples[stream->stsc_chunk_index];
9640 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9643 stream->stsc_chunk_index = j;
9648 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9651 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9652 "%" G_GUINT64_FORMAT, j, cur->offset);
9654 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9655 CUR_STREAM (stream)->bytes_per_frame > 0) {
9657 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9658 CUR_STREAM (stream)->samples_per_frame *
9659 CUR_STREAM (stream)->bytes_per_frame;
9661 cur->size = stream->samples_per_chunk;
9664 GST_DEBUG_OBJECT (qtdemux,
9665 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9666 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9667 stream->stco_sample_index)), cur->size);
9669 cur->timestamp = stream->stco_sample_index;
9670 cur->duration = stream->samples_per_chunk;
9671 cur->keyframe = TRUE;
9674 stream->stco_sample_index += stream->samples_per_chunk;
9676 stream->stsc_chunk_index = j;
9678 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9679 guint32 samples_per_chunk;
9680 guint64 chunk_offset;
9682 if (!stream->stsc_sample_index
9683 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9684 &stream->chunk_offset))
9687 samples_per_chunk = stream->samples_per_chunk;
9688 chunk_offset = stream->chunk_offset;
9690 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9691 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9692 G_GUINT64_FORMAT " and size %d",
9693 (guint) (cur - samples), chunk_offset, cur->size);
9695 cur->offset = chunk_offset;
9696 chunk_offset += cur->size;
9699 if (G_UNLIKELY (cur > last)) {
9701 stream->stsc_sample_index = k + 1;
9702 stream->chunk_offset = chunk_offset;
9703 stream->stsc_chunk_index = j;
9707 stream->stsc_sample_index = 0;
9709 stream->stsc_chunk_index = j;
9711 stream->stsc_index++;
9714 if (stream->chunks_are_samples)
9718 guint32 n_sample_times;
9720 n_sample_times = stream->n_sample_times;
9723 for (i = stream->stts_index; i < n_sample_times; i++) {
9724 guint32 stts_samples;
9725 gint32 stts_duration;
9728 if (stream->stts_sample_index >= stream->stts_samples
9729 || !stream->stts_sample_index) {
9731 stream->stts_samples =
9732 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9733 stream->stts_duration =
9734 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9736 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9737 i, stream->stts_samples, stream->stts_duration);
9739 stream->stts_sample_index = 0;
9742 stts_samples = stream->stts_samples;
9743 stts_duration = stream->stts_duration;
9744 stts_time = stream->stts_time;
9746 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9747 GST_DEBUG_OBJECT (qtdemux,
9748 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9749 (guint) (cur - samples), j,
9750 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9752 cur->timestamp = stts_time;
9753 cur->duration = stts_duration;
9755 /* avoid 32-bit wrap-around,
9756 * but still mind possible 'negative' duration */
9757 stts_time += (gint64) stts_duration;
9760 if (G_UNLIKELY (cur > last)) {
9762 stream->stts_time = stts_time;
9763 stream->stts_sample_index = j + 1;
9764 if (stream->stts_sample_index >= stream->stts_samples)
9765 stream->stts_index++;
9769 stream->stts_sample_index = 0;
9770 stream->stts_time = stts_time;
9771 stream->stts_index++;
9773 /* fill up empty timestamps with the last timestamp, this can happen when
9774 * the last samples do not decode and so we don't have timestamps for them.
9775 * We however look at the last timestamp to estimate the track length so we
9776 * need something in here. */
9777 for (; cur < last; cur++) {
9778 GST_DEBUG_OBJECT (qtdemux,
9779 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9780 (guint) (cur - samples),
9781 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9782 cur->timestamp = stream->stts_time;
9788 /* sample sync, can be NULL */
9789 if (stream->stss_present == TRUE) {
9790 guint32 n_sample_syncs;
9792 n_sample_syncs = stream->n_sample_syncs;
9794 if (!n_sample_syncs) {
9795 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9796 stream->all_keyframe = TRUE;
9798 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9799 /* note that the first sample is index 1, not 0 */
9802 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9804 if (G_LIKELY (index > 0 && index <= n_samples)) {
9806 samples[index].keyframe = TRUE;
9807 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9808 /* and exit if we have enough samples */
9809 if (G_UNLIKELY (index >= n)) {
9816 stream->stss_index = i;
9819 /* stps marks partial sync frames like open GOP I-Frames */
9820 if (stream->stps_present == TRUE) {
9821 guint32 n_sample_partial_syncs;
9823 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9825 /* if there are no entries, the stss table contains the real
9827 if (n_sample_partial_syncs) {
9828 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9829 /* note that the first sample is index 1, not 0 */
9832 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9834 if (G_LIKELY (index > 0 && index <= n_samples)) {
9836 samples[index].keyframe = TRUE;
9837 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9838 /* and exit if we have enough samples */
9839 if (G_UNLIKELY (index >= n)) {
9846 stream->stps_index = i;
9850 /* no stss, all samples are keyframes */
9851 stream->all_keyframe = TRUE;
9852 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9857 /* composition time to sample */
9858 if (stream->ctts_present == TRUE) {
9859 guint32 n_composition_times;
9861 gint32 ctts_soffset;
9863 /* Fill in the pts_offsets */
9865 n_composition_times = stream->n_composition_times;
9867 for (i = stream->ctts_index; i < n_composition_times; i++) {
9868 if (stream->ctts_sample_index >= stream->ctts_count
9869 || !stream->ctts_sample_index) {
9870 stream->ctts_count =
9871 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9872 stream->ctts_soffset =
9873 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9874 stream->ctts_sample_index = 0;
9877 ctts_count = stream->ctts_count;
9878 ctts_soffset = stream->ctts_soffset;
9880 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9881 cur->pts_offset = ctts_soffset;
9884 if (G_UNLIKELY (cur > last)) {
9886 stream->ctts_sample_index = j + 1;
9890 stream->ctts_sample_index = 0;
9891 stream->ctts_index++;
9895 stream->stbl_index = n;
9896 /* if index has been completely parsed, free data that is no-longer needed */
9897 if (n + 1 == stream->n_samples) {
9898 gst_qtdemux_stbl_free (stream);
9899 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9900 if (qtdemux->pullbased) {
9901 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9902 while (n + 1 == stream->n_samples)
9903 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9907 GST_OBJECT_UNLOCK (qtdemux);
9914 GST_LOG_OBJECT (qtdemux,
9915 "Tried to parse up to sample %u but this sample has already been parsed",
9917 /* if fragmented, there may be more */
9918 if (qtdemux->fragmented && n == stream->stbl_index)
9920 GST_OBJECT_UNLOCK (qtdemux);
9926 GST_LOG_OBJECT (qtdemux,
9927 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9929 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9930 (_("This file is corrupt and cannot be played.")), (NULL));
9935 GST_OBJECT_UNLOCK (qtdemux);
9936 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9937 (_("This file is corrupt and cannot be played.")), (NULL));
9942 /* collect all segment info for @stream.
9945 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9949 /* accept edts if they contain gaps at start and there is only
9950 * one media segment */
9951 gboolean allow_pushbased_edts = TRUE;
9952 gint media_segments_count = 0;
9954 /* parse and prepare segment info from the edit list */
9955 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9956 stream->n_segments = 0;
9957 stream->segments = NULL;
9958 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9961 gint segment_number, entry_size;
9964 const guint8 *buffer;
9968 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9969 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9972 buffer = elst->data;
9974 size = QT_UINT32 (buffer);
9975 /* version, flags, n_segments */
9977 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9980 version = QT_UINT8 (buffer + 8);
9981 entry_size = (version == 1) ? 20 : 12;
9983 n_segments = QT_UINT32 (buffer + 12);
9985 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9986 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9990 /* we might allocate a bit too much, at least allocate 1 segment */
9991 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9993 /* segments always start from 0 */
9997 for (segment_number = 0; segment_number < n_segments; segment_number++) {
10000 gboolean empty_edit = FALSE;
10001 QtDemuxSegment *segment;
10003 GstClockTime media_start = GST_CLOCK_TIME_NONE;
10005 if (version == 1) {
10006 media_time = QT_UINT64 (buffer + 8);
10007 duration = QT_UINT64 (buffer);
10008 if (media_time == G_MAXUINT64)
10011 media_time = QT_UINT32 (buffer + 4);
10012 duration = QT_UINT32 (buffer);
10013 if (media_time == G_MAXUINT32)
10018 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10020 segment = &stream->segments[segment_number];
10022 /* time and duration expressed in global timescale */
10023 segment->time = stime;
10024 if (duration != 0 || empty_edit) {
10025 /* edge case: empty edits with duration=zero are treated here.
10026 * (files should not have these anyway). */
10028 /* add non scaled values so we don't cause roundoff errors */
10030 stime = QTTIME_TO_GSTTIME (qtdemux, time);
10031 segment->duration = stime - segment->time;
10033 /* zero duration does not imply media_start == media_stop
10034 * but, only specify media_start. The edit ends with the track. */
10035 stime = segment->duration = GST_CLOCK_TIME_NONE;
10036 /* Don't allow more edits after this one. */
10037 n_segments = segment_number + 1;
10039 segment->stop_time = stime;
10041 segment->trak_media_start = media_time;
10042 /* media_time expressed in stream timescale */
10044 segment->media_start = media_start;
10045 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10046 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10047 media_segments_count++;
10049 segment->media_start = GST_CLOCK_TIME_NONE;
10050 segment->media_stop = GST_CLOCK_TIME_NONE;
10052 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10054 if (rate_int <= 1) {
10055 /* 0 is not allowed, some programs write 1 instead of the floating point
10057 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10061 segment->rate = rate_int / 65536.0;
10064 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10065 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10066 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10067 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10068 segment_number, GST_TIME_ARGS (segment->time),
10069 GST_TIME_ARGS (segment->duration),
10070 GST_TIME_ARGS (segment->media_start), media_time,
10071 GST_TIME_ARGS (segment->media_stop),
10072 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10073 stream->timescale);
10074 if (segment->stop_time > qtdemux->segment.stop &&
10075 !qtdemux->upstream_format_is_time) {
10076 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10077 " extends to %" GST_TIME_FORMAT
10078 " past the end of the declared movie duration %" GST_TIME_FORMAT
10079 " movie segment will be extended", segment_number,
10080 GST_TIME_ARGS (segment->stop_time),
10081 GST_TIME_ARGS (qtdemux->segment.stop));
10082 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10085 buffer += entry_size;
10087 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10088 stream->n_segments = n_segments;
10089 if (media_segments_count != 1)
10090 allow_pushbased_edts = FALSE;
10094 /* push based does not handle segments, so act accordingly here,
10095 * and warn if applicable */
10096 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10097 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10098 /* remove and use default one below, we stream like it anyway */
10099 g_free (stream->segments);
10100 stream->segments = NULL;
10101 stream->n_segments = 0;
10104 /* no segments, create one to play the complete trak */
10105 if (stream->n_segments == 0) {
10106 GstClockTime stream_duration =
10107 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10109 if (stream->segments == NULL)
10110 stream->segments = g_new (QtDemuxSegment, 1);
10112 /* represent unknown our way */
10113 if (stream_duration == 0)
10114 stream_duration = GST_CLOCK_TIME_NONE;
10116 stream->segments[0].time = 0;
10117 stream->segments[0].stop_time = stream_duration;
10118 stream->segments[0].duration = stream_duration;
10119 stream->segments[0].media_start = 0;
10120 stream->segments[0].media_stop = stream_duration;
10121 stream->segments[0].rate = 1.0;
10122 stream->segments[0].trak_media_start = 0;
10124 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10125 GST_TIME_ARGS (stream_duration));
10126 stream->n_segments = 1;
10127 stream->dummy_segment = TRUE;
10129 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10135 * Parses the stsd atom of a svq3 trak looking for
10136 * the SMI and gama atoms.
10139 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10140 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10142 const guint8 *_gamma = NULL;
10143 GstBuffer *_seqh = NULL;
10144 const guint8 *stsd_data = stsd_entry_data;
10145 guint32 length = QT_UINT32 (stsd_data);
10149 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10155 version = QT_UINT16 (stsd_data);
10156 if (version == 3) {
10157 if (length >= 70) {
10160 while (length > 8) {
10161 guint32 fourcc, size;
10162 const guint8 *data;
10163 size = QT_UINT32 (stsd_data);
10164 fourcc = QT_FOURCC (stsd_data + 4);
10165 data = stsd_data + 8;
10168 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10169 "svq3 atom parsing");
10178 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10179 " for gama atom, expected 12", size);
10184 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10186 if (_seqh != NULL) {
10187 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10188 " found, ignoring");
10190 seqh_size = QT_UINT32 (data + 4);
10191 if (seqh_size > 0) {
10192 _seqh = gst_buffer_new_and_alloc (seqh_size);
10193 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10200 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10201 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10205 if (size <= length) {
10211 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10214 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10215 G_GUINT16_FORMAT, version);
10225 } else if (_seqh) {
10226 gst_buffer_unref (_seqh);
10231 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10234 GstByteReader dref;
10238 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10239 * atom that might contain a 'data' atom with the rtsp uri.
10240 * This case was reported in bug #597497, some info about
10241 * the hndl atom can be found in TN1195
10243 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10244 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10247 guint32 dref_num_entries = 0;
10248 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10249 gst_byte_reader_skip (&dref, 4) &&
10250 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10253 /* search dref entries for hndl atom */
10254 for (i = 0; i < dref_num_entries; i++) {
10255 guint32 size = 0, type;
10256 guint8 string_len = 0;
10257 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10258 qt_atom_parser_get_fourcc (&dref, &type)) {
10259 if (type == FOURCC_hndl) {
10260 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10262 /* skip data reference handle bytes and the
10263 * following pascal string and some extra 4
10264 * bytes I have no idea what are */
10265 if (!gst_byte_reader_skip (&dref, 4) ||
10266 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10267 !gst_byte_reader_skip (&dref, string_len + 4)) {
10268 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10272 /* iterate over the atoms to find the data atom */
10273 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10277 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10278 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10279 if (atom_type == FOURCC_data) {
10280 const guint8 *uri_aux = NULL;
10282 /* found the data atom that might contain the rtsp uri */
10283 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10284 "hndl atom, interpreting it as an URI");
10285 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10287 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10288 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10290 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10291 "didn't contain a rtsp address");
10293 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10298 /* skipping to the next entry */
10299 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10302 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10309 /* skip to the next entry */
10310 if (!gst_byte_reader_skip (&dref, size - 8))
10313 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10316 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10322 #define AMR_NB_ALL_MODES 0x81ff
10323 #define AMR_WB_ALL_MODES 0x83ff
10325 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10327 /* The 'damr' atom is of the form:
10329 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10330 * 32 b 8 b 16 b 8 b 8 b
10332 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10333 * represents the highest mode used in the stream (and thus the maximum
10334 * bitrate), with a couple of special cases as seen below.
10337 /* Map of frame type ID -> bitrate */
10338 static const guint nb_bitrates[] = {
10339 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10341 static const guint wb_bitrates[] = {
10342 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10348 gst_buffer_map (buf, &map, GST_MAP_READ);
10350 if (map.size != 0x11) {
10351 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10355 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10356 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10357 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10361 mode_set = QT_UINT16 (map.data + 13);
10363 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10364 max_mode = 7 + (wb ? 1 : 0);
10366 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10367 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10369 if (max_mode == -1) {
10370 GST_DEBUG ("No mode indication was found (mode set) = %x",
10375 gst_buffer_unmap (buf, &map);
10376 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10379 gst_buffer_unmap (buf, &map);
10384 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10385 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10388 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10394 if (gst_byte_reader_get_remaining (reader) < 36)
10397 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10398 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10399 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10400 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10401 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10402 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10403 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10404 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10405 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10407 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10408 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10409 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10411 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10412 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10414 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10415 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10422 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10423 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10430 * This macro will only compare value abdegh, it expects cfi to have already
10433 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10434 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10436 /* only handle the cases where the last column has standard values */
10437 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10438 const gchar *rotation_tag = NULL;
10440 /* no rotation needed */
10441 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10443 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10444 rotation_tag = "rotate-90";
10445 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10446 rotation_tag = "rotate-180";
10447 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10448 rotation_tag = "rotate-270";
10450 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10453 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10454 GST_STR_NULL (rotation_tag));
10455 if (rotation_tag != NULL) {
10456 if (*taglist == NULL)
10457 *taglist = gst_tag_list_new_empty ();
10458 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10459 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10462 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10467 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10468 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10472 GstBuffer *adrm_buf = NULL;
10473 QtDemuxAavdEncryptionInfo *info;
10475 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10476 if (G_UNLIKELY (!adrm)) {
10477 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10480 adrm_size = QT_UINT32 (adrm->data);
10481 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10483 stream->protection_scheme_type = FOURCC_aavd;
10485 if (!stream->protection_scheme_info)
10486 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10488 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10490 if (info->default_properties)
10491 gst_structure_free (info->default_properties);
10492 info->default_properties = gst_structure_new ("application/x-aavd",
10493 "encrypted", G_TYPE_BOOLEAN, TRUE,
10494 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10495 gst_buffer_unref (adrm_buf);
10497 *original_fmt = FOURCC_mp4a;
10501 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10502 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10503 * Common Encryption (cenc), the function will also parse the tenc box (defined
10504 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10505 * (typically an enc[v|a|t|s] sample entry); the function will set
10506 * @original_fmt to the fourcc of the original unencrypted stream format.
10507 * Returns TRUE if successful; FALSE otherwise. */
10509 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10510 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10516 QtDemuxCencSampleSetInfo *info;
10518 const guint8 *tenc_data;
10520 g_return_val_if_fail (qtdemux != NULL, FALSE);
10521 g_return_val_if_fail (stream != NULL, FALSE);
10522 g_return_val_if_fail (container != NULL, FALSE);
10523 g_return_val_if_fail (original_fmt != NULL, FALSE);
10525 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10526 if (G_UNLIKELY (!sinf)) {
10527 if (stream->protection_scheme_type == FOURCC_cenc
10528 || stream->protection_scheme_type == FOURCC_cbcs) {
10529 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10530 "mandatory for Common Encryption");
10536 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10537 if (G_UNLIKELY (!frma)) {
10538 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10542 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10543 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10544 GST_FOURCC_ARGS (*original_fmt));
10546 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10548 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10551 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10552 stream->protection_scheme_version =
10553 QT_UINT32 ((const guint8 *) schm->data + 16);
10555 GST_DEBUG_OBJECT (qtdemux,
10556 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10557 "protection_scheme_version: %#010x",
10558 GST_FOURCC_ARGS (stream->protection_scheme_type),
10559 stream->protection_scheme_version);
10561 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10563 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10566 if (stream->protection_scheme_type != FOURCC_cenc &&
10567 stream->protection_scheme_type != FOURCC_piff &&
10568 stream->protection_scheme_type != FOURCC_cbcs) {
10569 GST_ERROR_OBJECT (qtdemux,
10570 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10571 GST_FOURCC_ARGS (stream->protection_scheme_type));
10575 if (G_UNLIKELY (!stream->protection_scheme_info))
10576 stream->protection_scheme_info =
10577 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10579 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10581 if (stream->protection_scheme_type == FOURCC_cenc
10582 || stream->protection_scheme_type == FOURCC_cbcs) {
10583 guint8 is_encrypted;
10585 guint8 constant_iv_size = 0;
10586 const guint8 *default_kid;
10587 guint8 crypt_byte_block = 0;
10588 guint8 skip_byte_block = 0;
10589 const guint8 *constant_iv = NULL;
10591 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10593 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10594 "which is mandatory for Common Encryption");
10597 tenc_data = (const guint8 *) tenc->data + 12;
10598 is_encrypted = QT_UINT8 (tenc_data + 2);
10599 iv_size = QT_UINT8 (tenc_data + 3);
10600 default_kid = (tenc_data + 4);
10601 if (stream->protection_scheme_type == FOURCC_cbcs) {
10602 guint8 possible_pattern_info;
10603 if (iv_size == 0) {
10604 constant_iv_size = QT_UINT8 (tenc_data + 20);
10605 if (constant_iv_size != 8 && constant_iv_size != 16) {
10606 GST_ERROR_OBJECT (qtdemux,
10607 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10610 constant_iv = (tenc_data + 21);
10612 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10613 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10614 skip_byte_block = possible_pattern_info & 0x0f;
10616 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10617 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10618 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10619 } else if (stream->protection_scheme_type == FOURCC_piff) {
10621 static const guint8 piff_track_encryption_uuid[] = {
10622 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10623 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10626 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10628 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10629 "which is mandatory for Common Encryption");
10633 tenc_data = (const guint8 *) tenc->data + 8;
10634 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10635 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10636 GST_ERROR_OBJECT (qtdemux,
10637 "Unsupported track encryption box with uuid: %s", box_uuid);
10641 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10642 gst_byte_reader_init (&br, tenc_data, 20);
10643 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10644 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10647 stream->protection_scheme_type = FOURCC_cenc;
10654 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10655 QtDemuxStream ** stream2)
10657 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10661 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10666 /*parse svmi header if existing */
10667 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10669 guint len = QT_UINT32 ((guint8 *) svmi->data);
10670 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10672 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10673 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10674 guint8 frame_type, frame_layout;
10675 guint32 stereo_mono_change_count;
10680 /* MPEG-A stereo video */
10681 if (qtdemux->major_brand == FOURCC_ss02)
10682 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10684 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10685 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10686 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10688 switch (frame_type) {
10690 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10693 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10696 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10699 /* mode 3 is primary/secondary view sequence, ie
10700 * left/right views in separate tracks. See section 7.2
10701 * of ISO/IEC 23000-11:2009 */
10702 /* In the future this might be supported using related
10703 * streams, like an enhancement track - if files like this
10705 GST_FIXME_OBJECT (qtdemux,
10706 "Implement stereo video in separate streams");
10709 if ((frame_layout & 0x1) == 0)
10710 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10712 GST_LOG_OBJECT (qtdemux,
10713 "StereoVideo: composition type: %u, is_left_first: %u",
10714 frame_type, frame_layout);
10716 if (stereo_mono_change_count > 1) {
10717 GST_FIXME_OBJECT (qtdemux,
10718 "Mixed-mono flags are not yet supported in qtdemux.");
10721 stream->multiview_mode = mode;
10722 stream->multiview_flags = flags;
10729 /* parse the traks.
10730 * With each track we associate a new QtDemuxStream that contains all the info
10732 * traks that do not decode to something (like strm traks) will not have a pad.
10735 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10737 GstByteReader tkhd;
10751 QtDemuxStream *stream = NULL;
10752 const guint8 *stsd_data;
10753 const guint8 *stsd_entry_data;
10754 guint remaining_stsd_len;
10755 guint stsd_entry_count;
10757 guint16 lang_code; /* quicktime lang code or packed iso code */
10759 guint32 tkhd_flags = 0;
10760 guint8 tkhd_version = 0;
10761 guint32 w = 0, h = 0;
10762 guint value_size, stsd_len, len;
10766 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10768 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10769 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10770 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10773 /* pick between 64 or 32 bits */
10774 value_size = tkhd_version == 1 ? 8 : 4;
10775 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10776 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10779 /* Check if current moov has duplicated track_id */
10780 if (qtdemux_find_stream (qtdemux, track_id))
10781 goto existing_stream;
10783 stream = _create_stream (qtdemux, track_id);
10784 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10786 /* need defaults for fragments */
10787 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10789 if ((tkhd_flags & 1) == 0)
10790 stream->disabled = TRUE;
10792 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10793 tkhd_version, tkhd_flags, stream->track_id);
10795 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10798 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10799 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10800 if (qtdemux->major_brand != FOURCC_mjp2 ||
10801 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10805 len = QT_UINT32 ((guint8 *) mdhd->data);
10806 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10807 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10808 if (version == 0x01000000) {
10811 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10812 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10813 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
10817 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10818 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10819 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10822 if (lang_code < 0x400) {
10823 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10824 } else if (lang_code == 0x7fff) {
10825 stream->lang_id[0] = 0; /* unspecified */
10827 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10828 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10829 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10830 stream->lang_id[3] = 0;
10833 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10834 stream->timescale);
10835 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10837 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10838 lang_code, stream->lang_id);
10840 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10843 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10844 /* chapters track reference */
10845 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10847 gsize length = GST_READ_UINT32_BE (chap->data);
10848 if (qtdemux->chapters_track_id)
10849 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10851 if (length >= 12) {
10852 qtdemux->chapters_track_id =
10853 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10858 /* fragmented files may have bogus duration in moov */
10859 if (!qtdemux->fragmented &&
10860 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10861 guint64 tdur1, tdur2;
10863 /* don't overflow */
10864 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10865 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10868 * some of those trailers, nowadays, have prologue images that are
10869 * themselves video tracks as well. I haven't really found a way to
10870 * identify those yet, except for just looking at their duration. */
10871 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10872 GST_WARNING_OBJECT (qtdemux,
10873 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10874 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10875 "found, assuming preview image or something; skipping track",
10876 stream->duration, stream->timescale, qtdemux->duration,
10877 qtdemux->timescale);
10878 gst_qtdemux_stream_unref (stream);
10883 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10886 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10887 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10889 len = QT_UINT32 ((guint8 *) hdlr->data);
10891 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10892 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10893 GST_FOURCC_ARGS (stream->subtype));
10895 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10898 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10901 /* Parse out svmi (and later st3d/sv3d) atoms */
10902 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
10905 /* parse rest of tkhd */
10906 if (stream->subtype == FOURCC_vide) {
10909 /* version 1 uses some 64-bit ints */
10910 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10913 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10916 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10917 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10920 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10921 &stream->stream_tags);
10925 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10927 stsd_data = (const guint8 *) stsd->data;
10929 /* stsd should at least have one entry */
10930 stsd_len = QT_UINT32 (stsd_data);
10931 if (stsd_len < 24) {
10932 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10933 if (stream->subtype == FOURCC_vivo) {
10934 gst_qtdemux_stream_unref (stream);
10941 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10942 /* each stsd entry must contain at least 8 bytes */
10943 if (stream->stsd_entries_length == 0
10944 || stream->stsd_entries_length > stsd_len / 8) {
10945 stream->stsd_entries_length = 0;
10948 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10949 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
10950 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
10952 stsd_entry_data = stsd_data + 16;
10953 remaining_stsd_len = stsd_len - 16;
10954 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10956 gchar *codec = NULL;
10957 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10959 /* and that entry should fit within stsd */
10960 len = QT_UINT32 (stsd_entry_data);
10961 if (len > remaining_stsd_len)
10964 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10965 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
10966 GST_FOURCC_ARGS (entry->fourcc));
10967 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
10969 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10970 goto error_encrypted;
10972 if (fourcc == FOURCC_aavd) {
10973 if (stream->subtype != FOURCC_soun) {
10974 GST_ERROR_OBJECT (qtdemux,
10975 "Unexpeced stsd type 'aavd' outside 'soun' track");
10977 /* encrypted audio with sound sample description v0 */
10978 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10979 stream->protected = TRUE;
10980 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
10981 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10985 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10986 /* FIXME this looks wrong, there might be multiple children
10987 * with the same type */
10988 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10989 stream->protected = TRUE;
10990 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10991 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10994 if (stream->subtype == FOURCC_vide) {
10999 gint depth, palette_size, palette_count;
11000 guint32 *palette_data = NULL;
11002 entry->sampled = TRUE;
11004 stream->display_width = w >> 16;
11005 stream->display_height = h >> 16;
11008 if (len < 86) /* TODO verify */
11011 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11012 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11013 entry->fps_n = 0; /* this is filled in later */
11014 entry->fps_d = 0; /* this is filled in later */
11015 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11016 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11018 /* if color_table_id is 0, ctab atom must follow; however some files
11019 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11020 * if color table is not present we'll correct the value */
11021 if (entry->color_table_id == 0 &&
11023 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11024 entry->color_table_id = -1;
11027 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11028 entry->width, entry->height, entry->bits_per_sample,
11029 entry->color_table_id);
11031 depth = entry->bits_per_sample;
11033 /* more than 32 bits means grayscale */
11034 gray = (depth > 32);
11035 /* low 32 bits specify the depth */
11038 /* different number of palette entries is determined by depth. */
11040 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11041 palette_count = (1 << depth);
11042 palette_size = palette_count * 4;
11044 if (entry->color_table_id) {
11045 switch (palette_count) {
11049 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11052 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11057 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11059 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11064 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11067 g_memdup2 (ff_qt_default_palette_256, palette_size);
11070 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11071 (_("The video in this file might not play correctly.")),
11072 ("unsupported palette depth %d", depth));
11076 gint i, j, start, end;
11082 start = QT_UINT32 (stsd_entry_data + offset + 70);
11083 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11084 end = QT_UINT16 (stsd_entry_data + offset + 76);
11086 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11087 start, end, palette_count);
11094 if (len < 94 + (end - start) * 8)
11097 /* palette is always the same size */
11098 palette_data = g_malloc0 (256 * 4);
11099 palette_size = 256 * 4;
11101 for (j = 0, i = start; i <= end; j++, i++) {
11102 guint32 a, r, g, b;
11104 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11105 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11106 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11107 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11109 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11110 (g & 0xff00) | (b >> 8);
11115 gst_caps_unref (entry->caps);
11118 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11120 if (G_UNLIKELY (!entry->caps)) {
11121 g_free (palette_data);
11122 goto unknown_stream;
11126 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11127 GST_TAG_VIDEO_CODEC, codec, NULL);
11132 if (palette_data) {
11135 if (entry->rgb8_palette)
11136 gst_memory_unref (entry->rgb8_palette);
11137 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11138 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11140 s = gst_caps_get_structure (entry->caps, 0);
11142 /* non-raw video has a palette_data property. raw video has the palette as
11143 * an extra plane that we append to the output buffers before we push
11145 if (!gst_structure_has_name (s, "video/x-raw")) {
11146 GstBuffer *palette;
11148 palette = gst_buffer_new ();
11149 gst_buffer_append_memory (palette, entry->rgb8_palette);
11150 entry->rgb8_palette = NULL;
11152 gst_caps_set_simple (entry->caps, "palette_data",
11153 GST_TYPE_BUFFER, palette, NULL);
11154 gst_buffer_unref (palette);
11156 } else if (palette_count != 0) {
11157 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11158 (NULL), ("Unsupported palette depth %d", depth));
11161 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11162 QT_UINT16 (stsd_entry_data + offset + 32));
11168 /* pick 'the' stsd child */
11169 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11170 // We should skip parsing the stsd for non-protected streams if
11171 // the entry doesn't match the fourcc, since they don't change
11172 // format. However, for protected streams we can have partial
11173 // encryption, where parts of the stream are encrypted and parts
11174 // not. For both parts of such streams, we should ensure the
11175 // esds overrides are parsed for both from the stsd.
11176 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11177 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11179 else if (!stream->protected)
11184 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11185 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11186 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11187 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11191 const guint8 *pasp_data = (const guint8 *) pasp->data;
11192 gint len = QT_UINT32 (pasp_data);
11195 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11196 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11198 CUR_STREAM (stream)->par_w = 0;
11199 CUR_STREAM (stream)->par_h = 0;
11202 CUR_STREAM (stream)->par_w = 0;
11203 CUR_STREAM (stream)->par_h = 0;
11207 const guint8 *fiel_data = (const guint8 *) fiel->data;
11208 gint len = QT_UINT32 (fiel_data);
11211 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11212 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11217 const guint8 *colr_data = (const guint8 *) colr->data;
11218 gint len = QT_UINT32 (colr_data);
11220 if (len == 19 || len == 18) {
11221 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11223 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11224 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11225 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11226 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11227 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11229 CUR_STREAM (stream)->colorimetry.primaries =
11230 gst_video_color_primaries_from_iso (primaries);
11231 CUR_STREAM (stream)->colorimetry.transfer =
11232 gst_video_transfer_function_from_iso (transfer_function);
11233 CUR_STREAM (stream)->colorimetry.matrix =
11234 gst_video_color_matrix_from_iso (matrix);
11235 CUR_STREAM (stream)->colorimetry.range =
11236 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11237 GST_VIDEO_COLOR_RANGE_16_235;
11239 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11242 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11247 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11248 stream->stream_tags);
11255 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11256 const guint8 *avc_data = stsd_entry_data + 0x56;
11259 while (len >= 0x8) {
11262 if (QT_UINT32 (avc_data) <= len)
11263 size = QT_UINT32 (avc_data) - 0x8;
11268 /* No real data, so break out */
11271 switch (QT_FOURCC (avc_data + 0x4)) {
11274 /* parse, if found */
11277 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11279 /* First 4 bytes are the length of the atom, the next 4 bytes
11280 * are the fourcc, the next 1 byte is the version, and the
11281 * subsequent bytes are profile_tier_level structure like data. */
11282 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11283 avc_data + 8 + 1, size - 1);
11284 buf = gst_buffer_new_and_alloc (size);
11285 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11286 gst_caps_set_simple (entry->caps,
11287 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11288 gst_buffer_unref (buf);
11296 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11298 /* First 4 bytes are the length of the atom, the next 4 bytes
11299 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11300 * next 1 byte is the version, and the
11301 * subsequent bytes are sequence parameter set like data. */
11303 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11305 gst_codec_utils_h264_caps_set_level_and_profile
11306 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11308 buf = gst_buffer_new_and_alloc (size);
11309 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11310 gst_caps_set_simple (entry->caps,
11311 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11312 gst_buffer_unref (buf);
11318 guint avg_bitrate, max_bitrate;
11320 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11324 max_bitrate = QT_UINT32 (avc_data + 0xc);
11325 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11327 if (!max_bitrate && !avg_bitrate)
11330 /* Some muxers seem to swap the average and maximum bitrates
11331 * (I'm looking at you, YouTube), so we swap for sanity. */
11332 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11333 guint temp = avg_bitrate;
11335 avg_bitrate = max_bitrate;
11336 max_bitrate = temp;
11339 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11340 gst_tag_list_add (stream->stream_tags,
11341 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11342 max_bitrate, NULL);
11344 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11345 gst_tag_list_add (stream->stream_tags,
11346 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11358 avc_data += size + 8;
11369 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11370 const guint8 *hevc_data = stsd_entry_data + 0x56;
11373 while (len >= 0x8) {
11376 if (QT_UINT32 (hevc_data) <= len)
11377 size = QT_UINT32 (hevc_data) - 0x8;
11382 /* No real data, so break out */
11385 switch (QT_FOURCC (hevc_data + 0x4)) {
11388 /* parse, if found */
11391 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11393 /* First 4 bytes are the length of the atom, the next 4 bytes
11394 * are the fourcc, the next 1 byte is the version, and the
11395 * subsequent bytes are sequence parameter set like data. */
11396 gst_codec_utils_h265_caps_set_level_tier_and_profile
11397 (entry->caps, hevc_data + 8 + 1, size - 1);
11399 buf = gst_buffer_new_and_alloc (size);
11400 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11401 gst_caps_set_simple (entry->caps,
11402 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11403 gst_buffer_unref (buf);
11410 hevc_data += size + 8;
11423 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11424 GST_FOURCC_ARGS (fourcc));
11426 /* codec data might be in glbl extension atom */
11428 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11434 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11436 len = QT_UINT32 (data);
11439 buf = gst_buffer_new_and_alloc (len);
11440 gst_buffer_fill (buf, 0, data + 8, len);
11441 gst_caps_set_simple (entry->caps,
11442 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11443 gst_buffer_unref (buf);
11450 /* see annex I of the jpeg2000 spec */
11451 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11452 const guint8 *data;
11453 const gchar *colorspace = NULL;
11455 guint32 ncomp_map = 0;
11456 gint32 *comp_map = NULL;
11457 guint32 nchan_def = 0;
11458 gint32 *chan_def = NULL;
11460 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11461 /* some required atoms */
11462 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11465 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11469 /* number of components; redundant with info in codestream, but useful
11471 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11472 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11474 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11476 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11479 GST_DEBUG_OBJECT (qtdemux, "found colr");
11480 /* extract colour space info */
11481 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11482 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11484 colorspace = "sRGB";
11487 colorspace = "GRAY";
11490 colorspace = "sYUV";
11498 /* colr is required, and only values 16, 17, and 18 are specified,
11499 so error if we have no colorspace */
11502 /* extract component mapping */
11503 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11505 guint32 cmap_len = 0;
11507 cmap_len = QT_UINT32 (cmap->data);
11508 if (cmap_len >= 8) {
11509 /* normal box, subtract off header */
11511 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11512 if (cmap_len % 4 == 0) {
11513 ncomp_map = (cmap_len / 4);
11514 comp_map = g_new0 (gint32, ncomp_map);
11515 for (i = 0; i < ncomp_map; i++) {
11518 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11519 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11520 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11521 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11526 /* extract channel definitions */
11527 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11529 guint32 cdef_len = 0;
11531 cdef_len = QT_UINT32 (cdef->data);
11532 if (cdef_len >= 10) {
11533 /* normal box, subtract off header and len */
11535 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11536 if (cdef_len % 6 == 0) {
11537 nchan_def = (cdef_len / 6);
11538 chan_def = g_new0 (gint32, nchan_def);
11539 for (i = 0; i < nchan_def; i++)
11541 for (i = 0; i < nchan_def; i++) {
11542 guint16 cn, typ, asoc;
11543 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11544 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11545 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11546 if (cn < nchan_def) {
11549 chan_def[cn] = asoc;
11552 chan_def[cn] = 0; /* alpha */
11555 chan_def[cn] = -typ;
11563 gst_caps_set_simple (entry->caps,
11564 "num-components", G_TYPE_INT, ncomp, NULL);
11565 gst_caps_set_simple (entry->caps,
11566 "colorspace", G_TYPE_STRING, colorspace, NULL);
11569 GValue arr = { 0, };
11570 GValue elt = { 0, };
11572 g_value_init (&arr, GST_TYPE_ARRAY);
11573 g_value_init (&elt, G_TYPE_INT);
11574 for (i = 0; i < ncomp_map; i++) {
11575 g_value_set_int (&elt, comp_map[i]);
11576 gst_value_array_append_value (&arr, &elt);
11578 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11579 "component-map", &arr);
11580 g_value_unset (&elt);
11581 g_value_unset (&arr);
11586 GValue arr = { 0, };
11587 GValue elt = { 0, };
11589 g_value_init (&arr, GST_TYPE_ARRAY);
11590 g_value_init (&elt, G_TYPE_INT);
11591 for (i = 0; i < nchan_def; i++) {
11592 g_value_set_int (&elt, chan_def[i]);
11593 gst_value_array_append_value (&arr, &elt);
11595 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11596 "channel-definitions", &arr);
11597 g_value_unset (&elt);
11598 g_value_unset (&arr);
11602 /* some optional atoms */
11603 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11604 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11606 /* indicate possible fields in caps */
11608 data = (guint8 *) field->data + 8;
11610 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11611 (gint) * data, NULL);
11613 /* add codec_data if provided */
11618 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11619 data = prefix->data;
11620 len = QT_UINT32 (data);
11623 buf = gst_buffer_new_and_alloc (len);
11624 gst_buffer_fill (buf, 0, data + 8, len);
11625 gst_caps_set_simple (entry->caps,
11626 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11627 gst_buffer_unref (buf);
11636 GstBuffer *seqh = NULL;
11637 const guint8 *gamma_data = NULL;
11638 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11640 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11643 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11644 QT_FP32 (gamma_data), NULL);
11647 /* sorry for the bad name, but we don't know what this is, other
11648 * than its own fourcc */
11649 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11651 gst_buffer_unref (seqh);
11654 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11655 buf = gst_buffer_new_and_alloc (len);
11656 gst_buffer_fill (buf, 0, stsd_data, len);
11657 gst_caps_set_simple (entry->caps,
11658 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11659 gst_buffer_unref (buf);
11664 /* https://developer.apple.com/standards/qtff-2001.pdf,
11665 * page 92, "Video Sample Description", under table 3.1 */
11668 const gint compressor_offset =
11669 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11670 const gint min_size = compressor_offset + 32 + 2 + 2;
11673 guint16 color_table_id = 0;
11676 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11678 /* recover information on interlaced/progressive */
11679 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11683 len = QT_UINT32 (jpeg->data);
11684 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11686 if (len >= min_size) {
11687 gst_byte_reader_init (&br, jpeg->data, len);
11689 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11690 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11691 if (color_table_id != 0) {
11692 /* the spec says there can be concatenated chunks in the data, and we want
11693 * to find one called field. Walk through them. */
11694 gint offset = min_size;
11695 while (offset + 8 < len) {
11696 guint32 size = 0, tag;
11697 ok = gst_byte_reader_get_uint32_le (&br, &size);
11698 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11699 if (!ok || size < 8) {
11700 GST_WARNING_OBJECT (qtdemux,
11701 "Failed to walk optional chunk list");
11704 GST_DEBUG_OBJECT (qtdemux,
11705 "Found optional %4.4s chunk, size %u",
11706 (const char *) &tag, size);
11707 if (tag == FOURCC_fiel) {
11708 guint8 n_fields = 0, ordering = 0;
11709 gst_byte_reader_get_uint8 (&br, &n_fields);
11710 gst_byte_reader_get_uint8 (&br, &ordering);
11711 if (n_fields == 1 || n_fields == 2) {
11712 GST_DEBUG_OBJECT (qtdemux,
11713 "Found fiel tag with %u fields, ordering %u",
11714 n_fields, ordering);
11716 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11717 "interlace-mode", G_TYPE_STRING, "interleaved",
11720 GST_WARNING_OBJECT (qtdemux,
11721 "Found fiel tag with invalid fields (%u)", n_fields);
11727 GST_DEBUG_OBJECT (qtdemux,
11728 "Color table ID is 0, not trying to get interlacedness");
11731 GST_WARNING_OBJECT (qtdemux,
11732 "Length of jpeg chunk is too small, not trying to get interlacedness");
11740 gst_caps_set_simple (entry->caps,
11741 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11747 GNode *xith, *xdxt;
11749 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11750 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11754 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11758 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11759 /* collect the headers and store them in a stream list so that we can
11760 * send them out first */
11761 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11771 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11772 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11775 ovc1_data = ovc1->data;
11776 ovc1_len = QT_UINT32 (ovc1_data);
11777 if (ovc1_len <= 198) {
11778 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11781 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11782 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11783 gst_caps_set_simple (entry->caps,
11784 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11785 gst_buffer_unref (buf);
11790 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11791 const guint8 *vc1_data = stsd_entry_data + 0x56;
11797 if (QT_UINT32 (vc1_data) <= len)
11798 size = QT_UINT32 (vc1_data) - 8;
11803 /* No real data, so break out */
11806 switch (QT_FOURCC (vc1_data + 0x4)) {
11807 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11811 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11812 buf = gst_buffer_new_and_alloc (size);
11813 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11814 gst_caps_set_simple (entry->caps,
11815 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11816 gst_buffer_unref (buf);
11823 vc1_data += size + 8;
11829 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11830 const guint8 *av1_data = stsd_entry_data + 0x56;
11833 while (len >= 0x8) {
11836 if (QT_UINT32 (av1_data) <= len)
11837 size = QT_UINT32 (av1_data) - 0x8;
11842 /* No real data, so break out */
11845 switch (QT_FOURCC (av1_data + 0x4)) {
11848 /* parse, if found */
11850 guint8 pres_delay_field;
11852 GST_DEBUG_OBJECT (qtdemux,
11853 "found av1C codec_data in stsd of size %d", size);
11855 /* not enough data, just ignore and hope for the best */
11860 * 4 bytes: atom length
11865 * 1 bits: initial_presentation_delay_present
11866 * 4 bits: initial_presentation_delay (if present else reserved
11870 if (av1_data[9] != 0) {
11871 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11875 /* We skip initial_presentation_delay* for now */
11876 pres_delay_field = *(av1_data + 12);
11877 if (pres_delay_field & (1 << 5)) {
11878 gst_caps_set_simple (entry->caps,
11879 "presentation-delay", G_TYPE_INT,
11880 (gint) (pres_delay_field & 0x0F) + 1, NULL);
11883 buf = gst_buffer_new_and_alloc (size - 5);
11884 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11885 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
11886 gst_caps_set_simple (entry->caps,
11887 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11888 gst_buffer_unref (buf);
11897 av1_data += size + 8;
11903 /* TODO: Need to parse vpcC for VP8 codec too.
11904 * Note that VPCodecConfigurationBox (vpcC) is defined for
11905 * vp08, vp09, and vp10 fourcc. */
11908 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11909 const guint8 *vpcc_data = stsd_entry_data + 0x56;
11912 while (len >= 0x8) {
11915 if (QT_UINT32 (vpcc_data) <= len)
11916 size = QT_UINT32 (vpcc_data) - 0x8;
11921 /* No real data, so break out */
11924 switch (QT_FOURCC (vpcc_data + 0x4)) {
11927 const gchar *profile_str = NULL;
11928 const gchar *chroma_format_str = NULL;
11931 guint8 chroma_format;
11932 GstVideoColorimetry cinfo;
11934 /* parse, if found */
11935 GST_DEBUG_OBJECT (qtdemux,
11936 "found vp codec_data in stsd of size %d", size);
11938 /* the meaning of "size" is length of the atom body, excluding
11939 * atom length and fourcc fields */
11944 * 4 bytes: atom length
11951 * 3 bits: chromaSubsampling
11952 * 1 bit: videoFullRangeFlag
11953 * 1 byte: colourPrimaries
11954 * 1 byte: transferCharacteristics
11955 * 1 byte: matrixCoefficients
11956 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
11957 * rest: codecIntializationData (not used for vp8 and vp9)
11960 if (vpcc_data[8] != 1) {
11961 GST_WARNING_OBJECT (qtdemux,
11962 "unknown vpcC version %d", vpcc_data[8]);
11966 profile = vpcc_data[12];
11985 gst_caps_set_simple (entry->caps,
11986 "profile", G_TYPE_STRING, profile_str, NULL);
11989 /* skip level, the VP9 spec v0.6 defines only one level atm,
11990 * but webm spec define various ones. Add level to caps
11991 * if we really need it then */
11993 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
11994 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
11995 gst_caps_set_simple (entry->caps,
11996 "bit-depth-luma", G_TYPE_UINT, bitdepth,
11997 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12000 chroma_format = (vpcc_data[14] & 0xe) >> 1;
12001 switch (chroma_format) {
12004 chroma_format_str = "4:2:0";
12007 chroma_format_str = "4:2:2";
12010 chroma_format_str = "4:4:4";
12016 if (chroma_format_str) {
12017 gst_caps_set_simple (entry->caps,
12018 "chroma-format", G_TYPE_STRING, chroma_format_str,
12022 if ((vpcc_data[14] & 0x1) != 0)
12023 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12025 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12027 gst_video_color_primaries_from_iso (vpcc_data[15]);
12029 gst_video_transfer_function_from_iso (vpcc_data[16]);
12031 gst_video_color_matrix_from_iso (vpcc_data[17]);
12033 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12034 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12035 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12036 /* set this only if all values are known, otherwise this
12037 * might overwrite valid ones parsed from other color box */
12038 CUR_STREAM (stream)->colorimetry = cinfo;
12047 vpcc_data += size + 8;
12057 GST_INFO_OBJECT (qtdemux,
12058 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12059 GST_FOURCC_ARGS (fourcc), entry->caps);
12061 } else if (stream->subtype == FOURCC_soun) {
12063 int version, samplesize;
12064 guint16 compression_id;
12065 gboolean amrwb = FALSE;
12068 /* sample description entry (16) + sound sample description v0 (20) */
12072 version = QT_UINT32 (stsd_entry_data + offset);
12073 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12074 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12075 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12076 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12078 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12079 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12080 QT_UINT32 (stsd_entry_data + offset + 4));
12081 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12082 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12083 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12084 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12085 QT_UINT16 (stsd_entry_data + offset + 14));
12086 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12088 if (compression_id == 0xfffe)
12089 entry->sampled = TRUE;
12091 /* first assume uncompressed audio */
12092 entry->bytes_per_sample = samplesize / 8;
12093 entry->samples_per_frame = entry->n_channels;
12094 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12095 entry->samples_per_packet = entry->samples_per_frame;
12096 entry->bytes_per_packet = entry->bytes_per_sample;
12100 if (version == 0x00010000) {
12101 /* sample description entry (16) + sound sample description v1 (20+16) */
12105 /* take information from here over the normal sample description */
12106 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12107 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12108 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12109 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12111 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12112 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12113 entry->samples_per_packet);
12114 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12115 entry->bytes_per_packet);
12116 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12117 entry->bytes_per_frame);
12118 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12119 entry->bytes_per_sample);
12121 if (!entry->sampled && entry->bytes_per_packet) {
12122 entry->samples_per_frame = (entry->bytes_per_frame /
12123 entry->bytes_per_packet) * entry->samples_per_packet;
12124 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12125 entry->samples_per_frame);
12127 } else if (version == 0x00020000) {
12128 /* sample description entry (16) + sound sample description v2 (56) */
12132 /* take information from here over the normal sample description */
12133 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12134 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12135 entry->samples_per_frame = entry->n_channels;
12136 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12137 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12138 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12139 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12141 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12142 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12143 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12144 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12145 entry->bytes_per_sample * 8);
12146 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12147 QT_UINT32 (stsd_entry_data + offset + 24));
12148 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12149 entry->bytes_per_packet);
12150 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12151 entry->samples_per_packet);
12152 } else if (version != 0x00000) {
12153 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12158 /* Yes, these have to be hard-coded */
12161 entry->samples_per_packet = 6;
12162 entry->bytes_per_packet = 1;
12163 entry->bytes_per_frame = 1 * entry->n_channels;
12164 entry->bytes_per_sample = 1;
12165 entry->samples_per_frame = 6 * entry->n_channels;
12170 entry->samples_per_packet = 3;
12171 entry->bytes_per_packet = 1;
12172 entry->bytes_per_frame = 1 * entry->n_channels;
12173 entry->bytes_per_sample = 1;
12174 entry->samples_per_frame = 3 * entry->n_channels;
12179 entry->samples_per_packet = 64;
12180 entry->bytes_per_packet = 34;
12181 entry->bytes_per_frame = 34 * entry->n_channels;
12182 entry->bytes_per_sample = 2;
12183 entry->samples_per_frame = 64 * entry->n_channels;
12189 entry->samples_per_packet = 1;
12190 entry->bytes_per_packet = 1;
12191 entry->bytes_per_frame = 1 * entry->n_channels;
12192 entry->bytes_per_sample = 1;
12193 entry->samples_per_frame = 1 * entry->n_channels;
12198 entry->samples_per_packet = 160;
12199 entry->bytes_per_packet = 33;
12200 entry->bytes_per_frame = 33 * entry->n_channels;
12201 entry->bytes_per_sample = 2;
12202 entry->samples_per_frame = 160 * entry->n_channels;
12205 /* fix up any invalid header information from above */
12210 /* Sometimes these are set to 0 in the sound sample descriptions so
12211 * let's try to infer useful values from the other information we
12212 * have available */
12213 if (entry->bytes_per_sample == 0)
12214 entry->bytes_per_sample =
12215 entry->bytes_per_frame / entry->n_channels;
12216 if (entry->bytes_per_sample == 0)
12217 entry->bytes_per_sample = samplesize / 8;
12219 if (entry->bytes_per_frame == 0)
12220 entry->bytes_per_frame =
12221 entry->bytes_per_sample * entry->n_channels;
12223 if (entry->bytes_per_packet == 0)
12224 entry->bytes_per_packet = entry->bytes_per_sample;
12226 if (entry->samples_per_frame == 0)
12227 entry->samples_per_frame = entry->n_channels;
12229 if (entry->samples_per_packet == 0)
12230 entry->samples_per_packet = entry->samples_per_frame;
12240 entry->bytes_per_sample = 3;
12244 entry->bytes_per_sample = 4;
12247 entry->bytes_per_sample = 8;
12250 entry->bytes_per_sample = 2;
12253 g_assert_not_reached ();
12256 entry->samples_per_frame = entry->n_channels;
12257 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12258 entry->samples_per_packet = entry->samples_per_frame;
12259 entry->bytes_per_packet = entry->bytes_per_sample;
12267 gst_caps_unref (entry->caps);
12269 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12270 stsd_entry_data + 32, len - 16, &codec);
12281 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12283 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12285 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12287 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12290 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12291 const gchar *format_str;
12295 format_str = (enda_value) ? "S24LE" : "S24BE";
12298 format_str = (enda_value) ? "S32LE" : "S32BE";
12301 format_str = (enda_value) ? "F32LE" : "F32BE";
12304 format_str = (enda_value) ? "F64LE" : "F64BE";
12307 g_assert_not_reached ();
12310 gst_caps_set_simple (entry->caps,
12311 "format", G_TYPE_STRING, format_str, NULL);
12317 const guint8 *owma_data;
12318 const gchar *codec_name = NULL;
12322 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12323 /* FIXME this should also be gst_riff_strf_auds,
12324 * but the latter one is actually missing bits-per-sample :( */
12329 gint32 nSamplesPerSec;
12330 gint32 nAvgBytesPerSec;
12331 gint16 nBlockAlign;
12332 gint16 wBitsPerSample;
12335 WAVEFORMATEX *wfex;
12337 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12338 owma_data = stsd_entry_data;
12339 owma_len = QT_UINT32 (owma_data);
12340 if (owma_len <= 54) {
12341 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12344 wfex = (WAVEFORMATEX *) (owma_data + 36);
12345 buf = gst_buffer_new_and_alloc (owma_len - 54);
12346 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12347 if (wfex->wFormatTag == 0x0161) {
12348 codec_name = "Windows Media Audio";
12350 } else if (wfex->wFormatTag == 0x0162) {
12351 codec_name = "Windows Media Audio 9 Pro";
12353 } else if (wfex->wFormatTag == 0x0163) {
12354 codec_name = "Windows Media Audio 9 Lossless";
12355 /* is that correct? gstffmpegcodecmap.c is missing it, but
12356 * fluendo codec seems to support it */
12360 gst_caps_set_simple (entry->caps,
12361 "codec_data", GST_TYPE_BUFFER, buf,
12362 "wmaversion", G_TYPE_INT, version,
12363 "block_align", G_TYPE_INT,
12364 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12365 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12366 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12367 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12368 gst_buffer_unref (buf);
12372 codec = g_strdup (codec_name);
12378 gint len = QT_UINT32 (stsd_entry_data) - offset;
12379 const guint8 *wfex_data = stsd_entry_data + offset;
12380 const gchar *codec_name = NULL;
12382 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12383 /* FIXME this should also be gst_riff_strf_auds,
12384 * but the latter one is actually missing bits-per-sample :( */
12389 gint32 nSamplesPerSec;
12390 gint32 nAvgBytesPerSec;
12391 gint16 nBlockAlign;
12392 gint16 wBitsPerSample;
12397 /* FIXME: unify with similar wavformatex parsing code above */
12398 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12404 if (QT_UINT32 (wfex_data) <= len)
12405 size = QT_UINT32 (wfex_data) - 8;
12410 /* No real data, so break out */
12413 switch (QT_FOURCC (wfex_data + 4)) {
12414 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12416 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12421 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12422 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12423 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12424 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12425 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12426 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12427 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12429 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12430 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12431 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12432 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12433 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12434 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12436 if (wfex.wFormatTag == 0x0161) {
12437 codec_name = "Windows Media Audio";
12439 } else if (wfex.wFormatTag == 0x0162) {
12440 codec_name = "Windows Media Audio 9 Pro";
12442 } else if (wfex.wFormatTag == 0x0163) {
12443 codec_name = "Windows Media Audio 9 Lossless";
12444 /* is that correct? gstffmpegcodecmap.c is missing it, but
12445 * fluendo codec seems to support it */
12449 gst_caps_set_simple (entry->caps,
12450 "wmaversion", G_TYPE_INT, version,
12451 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12452 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12453 "width", G_TYPE_INT, wfex.wBitsPerSample,
12454 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12456 if (size > wfex.cbSize) {
12459 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12460 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12461 size - wfex.cbSize);
12462 gst_caps_set_simple (entry->caps,
12463 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12464 gst_buffer_unref (buf);
12466 GST_WARNING_OBJECT (qtdemux, "no codec data");
12471 codec = g_strdup (codec_name);
12479 wfex_data += size + 8;
12485 const guint8 *dops_data;
12486 guint8 *channel_mapping = NULL;
12489 guint8 channel_mapping_family;
12490 guint8 stream_count;
12491 guint8 coupled_count;
12494 version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12496 dops_data = stsd_entry_data + 51;
12498 dops_data = stsd_entry_data + 35;
12500 channels = GST_READ_UINT8 (dops_data + 10);
12501 rate = GST_READ_UINT32_LE (dops_data + 13);
12502 channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12503 stream_count = GST_READ_UINT8 (dops_data + 20);
12504 coupled_count = GST_READ_UINT8 (dops_data + 21);
12506 if (channels > 0) {
12507 channel_mapping = g_malloc (channels * sizeof (guint8));
12508 for (i = 0; i < channels; i++)
12509 channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12512 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12513 channel_mapping_family, stream_count, coupled_count,
12525 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12526 GST_TAG_AUDIO_CODEC, codec, NULL);
12530 /* some bitrate info may have ended up in caps */
12531 s = gst_caps_get_structure (entry->caps, 0);
12532 gst_structure_get_int (s, "bitrate", &bitrate);
12534 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12535 GST_TAG_BITRATE, bitrate, NULL);
12539 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12540 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12541 if (stream->protected) {
12542 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12543 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12545 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12555 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12557 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12559 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12563 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12564 16 bits is a byte-swapped wave-style codec identifier,
12565 and we can find a WAVE header internally to a 'wave' atom here.
12566 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12567 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12570 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12571 if (len < offset + 20) {
12572 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12574 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12575 const guint8 *data = stsd_entry_data + offset + 16;
12577 GNode *waveheadernode;
12579 wavenode = g_node_new ((guint8 *) data);
12580 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12581 const guint8 *waveheader;
12584 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12585 if (waveheadernode) {
12586 waveheader = (const guint8 *) waveheadernode->data;
12587 headerlen = QT_UINT32 (waveheader);
12589 if (headerlen > 8) {
12590 gst_riff_strf_auds *header = NULL;
12591 GstBuffer *headerbuf;
12597 headerbuf = gst_buffer_new_and_alloc (headerlen);
12598 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12600 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12601 headerbuf, &header, &extra)) {
12602 gst_caps_unref (entry->caps);
12603 /* FIXME: Need to do something with the channel reorder map */
12605 gst_riff_create_audio_caps (header->format, NULL, header,
12606 extra, NULL, NULL, NULL);
12609 gst_buffer_unref (extra);
12614 GST_DEBUG ("Didn't find waveheadernode for this codec");
12616 g_node_destroy (wavenode);
12619 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12620 stream->stream_tags);
12624 /* FIXME: what is in the chunk? */
12627 gint len = QT_UINT32 (stsd_data);
12629 /* seems to be always = 116 = 0x74 */
12635 gint len = QT_UINT32 (stsd_entry_data);
12638 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12640 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12641 gst_caps_set_simple (entry->caps,
12642 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12643 gst_buffer_unref (buf);
12645 gst_caps_set_simple (entry->caps,
12646 "samplesize", G_TYPE_INT, samplesize, NULL);
12651 GNode *alac, *wave = NULL;
12653 /* apparently, m4a has this atom appended directly in the stsd entry,
12654 * while mov has it in a wave atom */
12655 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12657 /* alac now refers to stsd entry atom */
12658 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12660 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12662 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12665 const guint8 *alac_data = alac->data;
12666 gint len = QT_UINT32 (alac->data);
12670 GST_DEBUG_OBJECT (qtdemux,
12671 "discarding alac atom with unexpected len %d", len);
12673 /* codec-data contains alac atom size and prefix,
12674 * ffmpeg likes it that way, not quite gst-ish though ...*/
12675 buf = gst_buffer_new_and_alloc (len);
12676 gst_buffer_fill (buf, 0, alac->data, len);
12677 gst_caps_set_simple (entry->caps,
12678 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12679 gst_buffer_unref (buf);
12681 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12682 entry->n_channels = QT_UINT8 (alac_data + 21);
12683 entry->rate = QT_UINT32 (alac_data + 32);
12684 samplesize = QT_UINT8 (alac_data + 16 + 1);
12687 gst_caps_set_simple (entry->caps,
12688 "samplesize", G_TYPE_INT, samplesize, NULL);
12693 /* The codingname of the sample entry is 'fLaC' */
12694 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12697 /* The 'dfLa' box is added to the sample entry to convey
12698 initializing information for the decoder. */
12699 const GNode *dfla =
12700 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12703 const guint32 len = QT_UINT32 (dfla->data);
12705 /* Must contain at least dfLa box header (12),
12706 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12708 GST_DEBUG_OBJECT (qtdemux,
12709 "discarding dfla atom with unexpected len %d", len);
12711 /* skip dfLa header to get the METADATA_BLOCKs */
12712 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12713 const guint32 metadata_blocks_len = len - 12;
12715 gchar *stream_marker = g_strdup ("fLaC");
12716 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12717 strlen (stream_marker));
12720 guint32 remainder = 0;
12721 guint32 block_size = 0;
12722 gboolean is_last = FALSE;
12724 GValue array = G_VALUE_INIT;
12725 GValue value = G_VALUE_INIT;
12727 g_value_init (&array, GST_TYPE_ARRAY);
12728 g_value_init (&value, GST_TYPE_BUFFER);
12730 gst_value_set_buffer (&value, block);
12731 gst_value_array_append_value (&array, &value);
12732 g_value_reset (&value);
12734 gst_buffer_unref (block);
12736 /* check there's at least one METADATA_BLOCK_HEADER's worth
12737 * of data, and we haven't already finished parsing */
12738 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12739 remainder = metadata_blocks_len - index;
12741 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12743 (metadata_blocks[index + 1] << 16) +
12744 (metadata_blocks[index + 2] << 8) +
12745 metadata_blocks[index + 3];
12747 /* be careful not to read off end of box */
12748 if (block_size > remainder) {
12752 is_last = metadata_blocks[index] >> 7;
12754 block = gst_buffer_new_and_alloc (block_size);
12756 gst_buffer_fill (block, 0, &metadata_blocks[index],
12759 gst_value_set_buffer (&value, block);
12760 gst_value_array_append_value (&array, &value);
12761 g_value_reset (&value);
12763 gst_buffer_unref (block);
12765 index += block_size;
12768 /* only append the metadata if we successfully read all of it */
12770 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12771 (stream)->caps, 0), "streamheader", &array);
12773 GST_WARNING_OBJECT (qtdemux,
12774 "discarding all METADATA_BLOCKs due to invalid "
12775 "block_size %d at idx %d, rem %d", block_size, index,
12779 g_value_unset (&value);
12780 g_value_unset (&array);
12782 /* The sample rate obtained from the stsd may not be accurate
12783 * since it cannot represent rates greater than 65535Hz, so
12784 * override that value with the sample rate from the
12785 * METADATA_BLOCK_STREAMINFO block */
12786 CUR_STREAM (stream)->rate =
12787 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12798 gint len = QT_UINT32 (stsd_entry_data);
12801 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12804 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12806 /* If we have enough data, let's try to get the 'damr' atom. See
12807 * the 3GPP container spec (26.244) for more details. */
12808 if ((len - 0x34) > 8 &&
12809 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12810 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12811 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12814 gst_caps_set_simple (entry->caps,
12815 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12816 gst_buffer_unref (buf);
12822 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12823 gint len = QT_UINT32 (stsd_entry_data);
12824 guint16 sound_version = 0;
12825 /* FIXME: Can this be determined somehow? There doesn't seem to be
12826 * anything in mp4a atom that specifis compression */
12828 guint16 channels = entry->n_channels;
12829 guint32 time_scale = (guint32) entry->rate;
12830 gint sample_rate_index = -1;
12833 sound_version = QT_UINT16 (stsd_entry_data + 16);
12835 if (sound_version == 1) {
12836 channels = QT_UINT16 (stsd_entry_data + 24);
12837 time_scale = QT_UINT32 (stsd_entry_data + 30);
12839 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
12843 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
12847 sample_rate_index =
12848 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12849 if (sample_rate_index >= 0 && channels > 0) {
12850 guint8 codec_data[2];
12853 /* build AAC codec data */
12854 codec_data[0] = profile << 3;
12855 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12856 codec_data[1] = (sample_rate_index & 0x01) << 7;
12857 codec_data[1] |= (channels & 0xF) << 3;
12859 buf = gst_buffer_new_and_alloc (2);
12860 gst_buffer_fill (buf, 0, codec_data, 2);
12861 gst_caps_set_simple (entry->caps,
12862 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12863 gst_buffer_unref (buf);
12873 /* Fully handled elsewhere */
12876 GST_INFO_OBJECT (qtdemux,
12877 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12881 GST_INFO_OBJECT (qtdemux,
12882 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12883 GST_FOURCC_ARGS (fourcc), entry->caps);
12885 } else if (stream->subtype == FOURCC_strm) {
12886 if (fourcc == FOURCC_rtsp) {
12887 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12889 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12890 GST_FOURCC_ARGS (fourcc));
12891 goto unknown_stream;
12893 entry->sampled = TRUE;
12894 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12895 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12896 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
12898 entry->sampled = TRUE;
12899 entry->sparse = TRUE;
12902 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12905 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12906 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12911 /* hunt for sort-of codec data */
12915 GNode *mp4s = NULL;
12916 GNode *esds = NULL;
12918 /* look for palette in a stsd->mp4s->esds sub-atom */
12919 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12921 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12922 if (esds == NULL) {
12924 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12928 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12929 stream->stream_tags);
12933 GST_INFO_OBJECT (qtdemux,
12934 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12937 GST_INFO_OBJECT (qtdemux,
12938 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12939 GST_FOURCC_ARGS (fourcc), entry->caps);
12941 /* everything in 1 sample */
12942 entry->sampled = TRUE;
12945 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12948 if (entry->caps == NULL)
12949 goto unknown_stream;
12952 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12953 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12959 /* promote to sampled format */
12960 if (entry->fourcc == FOURCC_samr) {
12961 /* force mono 8000 Hz for AMR */
12962 entry->sampled = TRUE;
12963 entry->n_channels = 1;
12964 entry->rate = 8000;
12965 } else if (entry->fourcc == FOURCC_sawb) {
12966 /* force mono 16000 Hz for AMR-WB */
12967 entry->sampled = TRUE;
12968 entry->n_channels = 1;
12969 entry->rate = 16000;
12970 } else if (entry->fourcc == FOURCC_mp4a) {
12971 entry->sampled = TRUE;
12975 stsd_entry_data += len;
12976 remaining_stsd_len -= len;
12980 /* collect sample information */
12981 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12982 goto samples_failed;
12984 if (qtdemux->fragmented) {
12987 /* need all moov samples as basis; probably not many if any at all */
12988 /* prevent moof parsing taking of at this time */
12989 offset = qtdemux->moof_offset;
12990 qtdemux->moof_offset = 0;
12991 if (stream->n_samples &&
12992 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12993 qtdemux->moof_offset = offset;
12994 goto samples_failed;
12996 qtdemux->moof_offset = offset;
12997 /* movie duration more reliable in this case (e.g. mehd) */
12998 if (qtdemux->segment.duration &&
12999 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13001 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13004 /* configure segments */
13005 if (!qtdemux_parse_segments (qtdemux, stream, trak))
13006 goto segments_failed;
13008 /* add some language tag, if useful */
13009 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13010 strcmp (stream->lang_id, "und")) {
13011 const gchar *lang_code;
13013 /* convert ISO 639-2 code to ISO 639-1 */
13014 lang_code = gst_tag_get_language_code (stream->lang_id);
13015 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13016 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13019 /* Check for UDTA tags */
13020 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13021 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13024 /* Insert and sort new stream in track-id order.
13025 * This will help in comparing old/new streams during stream update check */
13026 g_ptr_array_add (qtdemux->active_streams, stream);
13027 g_ptr_array_sort (qtdemux->active_streams,
13028 (GCompareFunc) qtdemux_track_id_compare_func);
13029 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13030 QTDEMUX_N_STREAMS (qtdemux));
13037 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13038 (_("This file is corrupt and cannot be played.")), (NULL));
13040 gst_qtdemux_stream_unref (stream);
13045 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13046 gst_qtdemux_stream_unref (stream);
13052 /* we posted an error already */
13053 /* free stbl sub-atoms */
13054 gst_qtdemux_stbl_free (stream);
13055 gst_qtdemux_stream_unref (stream);
13060 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13066 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13067 GST_FOURCC_ARGS (stream->subtype));
13068 gst_qtdemux_stream_unref (stream);
13073 /* If we can estimate the overall bitrate, and don't have information about the
13074 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13075 * the overall bitrate minus the sum of the bitrates of all other streams. This
13076 * should be useful for the common case where we have one audio and one video
13077 * stream and can estimate the bitrate of one, but not the other. */
13079 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13081 QtDemuxStream *stream = NULL;
13082 gint64 size, sys_bitrate, sum_bitrate = 0;
13083 GstClockTime duration;
13087 if (qtdemux->fragmented)
13090 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13092 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13094 GST_DEBUG_OBJECT (qtdemux,
13095 "Size in bytes of the stream not known - bailing");
13099 /* Subtract the header size */
13100 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13101 size, qtdemux->header_size);
13103 if (size < qtdemux->header_size)
13106 size = size - qtdemux->header_size;
13108 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13109 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13113 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13114 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13115 switch (str->subtype) {
13118 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13119 CUR_STREAM (str)->caps);
13120 /* retrieve bitrate, prefer avg then max */
13122 if (str->stream_tags) {
13123 if (gst_tag_list_get_uint (str->stream_tags,
13124 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13125 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13126 if (gst_tag_list_get_uint (str->stream_tags,
13127 GST_TAG_NOMINAL_BITRATE, &bitrate))
13128 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13129 if (gst_tag_list_get_uint (str->stream_tags,
13130 GST_TAG_BITRATE, &bitrate))
13131 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13134 sum_bitrate += bitrate;
13137 GST_DEBUG_OBJECT (qtdemux,
13138 ">1 stream with unknown bitrate - bailing");
13145 /* For other subtypes, we assume no significant impact on bitrate */
13151 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13155 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13157 if (sys_bitrate < sum_bitrate) {
13158 /* This can happen, since sum_bitrate might be derived from maximum
13159 * bitrates and not average bitrates */
13160 GST_DEBUG_OBJECT (qtdemux,
13161 "System bitrate less than sum bitrate - bailing");
13165 bitrate = sys_bitrate - sum_bitrate;
13166 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13167 ", Stream bitrate = %u", sys_bitrate, bitrate);
13169 if (!stream->stream_tags)
13170 stream->stream_tags = gst_tag_list_new_empty ();
13172 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13174 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13175 GST_TAG_BITRATE, bitrate, NULL);
13178 static GstFlowReturn
13179 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13181 GstFlowReturn ret = GST_FLOW_OK;
13184 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13186 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13187 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13188 guint32 sample_num = 0;
13190 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13191 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13193 if (qtdemux->fragmented && qtdemux->pullbased) {
13194 /* need all moov samples first */
13195 GST_OBJECT_LOCK (qtdemux);
13196 while (stream->n_samples == 0)
13197 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13199 GST_OBJECT_UNLOCK (qtdemux);
13201 /* discard any stray moof */
13202 qtdemux->moof_offset = 0;
13205 /* prepare braking */
13206 if (ret != GST_FLOW_ERROR)
13209 /* in pull mode, we should have parsed some sample info by now;
13210 * and quite some code will not handle no samples.
13211 * in push mode, we'll just have to deal with it */
13212 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13213 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13214 g_ptr_array_remove_index (qtdemux->active_streams, i);
13217 } else if (stream->track_id == qtdemux->chapters_track_id &&
13218 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13219 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13220 so that it doesn't look like a subtitle track */
13221 g_ptr_array_remove_index (qtdemux->active_streams, i);
13226 /* parse the initial sample for use in setting the frame rate cap */
13227 while (sample_num == 0 && sample_num < stream->n_samples) {
13228 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13238 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13240 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13244 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13248 /* Different length, updated */
13249 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13252 /* streams in list are sorted in track-id order */
13253 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13254 /* Different stream-id, updated */
13255 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13256 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13264 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13265 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13267 /* Connect old stream's srcpad to new stream */
13268 newstream->pad = oldstream->pad;
13269 oldstream->pad = NULL;
13271 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13272 * case we need to force one through */
13273 newstream->new_stream = GST_PAD_IS_EOS (newstream->pad);
13275 return gst_qtdemux_configure_stream (qtdemux, newstream);
13279 qtdemux_update_streams (GstQTDemux * qtdemux)
13282 g_assert (qtdemux->streams_aware);
13284 /* At below, figure out which stream in active_streams has identical stream-id
13285 * with that of in old_streams. If there is matching stream-id,
13286 * corresponding newstream will not be exposed again,
13287 * but demux will reuse srcpad of matched old stream
13289 * active_streams : newly created streams from the latest moov
13290 * old_streams : existing streams (belong to previous moov)
13293 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13294 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13295 QtDemuxStream *oldstream = NULL;
13298 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13299 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13301 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13302 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13303 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13305 /* null pad stream cannot be reused */
13306 if (oldstream->pad == NULL)
13311 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13313 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13316 /* we don't need to preserve order of old streams */
13317 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13321 /* now we have all info and can expose */
13322 list = stream->stream_tags;
13323 stream->stream_tags = NULL;
13324 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13332 /* Must be called with expose lock */
13333 static GstFlowReturn
13334 qtdemux_expose_streams (GstQTDemux * qtdemux)
13338 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13340 if (!qtdemux_is_streams_update (qtdemux)) {
13341 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13342 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13343 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13344 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13345 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13346 return GST_FLOW_ERROR;
13349 g_ptr_array_set_size (qtdemux->old_streams, 0);
13350 qtdemux->need_segment = TRUE;
13352 return GST_FLOW_OK;
13355 if (qtdemux->streams_aware) {
13356 if (!qtdemux_update_streams (qtdemux))
13357 return GST_FLOW_ERROR;
13359 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13360 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13363 /* now we have all info and can expose */
13364 list = stream->stream_tags;
13365 stream->stream_tags = NULL;
13366 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13367 return GST_FLOW_ERROR;
13372 gst_qtdemux_guess_bitrate (qtdemux);
13374 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13376 /* If we have still old_streams, it's no more used stream */
13377 for (i = 0; i < qtdemux->old_streams->len; i++) {
13378 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13383 event = gst_event_new_eos ();
13384 if (qtdemux->segment_seqnum)
13385 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13387 gst_pad_push_event (stream->pad, event);
13391 g_ptr_array_set_size (qtdemux->old_streams, 0);
13393 /* check if we should post a redirect in case there is a single trak
13394 * and it is a redirecting trak */
13395 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13396 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13399 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13400 "an external content");
13401 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13402 gst_structure_new ("redirect",
13403 "new-location", G_TYPE_STRING,
13404 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13405 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13406 g_free (qtdemux->redirect_location);
13407 qtdemux->redirect_location =
13408 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13411 g_ptr_array_foreach (qtdemux->active_streams,
13412 (GFunc) qtdemux_do_allocation, qtdemux);
13414 qtdemux->need_segment = TRUE;
13416 qtdemux->exposed = TRUE;
13417 return GST_FLOW_OK;
13422 GstStructure *structure; /* helper for sort function */
13424 guint min_req_bitrate;
13425 guint min_req_qt_version;
13429 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13431 GstQtReference *ref_a = (GstQtReference *) a;
13432 GstQtReference *ref_b = (GstQtReference *) b;
13434 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13435 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13437 /* known bitrates go before unknown; higher bitrates go first */
13438 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13441 /* sort the redirects and post a message for the application.
13444 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13446 GstQtReference *best;
13449 GValue list_val = { 0, };
13452 g_assert (references != NULL);
13454 references = g_list_sort (references, qtdemux_redirects_sort_func);
13456 best = (GstQtReference *) references->data;
13458 g_value_init (&list_val, GST_TYPE_LIST);
13460 for (l = references; l != NULL; l = l->next) {
13461 GstQtReference *ref = (GstQtReference *) l->data;
13462 GValue struct_val = { 0, };
13464 ref->structure = gst_structure_new ("redirect",
13465 "new-location", G_TYPE_STRING, ref->location, NULL);
13467 if (ref->min_req_bitrate > 0) {
13468 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13469 ref->min_req_bitrate, NULL);
13472 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13473 g_value_set_boxed (&struct_val, ref->structure);
13474 gst_value_list_append_value (&list_val, &struct_val);
13475 g_value_unset (&struct_val);
13476 /* don't free anything here yet, since we need best->structure below */
13479 g_assert (best != NULL);
13480 s = gst_structure_copy (best->structure);
13482 if (g_list_length (references) > 1) {
13483 gst_structure_set_value (s, "locations", &list_val);
13486 g_value_unset (&list_val);
13488 for (l = references; l != NULL; l = l->next) {
13489 GstQtReference *ref = (GstQtReference *) l->data;
13491 gst_structure_free (ref->structure);
13492 g_free (ref->location);
13495 g_list_free (references);
13497 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13498 g_free (qtdemux->redirect_location);
13499 qtdemux->redirect_location =
13500 g_strdup (gst_structure_get_string (s, "new-location"));
13501 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13502 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13505 /* look for redirect nodes, collect all redirect information and
13509 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13511 GNode *rmra, *rmda, *rdrf;
13513 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13515 GList *redirects = NULL;
13517 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13519 GstQtReference ref = { NULL, NULL, 0, 0 };
13520 GNode *rmdr, *rmvc;
13522 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13523 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13524 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13525 ref.min_req_bitrate);
13528 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13529 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13530 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13532 #ifndef GST_DISABLE_GST_DEBUG
13533 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13535 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13537 GST_LOG_OBJECT (qtdemux,
13538 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13539 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13540 bitmask, check_type);
13541 if (package == FOURCC_qtim && check_type == 0) {
13542 ref.min_req_qt_version = version;
13546 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13552 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13553 if (ref_len > 20) {
13554 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13555 ref_data = (guint8 *) rdrf->data + 20;
13556 if (ref_type == FOURCC_alis) {
13557 guint record_len, record_version, fn_len;
13559 if (ref_len > 70) {
13560 /* MacOSX alias record, google for alias-layout.txt */
13561 record_len = QT_UINT16 (ref_data + 4);
13562 record_version = QT_UINT16 (ref_data + 4 + 2);
13563 fn_len = QT_UINT8 (ref_data + 50);
13564 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13565 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13568 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13571 } else if (ref_type == FOURCC_url_) {
13572 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13574 GST_DEBUG_OBJECT (qtdemux,
13575 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13576 GST_FOURCC_ARGS (ref_type));
13578 if (ref.location != NULL) {
13579 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13581 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13583 GST_WARNING_OBJECT (qtdemux,
13584 "Failed to extract redirect location from rdrf atom");
13587 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13591 /* look for others */
13592 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13595 if (redirects != NULL) {
13596 qtdemux_process_redirects (qtdemux, redirects);
13602 static GstTagList *
13603 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13607 if (tags == NULL) {
13608 tags = gst_tag_list_new_empty ();
13609 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13612 if (qtdemux->major_brand == FOURCC_mjp2)
13613 fmt = "Motion JPEG 2000";
13614 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13616 else if (qtdemux->major_brand == FOURCC_qt__)
13618 else if (qtdemux->fragmented)
13621 fmt = "ISO MP4/M4A";
13623 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13624 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13626 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13632 /* we have read the complete moov node now.
13633 * This function parses all of the relevant info, creates the traks and
13634 * prepares all data structures for playback
13637 qtdemux_parse_tree (GstQTDemux * qtdemux)
13644 guint64 creation_time;
13645 GstDateTime *datetime = NULL;
13648 /* make sure we have a usable taglist */
13649 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13651 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13652 if (mvhd == NULL) {
13653 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13654 return qtdemux_parse_redirects (qtdemux);
13657 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13658 if (version == 1) {
13659 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13660 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13661 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13662 } else if (version == 0) {
13663 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13664 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13665 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13667 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13671 /* Moving qt creation time (secs since 1904) to unix time */
13672 if (creation_time != 0) {
13673 /* Try to use epoch first as it should be faster and more commonly found */
13674 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13677 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13678 /* some data cleansing sanity */
13679 now_s = g_get_real_time () / G_USEC_PER_SEC;
13680 if (now_s + 24 * 3600 < creation_time) {
13681 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13683 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13686 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13687 GDateTime *dt, *dt_local;
13689 dt = g_date_time_add_seconds (base_dt, creation_time);
13690 dt_local = g_date_time_to_local (dt);
13691 datetime = gst_date_time_new_from_g_date_time (dt_local);
13693 g_date_time_unref (base_dt);
13694 g_date_time_unref (dt);
13698 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13699 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13701 gst_date_time_unref (datetime);
13704 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13705 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13707 /* check for fragmented file and get some (default) data */
13708 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13711 GstByteReader mehd_data;
13713 /* let track parsing or anyone know weird stuff might happen ... */
13714 qtdemux->fragmented = TRUE;
13716 /* compensate for total duration */
13717 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13719 qtdemux_parse_mehd (qtdemux, &mehd_data);
13722 /* Update the movie segment duration, unless it was directly given to us
13723 * by upstream. Otherwise let it as is, as we don't want to mangle the
13724 * duration provided by upstream that may come e.g. from a MPD file. */
13725 if (!qtdemux->upstream_format_is_time) {
13726 GstClockTime duration;
13727 /* set duration in the segment info */
13728 gst_qtdemux_get_duration (qtdemux, &duration);
13729 qtdemux->segment.duration = duration;
13730 /* also do not exceed duration; stop is set that way post seek anyway,
13731 * and segment activation falls back to duration,
13732 * whereas loop only checks stop, so let's align this here as well */
13733 qtdemux->segment.stop = duration;
13736 /* parse all traks */
13737 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13739 qtdemux_parse_trak (qtdemux, trak);
13740 /* iterate all siblings */
13741 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13744 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13747 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13749 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13751 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13754 /* maybe also some tags in meta box */
13755 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13757 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13758 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13760 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13763 /* parse any protection system info */
13764 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13766 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13767 qtdemux_parse_pssh (qtdemux, pssh);
13768 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13771 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13776 /* taken from ffmpeg */
13778 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13790 len = (len << 7) | (c & 0x7f);
13799 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13800 gsize codec_data_size)
13802 GList *list = NULL;
13803 guint8 *p = codec_data;
13804 gint i, offset, num_packets;
13805 guint *length, last;
13807 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13809 if (codec_data == NULL || codec_data_size == 0)
13812 /* start of the stream and vorbis audio or theora video, need to
13813 * send the codec_priv data as first three packets */
13814 num_packets = p[0] + 1;
13815 GST_DEBUG_OBJECT (qtdemux,
13816 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13817 (guint) num_packets, codec_data_size);
13819 /* Let's put some limits, Don't think there even is a xiph codec
13820 * with more than 3-4 headers */
13821 if (G_UNLIKELY (num_packets > 16)) {
13822 GST_WARNING_OBJECT (qtdemux,
13823 "Unlikely number of xiph headers, most likely not valid");
13827 length = g_alloca (num_packets * sizeof (guint));
13831 /* first packets, read length values */
13832 for (i = 0; i < num_packets - 1; i++) {
13834 while (offset < codec_data_size) {
13835 length[i] += p[offset];
13836 if (p[offset++] != 0xff)
13841 if (offset + last > codec_data_size)
13844 /* last packet is the remaining size */
13845 length[i] = codec_data_size - offset - last;
13847 for (i = 0; i < num_packets; i++) {
13850 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
13852 if (offset + length[i] > codec_data_size)
13855 hdr = gst_buffer_new_memdup (p + offset, length[i]);
13856 list = g_list_append (list, hdr);
13858 offset += length[i];
13867 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
13873 /* this can change the codec originally present in @list */
13875 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13876 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13878 int len = QT_UINT32 (esds->data);
13879 guint8 *ptr = esds->data;
13880 guint8 *end = ptr + len;
13882 guint8 *data_ptr = NULL;
13884 guint8 object_type_id = 0;
13885 guint8 stream_type = 0;
13886 const char *codec_name = NULL;
13887 GstCaps *caps = NULL;
13889 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13891 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13893 while (ptr + 1 < end) {
13894 tag = QT_UINT8 (ptr);
13895 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13897 len = read_descr_size (ptr, end, &ptr);
13898 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13900 /* Check the stated amount of data is available for reading */
13901 if (len < 0 || ptr + len > end)
13905 case ES_DESCRIPTOR_TAG:
13906 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
13907 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
13910 case DECODER_CONFIG_DESC_TAG:{
13911 guint max_bitrate, avg_bitrate;
13913 object_type_id = QT_UINT8 (ptr);
13914 stream_type = QT_UINT8 (ptr + 1) >> 2;
13915 max_bitrate = QT_UINT32 (ptr + 5);
13916 avg_bitrate = QT_UINT32 (ptr + 9);
13917 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13918 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
13919 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13920 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13921 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13922 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13923 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13924 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13926 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13927 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13928 avg_bitrate, NULL);
13933 case DECODER_SPECIFIC_INFO_TAG:
13934 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13935 if (object_type_id == 0xe0 && len == 0x40) {
13941 GST_DEBUG_OBJECT (qtdemux,
13942 "Have VOBSUB palette. Creating palette event");
13943 /* move to decConfigDescr data and read palette */
13945 for (i = 0; i < 16; i++) {
13946 clut[i] = QT_UINT32 (data);
13950 s = gst_structure_new ("application/x-gst-dvd", "event",
13951 G_TYPE_STRING, "dvd-spu-clut-change",
13952 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13953 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13954 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13955 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13956 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13957 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13958 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13959 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13962 /* store event and trigger custom processing */
13963 stream->pending_event =
13964 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13966 /* Generic codec_data handler puts it on the caps */
13973 case SL_CONFIG_DESC_TAG:
13974 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13978 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13980 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13986 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13987 * in use, and should also be used to override some other parameters for some
13989 switch (object_type_id) {
13990 case 0x20: /* MPEG-4 */
13991 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13992 * profile_and_level_indication */
13993 if (data_ptr != NULL && data_len >= 5 &&
13994 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13995 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13996 data_ptr + 4, data_len - 4);
13998 break; /* Nothing special needed here */
13999 case 0x21: /* H.264 */
14000 codec_name = "H.264 / AVC";
14001 caps = gst_caps_new_simple ("video/x-h264",
14002 "stream-format", G_TYPE_STRING, "avc",
14003 "alignment", G_TYPE_STRING, "au", NULL);
14005 case 0x40: /* AAC (any) */
14006 case 0x66: /* AAC Main */
14007 case 0x67: /* AAC LC */
14008 case 0x68: /* AAC SSR */
14009 /* Override channels and rate based on the codec_data, as it's often
14011 /* Only do so for basic setup without HE-AAC extension */
14012 if (data_ptr && data_len == 2) {
14013 guint channels, rate;
14015 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14017 entry->n_channels = channels;
14019 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14021 entry->rate = rate;
14024 /* Set level and profile if possible */
14025 if (data_ptr != NULL && data_len >= 2) {
14026 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14027 data_ptr, data_len);
14029 const gchar *profile_str = NULL;
14032 guint8 *codec_data;
14033 gint rate_idx, profile;
14035 /* No codec_data, let's invent something.
14036 * FIXME: This is wrong for SBR! */
14038 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14040 buffer = gst_buffer_new_and_alloc (2);
14041 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14042 codec_data = map.data;
14045 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14048 switch (object_type_id) {
14050 profile_str = "main";
14054 profile_str = "lc";
14058 profile_str = "ssr";
14066 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14068 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14070 gst_buffer_unmap (buffer, &map);
14071 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14072 GST_TYPE_BUFFER, buffer, NULL);
14073 gst_buffer_unref (buffer);
14076 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14077 G_TYPE_STRING, profile_str, NULL);
14081 case 0x60: /* MPEG-2, various profiles */
14087 codec_name = "MPEG-2 video";
14088 caps = gst_caps_new_simple ("video/mpeg",
14089 "mpegversion", G_TYPE_INT, 2,
14090 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14092 case 0x69: /* MPEG-2 BC audio */
14093 case 0x6B: /* MPEG-1 audio */
14094 caps = gst_caps_new_simple ("audio/mpeg",
14095 "mpegversion", G_TYPE_INT, 1, NULL);
14096 codec_name = "MPEG-1 audio";
14098 case 0x6A: /* MPEG-1 */
14099 codec_name = "MPEG-1 video";
14100 caps = gst_caps_new_simple ("video/mpeg",
14101 "mpegversion", G_TYPE_INT, 1,
14102 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14104 case 0x6C: /* MJPEG */
14106 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14108 codec_name = "Motion-JPEG";
14110 case 0x6D: /* PNG */
14112 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14114 codec_name = "PNG still images";
14116 case 0x6E: /* JPEG2000 */
14117 codec_name = "JPEG-2000";
14118 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14120 case 0xA4: /* Dirac */
14121 codec_name = "Dirac";
14122 caps = gst_caps_new_empty_simple ("video/x-dirac");
14124 case 0xA5: /* AC3 */
14125 codec_name = "AC-3 audio";
14126 caps = gst_caps_new_simple ("audio/x-ac3",
14127 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14129 case 0xA9: /* AC3 */
14130 codec_name = "DTS audio";
14131 caps = gst_caps_new_simple ("audio/x-dts",
14132 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14135 if (stream_type == 0x05 && data_ptr) {
14137 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14140 GValue arr_val = G_VALUE_INIT;
14141 GValue buf_val = G_VALUE_INIT;
14144 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14145 codec_name = "Vorbis";
14146 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14147 g_value_init (&arr_val, GST_TYPE_ARRAY);
14148 g_value_init (&buf_val, GST_TYPE_BUFFER);
14149 for (tmp = headers; tmp; tmp = tmp->next) {
14150 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14151 gst_value_array_append_value (&arr_val, &buf_val);
14153 s = gst_caps_get_structure (caps, 0);
14154 gst_structure_take_value (s, "streamheader", &arr_val);
14155 g_value_unset (&buf_val);
14156 g_list_free (headers);
14163 case 0xE1: /* QCELP */
14164 /* QCELP, the codec_data is a riff tag (little endian) with
14165 * 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). */
14166 caps = gst_caps_new_empty_simple ("audio/qcelp");
14167 codec_name = "QCELP";
14173 /* If we have a replacement caps, then change our caps for this stream */
14175 gst_caps_unref (entry->caps);
14176 entry->caps = caps;
14179 if (codec_name && list)
14180 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14181 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14183 /* Add the codec_data attribute to caps, if we have it */
14187 buffer = gst_buffer_new_and_alloc (data_len);
14188 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14190 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14191 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14193 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14195 gst_buffer_unref (buffer);
14200 static inline GstCaps *
14201 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14205 char *s, fourstr[5];
14207 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14208 for (i = 0; i < 4; i++) {
14209 if (!g_ascii_isalnum (fourstr[i]))
14212 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14213 caps = gst_caps_new_empty_simple (s);
14218 #define _codec(name) \
14220 if (codec_name) { \
14221 *codec_name = g_strdup (name); \
14226 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14227 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14228 const guint8 * stsd_entry_data, gchar ** codec_name)
14230 GstCaps *caps = NULL;
14231 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14235 _codec ("PNG still images");
14236 caps = gst_caps_new_empty_simple ("image/png");
14239 _codec ("JPEG still images");
14241 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14244 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14245 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14246 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14247 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14248 _codec ("Motion-JPEG");
14250 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14253 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14254 _codec ("Motion-JPEG format B");
14255 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14258 _codec ("JPEG-2000");
14259 /* override to what it should be according to spec, avoid palette_data */
14260 entry->bits_per_sample = 24;
14261 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14264 _codec ("Sorensen video v.3");
14265 caps = gst_caps_new_simple ("video/x-svq",
14266 "svqversion", G_TYPE_INT, 3, NULL);
14268 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14269 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14270 _codec ("Sorensen video v.1");
14271 caps = gst_caps_new_simple ("video/x-svq",
14272 "svqversion", G_TYPE_INT, 1, NULL);
14274 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14275 caps = gst_caps_new_empty_simple ("video/x-raw");
14276 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14277 _codec ("Windows Raw RGB");
14278 stream->alignment = 32;
14284 bps = QT_UINT16 (stsd_entry_data + 82);
14287 format = GST_VIDEO_FORMAT_RGB15;
14290 format = GST_VIDEO_FORMAT_RGB16;
14293 format = GST_VIDEO_FORMAT_RGB;
14296 format = GST_VIDEO_FORMAT_ARGB;
14304 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14305 format = GST_VIDEO_FORMAT_I420;
14307 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14308 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14309 format = GST_VIDEO_FORMAT_I420;
14312 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14313 format = GST_VIDEO_FORMAT_UYVY;
14315 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14316 format = GST_VIDEO_FORMAT_v308;
14318 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14319 format = GST_VIDEO_FORMAT_v216;
14322 format = GST_VIDEO_FORMAT_v210;
14324 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14325 format = GST_VIDEO_FORMAT_r210;
14327 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14328 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14329 format = GST_VIDEO_FORMAT_v410;
14332 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14333 * but different order than AYUV
14334 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14335 format = GST_VIDEO_FORMAT_v408;
14338 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14339 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14340 _codec ("MPEG-1 video");
14341 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14342 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14344 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14345 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14346 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14347 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14348 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14349 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14350 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14351 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14352 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14353 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14354 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14355 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14356 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14357 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14358 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14359 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14360 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14361 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14362 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14363 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14364 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14365 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14366 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14367 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14368 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14369 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14370 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14371 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14372 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14373 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14374 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14375 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14376 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14377 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14378 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14379 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14380 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14381 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14382 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14383 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14384 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14385 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14386 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14387 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14388 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14389 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14390 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14391 _codec ("MPEG-2 video");
14392 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14393 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14395 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14396 _codec ("GIF still images");
14397 caps = gst_caps_new_empty_simple ("image/gif");
14400 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14402 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14404 /* ffmpeg uses the height/width props, don't know why */
14405 caps = gst_caps_new_simple ("video/x-h263",
14406 "variant", G_TYPE_STRING, "itu", NULL);
14410 _codec ("MPEG-4 video");
14411 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14412 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14414 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14415 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14416 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14417 caps = gst_caps_new_simple ("video/x-msmpeg",
14418 "msmpegversion", G_TYPE_INT, 43, NULL);
14420 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14422 caps = gst_caps_new_simple ("video/x-divx",
14423 "divxversion", G_TYPE_INT, 3, NULL);
14425 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14426 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14428 caps = gst_caps_new_simple ("video/x-divx",
14429 "divxversion", G_TYPE_INT, 4, NULL);
14431 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14433 caps = gst_caps_new_simple ("video/x-divx",
14434 "divxversion", G_TYPE_INT, 5, NULL);
14437 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14439 caps = gst_caps_new_simple ("video/x-ffv",
14440 "ffvversion", G_TYPE_INT, 1, NULL);
14443 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14444 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14449 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14450 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14451 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14455 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14456 _codec ("Cinepak");
14457 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14459 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14460 _codec ("Apple QuickDraw");
14461 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14463 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14464 _codec ("Apple video");
14465 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14470 _codec ("H.264 / AVC");
14471 caps = gst_caps_new_simple ("video/x-h264",
14472 "stream-format", G_TYPE_STRING, "avc",
14473 "alignment", G_TYPE_STRING, "au", NULL);
14477 _codec ("H.264 / AVC");
14478 caps = gst_caps_new_simple ("video/x-h264",
14479 "stream-format", G_TYPE_STRING, "avc3",
14480 "alignment", G_TYPE_STRING, "au", NULL);
14485 _codec ("H.265 / HEVC");
14486 caps = gst_caps_new_simple ("video/x-h265",
14487 "stream-format", G_TYPE_STRING, "hvc1",
14488 "alignment", G_TYPE_STRING, "au", NULL);
14492 _codec ("H.265 / HEVC");
14493 caps = gst_caps_new_simple ("video/x-h265",
14494 "stream-format", G_TYPE_STRING, "hev1",
14495 "alignment", G_TYPE_STRING, "au", NULL);
14498 _codec ("Run-length encoding");
14499 caps = gst_caps_new_simple ("video/x-rle",
14500 "layout", G_TYPE_STRING, "quicktime", NULL);
14503 _codec ("Run-length encoding");
14504 caps = gst_caps_new_simple ("video/x-rle",
14505 "layout", G_TYPE_STRING, "microsoft", NULL);
14507 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14508 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14509 _codec ("Indeo Video 3");
14510 caps = gst_caps_new_simple ("video/x-indeo",
14511 "indeoversion", G_TYPE_INT, 3, NULL);
14513 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14514 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14515 _codec ("Intel Video 4");
14516 caps = gst_caps_new_simple ("video/x-indeo",
14517 "indeoversion", G_TYPE_INT, 4, NULL);
14521 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14522 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14523 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14524 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14525 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14526 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14527 _codec ("DV Video");
14528 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14529 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14531 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14532 case FOURCC_dv5p: /* DVCPRO50 PAL */
14533 _codec ("DVCPro50 Video");
14534 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14535 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14537 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14538 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14539 _codec ("DVCProHD Video");
14540 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14541 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14543 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14544 _codec ("Apple Graphics (SMC)");
14545 caps = gst_caps_new_empty_simple ("video/x-smc");
14547 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14549 caps = gst_caps_new_empty_simple ("video/x-vp3");
14551 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14552 _codec ("VP6 Flash");
14553 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14557 caps = gst_caps_new_empty_simple ("video/x-theora");
14558 /* theora uses one byte of padding in the data stream because it does not
14559 * allow 0 sized packets while theora does */
14560 entry->padding = 1;
14564 caps = gst_caps_new_empty_simple ("video/x-dirac");
14566 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14567 _codec ("TIFF still images");
14568 caps = gst_caps_new_empty_simple ("image/tiff");
14570 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14571 _codec ("Apple Intermediate Codec");
14572 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14574 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14575 _codec ("AVID DNxHD");
14576 caps = gst_caps_from_string ("video/x-dnxhd");
14580 _codec ("On2 VP8");
14581 caps = gst_caps_from_string ("video/x-vp8");
14584 _codec ("Google VP9");
14585 caps = gst_caps_from_string ("video/x-vp9");
14588 _codec ("Apple ProRes LT");
14590 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14594 _codec ("Apple ProRes HQ");
14596 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14600 _codec ("Apple ProRes");
14602 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14606 _codec ("Apple ProRes Proxy");
14608 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14612 _codec ("Apple ProRes 4444");
14614 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14617 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14618 if (entry->bits_per_sample > 0) {
14619 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14624 _codec ("Apple ProRes 4444 XQ");
14626 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14629 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14630 if (entry->bits_per_sample > 0) {
14631 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14636 _codec ("GoPro CineForm");
14637 caps = gst_caps_from_string ("video/x-cineform");
14642 caps = gst_caps_new_simple ("video/x-wmv",
14643 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14647 caps = gst_caps_new_empty_simple ("video/x-av1");
14649 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14652 caps = _get_unknown_codec_name ("video", fourcc);
14657 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14660 gst_video_info_init (&info);
14661 gst_video_info_set_format (&info, format, entry->width, entry->height);
14663 caps = gst_video_info_to_caps (&info);
14664 *codec_name = gst_pb_utils_get_codec_description (caps);
14666 /* enable clipping for raw video streams */
14667 stream->need_clip = TRUE;
14668 stream->alignment = 32;
14675 round_up_pow2 (guint n)
14687 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14688 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14689 int len, gchar ** codec_name)
14692 const GstStructure *s;
14695 GstAudioFormat format = 0;
14698 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14700 depth = entry->bytes_per_packet * 8;
14703 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14705 /* 8-bit audio is unsigned */
14707 format = GST_AUDIO_FORMAT_U8;
14708 /* otherwise it's signed and big-endian just like 'twos' */
14710 endian = G_BIG_ENDIAN;
14717 endian = G_LITTLE_ENDIAN;
14720 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14722 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14726 caps = gst_caps_new_simple ("audio/x-raw",
14727 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14728 "layout", G_TYPE_STRING, "interleaved", NULL);
14729 stream->alignment = GST_ROUND_UP_8 (depth);
14730 stream->alignment = round_up_pow2 (stream->alignment);
14734 _codec ("Raw 64-bit floating-point audio");
14735 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14737 caps = gst_caps_new_simple ("audio/x-raw",
14738 "format", G_TYPE_STRING, "F64BE",
14739 "layout", G_TYPE_STRING, "interleaved", NULL);
14740 stream->alignment = 8;
14743 _codec ("Raw 32-bit floating-point audio");
14744 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14746 caps = gst_caps_new_simple ("audio/x-raw",
14747 "format", G_TYPE_STRING, "F32BE",
14748 "layout", G_TYPE_STRING, "interleaved", NULL);
14749 stream->alignment = 4;
14752 _codec ("Raw 24-bit PCM audio");
14753 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14755 caps = gst_caps_new_simple ("audio/x-raw",
14756 "format", G_TYPE_STRING, "S24BE",
14757 "layout", G_TYPE_STRING, "interleaved", NULL);
14758 stream->alignment = 4;
14761 _codec ("Raw 32-bit PCM audio");
14762 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14764 caps = gst_caps_new_simple ("audio/x-raw",
14765 "format", G_TYPE_STRING, "S32BE",
14766 "layout", G_TYPE_STRING, "interleaved", NULL);
14767 stream->alignment = 4;
14770 _codec ("Raw 16-bit PCM audio");
14771 caps = gst_caps_new_simple ("audio/x-raw",
14772 "format", G_TYPE_STRING, "S16LE",
14773 "layout", G_TYPE_STRING, "interleaved", NULL);
14774 stream->alignment = 2;
14777 _codec ("Mu-law audio");
14778 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14781 _codec ("A-law audio");
14782 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14786 _codec ("Microsoft ADPCM");
14787 /* Microsoft ADPCM-ACM code 2 */
14788 caps = gst_caps_new_simple ("audio/x-adpcm",
14789 "layout", G_TYPE_STRING, "microsoft", NULL);
14793 _codec ("DVI/IMA ADPCM");
14794 caps = gst_caps_new_simple ("audio/x-adpcm",
14795 "layout", G_TYPE_STRING, "dvi", NULL);
14799 _codec ("DVI/Intel IMA ADPCM");
14800 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14801 caps = gst_caps_new_simple ("audio/x-adpcm",
14802 "layout", G_TYPE_STRING, "quicktime", NULL);
14806 /* MPEG layer 3, CBR only (pre QT4.1) */
14809 _codec ("MPEG-1 layer 3");
14810 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14811 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14812 "mpegversion", G_TYPE_INT, 1, NULL);
14814 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14815 _codec ("MPEG-1 layer 2");
14817 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14818 "mpegversion", G_TYPE_INT, 1, NULL);
14821 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14822 _codec ("EAC-3 audio");
14823 caps = gst_caps_new_simple ("audio/x-eac3",
14824 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14825 entry->sampled = TRUE;
14827 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14829 _codec ("AC-3 audio");
14830 caps = gst_caps_new_simple ("audio/x-ac3",
14831 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14832 entry->sampled = TRUE;
14834 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14835 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14836 _codec ("DTS audio");
14837 caps = gst_caps_new_simple ("audio/x-dts",
14838 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14839 entry->sampled = TRUE;
14841 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14842 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14843 _codec ("DTS-HD audio");
14844 caps = gst_caps_new_simple ("audio/x-dts",
14845 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14846 entry->sampled = TRUE;
14850 caps = gst_caps_new_simple ("audio/x-mace",
14851 "maceversion", G_TYPE_INT, 3, NULL);
14855 caps = gst_caps_new_simple ("audio/x-mace",
14856 "maceversion", G_TYPE_INT, 6, NULL);
14858 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14860 caps = gst_caps_new_empty_simple ("application/ogg");
14862 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14863 _codec ("DV audio");
14864 caps = gst_caps_new_empty_simple ("audio/x-dv");
14867 _codec ("MPEG-4 AAC audio");
14868 caps = gst_caps_new_simple ("audio/mpeg",
14869 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14870 "stream-format", G_TYPE_STRING, "raw", NULL);
14872 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14873 _codec ("QDesign Music");
14874 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14877 _codec ("QDesign Music v.2");
14878 /* FIXME: QDesign music version 2 (no constant) */
14879 if (FALSE && data) {
14880 caps = gst_caps_new_simple ("audio/x-qdm2",
14881 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14882 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14883 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14885 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14889 _codec ("GSM audio");
14890 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14893 _codec ("AMR audio");
14894 caps = gst_caps_new_empty_simple ("audio/AMR");
14897 _codec ("AMR-WB audio");
14898 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14901 _codec ("Quicktime IMA ADPCM");
14902 caps = gst_caps_new_simple ("audio/x-adpcm",
14903 "layout", G_TYPE_STRING, "quicktime", NULL);
14906 _codec ("Apple lossless audio");
14907 caps = gst_caps_new_empty_simple ("audio/x-alac");
14910 _codec ("Free Lossless Audio Codec");
14911 caps = gst_caps_new_simple ("audio/x-flac",
14912 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14914 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14915 _codec ("QualComm PureVoice");
14916 caps = gst_caps_from_string ("audio/qcelp");
14921 caps = gst_caps_new_empty_simple ("audio/x-wma");
14925 caps = gst_caps_new_empty_simple ("audio/x-opus");
14932 GstAudioFormat format;
14935 FLAG_IS_FLOAT = 0x1,
14936 FLAG_IS_BIG_ENDIAN = 0x2,
14937 FLAG_IS_SIGNED = 0x4,
14938 FLAG_IS_PACKED = 0x8,
14939 FLAG_IS_ALIGNED_HIGH = 0x10,
14940 FLAG_IS_NON_INTERLEAVED = 0x20
14942 _codec ("Raw LPCM audio");
14944 if (data && len >= 36) {
14945 depth = QT_UINT32 (data + 24);
14946 flags = QT_UINT32 (data + 28);
14947 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
14949 if ((flags & FLAG_IS_FLOAT) == 0) {
14954 if ((flags & FLAG_IS_ALIGNED_HIGH))
14957 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14958 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14959 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14960 caps = gst_caps_new_simple ("audio/x-raw",
14961 "format", G_TYPE_STRING,
14963 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
14964 "UNKNOWN", "layout", G_TYPE_STRING,
14965 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
14966 "interleaved", NULL);
14967 stream->alignment = GST_ROUND_UP_8 (depth);
14968 stream->alignment = round_up_pow2 (stream->alignment);
14973 if (flags & FLAG_IS_BIG_ENDIAN)
14974 format = GST_AUDIO_FORMAT_F64BE;
14976 format = GST_AUDIO_FORMAT_F64LE;
14978 if (flags & FLAG_IS_BIG_ENDIAN)
14979 format = GST_AUDIO_FORMAT_F32BE;
14981 format = GST_AUDIO_FORMAT_F32LE;
14983 caps = gst_caps_new_simple ("audio/x-raw",
14984 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14985 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14986 "non-interleaved" : "interleaved", NULL);
14987 stream->alignment = width / 8;
14991 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
14994 caps = gst_caps_new_empty_simple ("audio/x-ac4");
14997 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15001 caps = _get_unknown_codec_name ("audio", fourcc);
15007 GstCaps *templ_caps =
15008 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15009 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15010 gst_caps_unref (caps);
15011 gst_caps_unref (templ_caps);
15012 caps = intersection;
15015 /* enable clipping for raw audio streams */
15016 s = gst_caps_get_structure (caps, 0);
15017 name = gst_structure_get_name (s);
15018 if (g_str_has_prefix (name, "audio/x-raw")) {
15019 stream->need_clip = TRUE;
15020 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15021 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15022 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15023 stream->max_buffer_size);
15029 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15030 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15031 const guint8 * stsd_entry_data, gchar ** codec_name)
15035 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15039 _codec ("DVD subtitle");
15040 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15041 stream->process_func = gst_qtdemux_process_buffer_dvd;
15044 _codec ("Quicktime timed text");
15047 _codec ("3GPP timed text");
15049 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15051 /* actual text piece needs to be extracted */
15052 stream->process_func = gst_qtdemux_process_buffer_text;
15055 _codec ("XML subtitles");
15056 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15061 const gchar *buf = "WEBVTT\n\n";
15063 _codec ("WebVTT subtitles");
15064 caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15065 stream->process_func = gst_qtdemux_process_buffer_wvtt;
15067 /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15068 buffer = gst_buffer_new_and_alloc (8);
15069 gst_buffer_fill (buffer, 0, buf, 8);
15070 stream->buffers = g_slist_append (stream->buffers, buffer);
15075 _codec ("CEA 608 Closed Caption");
15077 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15078 G_TYPE_STRING, "s334-1a", NULL);
15079 stream->process_func = gst_qtdemux_process_buffer_clcp;
15080 stream->need_split = TRUE;
15083 _codec ("CEA 708 Closed Caption");
15085 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15086 G_TYPE_STRING, "cdp", NULL);
15087 stream->process_func = gst_qtdemux_process_buffer_clcp;
15092 caps = _get_unknown_codec_name ("text", fourcc);
15100 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15101 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15102 const guint8 * stsd_entry_data, gchar ** codec_name)
15108 _codec ("MPEG 1 video");
15109 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15110 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15120 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15121 const gchar * system_id)
15125 if (!qtdemux->protection_system_ids)
15126 qtdemux->protection_system_ids =
15127 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15128 /* Check whether we already have an entry for this system ID. */
15129 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15130 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15131 if (g_ascii_strcasecmp (system_id, id) == 0) {
15135 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15136 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,