2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
12 * Copyright (C) <2016> British Broadcasting Corporation
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with this library; if not, write to the
26 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
31 * SECTION:element-qtdemux
34 * Demuxes a .mov file into raw or compressed audio and/or video streams.
36 * This element supports both push and pull-based scheduling, depending on the
37 * capabilities of the upstream elements.
39 * ## Example launch line
41 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
42 * ]| Play (parse and decode) a .mov file and try to output it to
43 * an automatically detected soundcard and videosink. If the MOV file contains
44 * compressed audio or video data, this will only work if you have the
45 * right decoder elements/plugins installed.
53 #include "gst/gst-i18n-plugin.h"
55 #include <glib/gprintf.h>
56 #include <gst/base/base.h>
57 #include <gst/tag/tag.h>
58 #include <gst/audio/audio.h>
59 #include <gst/riff/riff.h>
60 #include <gst/pbutils/pbutils.h>
62 #include "gstisomp4elements.h"
63 #include "qtatomparser.h"
64 #include "qtdemux_types.h"
65 #include "qtdemux_dump.h"
67 #include "descriptors.h"
68 #include "qtdemux_lang.h"
70 #include "qtpalette.h"
71 #include "qtdemux_tags.h"
72 #include "qtdemux_tree.h"
73 #include "qtdemux-webvtt.h"
79 #include <gst/math-compat.h>
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
97 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
99 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
101 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
103 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
104 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
105 #define QTDEMUX_NTH_STREAM(demux,idx) \
106 QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
107 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
108 QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
110 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
112 GST_DEBUG_CATEGORY (qtdemux_debug);
113 #define GST_CAT_DEFAULT qtdemux_debug
115 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
116 typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
118 /* Macros for converting to/from timescale */
119 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
120 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
122 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
123 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
125 /* timestamp is the DTS */
126 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
127 /* timestamp + offset + cslg_shift is the outgoing PTS */
128 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
129 /* timestamp + offset is the PTS used for internal seek calculations */
130 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
131 /* timestamp + duration - dts is the duration */
132 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
134 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
136 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
137 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
138 GST_TRACE("Locking from thread %p", g_thread_self()); \
139 g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
140 GST_TRACE("Locked from thread %p", g_thread_self()); \
143 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
144 GST_TRACE("Unlocking from thread %p", g_thread_self()); \
145 g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
149 * Quicktime has tracks and segments. A track is a continuous piece of
150 * multimedia content. The track is not always played from start to finish but
151 * instead, pieces of the track are 'cut out' and played in sequence. This is
152 * what the segments do.
154 * Inside the track we have keyframes (K) and delta frames. The track has its
155 * own timing, which starts from 0 and extends to end. The position in the track
156 * is called the media_time.
158 * The segments now describe the pieces that should be played from this track
159 * and are basically tuples of media_time/duration/rate entries. We can have
160 * multiple segments and they are all played after one another. An example:
162 * segment 1: media_time: 1 second, duration: 1 second, rate 1
163 * segment 2: media_time: 3 second, duration: 2 second, rate 2
165 * To correctly play back this track, one must play: 1 second of media starting
166 * from media_time 1 followed by 2 seconds of media starting from media_time 3
169 * Each of the segments will be played at a specific time, the first segment at
170 * time 0, the second one after the duration of the first one, etc.. Note that
171 * the time in resulting playback is not identical to the media_time of the
174 * Visually, assuming the track has 4 second of media_time:
177 * .-----------------------------------------------------------.
178 * track: | K.....K.........K........K.......K.......K...........K... |
179 * '-----------------------------------------------------------'
181 * .------------^ ^ .----------^ ^
182 * / .-------------' / .------------------'
184 * .--------------. .--------------.
185 * | segment 1 | | segment 2 |
186 * '--------------' '--------------'
188 * The challenge here is to cut out the right pieces of the track for each of
189 * the playback segments. This fortunately can easily be done with the SEGMENT
190 * events of GStreamer.
192 * For playback of segment 1, we need to provide the decoder with the keyframe
193 * (a), in the above figure, but we must instruct it only to output the decoded
194 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
195 * position set to the time of the segment: 0.
197 * We then proceed to push data from keyframe (a) to frame (b). The decoder
198 * decodes but clips all before media_time 1.
200 * After finishing a segment, we push out a new SEGMENT event with the clipping
201 * boundaries of the new data.
203 * This is a good usecase for the GStreamer accumulated SEGMENT events.
206 struct _QtDemuxSegment
208 /* global time and duration, all gst time */
210 GstClockTime stop_time;
211 GstClockTime duration;
212 /* media time of trak, all gst time */
213 GstClockTime media_start;
214 GstClockTime media_stop;
216 /* Media start time in trak timescale units */
217 guint32 trak_media_start;
220 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
222 /* Used with fragmented MP4 files (mfra atom) */
223 struct _QtDemuxRandomAccessEntry
230 /* Contains properties and cryptographic info for a set of samples from a
231 * track protected using Common Encryption (cenc) */
232 struct _QtDemuxCencSampleSetInfo
234 GstStructure *default_properties;
236 /* @crypto_info holds one GstStructure per sample */
237 GPtrArray *crypto_info;
240 struct _QtDemuxAavdEncryptionInfo
242 GstStructure *default_properties;
246 qt_demux_state_string (enum QtDemuxState state)
249 case QTDEMUX_STATE_INITIAL:
251 case QTDEMUX_STATE_HEADER:
253 case QTDEMUX_STATE_MOVIE:
255 case QTDEMUX_STATE_BUFFER_MDAT:
256 return "<BUFFER_MDAT>";
262 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
264 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
266 static GstStaticPadTemplate gst_qtdemux_sink_template =
267 GST_STATIC_PAD_TEMPLATE ("sink",
270 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
274 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
275 GST_STATIC_PAD_TEMPLATE ("video_%u",
278 GST_STATIC_CAPS_ANY);
280 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
281 GST_STATIC_PAD_TEMPLATE ("audio_%u",
284 GST_STATIC_CAPS_ANY);
286 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
287 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
290 GST_STATIC_CAPS_ANY);
292 #define gst_qtdemux_parent_class parent_class
293 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
294 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
295 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
297 static void gst_qtdemux_dispose (GObject * object);
298 static void gst_qtdemux_finalize (GObject * object);
301 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
302 GstClockTime media_time);
304 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
305 QtDemuxStream * str, gint64 media_offset);
308 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
309 static GstIndex *gst_qtdemux_get_index (GstElement * element);
311 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
312 GstStateChange transition);
313 static void gst_qtdemux_set_context (GstElement * element,
314 GstContext * context);
315 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
316 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
317 GstObject * parent, GstPadMode mode, gboolean active);
319 static void gst_qtdemux_loop (GstPad * pad);
320 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
322 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
324 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
326 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
327 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
328 QtDemuxStream * stream);
329 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
330 QtDemuxStream * stream);
331 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
334 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
336 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
337 const guint8 * buffer, guint length);
338 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
339 const guint8 * buffer, guint length);
340 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
342 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
343 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
345 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
346 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
347 const guint8 * stsd_entry_data, gchar ** codec_name);
348 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
349 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
350 const guint8 * data, int len, gchar ** codec_name);
351 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
352 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
353 gchar ** codec_name);
354 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
355 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
356 const guint8 * stsd_entry_data, gchar ** codec_name);
358 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
359 QtDemuxStream * stream, guint32 n);
360 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
361 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
362 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
363 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
364 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
365 static void qtdemux_do_allocation (QtDemuxStream * stream,
366 GstQTDemux * qtdemux);
367 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
368 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
369 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
370 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
371 GstClockTime * _start, GstClockTime * _stop);
372 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
373 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
375 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
376 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
378 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
380 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
381 QtDemuxStream * stream, guint sample_index);
382 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
384 static void qtdemux_gst_structure_free (GstStructure * gststructure);
385 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
388 gst_qtdemux_class_init (GstQTDemuxClass * klass)
390 GObjectClass *gobject_class;
391 GstElementClass *gstelement_class;
393 gobject_class = (GObjectClass *) klass;
394 gstelement_class = (GstElementClass *) klass;
396 parent_class = g_type_class_peek_parent (klass);
398 gobject_class->dispose = gst_qtdemux_dispose;
399 gobject_class->finalize = gst_qtdemux_finalize;
401 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
403 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
404 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
406 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
408 gst_tag_register_musicbrainz_tags ();
410 gst_element_class_add_static_pad_template (gstelement_class,
411 &gst_qtdemux_sink_template);
412 gst_element_class_add_static_pad_template (gstelement_class,
413 &gst_qtdemux_videosrc_template);
414 gst_element_class_add_static_pad_template (gstelement_class,
415 &gst_qtdemux_audiosrc_template);
416 gst_element_class_add_static_pad_template (gstelement_class,
417 &gst_qtdemux_subsrc_template);
418 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
420 "Demultiplex a QuickTime file into audio and video streams",
421 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
423 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
428 gst_qtdemux_init (GstQTDemux * qtdemux)
431 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
432 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
433 gst_pad_set_activatemode_function (qtdemux->sinkpad,
434 qtdemux_sink_activate_mode);
435 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
436 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
437 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
438 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
440 qtdemux->adapter = gst_adapter_new ();
441 g_queue_init (&qtdemux->protection_event_queue);
442 qtdemux->flowcombiner = gst_flow_combiner_new ();
443 g_mutex_init (&qtdemux->expose_lock);
445 qtdemux->active_streams = g_ptr_array_new_with_free_func
446 ((GDestroyNotify) gst_qtdemux_stream_unref);
447 qtdemux->old_streams = g_ptr_array_new_with_free_func
448 ((GDestroyNotify) gst_qtdemux_stream_unref);
450 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
452 gst_qtdemux_reset (qtdemux, TRUE);
456 gst_qtdemux_finalize (GObject * object)
458 GstQTDemux *qtdemux = GST_QTDEMUX (object);
460 g_free (qtdemux->redirect_location);
462 G_OBJECT_CLASS (parent_class)->finalize (object);
466 gst_qtdemux_dispose (GObject * object)
468 GstQTDemux *qtdemux = GST_QTDEMUX (object);
470 if (qtdemux->adapter) {
471 g_object_unref (G_OBJECT (qtdemux->adapter));
472 qtdemux->adapter = NULL;
474 gst_tag_list_unref (qtdemux->tag_list);
475 gst_flow_combiner_free (qtdemux->flowcombiner);
476 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
478 g_queue_clear (&qtdemux->protection_event_queue);
480 g_free (qtdemux->cenc_aux_info_sizes);
481 qtdemux->cenc_aux_info_sizes = NULL;
482 g_mutex_clear (&qtdemux->expose_lock);
484 g_ptr_array_free (qtdemux->active_streams, TRUE);
485 g_ptr_array_free (qtdemux->old_streams, TRUE);
487 G_OBJECT_CLASS (parent_class)->dispose (object);
491 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
493 if (qtdemux->redirect_location) {
494 GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
495 (_("This file contains no playable streams.")),
496 ("no known streams found, a redirect message has been posted"),
497 ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
499 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
500 (_("This file contains no playable streams.")),
501 ("no known streams found"));
506 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
508 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
509 mem, size, 0, size, mem, free_func);
513 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
520 if (G_UNLIKELY (size == 0)) {
522 GstBuffer *tmp = NULL;
524 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
525 if (ret != GST_FLOW_OK)
528 gst_buffer_map (tmp, &map, GST_MAP_READ);
529 size = QT_UINT32 (map.data);
530 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
532 gst_buffer_unmap (tmp, &map);
533 gst_buffer_unref (tmp);
536 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
537 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
538 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
539 /* we're pulling header but already got most interesting bits,
540 * so never mind the rest (e.g. tags) (that much) */
541 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
545 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
546 (_("This file is invalid and cannot be played.")),
547 ("atom has bogus size %" G_GUINT64_FORMAT, size));
548 return GST_FLOW_ERROR;
552 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
554 if (G_UNLIKELY (flow != GST_FLOW_OK))
557 bsize = gst_buffer_get_size (*buf);
558 /* Catch short reads - we don't want any partial atoms */
559 if (G_UNLIKELY (bsize < size)) {
560 GST_WARNING_OBJECT (qtdemux,
561 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
562 gst_buffer_unref (*buf);
572 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
573 GstFormat src_format, gint64 src_value, GstFormat dest_format,
577 QtDemuxStream *stream = gst_pad_get_element_private (pad);
580 if (stream->subtype != FOURCC_vide) {
585 switch (src_format) {
586 case GST_FORMAT_TIME:
587 switch (dest_format) {
588 case GST_FORMAT_BYTES:{
589 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
595 *dest_value = stream->samples[index].offset;
597 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
598 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
599 GST_TIME_ARGS (src_value), *dest_value);
607 case GST_FORMAT_BYTES:
608 switch (dest_format) {
609 case GST_FORMAT_TIME:{
611 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
620 QTSTREAMTIME_TO_GSTTIME (stream,
621 stream->samples[index].timestamp);
622 GST_DEBUG_OBJECT (qtdemux,
623 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
624 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
643 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
645 gboolean res = FALSE;
647 *duration = GST_CLOCK_TIME_NONE;
649 if (qtdemux->duration != 0 &&
650 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
651 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
654 *duration = GST_CLOCK_TIME_NONE;
661 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
664 gboolean res = FALSE;
665 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
667 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
669 switch (GST_QUERY_TYPE (query)) {
670 case GST_QUERY_POSITION:{
673 gst_query_parse_position (query, &fmt, NULL);
674 if (fmt == GST_FORMAT_TIME
675 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
676 gst_query_set_position (query, GST_FORMAT_TIME,
677 qtdemux->segment.position);
682 case GST_QUERY_DURATION:{
685 gst_query_parse_duration (query, &fmt, NULL);
686 if (fmt == GST_FORMAT_TIME) {
687 /* First try to query upstream */
688 res = gst_pad_query_default (pad, parent, query);
690 GstClockTime duration;
691 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
692 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
699 case GST_QUERY_CONVERT:{
700 GstFormat src_fmt, dest_fmt;
701 gint64 src_value, dest_value = 0;
703 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
705 res = gst_qtdemux_src_convert (qtdemux, pad,
706 src_fmt, src_value, dest_fmt, &dest_value);
708 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
712 case GST_QUERY_FORMATS:
713 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
716 case GST_QUERY_SEEKING:{
720 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
722 if (fmt == GST_FORMAT_BYTES) {
723 /* We always refuse BYTES seeks from downstream */
727 /* try upstream first */
728 res = gst_pad_query_default (pad, parent, query);
731 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
732 if (fmt == GST_FORMAT_TIME) {
733 GstClockTime duration;
735 gst_qtdemux_get_duration (qtdemux, &duration);
737 if (!qtdemux->pullbased) {
740 /* we might be able with help from upstream */
742 q = gst_query_new_seeking (GST_FORMAT_BYTES);
743 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
744 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
745 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
749 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
755 case GST_QUERY_SEGMENT:
760 format = qtdemux->segment.format;
763 gst_segment_to_stream_time (&qtdemux->segment, format,
764 qtdemux->segment.start);
765 if ((stop = qtdemux->segment.stop) == -1)
766 stop = qtdemux->segment.duration;
768 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
770 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
775 res = gst_pad_query_default (pad, parent, query);
783 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
785 if (G_LIKELY (stream->pad)) {
786 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
787 GST_DEBUG_PAD_NAME (stream->pad));
789 if (!gst_tag_list_is_empty (stream->stream_tags)) {
790 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
791 stream->stream_tags);
792 gst_pad_push_event (stream->pad,
793 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
796 if (G_UNLIKELY (stream->send_global_tags)) {
797 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
799 gst_pad_push_event (stream->pad,
800 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
801 stream->send_global_tags = FALSE;
806 /* push event on all source pads; takes ownership of the event */
808 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
810 gboolean has_valid_stream = FALSE;
811 GstEventType etype = GST_EVENT_TYPE (event);
814 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
815 GST_EVENT_TYPE_NAME (event));
817 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
819 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
820 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
822 if ((pad = stream->pad)) {
823 has_valid_stream = TRUE;
825 if (etype == GST_EVENT_EOS) {
826 /* let's not send twice */
827 if (stream->sent_eos)
829 stream->sent_eos = TRUE;
832 gst_pad_push_event (pad, gst_event_ref (event));
836 gst_event_unref (event);
838 /* if it is EOS and there are no pads, post an error */
839 if (!has_valid_stream && etype == GST_EVENT_EOS) {
840 gst_qtdemux_post_no_playable_stream_error (qtdemux);
850 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
852 if ((gint64) s1->timestamp > *media_time)
854 if ((gint64) s1->timestamp == *media_time)
860 /* find the index of the sample that includes the data for @media_time using a
861 * binary search. Only to be called in optimized cases of linear search below.
863 * Returns the index of the sample with the corresponding *DTS*.
866 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
869 QtDemuxSample *result;
872 /* convert media_time to mov format */
874 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
876 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
877 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
878 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
880 if (G_LIKELY (result))
881 index = result - str->samples;
890 /* find the index of the sample that includes the data for @media_offset using a
893 * Returns the index of the sample.
896 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
897 QtDemuxStream * str, gint64 media_offset)
899 QtDemuxSample *result = str->samples;
902 if (result == NULL || str->n_samples == 0)
905 if (media_offset == result->offset)
909 while (index < str->n_samples - 1) {
910 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
913 if (media_offset < result->offset)
924 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
929 /* find the index of the sample that includes the data for @media_time using a
930 * linear search, and keeping in mind that not all samples may have been parsed
931 * yet. If possible, it will delegate to binary search.
933 * Returns the index of the sample.
936 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
937 GstClockTime media_time)
941 QtDemuxSample *sample;
943 /* convert media_time to mov format */
945 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
947 sample = str->samples;
948 if (mov_time == sample->timestamp + sample->pts_offset)
951 /* use faster search if requested time in already parsed range */
952 sample = str->samples + str->stbl_index;
953 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
954 index = gst_qtdemux_find_index (qtdemux, str, media_time);
955 sample = str->samples + index;
957 while (index < str->n_samples - 1) {
958 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
961 sample = str->samples + index + 1;
962 if (mov_time < sample->timestamp) {
963 sample = str->samples + index;
971 /* sample->timestamp is now <= media_time, need to find the corresponding
972 * PTS now by looking backwards */
973 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
975 sample = str->samples + index;
983 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
988 /* find the index of the keyframe needed to decode the sample at @index
989 * of stream @str, or of a subsequent keyframe (depending on @next)
991 * Returns the index of the keyframe.
994 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
995 guint32 index, gboolean next)
997 guint32 new_index = index;
999 if (index >= str->n_samples) {
1000 new_index = str->n_samples;
1004 /* all keyframes, return index */
1005 if (str->all_keyframe) {
1010 /* else search until we have a keyframe */
1011 while (new_index < str->n_samples) {
1012 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1015 if (str->samples[new_index].keyframe)
1027 if (new_index == str->n_samples) {
1028 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1033 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1034 "gave %u", next ? "after" : "before", index, new_index);
1041 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1046 /* find the segment for @time_position for @stream
1048 * Returns the index of the segment containing @time_position.
1049 * Returns the last segment and sets the @eos variable to TRUE
1050 * if the time is beyond the end. @eos may be NULL
1053 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1054 GstClockTime time_position)
1059 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1060 GST_TIME_ARGS (time_position));
1063 for (i = 0; i < stream->n_segments; i++) {
1064 QtDemuxSegment *segment = &stream->segments[i];
1066 GST_LOG_OBJECT (stream->pad,
1067 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1068 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1070 /* For the last segment we include stop_time in the last segment */
1071 if (i < stream->n_segments - 1) {
1072 if (segment->time <= time_position && time_position < segment->stop_time) {
1073 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1078 /* Last segment always matches */
1086 /* move the stream @str to the sample position @index.
1088 * Updates @str->sample_index and marks discontinuity if needed.
1091 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1094 /* no change needed */
1095 if (index == str->sample_index)
1098 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1101 /* position changed, we have a discont */
1102 str->sample_index = index;
1103 str->offset_in_sample = 0;
1104 /* Each time we move in the stream we store the position where we are
1106 str->from_sample = index;
1107 str->discont = TRUE;
1111 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1112 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1115 gint64 min_byte_offset = -1;
1118 min_offset = desired_time;
1120 /* for each stream, find the index of the sample in the segment
1121 * and move back to the previous keyframe. */
1122 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1124 guint32 index, kindex;
1126 GstClockTime media_start;
1127 GstClockTime media_time;
1128 GstClockTime seg_time;
1129 QtDemuxSegment *seg;
1130 gboolean empty_segment = FALSE;
1132 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1134 if (CUR_STREAM (str)->sparse && !use_sparse)
1137 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1138 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1140 /* get segment and time in the segment */
1141 seg = &str->segments[seg_idx];
1142 seg_time = (desired_time - seg->time) * seg->rate;
1144 while (QTSEGMENT_IS_EMPTY (seg)) {
1146 empty_segment = TRUE;
1147 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1150 if (seg_idx == str->n_segments)
1152 seg = &str->segments[seg_idx];
1155 if (seg_idx == str->n_segments) {
1156 /* FIXME track shouldn't have the last segment as empty, but if it
1157 * happens we better handle it */
1161 /* get the media time in the segment */
1162 media_start = seg->media_start + seg_time;
1164 /* get the index of the sample with media time */
1165 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1166 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1167 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1168 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1171 /* shift to next frame if we are looking for next keyframe */
1172 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1173 && index < str->stbl_index)
1176 if (!empty_segment) {
1177 /* find previous keyframe */
1178 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1180 /* we will settle for one before if none found after */
1181 if (next && kindex == -1)
1182 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1184 /* Update the requested time whenever a keyframe was found, to make it
1185 * accurate and avoid having the first buffer fall outside of the segment
1190 /* get timestamp of keyframe */
1191 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1192 GST_DEBUG_OBJECT (qtdemux,
1193 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1194 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1195 str->samples[kindex].offset);
1197 /* keyframes in the segment get a chance to change the
1198 * desired_offset. keyframes out of the segment are
1200 if (media_time >= seg->media_start) {
1201 GstClockTime seg_time;
1203 /* this keyframe is inside the segment, convert back to
1205 seg_time = (media_time - seg->media_start) + seg->time;
1206 if ((!next && (seg_time < min_offset)) ||
1207 (next && (seg_time > min_offset)))
1208 min_offset = seg_time;
1213 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1214 min_byte_offset = str->samples[index].offset;
1218 *key_time = min_offset;
1220 *key_offset = min_byte_offset;
1224 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1225 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1229 g_return_val_if_fail (format != NULL, FALSE);
1230 g_return_val_if_fail (cur != NULL, FALSE);
1231 g_return_val_if_fail (stop != NULL, FALSE);
1233 if (*format == GST_FORMAT_TIME)
1237 if (cur_type != GST_SEEK_TYPE_NONE)
1238 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1239 if (res && stop_type != GST_SEEK_TYPE_NONE)
1240 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1243 *format = GST_FORMAT_TIME;
1248 /* perform seek in push based mode:
1249 find BYTE position to move to based on time and delegate to upstream
1252 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1257 GstSeekType cur_type, stop_type;
1258 gint64 cur, stop, key_cur;
1261 gint64 original_stop;
1264 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1266 gst_event_parse_seek (event, &rate, &format, &flags,
1267 &cur_type, &cur, &stop_type, &stop);
1268 seqnum = gst_event_get_seqnum (event);
1270 /* Directly send the instant-rate-change event here before taking the
1271 * stream-lock so that it can be applied as soon as possible */
1272 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1275 /* instant rate change only supported if direction does not change. All
1276 * other requirements are already checked before creating the seek event
1277 * but let's double-check here to be sure */
1278 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1279 (qtdemux->segment.rate < 0 && rate > 0) ||
1280 cur_type != GST_SEEK_TYPE_NONE ||
1281 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1282 GST_ERROR_OBJECT (qtdemux,
1283 "Instant rate change seeks only supported in the "
1284 "same direction, without flushing and position change");
1288 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1289 (GstSegmentFlags) flags);
1290 gst_event_set_seqnum (ev, seqnum);
1291 gst_qtdemux_push_event (qtdemux, ev);
1295 /* only forward streaming and seeking is possible */
1297 goto unsupported_seek;
1299 /* convert to TIME if needed and possible */
1300 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1304 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1305 * the original stop position to use when upstream pushes the new segment
1307 original_stop = stop;
1310 /* find reasonable corresponding BYTE position,
1311 * also try to mind about keyframes, since we can not go back a bit for them
1313 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1314 * mostly just work, but let's not yet boldly go there ... */
1315 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1320 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1321 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1324 GST_OBJECT_LOCK (qtdemux);
1325 qtdemux->seek_offset = byte_cur;
1326 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1327 qtdemux->push_seek_start = cur;
1329 qtdemux->push_seek_start = key_cur;
1332 if (stop_type == GST_SEEK_TYPE_NONE) {
1333 qtdemux->push_seek_stop = qtdemux->segment.stop;
1335 qtdemux->push_seek_stop = original_stop;
1337 GST_OBJECT_UNLOCK (qtdemux);
1339 qtdemux->segment_seqnum = seqnum;
1340 /* BYTE seek event */
1341 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1343 gst_event_set_seqnum (event, seqnum);
1344 res = gst_pad_push_event (qtdemux->sinkpad, event);
1351 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1357 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1362 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1367 /* perform the seek.
1369 * We set all segment_indexes in the streams to unknown and
1370 * adjust the time_position to the desired position. this is enough
1371 * to trigger a segment switch in the streaming thread to start
1372 * streaming from the desired position.
1374 * Keyframe seeking is a little more complicated when dealing with
1375 * segments. Ideally we want to move to the previous keyframe in
1376 * the segment but there might not be a keyframe in the segment. In
1377 * fact, none of the segments could contain a keyframe. We take a
1378 * practical approach: seek to the previous keyframe in the segment,
1379 * if there is none, seek to the beginning of the segment.
1381 * Called with STREAM_LOCK
1384 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1385 guint32 seqnum, GstSeekFlags flags)
1387 gint64 desired_offset;
1390 desired_offset = segment->position;
1392 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1393 GST_TIME_ARGS (desired_offset));
1395 /* may not have enough fragmented info to do this adjustment,
1396 * and we can't scan (and probably should not) at this time with
1397 * possibly flushing upstream */
1398 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1400 gboolean next, before, after;
1402 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1403 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1404 next = after && !before;
1405 if (segment->rate < 0)
1408 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1410 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1411 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1412 desired_offset = min_offset;
1415 /* and set all streams to the final position */
1416 GST_OBJECT_LOCK (qtdemux);
1417 gst_flow_combiner_reset (qtdemux->flowcombiner);
1418 GST_OBJECT_UNLOCK (qtdemux);
1419 qtdemux->segment_seqnum = seqnum;
1420 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1421 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1423 stream->time_position = desired_offset;
1424 stream->accumulated_base = 0;
1425 stream->sample_index = -1;
1426 stream->offset_in_sample = 0;
1427 stream->segment_index = -1;
1428 stream->sent_eos = FALSE;
1429 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1431 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1432 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1434 segment->position = desired_offset;
1435 if (segment->rate >= 0) {
1436 segment->start = desired_offset;
1437 /* We need to update time as we update start in that direction */
1438 segment->time = desired_offset;
1440 /* we stop at the end */
1441 if (segment->stop == -1)
1442 segment->stop = segment->duration;
1444 segment->stop = desired_offset;
1447 if (qtdemux->fragmented)
1448 qtdemux->fragmented_seek_pending = TRUE;
1453 /* do a seek in pull based mode */
1455 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1460 GstSeekType cur_type, stop_type;
1462 gboolean flush, instant_rate_change;
1464 GstSegment seeksegment;
1465 guint32 seqnum = GST_SEQNUM_INVALID;
1466 GstEvent *flush_event;
1469 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1471 gst_event_parse_seek (event, &rate, &format, &flags,
1472 &cur_type, &cur, &stop_type, &stop);
1473 seqnum = gst_event_get_seqnum (event);
1475 /* we have to have a format as the segment format. Try to convert
1477 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1481 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1483 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1484 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1486 /* Directly send the instant-rate-change event here before taking the
1487 * stream-lock so that it can be applied as soon as possible */
1488 if (instant_rate_change) {
1491 /* instant rate change only supported if direction does not change. All
1492 * other requirements are already checked before creating the seek event
1493 * but let's double-check here to be sure */
1494 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1495 (qtdemux->segment.rate < 0 && rate > 0) ||
1496 cur_type != GST_SEEK_TYPE_NONE ||
1497 stop_type != GST_SEEK_TYPE_NONE || flush) {
1498 GST_ERROR_OBJECT (qtdemux,
1499 "Instant rate change seeks only supported in the "
1500 "same direction, without flushing and position change");
1504 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1505 (GstSegmentFlags) flags);
1506 gst_event_set_seqnum (ev, seqnum);
1507 gst_qtdemux_push_event (qtdemux, ev);
1511 /* stop streaming, either by flushing or by pausing the task */
1513 flush_event = gst_event_new_flush_start ();
1514 if (seqnum != GST_SEQNUM_INVALID)
1515 gst_event_set_seqnum (flush_event, seqnum);
1516 /* unlock upstream pull_range */
1517 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1518 /* make sure out loop function exits */
1519 gst_qtdemux_push_event (qtdemux, flush_event);
1521 /* non flushing seek, pause the task */
1522 gst_pad_pause_task (qtdemux->sinkpad);
1525 /* wait for streaming to finish */
1526 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1528 /* copy segment, we need this because we still need the old
1529 * segment when we close the current segment. */
1530 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1532 /* configure the segment with the seek variables */
1533 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1534 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1535 cur_type, cur, stop_type, stop, &update)) {
1537 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1539 /* now do the seek */
1540 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1543 /* prepare for streaming again */
1545 flush_event = gst_event_new_flush_stop (TRUE);
1546 if (seqnum != GST_SEQNUM_INVALID)
1547 gst_event_set_seqnum (flush_event, seqnum);
1549 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1550 gst_qtdemux_push_event (qtdemux, flush_event);
1553 /* commit the new segment */
1554 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1556 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1557 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1558 qtdemux->segment.format, qtdemux->segment.position);
1559 if (seqnum != GST_SEQNUM_INVALID)
1560 gst_message_set_seqnum (msg, seqnum);
1561 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1564 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1565 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1566 qtdemux->sinkpad, NULL);
1568 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1575 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1581 qtdemux_ensure_index (GstQTDemux * qtdemux)
1585 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1587 /* Build complete index */
1588 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1589 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1591 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1592 GST_LOG_OBJECT (qtdemux,
1593 "Building complete index of track-id %u for seeking failed!",
1603 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1606 gboolean res = TRUE;
1607 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1609 switch (GST_EVENT_TYPE (event)) {
1610 case GST_EVENT_RECONFIGURE:
1611 GST_OBJECT_LOCK (qtdemux);
1612 gst_flow_combiner_reset (qtdemux->flowcombiner);
1613 GST_OBJECT_UNLOCK (qtdemux);
1614 res = gst_pad_event_default (pad, parent, event);
1616 case GST_EVENT_SEEK:
1618 GstSeekFlags flags = 0;
1619 GstFormat seek_format;
1620 gboolean instant_rate_change;
1622 #ifndef GST_DISABLE_GST_DEBUG
1623 GstClockTime ts = gst_util_get_timestamp ();
1625 guint32 seqnum = gst_event_get_seqnum (event);
1627 qtdemux->received_seek = TRUE;
1629 gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1631 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1633 if (seqnum == qtdemux->segment_seqnum) {
1634 GST_LOG_OBJECT (pad,
1635 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1636 gst_event_unref (event);
1640 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1641 /* seek should be handled by upstream, we might need to re-download fragments */
1642 GST_DEBUG_OBJECT (qtdemux,
1643 "let upstream handle seek for fragmented playback");
1647 if (seek_format == GST_FORMAT_BYTES) {
1648 GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1649 gst_event_unref (event);
1653 gst_event_parse_seek_trickmode_interval (event,
1654 &qtdemux->trickmode_interval);
1656 /* Build complete index for seeking;
1657 * if not a fragmented file at least and we're really doing a seek,
1658 * not just an instant-rate-change */
1659 if (!qtdemux->fragmented && !instant_rate_change) {
1660 if (!qtdemux_ensure_index (qtdemux))
1663 #ifndef GST_DISABLE_GST_DEBUG
1664 ts = gst_util_get_timestamp () - ts;
1665 GST_INFO_OBJECT (qtdemux,
1666 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1668 if (qtdemux->pullbased) {
1669 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1670 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1671 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1673 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1674 && QTDEMUX_N_STREAMS (qtdemux)
1675 && !qtdemux->fragmented) {
1676 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1678 GST_DEBUG_OBJECT (qtdemux,
1679 "ignoring seek in push mode in current state");
1682 gst_event_unref (event);
1687 res = gst_pad_event_default (pad, parent, event);
1697 GST_ERROR_OBJECT (qtdemux, "Index failed");
1698 gst_event_unref (event);
1704 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1706 * If @fw is false, the coding order is explored backwards.
1708 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1709 * sample is found for that track.
1711 * The stream and sample index of the sample with the minimum offset in the direction explored
1712 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1714 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1715 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1716 * @_stream and @_index. */
1718 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1719 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1722 gint64 time, min_time;
1723 QtDemuxStream *stream;
1730 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1733 gboolean set_sample;
1735 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1742 i = str->n_samples - 1;
1746 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1747 if (str->samples[i].size == 0)
1750 if (fw && (str->samples[i].offset < byte_pos))
1753 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1756 /* move stream to first available sample */
1758 gst_qtdemux_move_stream (qtdemux, str, i);
1762 /* avoid index from sparse streams since they might be far away */
1763 if (!CUR_STREAM (str)->sparse) {
1764 /* determine min/max time */
1765 time = QTSAMPLE_PTS (str, &str->samples[i]);
1766 if (min_time == -1 || (!fw && time > min_time) ||
1767 (fw && time < min_time)) {
1771 /* determine stream with leading sample, to get its position */
1773 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1774 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1782 /* no sample for this stream, mark eos */
1784 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1795 /* Copied from mpegtsbase code */
1796 /* FIXME: replace this function when we add new util function for stream-id creation */
1798 _get_upstream_id (GstQTDemux * demux)
1800 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1803 /* Try to create one from the upstream URI, else use a randome number */
1807 /* Try to generate one from the URI query and
1808 * if it fails take a random number instead */
1809 query = gst_query_new_uri ();
1810 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1811 gst_query_parse_uri (query, &uri);
1817 /* And then generate an SHA256 sum of the URI */
1818 cs = g_checksum_new (G_CHECKSUM_SHA256);
1819 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1821 upstream_id = g_strdup (g_checksum_get_string (cs));
1822 g_checksum_free (cs);
1824 /* Just get some random number if the URI query fails */
1825 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1826 "implementing a deterministic way of creating a stream-id");
1828 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1829 g_random_int (), g_random_int ());
1832 gst_query_unref (query);
1837 static QtDemuxStream *
1838 _create_stream (GstQTDemux * demux, guint32 track_id)
1840 QtDemuxStream *stream;
1843 stream = g_new0 (QtDemuxStream, 1);
1844 stream->demux = demux;
1845 stream->track_id = track_id;
1846 upstream_id = _get_upstream_id (demux);
1847 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1848 g_free (upstream_id);
1849 /* new streams always need a discont */
1850 stream->discont = TRUE;
1851 /* we enable clipping for raw audio/video streams */
1852 stream->need_clip = FALSE;
1853 stream->process_func = NULL;
1854 stream->segment_index = -1;
1855 stream->time_position = 0;
1856 stream->sample_index = -1;
1857 stream->offset_in_sample = 0;
1858 stream->new_stream = TRUE;
1859 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1860 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1861 stream->protected = FALSE;
1862 stream->protection_scheme_type = 0;
1863 stream->protection_scheme_version = 0;
1864 stream->protection_scheme_info = NULL;
1865 stream->n_samples_moof = 0;
1866 stream->duration_moof = 0;
1867 stream->duration_last_moof = 0;
1868 stream->alignment = 1;
1869 stream->stream_tags = gst_tag_list_new_empty ();
1870 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1871 g_queue_init (&stream->protection_scheme_event_queue);
1872 stream->ref_count = 1;
1873 /* consistent default for push based mode */
1874 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1879 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1881 GstStructure *structure;
1882 const gchar *variant;
1883 const GstCaps *mediacaps = NULL;
1885 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1887 structure = gst_caps_get_structure (caps, 0);
1888 variant = gst_structure_get_string (structure, "variant");
1890 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1891 QtDemuxStream *stream;
1892 const GValue *value;
1894 demux->fragmented = TRUE;
1895 demux->mss_mode = TRUE;
1897 if (QTDEMUX_N_STREAMS (demux) > 1) {
1898 /* can't do this, we can only renegotiate for another mss format */
1902 value = gst_structure_get_value (structure, "media-caps");
1905 const GValue *timescale_v;
1907 /* TODO update when stream changes during playback */
1909 if (QTDEMUX_N_STREAMS (demux) == 0) {
1910 stream = _create_stream (demux, 1);
1911 g_ptr_array_add (demux->active_streams, stream);
1912 /* mss has no stsd/stsd entry, use id 0 as default */
1913 stream->stsd_entries_length = 1;
1914 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1915 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1917 stream = QTDEMUX_NTH_STREAM (demux, 0);
1920 timescale_v = gst_structure_get_value (structure, "timescale");
1922 stream->timescale = g_value_get_uint64 (timescale_v);
1924 /* default mss timescale */
1925 stream->timescale = 10000000;
1927 demux->timescale = stream->timescale;
1929 mediacaps = gst_value_get_caps (value);
1930 if (!CUR_STREAM (stream)->caps
1931 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1932 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1934 stream->new_caps = TRUE;
1936 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1937 structure = gst_caps_get_structure (mediacaps, 0);
1938 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1939 stream->subtype = FOURCC_vide;
1941 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1942 gst_structure_get_int (structure, "height",
1943 &CUR_STREAM (stream)->height);
1944 gst_structure_get_fraction (structure, "framerate",
1945 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1946 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1948 stream->subtype = FOURCC_soun;
1949 gst_structure_get_int (structure, "channels",
1950 &CUR_STREAM (stream)->n_channels);
1951 gst_structure_get_int (structure, "rate", &rate);
1952 CUR_STREAM (stream)->rate = rate;
1953 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1954 if (gst_structure_has_field (structure, "original-media-type")) {
1955 const gchar *media_type =
1956 gst_structure_get_string (structure, "original-media-type");
1957 if (g_str_has_prefix (media_type, "video")) {
1958 stream->subtype = FOURCC_vide;
1959 } else if (g_str_has_prefix (media_type, "audio")) {
1960 stream->subtype = FOURCC_soun;
1965 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1967 demux->mss_mode = FALSE;
1974 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1978 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1979 gst_pad_stop_task (qtdemux->sinkpad);
1981 if (hard || qtdemux->upstream_format_is_time) {
1982 qtdemux->state = QTDEMUX_STATE_INITIAL;
1983 qtdemux->neededbytes = 16;
1984 qtdemux->todrop = 0;
1985 qtdemux->pullbased = FALSE;
1986 g_clear_pointer (&qtdemux->redirect_location, g_free);
1987 qtdemux->first_mdat = -1;
1988 qtdemux->header_size = 0;
1989 qtdemux->mdatoffset = -1;
1990 qtdemux->restoredata_offset = -1;
1991 if (qtdemux->mdatbuffer)
1992 gst_buffer_unref (qtdemux->mdatbuffer);
1993 if (qtdemux->restoredata_buffer)
1994 gst_buffer_unref (qtdemux->restoredata_buffer);
1995 qtdemux->mdatbuffer = NULL;
1996 qtdemux->restoredata_buffer = NULL;
1997 qtdemux->mdatleft = 0;
1998 qtdemux->mdatsize = 0;
1999 if (qtdemux->comp_brands)
2000 gst_buffer_unref (qtdemux->comp_brands);
2001 qtdemux->comp_brands = NULL;
2002 qtdemux->last_moov_offset = -1;
2003 if (qtdemux->moov_node_compressed) {
2004 g_node_destroy (qtdemux->moov_node_compressed);
2005 if (qtdemux->moov_node)
2006 g_free (qtdemux->moov_node->data);
2008 qtdemux->moov_node_compressed = NULL;
2009 if (qtdemux->moov_node)
2010 g_node_destroy (qtdemux->moov_node);
2011 qtdemux->moov_node = NULL;
2012 if (qtdemux->tag_list)
2013 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2014 qtdemux->tag_list = gst_tag_list_new_empty ();
2015 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2017 if (qtdemux->element_index)
2018 gst_object_unref (qtdemux->element_index);
2019 qtdemux->element_index = NULL;
2021 qtdemux->major_brand = 0;
2022 qtdemux->upstream_format_is_time = FALSE;
2023 qtdemux->upstream_seekable = FALSE;
2024 qtdemux->upstream_size = 0;
2026 qtdemux->fragment_start = -1;
2027 qtdemux->fragment_start_offset = -1;
2028 qtdemux->duration = 0;
2029 qtdemux->moof_offset = 0;
2030 qtdemux->chapters_track_id = 0;
2031 qtdemux->have_group_id = FALSE;
2032 qtdemux->group_id = G_MAXUINT;
2034 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2036 g_queue_clear (&qtdemux->protection_event_queue);
2038 qtdemux->received_seek = FALSE;
2039 qtdemux->first_moof_already_parsed = FALSE;
2041 qtdemux->offset = 0;
2042 gst_adapter_clear (qtdemux->adapter);
2043 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2044 qtdemux->need_segment = TRUE;
2047 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2048 qtdemux->trickmode_interval = 0;
2049 g_ptr_array_set_size (qtdemux->active_streams, 0);
2050 g_ptr_array_set_size (qtdemux->old_streams, 0);
2051 qtdemux->n_video_streams = 0;
2052 qtdemux->n_audio_streams = 0;
2053 qtdemux->n_sub_streams = 0;
2054 qtdemux->exposed = FALSE;
2055 qtdemux->fragmented = FALSE;
2056 qtdemux->mss_mode = FALSE;
2057 gst_caps_replace (&qtdemux->media_caps, NULL);
2058 qtdemux->timescale = 0;
2059 qtdemux->got_moov = FALSE;
2060 qtdemux->cenc_aux_info_offset = 0;
2061 qtdemux->cenc_aux_info_sizes = NULL;
2062 qtdemux->cenc_aux_sample_count = 0;
2063 if (qtdemux->protection_system_ids) {
2064 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2065 qtdemux->protection_system_ids = NULL;
2067 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2068 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2069 GST_BIN_FLAG_STREAMS_AWARE);
2071 if (qtdemux->preferred_protection_system_id) {
2072 g_free (qtdemux->preferred_protection_system_id);
2073 qtdemux->preferred_protection_system_id = NULL;
2075 } else if (qtdemux->mss_mode) {
2076 gst_flow_combiner_reset (qtdemux->flowcombiner);
2077 g_ptr_array_foreach (qtdemux->active_streams,
2078 (GFunc) gst_qtdemux_stream_clear, NULL);
2080 gst_flow_combiner_reset (qtdemux->flowcombiner);
2081 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2082 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2083 stream->sent_eos = FALSE;
2084 stream->time_position = 0;
2085 stream->accumulated_base = 0;
2086 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2092 /* Maps the @segment to the qt edts internal segments and pushes
2093 * the corresponding segment event.
2095 * If it ends up being at a empty segment, a gap will be pushed and the next
2096 * edts segment will be activated in sequence.
2098 * To be used in push-mode only */
2100 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2104 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2105 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2107 stream->time_position = segment->start;
2109 /* in push mode we should be guaranteed that we will have empty segments
2110 * at the beginning and then one segment after, other scenarios are not
2111 * supported and are discarded when parsing the edts */
2112 for (i = 0; i < stream->n_segments; i++) {
2113 if (stream->segments[i].stop_time > segment->start) {
2114 /* push the empty segment and move to the next one */
2115 gst_qtdemux_activate_segment (qtdemux, stream, i,
2116 stream->time_position);
2117 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2118 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2119 stream->time_position);
2121 /* accumulate previous segments */
2122 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2123 stream->accumulated_base +=
2124 (stream->segment.stop -
2125 stream->segment.start) / ABS (stream->segment.rate);
2129 g_assert (i == stream->n_segments - 1);
2136 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2147 for (i = 0; i < len; i++) {
2148 QtDemuxStream *stream = g_ptr_array_index (src, i);
2150 #ifndef GST_DISABLE_GST_DEBUG
2151 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2152 stream, GST_STR_NULL (stream->stream_id), dest);
2154 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2157 g_ptr_array_set_size (src, 0);
2161 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2164 GstQTDemux *demux = GST_QTDEMUX (parent);
2165 gboolean res = TRUE;
2167 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2169 switch (GST_EVENT_TYPE (event)) {
2170 case GST_EVENT_SEGMENT:
2173 QtDemuxStream *stream;
2177 /* some debug output */
2178 gst_event_copy_segment (event, &segment);
2179 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2182 if (segment.format == GST_FORMAT_TIME) {
2183 demux->upstream_format_is_time = TRUE;
2184 demux->segment_seqnum = gst_event_get_seqnum (event);
2186 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2187 "not in time format");
2189 /* chain will send initial newsegment after pads have been added */
2190 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2191 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2196 /* check if this matches a time seek we received previously
2197 * FIXME for backwards compatibility reasons we use the
2198 * seek_offset here to compare. In the future we might want to
2199 * change this to use the seqnum as it uniquely should identify
2200 * the segment that corresponds to the seek. */
2201 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2202 ", received segment offset %" G_GINT64_FORMAT,
2203 demux->seek_offset, segment.start);
2204 if (segment.format == GST_FORMAT_BYTES
2205 && demux->seek_offset == segment.start) {
2206 GST_OBJECT_LOCK (demux);
2207 offset = segment.start;
2209 segment.format = GST_FORMAT_TIME;
2210 segment.start = demux->push_seek_start;
2211 segment.stop = demux->push_seek_stop;
2212 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2213 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2214 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2215 GST_OBJECT_UNLOCK (demux);
2218 /* we only expect a BYTE segment, e.g. following a seek */
2219 if (segment.format == GST_FORMAT_BYTES) {
2220 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2221 offset = segment.start;
2223 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2224 NULL, (gint64 *) & segment.start);
2225 if ((gint64) segment.start < 0)
2228 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2229 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2230 NULL, (gint64 *) & segment.stop);
2231 /* keyframe seeking should already arrange for start >= stop,
2232 * but make sure in other rare cases */
2233 segment.stop = MAX (segment.stop, segment.start);
2235 } else if (segment.format == GST_FORMAT_TIME) {
2236 /* push all data on the adapter before starting this
2238 gst_qtdemux_process_adapter (demux, TRUE);
2240 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2244 /* We shouldn't modify upstream driven TIME FORMAT segment */
2245 if (!demux->upstream_format_is_time) {
2246 /* accept upstream's notion of segment and distribute along */
2247 segment.format = GST_FORMAT_TIME;
2248 segment.position = segment.time = segment.start;
2249 segment.duration = demux->segment.duration;
2250 segment.base = gst_segment_to_running_time (&demux->segment,
2251 GST_FORMAT_TIME, demux->segment.position);
2254 gst_segment_copy_into (&segment, &demux->segment);
2255 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2257 /* map segment to internal qt segments and push on each stream */
2258 if (QTDEMUX_N_STREAMS (demux)) {
2259 demux->need_segment = TRUE;
2260 gst_qtdemux_check_send_pending_segment (demux);
2263 /* clear leftover in current segment, if any */
2264 gst_adapter_clear (demux->adapter);
2266 /* set up streaming thread */
2267 demux->offset = offset;
2268 if (demux->upstream_format_is_time) {
2269 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2270 "set values to restart reading from a new atom");
2271 demux->neededbytes = 16;
2274 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2277 demux->todrop = stream->samples[idx].offset - offset;
2278 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2280 /* set up for EOS */
2281 demux->neededbytes = -1;
2286 gst_event_unref (event);
2290 case GST_EVENT_FLUSH_START:
2292 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2293 gst_event_unref (event);
2296 QTDEMUX_EXPOSE_LOCK (demux);
2297 res = gst_pad_event_default (demux->sinkpad, parent, event);
2298 QTDEMUX_EXPOSE_UNLOCK (demux);
2301 case GST_EVENT_FLUSH_STOP:
2305 dur = demux->segment.duration;
2306 gst_qtdemux_reset (demux, FALSE);
2307 demux->segment.duration = dur;
2309 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2310 gst_event_unref (event);
2316 /* If we are in push mode, and get an EOS before we've seen any streams,
2317 * then error out - we have nowhere to send the EOS */
2318 if (!demux->pullbased) {
2320 gboolean has_valid_stream = FALSE;
2321 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2322 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2323 has_valid_stream = TRUE;
2327 if (!has_valid_stream)
2328 gst_qtdemux_post_no_playable_stream_error (demux);
2330 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2331 (guint) gst_adapter_available (demux->adapter));
2332 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2338 case GST_EVENT_CAPS:{
2339 GstCaps *caps = NULL;
2341 gst_event_parse_caps (event, &caps);
2342 gst_qtdemux_setcaps (demux, caps);
2344 gst_event_unref (event);
2347 case GST_EVENT_PROTECTION:
2349 const gchar *system_id = NULL;
2351 gst_event_parse_protection (event, &system_id, NULL, NULL);
2352 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2354 gst_qtdemux_append_protection_system_id (demux, system_id);
2355 /* save the event for later, for source pads that have not been created */
2356 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2357 /* send it to all pads that already exist */
2358 gst_qtdemux_push_event (demux, event);
2362 case GST_EVENT_STREAM_START:
2365 gst_event_unref (event);
2367 /* Drain all the buffers */
2368 gst_qtdemux_process_adapter (demux, TRUE);
2369 gst_qtdemux_reset (demux, FALSE);
2370 /* We expect new moov box after new stream-start event */
2371 if (demux->exposed) {
2372 gst_qtdemux_stream_concat (demux,
2373 demux->old_streams, demux->active_streams);
2382 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2389 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2392 GstQTDemux *demux = GST_QTDEMUX (parent);
2393 gboolean res = FALSE;
2395 switch (GST_QUERY_TYPE (query)) {
2396 case GST_QUERY_BITRATE:
2398 GstClockTime duration;
2400 /* populate demux->upstream_size if not done yet */
2401 gst_qtdemux_check_seekability (demux);
2403 if (demux->upstream_size != -1
2404 && gst_qtdemux_get_duration (demux, &duration)) {
2406 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2409 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2410 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2411 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2413 /* TODO: better results based on ranges/index tables */
2414 gst_query_set_bitrate (query, bitrate);
2420 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2430 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2432 GstQTDemux *demux = GST_QTDEMUX (element);
2434 GST_OBJECT_LOCK (demux);
2435 if (demux->element_index)
2436 gst_object_unref (demux->element_index);
2438 demux->element_index = gst_object_ref (index);
2440 demux->element_index = NULL;
2442 GST_OBJECT_UNLOCK (demux);
2443 /* object lock might be taken again */
2445 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2446 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2447 demux->element_index, demux->index_id);
2451 gst_qtdemux_get_index (GstElement * element)
2453 GstIndex *result = NULL;
2454 GstQTDemux *demux = GST_QTDEMUX (element);
2456 GST_OBJECT_LOCK (demux);
2457 if (demux->element_index)
2458 result = gst_object_ref (demux->element_index);
2459 GST_OBJECT_UNLOCK (demux);
2461 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2468 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2470 g_free ((gpointer) stream->stco.data);
2471 stream->stco.data = NULL;
2472 g_free ((gpointer) stream->stsz.data);
2473 stream->stsz.data = NULL;
2474 g_free ((gpointer) stream->stsc.data);
2475 stream->stsc.data = NULL;
2476 g_free ((gpointer) stream->stts.data);
2477 stream->stts.data = NULL;
2478 g_free ((gpointer) stream->stss.data);
2479 stream->stss.data = NULL;
2480 g_free ((gpointer) stream->stps.data);
2481 stream->stps.data = NULL;
2482 g_free ((gpointer) stream->ctts.data);
2483 stream->ctts.data = NULL;
2487 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2489 g_free (stream->segments);
2490 stream->segments = NULL;
2491 stream->segment_index = -1;
2492 stream->accumulated_base = 0;
2496 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2498 g_free (stream->samples);
2499 stream->samples = NULL;
2500 gst_qtdemux_stbl_free (stream);
2503 g_free (stream->ra_entries);
2504 stream->ra_entries = NULL;
2505 stream->n_ra_entries = 0;
2507 stream->sample_index = -1;
2508 stream->stbl_index = -1;
2509 stream->n_samples = 0;
2510 stream->time_position = 0;
2512 stream->n_samples_moof = 0;
2513 stream->duration_moof = 0;
2514 stream->duration_last_moof = 0;
2518 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2521 if (stream->allocator)
2522 gst_object_unref (stream->allocator);
2523 while (stream->buffers) {
2524 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2525 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2527 for (i = 0; i < stream->stsd_entries_length; i++) {
2528 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2529 if (entry->rgb8_palette) {
2530 gst_memory_unref (entry->rgb8_palette);
2531 entry->rgb8_palette = NULL;
2533 entry->sparse = FALSE;
2536 if (stream->stream_tags)
2537 gst_tag_list_unref (stream->stream_tags);
2539 stream->stream_tags = gst_tag_list_new_empty ();
2540 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2541 g_free (stream->redirect_uri);
2542 stream->redirect_uri = NULL;
2543 stream->sent_eos = FALSE;
2544 stream->protected = FALSE;
2545 if (stream->protection_scheme_info) {
2546 if (stream->protection_scheme_type == FOURCC_cenc
2547 || stream->protection_scheme_type == FOURCC_cbcs) {
2548 QtDemuxCencSampleSetInfo *info =
2549 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2550 if (info->default_properties)
2551 gst_structure_free (info->default_properties);
2552 if (info->crypto_info)
2553 g_ptr_array_free (info->crypto_info, TRUE);
2555 if (stream->protection_scheme_type == FOURCC_aavd) {
2556 QtDemuxAavdEncryptionInfo *info =
2557 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2558 if (info->default_properties)
2559 gst_structure_free (info->default_properties);
2561 g_free (stream->protection_scheme_info);
2562 stream->protection_scheme_info = NULL;
2564 stream->protection_scheme_type = 0;
2565 stream->protection_scheme_version = 0;
2566 g_queue_foreach (&stream->protection_scheme_event_queue,
2567 (GFunc) gst_event_unref, NULL);
2568 g_queue_clear (&stream->protection_scheme_event_queue);
2569 gst_qtdemux_stream_flush_segments_data (stream);
2570 gst_qtdemux_stream_flush_samples_data (stream);
2574 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2577 gst_qtdemux_stream_clear (stream);
2578 for (i = 0; i < stream->stsd_entries_length; i++) {
2579 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2581 gst_caps_unref (entry->caps);
2585 g_free (stream->stsd_entries);
2586 stream->stsd_entries = NULL;
2587 stream->stsd_entries_length = 0;
2590 static QtDemuxStream *
2591 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2593 g_atomic_int_add (&stream->ref_count, 1);
2599 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2601 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2602 gst_qtdemux_stream_reset (stream);
2603 gst_tag_list_unref (stream->stream_tags);
2605 GstQTDemux *demux = stream->demux;
2606 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2607 GST_OBJECT_LOCK (demux);
2608 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2609 GST_OBJECT_UNLOCK (demux);
2611 g_free (stream->stream_id);
2616 static GstStateChangeReturn
2617 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2619 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2620 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2622 switch (transition) {
2623 case GST_STATE_CHANGE_READY_TO_PAUSED:
2624 gst_qtdemux_reset (qtdemux, TRUE);
2630 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2632 switch (transition) {
2633 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2634 gst_qtdemux_reset (qtdemux, TRUE);
2645 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2647 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2649 g_return_if_fail (GST_IS_CONTEXT (context));
2651 if (gst_context_has_context_type (context,
2652 "drm-preferred-decryption-system-id")) {
2653 const GstStructure *s;
2655 s = gst_context_get_structure (context);
2656 g_free (qtdemux->preferred_protection_system_id);
2657 qtdemux->preferred_protection_system_id =
2658 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2659 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2660 qtdemux->preferred_protection_system_id);
2663 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2667 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2669 /* counts as header data */
2670 qtdemux->header_size += length;
2672 /* only consider at least a sufficiently complete ftyp atom */
2676 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2677 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2678 GST_FOURCC_ARGS (qtdemux->major_brand));
2679 if (qtdemux->comp_brands)
2680 gst_buffer_unref (qtdemux->comp_brands);
2681 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2682 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2687 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2688 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2689 guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2690 guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2691 const guint8 * constant_iv)
2693 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2694 gst_buffer_fill (kid_buf, 0, kid, 16);
2695 if (info->default_properties)
2696 gst_structure_free (info->default_properties);
2697 info->default_properties =
2698 gst_structure_new ("application/x-cenc",
2699 "iv_size", G_TYPE_UINT, iv_size,
2700 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2701 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2702 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2703 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2704 gst_buffer_unref (kid_buf);
2705 if (protection_scheme_type == FOURCC_cbcs) {
2706 if (crypt_byte_block != 0 || skip_byte_block != 0) {
2707 gst_structure_set (info->default_properties, "crypt_byte_block",
2708 G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2709 skip_byte_block, NULL);
2711 if (constant_iv != NULL) {
2712 GstBuffer *constant_iv_buf =
2713 gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2714 gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2715 gst_structure_set (info->default_properties, "constant_iv_size",
2716 G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2718 gst_buffer_unref (constant_iv_buf);
2720 gst_structure_set (info->default_properties, "cipher-mode",
2721 G_TYPE_STRING, "cbcs", NULL);
2723 gst_structure_set (info->default_properties, "cipher-mode",
2724 G_TYPE_STRING, "cenc", NULL);
2729 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2730 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2732 guint32 algorithm_id = 0;
2734 gboolean is_encrypted = TRUE;
2737 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2738 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2743 if (algorithm_id == 0) {
2744 is_encrypted = FALSE;
2745 } else if (algorithm_id == 1) {
2746 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2747 } else if (algorithm_id == 2) {
2748 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2751 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2754 if (!gst_byte_reader_get_data (br, 16, &kid))
2757 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2758 is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2759 gst_structure_set (info->default_properties, "piff_algorithm_id",
2760 G_TYPE_UINT, algorithm_id, NULL);
2766 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2774 QtDemuxStream *stream;
2775 GstStructure *structure;
2776 QtDemuxCencSampleSetInfo *ss_info = NULL;
2777 const gchar *system_id;
2778 gboolean uses_sub_sample_encryption = FALSE;
2779 guint32 sample_count;
2781 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2784 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2786 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2787 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2788 GST_WARNING_OBJECT (qtdemux,
2789 "Attempting PIFF box parsing on an unencrypted stream.");
2793 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2794 G_TYPE_STRING, &system_id, NULL);
2795 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2797 stream->protected = TRUE;
2798 stream->protection_scheme_type = FOURCC_cenc;
2800 if (!stream->protection_scheme_info)
2801 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2803 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2804 if (!ss_info->default_properties) {
2805 ss_info->default_properties =
2806 gst_structure_new ("application/x-cenc",
2807 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2812 if (ss_info->crypto_info) {
2813 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2814 g_ptr_array_free (ss_info->crypto_info, TRUE);
2815 ss_info->crypto_info = NULL;
2819 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2821 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2822 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2826 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2827 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2831 if ((flags & 0x000001)) {
2832 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2835 } else if ((flags & 0x000002)) {
2836 uses_sub_sample_encryption = TRUE;
2839 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2841 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2845 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2846 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2850 ss_info->crypto_info =
2851 g_ptr_array_new_full (sample_count,
2852 (GDestroyNotify) qtdemux_gst_structure_free);
2854 for (i = 0; i < sample_count; ++i) {
2855 GstStructure *properties;
2859 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2860 if (properties == NULL) {
2861 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2862 qtdemux->cenc_aux_sample_count = i;
2866 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2867 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2868 gst_structure_free (properties);
2869 qtdemux->cenc_aux_sample_count = i;
2872 buf = gst_buffer_new_wrapped (data, iv_size);
2873 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2874 gst_buffer_unref (buf);
2876 if (uses_sub_sample_encryption) {
2877 guint16 n_subsamples;
2878 const GValue *kid_buf_value;
2880 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2881 || n_subsamples == 0) {
2882 GST_ERROR_OBJECT (qtdemux,
2883 "failed to get subsample count for sample %u", i);
2884 gst_structure_free (properties);
2885 qtdemux->cenc_aux_sample_count = i;
2888 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2889 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2890 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2892 gst_structure_free (properties);
2893 qtdemux->cenc_aux_sample_count = i;
2896 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2899 gst_structure_get_value (ss_info->default_properties, "kid");
2901 gst_structure_set (properties,
2902 "subsample_count", G_TYPE_UINT, n_subsamples,
2903 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2904 gst_structure_set_value (properties, "kid", kid_buf_value);
2905 gst_buffer_unref (buf);
2907 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2910 g_ptr_array_add (ss_info->crypto_info, properties);
2913 qtdemux->cenc_aux_sample_count = sample_count;
2917 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2919 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2920 0x97, 0xA9, 0x42, 0xE8,
2921 0x9C, 0x71, 0x99, 0x94,
2922 0x91, 0xE3, 0xAF, 0xAC
2924 static const guint8 playready_uuid[] = {
2925 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2926 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2929 static const guint8 piff_sample_encryption_uuid[] = {
2930 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2931 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2936 /* counts as header data */
2937 qtdemux->header_size += length;
2939 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2941 if (length <= offset + 16) {
2942 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2946 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2948 GstTagList *taglist;
2950 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2951 length - offset - 16, NULL);
2952 taglist = gst_tag_list_from_xmp_buffer (buf);
2953 gst_buffer_unref (buf);
2955 /* make sure we have a usable taglist */
2956 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2958 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2960 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2962 const gunichar2 *s_utf16;
2965 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2966 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2967 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2968 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2972 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2973 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2975 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2976 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2978 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2979 GST_READ_UINT32_LE (buffer + offset),
2980 GST_READ_UINT32_LE (buffer + offset + 4),
2981 GST_READ_UINT32_LE (buffer + offset + 8),
2982 GST_READ_UINT32_LE (buffer + offset + 12));
2987 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2989 GstSidxParser sidx_parser;
2990 GstIsoffParserResult res;
2993 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2996 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2998 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2999 if (res == GST_ISOFF_QT_PARSER_DONE) {
3000 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3002 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3005 /* caller verifies at least 8 bytes in buf */
3007 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3008 guint64 * plength, guint32 * pfourcc)
3013 length = QT_UINT32 (data);
3014 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3015 fourcc = QT_FOURCC (data + 4);
3016 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3019 length = G_MAXUINT64;
3020 } else if (length == 1 && size >= 16) {
3021 /* this means we have an extended size, which is the 64 bit value of
3022 * the next 8 bytes */
3023 length = QT_UINT64 (data + 8);
3024 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3034 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3036 guint32 version = 0;
3037 GstClockTime duration = 0;
3039 if (!gst_byte_reader_get_uint32_be (br, &version))
3044 if (!gst_byte_reader_get_uint64_be (br, &duration))
3049 if (!gst_byte_reader_get_uint32_be (br, &dur))
3054 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3055 qtdemux->duration = duration;
3061 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3067 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3068 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3070 if (!stream->parsed_trex && qtdemux->moov_node) {
3072 GstByteReader trex_data;
3074 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3076 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3079 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3081 /* skip version/flags */
3082 if (!gst_byte_reader_skip (&trex_data, 4))
3084 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3086 if (id != stream->track_id)
3088 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3090 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3092 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3094 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3097 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3098 "duration %d, size %d, flags 0x%x", stream->track_id,
3101 stream->parsed_trex = TRUE;
3102 stream->def_sample_description_index = sdi;
3103 stream->def_sample_duration = dur;
3104 stream->def_sample_size = size;
3105 stream->def_sample_flags = flags;
3108 /* iterate all siblings */
3109 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3115 *ds_duration = stream->def_sample_duration;
3116 *ds_size = stream->def_sample_size;
3117 *ds_flags = stream->def_sample_flags;
3119 /* even then, above values are better than random ... */
3120 if (G_UNLIKELY (!stream->parsed_trex)) {
3121 GST_WARNING_OBJECT (qtdemux,
3122 "failed to find fragment defaults for stream %d", stream->track_id);
3129 /* This method should be called whenever a more accurate duration might
3130 * have been found. It will update all relevant variables if/where needed
3133 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3137 GstClockTime prevdur;
3139 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3141 if (movdur > qtdemux->duration) {
3142 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3143 GST_DEBUG_OBJECT (qtdemux,
3144 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3145 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3146 qtdemux->duration = movdur;
3147 GST_DEBUG_OBJECT (qtdemux,
3148 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3149 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3150 GST_TIME_ARGS (qtdemux->segment.stop));
3151 if (qtdemux->segment.duration == prevdur) {
3152 /* If the current segment has duration/stop identical to previous duration
3153 * update them also (because they were set at that point in time with
3154 * the wrong duration */
3155 /* We convert the value *from* the timescale version to avoid rounding errors */
3156 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3157 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3158 qtdemux->segment.duration = fixeddur;
3159 qtdemux->segment.stop = fixeddur;
3163 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3164 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3166 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3167 if (movdur > stream->duration) {
3168 GST_DEBUG_OBJECT (qtdemux,
3169 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3170 GST_TIME_ARGS (duration));
3171 stream->duration = movdur;
3172 /* internal duration tracking state has been updated above, so */
3173 /* preserve an open-ended dummy segment rather than repeatedly updating
3174 * it and spamming downstream accordingly with segment events */
3175 /* also mangle the edit list end time when fragmented with a single edit
3176 * list that may only cover any non-fragmented data */
3177 if ((stream->dummy_segment ||
3178 (qtdemux->fragmented && stream->n_segments == 1)) &&
3179 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3180 /* Update all dummy values to new duration */
3181 stream->segments[0].stop_time = duration;
3182 stream->segments[0].duration = duration;
3183 stream->segments[0].media_stop = duration;
3185 /* let downstream know we possibly have a new stop time */
3186 if (stream->segment_index != -1) {
3189 if (qtdemux->segment.rate >= 0) {
3190 pos = stream->segment.start;
3192 pos = stream->segment.stop;
3195 gst_qtdemux_stream_update_segment (qtdemux, stream,
3196 stream->segment_index, pos, NULL, NULL);
3204 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3205 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3206 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3207 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3210 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3212 gint32 data_offset = 0;
3214 guint32 flags = 0, first_flags = 0, samples_count = 0;
3217 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3218 QtDemuxSample *sample;
3219 gboolean ismv = FALSE;
3220 gint64 initial_offset;
3223 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3224 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3225 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3226 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3228 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3229 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3233 /* presence of stss or not can't really tell us much,
3234 * and flags and so on tend to be marginally reliable in these files */
3235 if (stream->subtype == FOURCC_soun) {
3236 GST_DEBUG_OBJECT (qtdemux,
3237 "sound track in fragmented file; marking all keyframes");
3238 stream->all_keyframe = TRUE;
3241 if (!gst_byte_reader_get_uint8 (trun, &version) ||
3242 !gst_byte_reader_get_uint24_be (trun, &flags))
3245 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3248 if (flags & TR_DATA_OFFSET) {
3249 /* note this is really signed */
3250 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3252 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3253 /* default base offset = first byte of moof */
3254 if (*base_offset == -1) {
3255 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3256 *base_offset = moof_offset;
3258 *running_offset = *base_offset + data_offset;
3260 /* if no offset at all, that would mean data starts at moof start,
3261 * which is a bit wrong and is ismv crappy way, so compensate
3262 * assuming data is in mdat following moof */
3263 if (*base_offset == -1) {
3264 *base_offset = moof_offset + moof_length + 8;
3265 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3268 if (*running_offset == -1)
3269 *running_offset = *base_offset;
3272 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3274 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3275 data_offset, flags, samples_count);
3277 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3278 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3279 GST_DEBUG_OBJECT (qtdemux,
3280 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3281 flags ^= TR_FIRST_SAMPLE_FLAGS;
3283 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3285 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3289 /* FIXME ? spec says other bits should also be checked to determine
3290 * entry size (and prefix size for that matter) */
3292 dur_offset = size_offset = 0;
3293 if (flags & TR_SAMPLE_DURATION) {
3294 GST_LOG_OBJECT (qtdemux, "entry duration present");
3295 dur_offset = entry_size;
3298 if (flags & TR_SAMPLE_SIZE) {
3299 GST_LOG_OBJECT (qtdemux, "entry size present");
3300 size_offset = entry_size;
3303 if (flags & TR_SAMPLE_FLAGS) {
3304 GST_LOG_OBJECT (qtdemux, "entry flags present");
3305 flags_offset = entry_size;
3308 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3309 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3310 ct_offset = entry_size;
3314 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3316 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3318 if (stream->n_samples + samples_count >=
3319 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3322 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3323 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3324 (stream->n_samples + samples_count) *
3325 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3327 /* create a new array of samples if it's the first sample parsed */
3328 if (stream->n_samples == 0) {
3329 g_assert (stream->samples == NULL);
3330 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3331 /* or try to reallocate it with space enough to insert the new samples */
3333 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3334 stream->n_samples + samples_count);
3335 if (stream->samples == NULL)
3338 if (qtdemux->fragment_start != -1) {
3339 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3340 qtdemux->fragment_start = -1;
3342 if (stream->n_samples == 0) {
3343 if (decode_ts > 0) {
3344 timestamp = decode_ts;
3345 } else if (stream->pending_seek != NULL) {
3346 /* if we don't have a timestamp from a tfdt box, we'll use the one
3347 * from the mfra seek table */
3348 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3349 GST_TIME_ARGS (stream->pending_seek->ts));
3351 /* FIXME: this is not fully correct, the timestamp refers to the random
3352 * access sample refered to in the tfra entry, which may not necessarily
3353 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3354 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3359 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3360 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3361 GST_TIME_ARGS (gst_ts));
3363 /* subsequent fragments extend stream */
3365 stream->samples[stream->n_samples - 1].timestamp +
3366 stream->samples[stream->n_samples - 1].duration;
3368 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3369 * difference (1 sec.) between decode_ts and timestamp, prefer the
3371 if (has_tfdt && !qtdemux->upstream_format_is_time
3372 && ABSDIFF (decode_ts, timestamp) >
3373 MAX (stream->duration_last_moof / 2,
3374 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3375 GST_INFO_OBJECT (qtdemux,
3376 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3377 ") are significantly different (more than %" GST_TIME_FORMAT
3378 "), using decode_ts",
3379 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3380 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3381 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3382 MAX (stream->duration_last_moof / 2,
3383 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3384 timestamp = decode_ts;
3387 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3388 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3389 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3393 initial_offset = *running_offset;
3395 sample = stream->samples + stream->n_samples;
3396 for (i = 0; i < samples_count; i++) {
3397 guint32 dur, size, sflags;
3400 /* first read sample data */
3401 if (flags & TR_SAMPLE_DURATION) {
3402 dur = QT_UINT32 (data + dur_offset);
3404 dur = d_sample_duration;
3406 if (flags & TR_SAMPLE_SIZE) {
3407 size = QT_UINT32 (data + size_offset);
3409 size = d_sample_size;
3411 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3413 sflags = first_flags;
3415 sflags = d_sample_flags;
3417 } else if (flags & TR_SAMPLE_FLAGS) {
3418 sflags = QT_UINT32 (data + flags_offset);
3420 sflags = d_sample_flags;
3423 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3424 /* Read offsets as signed numbers regardless of trun version as very
3425 * high offsets are unlikely and there are files out there that use
3426 * version=0 truns with negative offsets */
3427 ct = QT_UINT32 (data + ct_offset);
3429 /* FIXME: Set offset to 0 for "no decode samples". This needs
3430 * to be handled in a codec specific manner ideally. */
3431 if (ct == G_MININT32)
3438 /* fill the sample information */
3439 sample->offset = *running_offset;
3440 sample->pts_offset = ct;
3441 sample->size = size;
3442 sample->timestamp = timestamp;
3443 sample->duration = dur;
3444 /* sample-is-difference-sample */
3445 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3446 * now idea how it relates to bitfield other than massive LE/BE confusion */
3447 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3448 *running_offset += size;
3450 stream->duration_moof += dur;
3457 /* Shift PTS/DTS to allow for negative composition offsets while keeping
3458 * A/V sync in place. This is similar to the code handling ctts/cslg in the
3459 * non-fragmented case.
3462 stream->cslg_shift = -min_ct;
3464 stream->cslg_shift = 0;
3466 /* Update total duration if needed */
3467 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3469 /* Pre-emptively figure out size of mdat based on trun information.
3470 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3471 * size, else we will still be able to use this when dealing with gap'ed
3473 qtdemux->mdatleft = *running_offset - initial_offset;
3474 qtdemux->mdatoffset = initial_offset;
3475 qtdemux->mdatsize = qtdemux->mdatleft;
3477 stream->n_samples += samples_count;
3478 stream->n_samples_moof += samples_count;
3480 if (stream->pending_seek != NULL)
3481 stream->pending_seek = NULL;
3487 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3492 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3498 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3499 "be larger than %uMB (broken file?)", stream->n_samples,
3500 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3505 /* find stream with @id */
3506 static inline QtDemuxStream *
3507 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3509 QtDemuxStream *stream;
3513 if (G_UNLIKELY (!id)) {
3514 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3518 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3519 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3520 if (stream->track_id == id)
3523 if (qtdemux->mss_mode) {
3524 /* mss should have only 1 stream anyway */
3525 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3532 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3533 guint32 * fragment_number)
3535 if (!gst_byte_reader_skip (mfhd, 4))
3537 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3542 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3548 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3549 QtDemuxStream ** stream, guint32 * default_sample_duration,
3550 guint32 * default_sample_size, guint32 * default_sample_flags,
3551 gint64 * base_offset)
3554 guint32 track_id = 0;
3556 if (!gst_byte_reader_skip (tfhd, 1) ||
3557 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3560 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3563 *stream = qtdemux_find_stream (qtdemux, track_id);
3564 if (G_UNLIKELY (!*stream))
3565 goto unknown_stream;
3567 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3568 *base_offset = qtdemux->moof_offset;
3570 if (flags & TF_BASE_DATA_OFFSET)
3571 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3574 /* obtain stream defaults */
3575 qtdemux_parse_trex (qtdemux, *stream,
3576 default_sample_duration, default_sample_size, default_sample_flags);
3578 (*stream)->stsd_sample_description_id =
3579 (*stream)->def_sample_description_index - 1;
3581 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3582 guint32 sample_description_index;
3583 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3585 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3588 if (qtdemux->mss_mode) {
3589 /* mss has no stsd entry */
3590 (*stream)->stsd_sample_description_id = 0;
3593 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3594 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3597 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3598 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3601 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3602 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3609 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3614 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3620 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3621 guint64 * decode_time)
3623 guint32 version = 0;
3625 if (!gst_byte_reader_get_uint32_be (br, &version))
3630 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3633 guint32 dec_time = 0;
3634 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3636 *decode_time = dec_time;
3639 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3646 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3651 /* Returns a pointer to a GstStructure containing the properties of
3652 * the stream sample identified by @sample_index. The caller must unref
3653 * the returned object after use. Returns NULL if unsuccessful. */
3654 static GstStructure *
3655 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3656 QtDemuxStream * stream, guint sample_index)
3658 QtDemuxCencSampleSetInfo *info = NULL;
3660 g_return_val_if_fail (stream != NULL, NULL);
3661 g_return_val_if_fail (stream->protected, NULL);
3662 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3664 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3666 /* Currently, cenc properties for groups of samples are not supported, so
3667 * simply return a copy of the default sample properties */
3668 return gst_structure_copy (info->default_properties);
3671 /* Parses the sizes of sample auxiliary information contained within a stream,
3672 * as given in a saiz box. Returns array of sample_count guint8 size values,
3673 * or NULL on failure */
3675 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3676 GstByteReader * br, guint32 * sample_count)
3680 guint8 default_info_size;
3682 g_return_val_if_fail (qtdemux != NULL, NULL);
3683 g_return_val_if_fail (stream != NULL, NULL);
3684 g_return_val_if_fail (br != NULL, NULL);
3685 g_return_val_if_fail (sample_count != NULL, NULL);
3687 if (!gst_byte_reader_get_uint32_be (br, &flags))
3691 /* aux_info_type and aux_info_type_parameter are ignored */
3692 if (!gst_byte_reader_skip (br, 8))
3696 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3698 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3700 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3702 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3705 if (default_info_size == 0) {
3706 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3710 info_sizes = g_new (guint8, *sample_count);
3711 memset (info_sizes, default_info_size, *sample_count);
3717 /* Parses the offset of sample auxiliary information contained within a stream,
3718 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3720 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3721 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3726 guint32 aux_info_type = 0;
3727 guint32 aux_info_type_parameter = 0;
3728 guint32 entry_count;
3731 const guint8 *aux_info_type_data = NULL;
3733 g_return_val_if_fail (qtdemux != NULL, FALSE);
3734 g_return_val_if_fail (stream != NULL, FALSE);
3735 g_return_val_if_fail (br != NULL, FALSE);
3736 g_return_val_if_fail (offset != NULL, FALSE);
3738 if (!gst_byte_reader_get_uint8 (br, &version))
3741 if (!gst_byte_reader_get_uint24_be (br, &flags))
3746 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3748 aux_info_type = QT_FOURCC (aux_info_type_data);
3750 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3752 } else if (stream->protected) {
3753 aux_info_type = stream->protection_scheme_type;
3755 aux_info_type = CUR_STREAM (stream)->fourcc;
3759 *info_type = aux_info_type;
3760 if (info_type_parameter)
3761 *info_type_parameter = aux_info_type_parameter;
3763 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3764 "aux_info_type_parameter: %#06x",
3765 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3767 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3770 if (entry_count != 1) {
3771 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3776 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3778 *offset = (guint64) off_32;
3780 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3785 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3790 qtdemux_gst_structure_free (GstStructure * gststructure)
3793 gst_structure_free (gststructure);
3797 /* Parses auxiliary information relating to samples protected using
3798 * Common Encryption (cenc); the format of this information
3799 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3802 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3803 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3805 QtDemuxCencSampleSetInfo *ss_info = NULL;
3808 GPtrArray *old_crypto_info = NULL;
3809 guint old_entries = 0;
3811 g_return_val_if_fail (qtdemux != NULL, FALSE);
3812 g_return_val_if_fail (stream != NULL, FALSE);
3813 g_return_val_if_fail (br != NULL, FALSE);
3814 g_return_val_if_fail (stream->protected, FALSE);
3815 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3817 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3819 if (ss_info->crypto_info) {
3820 old_crypto_info = ss_info->crypto_info;
3821 /* Count number of non-null entries remaining at the tail end */
3822 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3823 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3829 ss_info->crypto_info =
3830 g_ptr_array_new_full (sample_count + old_entries,
3831 (GDestroyNotify) qtdemux_gst_structure_free);
3833 /* We preserve old entries because we parse the next moof in advance
3834 * of consuming all samples from the previous moof, and otherwise
3835 * we'd discard the corresponding crypto info for the samples
3836 * from the previous fragment. */
3838 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3840 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3841 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3843 g_ptr_array_index (old_crypto_info, i) = NULL;
3847 if (old_crypto_info) {
3848 /* Everything now belongs to the new array */
3849 g_ptr_array_free (old_crypto_info, TRUE);
3852 for (i = 0; i < sample_count; ++i) {
3853 GstStructure *properties;
3854 guint16 n_subsamples = 0;
3858 gboolean could_read_iv;
3860 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3861 if (properties == NULL) {
3862 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3865 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3866 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3867 gst_structure_free (properties);
3871 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3872 if (could_read_iv) {
3873 buf = gst_buffer_new_wrapped (data, iv_size);
3874 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3875 gst_buffer_unref (buf);
3876 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3877 const GValue *constant_iv_size_value =
3878 gst_structure_get_value (properties, "constant_iv_size");
3879 const GValue *constant_iv_value =
3880 gst_structure_get_value (properties, "iv");
3881 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3882 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3883 gst_structure_free (properties);
3886 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3887 gst_structure_remove_field (properties, "constant_iv_size");
3888 } else if (stream->protection_scheme_type == FOURCC_cenc) {
3889 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3890 gst_structure_free (properties);
3893 size = info_sizes[i];
3894 if (size > iv_size) {
3895 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3896 || !(n_subsamples > 0)) {
3897 gst_structure_free (properties);
3898 GST_ERROR_OBJECT (qtdemux,
3899 "failed to get subsample count for sample %u", i);
3902 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3903 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3904 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3906 gst_structure_free (properties);
3909 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3911 gst_structure_free (properties);
3914 gst_structure_set (properties,
3915 "subsample_count", G_TYPE_UINT, n_subsamples,
3916 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3917 gst_buffer_unref (buf);
3919 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3921 g_ptr_array_add (ss_info->crypto_info, properties);
3926 /* Converts a UUID in raw byte form to a string representation, as defined in
3927 * RFC 4122. The caller takes ownership of the returned string and is
3928 * responsible for freeing it after use. */
3930 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3932 const guint8 *uuid = (const guint8 *) uuid_bytes;
3934 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3935 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3936 uuid[0], uuid[1], uuid[2], uuid[3],
3937 uuid[4], uuid[5], uuid[6], uuid[7],
3938 uuid[8], uuid[9], uuid[10], uuid[11],
3939 uuid[12], uuid[13], uuid[14], uuid[15]);
3942 /* Parses a Protection System Specific Header box (pssh), as defined in the
3943 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3944 * information needed by a specific content protection system in order to
3945 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3948 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3950 gchar *sysid_string;
3951 guint32 pssh_size = QT_UINT32 (node->data);
3952 GstBuffer *pssh = NULL;
3953 GstEvent *event = NULL;
3954 guint32 parent_box_type;
3957 if (G_UNLIKELY (pssh_size < 32U)) {
3958 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3963 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3965 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3967 pssh = gst_buffer_new_memdup (node->data, pssh_size);
3968 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3969 gst_buffer_get_size (pssh));
3971 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3973 /* Push an event containing the pssh box onto the queues of all streams. */
3974 event = gst_event_new_protection (sysid_string, pssh,
3975 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3976 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3977 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3978 GST_TRACE_OBJECT (qtdemux,
3979 "adding protection event for stream %s and system %s",
3980 stream->stream_id, sysid_string);
3981 g_queue_push_tail (&stream->protection_scheme_event_queue,
3982 gst_event_ref (event));
3984 g_free (sysid_string);
3985 gst_event_unref (event);
3986 gst_buffer_unref (pssh);
3991 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3992 guint64 moof_offset, QtDemuxStream * stream)
3994 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3996 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3997 GNode *saiz_node, *saio_node, *pssh_node;
3998 GstByteReader saiz_data, saio_data;
3999 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4000 gint64 base_offset, running_offset;
4002 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4004 /* NOTE @stream ignored */
4006 moof_node = g_node_new ((guint8 *) buffer);
4007 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4008 qtdemux_node_dump (qtdemux, moof_node);
4010 /* Get fragment number from mfhd and check it's valid */
4012 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4013 if (mfhd_node == NULL)
4015 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4017 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4019 /* unknown base_offset to start with */
4020 base_offset = running_offset = -1;
4021 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4023 guint64 decode_time = 0;
4025 /* Fragment Header node */
4027 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4031 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4032 &ds_size, &ds_flags, &base_offset))
4035 /* The following code assumes at most a single set of sample auxiliary
4036 * data in the fragment (consisting of a saiz box and a corresponding saio
4037 * box); in theory, however, there could be multiple sets of sample
4038 * auxiliary data in a fragment. */
4040 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4043 guint32 info_type = 0;
4045 guint32 info_type_parameter = 0;
4047 g_free (qtdemux->cenc_aux_info_sizes);
4049 qtdemux->cenc_aux_info_sizes =
4050 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4051 &qtdemux->cenc_aux_sample_count);
4052 if (qtdemux->cenc_aux_info_sizes == NULL) {
4053 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4057 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4060 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4061 g_free (qtdemux->cenc_aux_info_sizes);
4062 qtdemux->cenc_aux_info_sizes = NULL;
4066 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4067 &info_type, &info_type_parameter, &offset))) {
4068 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4069 g_free (qtdemux->cenc_aux_info_sizes);
4070 qtdemux->cenc_aux_info_sizes = NULL;
4073 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4074 offset += (guint64) (base_offset - qtdemux->moof_offset);
4075 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4076 && info_type_parameter == 0U) {
4078 if (offset > length) {
4079 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4080 qtdemux->cenc_aux_info_offset = offset;
4082 gst_byte_reader_init (&br, buffer + offset, length - offset);
4083 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4084 qtdemux->cenc_aux_info_sizes,
4085 qtdemux->cenc_aux_sample_count)) {
4086 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4087 g_free (qtdemux->cenc_aux_info_sizes);
4088 qtdemux->cenc_aux_info_sizes = NULL;
4096 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4099 /* We'll use decode_time to interpolate timestamps
4100 * in case the input timestamps are missing */
4101 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4103 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4104 " (%" GST_TIME_FORMAT ")", decode_time,
4105 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4106 decode_time) : GST_CLOCK_TIME_NONE));
4108 /* Discard the fragment buffer timestamp info to avoid using it.
4109 * Rely on tfdt instead as it is more accurate than the timestamp
4110 * that is fetched from a manifest/playlist and is usually
4112 qtdemux->fragment_start = -1;
4115 if (G_UNLIKELY (!stream)) {
4116 /* we lost track of offset, we'll need to regain it,
4117 * but can delay complaining until later or avoid doing so altogether */
4121 if (G_UNLIKELY (base_offset < -1))
4124 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4126 if (!qtdemux->pullbased) {
4127 /* Sample tables can grow enough to be problematic if the system memory
4128 * is very low (e.g. embedded devices) and the videos very long
4129 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4130 * Fortunately, we can easily discard them for each new fragment when
4131 * we know qtdemux will not receive seeks outside of the current fragment.
4132 * adaptivedemux honors this assumption.
4133 * This optimization is also useful for applications that use qtdemux as
4134 * a push-based simple demuxer, like Media Source Extensions. */
4135 gst_qtdemux_stream_flush_samples_data (stream);
4138 /* initialise moof sample data */
4139 stream->n_samples_moof = 0;
4140 stream->duration_last_moof = stream->duration_moof;
4141 stream->duration_moof = 0;
4143 /* Track Run node */
4145 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4148 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4149 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4150 &running_offset, decode_time, (tfdt_node != NULL));
4151 /* iterate all siblings */
4152 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4156 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4158 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4159 guint32 box_length = QT_UINT32 (uuid_buffer);
4161 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4164 /* if no new base_offset provided for next traf,
4165 * base is end of current traf */
4166 base_offset = running_offset;
4167 running_offset = -1;
4169 if (stream->n_samples_moof && stream->duration_moof)
4170 stream->new_caps = TRUE;
4173 /* iterate all siblings */
4174 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4177 /* parse any protection system info */
4178 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4180 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4181 qtdemux_parse_pssh (qtdemux, pssh_node);
4182 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4185 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4186 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4188 /* Unless the user has explicitly requested another seek, perform an
4189 * internal seek to the time specified in the tfdt.
4191 * This way if the user opens a file where the first tfdt is 1 hour
4192 * into the presentation, they will not have to wait 1 hour for run
4193 * time to catch up and actual playback to start. */
4196 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4197 "performing an internal seek to %" GST_TIME_FORMAT,
4198 GST_TIME_ARGS (min_dts));
4200 qtdemux->segment.start = min_dts;
4201 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4203 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4204 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4205 stream->time_position = min_dts;
4208 /* Before this code was run a segment was already sent when the moov was
4209 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4210 * be emitted after a moov, and we can emit a second segment anyway for
4211 * special cases like this. */
4212 qtdemux->need_segment = TRUE;
4215 qtdemux->first_moof_already_parsed = TRUE;
4217 g_node_destroy (moof_node);
4222 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4227 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4232 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4237 g_node_destroy (moof_node);
4238 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4239 (_("This file is corrupt and cannot be played.")), (NULL));
4245 /* might be used if some day we actually use mfra & co
4246 * for random access to fragments,
4247 * but that will require quite some modifications and much less relying
4248 * on a sample array */
4252 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4254 QtDemuxStream *stream;
4255 guint32 ver_flags, track_id, len, num_entries, i;
4256 guint value_size, traf_size, trun_size, sample_size;
4257 guint64 time = 0, moof_offset = 0;
4259 GstBuffer *buf = NULL;
4264 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4266 if (!gst_byte_reader_skip (&tfra, 8))
4269 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4272 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4273 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4274 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4277 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4279 stream = qtdemux_find_stream (qtdemux, track_id);
4281 goto unknown_trackid;
4283 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4284 sample_size = (len & 3) + 1;
4285 trun_size = ((len & 12) >> 2) + 1;
4286 traf_size = ((len & 48) >> 4) + 1;
4288 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4289 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4291 if (num_entries == 0)
4294 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4295 value_size + value_size + traf_size + trun_size + sample_size))
4298 g_free (stream->ra_entries);
4299 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4300 stream->n_ra_entries = num_entries;
4302 for (i = 0; i < num_entries; i++) {
4303 qt_atom_parser_get_offset (&tfra, value_size, &time);
4304 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4305 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4306 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4307 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4309 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4311 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4312 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4314 stream->ra_entries[i].ts = time;
4315 stream->ra_entries[i].moof_offset = moof_offset;
4317 /* don't want to go through the entire file and read all moofs at startup */
4319 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4320 if (ret != GST_FLOW_OK)
4322 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4323 moof_offset, stream);
4324 gst_buffer_unref (buf);
4328 check_update_duration (qtdemux, time);
4335 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4340 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4345 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4351 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4353 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4354 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4355 GstBuffer *mfro = NULL, *mfra = NULL;
4357 gboolean ret = FALSE;
4358 GNode *mfra_node, *tfra_node;
4359 guint64 mfra_offset = 0;
4360 guint32 fourcc, mfra_size;
4363 /* query upstream size in bytes */
4364 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4365 goto size_query_failed;
4367 /* mfro box should be at the very end of the file */
4368 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4369 if (flow != GST_FLOW_OK)
4372 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4374 fourcc = QT_FOURCC (mfro_map.data + 4);
4375 if (fourcc != FOURCC_mfro)
4378 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4379 if (mfro_map.size < 16)
4380 goto invalid_mfro_size;
4382 mfra_size = QT_UINT32 (mfro_map.data + 12);
4383 if (mfra_size >= len)
4384 goto invalid_mfra_size;
4386 mfra_offset = len - mfra_size;
4388 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4389 mfra_offset, mfra_size);
4391 /* now get and parse mfra box */
4392 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4393 if (flow != GST_FLOW_OK)
4396 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4398 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4399 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4401 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4404 qtdemux_parse_tfra (qtdemux, tfra_node);
4405 /* iterate all siblings */
4406 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4408 g_node_destroy (mfra_node);
4410 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4416 if (mfro_map.memory != NULL)
4417 gst_buffer_unmap (mfro, &mfro_map);
4418 gst_buffer_unref (mfro);
4421 if (mfra_map.memory != NULL)
4422 gst_buffer_unmap (mfra, &mfra_map);
4423 gst_buffer_unref (mfra);
4430 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4435 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4440 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4445 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4451 add_offset (guint64 offset, guint64 advance)
4453 /* Avoid 64-bit overflow by clamping */
4454 if (offset > G_MAXUINT64 - advance)
4456 return offset + advance;
4459 static GstFlowReturn
4460 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4464 GstBuffer *buf = NULL;
4465 GstFlowReturn ret = GST_FLOW_OK;
4466 guint64 cur_offset = qtdemux->offset;
4469 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4470 if (G_UNLIKELY (ret != GST_FLOW_OK))
4472 gst_buffer_map (buf, &map, GST_MAP_READ);
4473 if (G_LIKELY (map.size >= 8))
4474 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4475 gst_buffer_unmap (buf, &map);
4476 gst_buffer_unref (buf);
4478 /* maybe we already got most we needed, so only consider this eof */
4479 if (G_UNLIKELY (length == 0)) {
4480 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4481 (_("Invalid atom size.")),
4482 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4483 GST_FOURCC_ARGS (fourcc)));
4490 /* record for later parsing when needed */
4491 if (!qtdemux->moof_offset) {
4492 qtdemux->moof_offset = qtdemux->offset;
4494 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4497 qtdemux->offset += length; /* skip moof and keep going */
4499 if (qtdemux->got_moov) {
4500 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4512 GST_LOG_OBJECT (qtdemux,
4513 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4514 GST_FOURCC_ARGS (fourcc), cur_offset);
4515 qtdemux->offset = add_offset (qtdemux->offset, length);
4520 GstBuffer *moov = NULL;
4522 if (qtdemux->got_moov) {
4523 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4524 qtdemux->offset = add_offset (qtdemux->offset, length);
4528 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4529 if (ret != GST_FLOW_OK)
4531 gst_buffer_map (moov, &map, GST_MAP_READ);
4533 if (length != map.size) {
4534 /* Some files have a 'moov' atom at the end of the file which contains
4535 * a terminal 'free' atom where the body of the atom is missing.
4536 * Check for, and permit, this special case.
4538 if (map.size >= 8) {
4539 guint8 *final_data = map.data + (map.size - 8);
4540 guint32 final_length = QT_UINT32 (final_data);
4541 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4543 if (final_fourcc == FOURCC_free
4544 && map.size + final_length - 8 == length) {
4545 /* Ok, we've found that special case. Allocate a new buffer with
4546 * that free atom actually present. */
4547 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4548 gst_buffer_fill (newmoov, 0, map.data, map.size);
4549 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4550 gst_buffer_unmap (moov, &map);
4551 gst_buffer_unref (moov);
4553 gst_buffer_map (moov, &map, GST_MAP_READ);
4558 if (length != map.size) {
4559 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4560 (_("This file is incomplete and cannot be played.")),
4561 ("We got less than expected (received %" G_GSIZE_FORMAT
4562 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4563 (guint) length, cur_offset));
4564 gst_buffer_unmap (moov, &map);
4565 gst_buffer_unref (moov);
4566 ret = GST_FLOW_ERROR;
4569 qtdemux->offset += length;
4571 qtdemux_parse_moov (qtdemux, map.data, length);
4572 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4574 qtdemux_parse_tree (qtdemux);
4575 if (qtdemux->moov_node_compressed) {
4576 g_node_destroy (qtdemux->moov_node_compressed);
4577 g_free (qtdemux->moov_node->data);
4579 qtdemux->moov_node_compressed = NULL;
4580 g_node_destroy (qtdemux->moov_node);
4581 qtdemux->moov_node = NULL;
4582 gst_buffer_unmap (moov, &map);
4583 gst_buffer_unref (moov);
4584 qtdemux->got_moov = TRUE;
4590 GstBuffer *ftyp = NULL;
4592 /* extract major brand; might come in handy for ISO vs QT issues */
4593 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4594 if (ret != GST_FLOW_OK)
4596 qtdemux->offset += length;
4597 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4598 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4599 gst_buffer_unmap (ftyp, &map);
4600 gst_buffer_unref (ftyp);
4605 GstBuffer *uuid = NULL;
4607 /* uuid are extension atoms */
4608 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4609 if (ret != GST_FLOW_OK)
4611 qtdemux->offset += length;
4612 gst_buffer_map (uuid, &map, GST_MAP_READ);
4613 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4614 gst_buffer_unmap (uuid, &map);
4615 gst_buffer_unref (uuid);
4620 GstBuffer *sidx = NULL;
4621 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4622 if (ret != GST_FLOW_OK)
4624 qtdemux->offset += length;
4625 gst_buffer_map (sidx, &map, GST_MAP_READ);
4626 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4627 gst_buffer_unmap (sidx, &map);
4628 gst_buffer_unref (sidx);
4633 GstBuffer *unknown = NULL;
4635 GST_LOG_OBJECT (qtdemux,
4636 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4637 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4639 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4640 if (ret != GST_FLOW_OK)
4642 gst_buffer_map (unknown, &map, GST_MAP_READ);
4643 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4644 gst_buffer_unmap (unknown, &map);
4645 gst_buffer_unref (unknown);
4646 qtdemux->offset += length;
4652 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4653 /* digested all data, show what we have */
4654 qtdemux_prepare_streams (qtdemux);
4655 QTDEMUX_EXPOSE_LOCK (qtdemux);
4656 ret = qtdemux_expose_streams (qtdemux);
4657 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4659 qtdemux->state = QTDEMUX_STATE_MOVIE;
4660 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4667 /* Seeks to the previous keyframe of the indexed stream and
4668 * aligns other streams with respect to the keyframe timestamp
4669 * of indexed stream. Only called in case of Reverse Playback
4671 static GstFlowReturn
4672 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4674 guint32 seg_idx = 0, k_index = 0;
4675 guint32 ref_seg_idx, ref_k_index;
4676 GstClockTime k_pos = 0, last_stop = 0;
4677 QtDemuxSegment *seg = NULL;
4678 QtDemuxStream *ref_str = NULL;
4679 guint64 seg_media_start_mov; /* segment media start time in mov format */
4683 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4684 * and finally align all the other streams on that timestamp with their
4685 * respective keyframes */
4686 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4687 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4689 /* No candidate yet, take the first stream */
4695 /* So that stream has a segment, we prefer video streams */
4696 if (str->subtype == FOURCC_vide) {
4702 if (G_UNLIKELY (!ref_str)) {
4703 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4707 if (G_UNLIKELY (!ref_str->from_sample)) {
4708 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4712 /* So that stream has been playing from from_sample to to_sample. We will
4713 * get the timestamp of the previous sample and search for a keyframe before
4714 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4715 if (ref_str->subtype == FOURCC_vide) {
4716 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4717 ref_str->from_sample - 1, FALSE);
4719 if (ref_str->from_sample >= 10)
4720 k_index = ref_str->from_sample - 10;
4726 ref_str->samples[k_index].timestamp +
4727 ref_str->samples[k_index].pts_offset;
4729 /* get current segment for that stream */
4730 seg = &ref_str->segments[ref_str->segment_index];
4731 /* Use segment start in original timescale for comparisons */
4732 seg_media_start_mov = seg->trak_media_start;
4734 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4735 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4736 k_index, target_ts, seg_media_start_mov,
4737 GST_TIME_ARGS (seg->media_start));
4739 /* Crawl back through segments to find the one containing this I frame */
4740 while (target_ts < seg_media_start_mov) {
4741 GST_DEBUG_OBJECT (qtdemux,
4742 "keyframe position (sample %u) is out of segment %u " " target %"
4743 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4744 ref_str->segment_index, target_ts, seg_media_start_mov);
4746 if (G_UNLIKELY (!ref_str->segment_index)) {
4747 /* Reached first segment, let's consider it's EOS */
4750 ref_str->segment_index--;
4751 seg = &ref_str->segments[ref_str->segment_index];
4752 /* Use segment start in original timescale for comparisons */
4753 seg_media_start_mov = seg->trak_media_start;
4755 /* Calculate time position of the keyframe and where we should stop */
4757 QTSTREAMTIME_TO_GSTTIME (ref_str,
4758 target_ts - seg->trak_media_start) + seg->time;
4760 QTSTREAMTIME_TO_GSTTIME (ref_str,
4761 ref_str->samples[ref_str->from_sample].timestamp -
4762 seg->trak_media_start) + seg->time;
4764 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4765 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4766 k_index, GST_TIME_ARGS (k_pos));
4768 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4769 qtdemux->segment.position = last_stop;
4770 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4771 GST_TIME_ARGS (last_stop));
4773 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4774 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4778 ref_seg_idx = ref_str->segment_index;
4779 ref_k_index = k_index;
4781 /* Align them all on this */
4782 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4784 GstClockTime seg_time = 0;
4785 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4787 /* aligning reference stream again might lead to backing up to yet another
4788 * keyframe (due to timestamp rounding issues),
4789 * potentially putting more load on downstream; so let's try to avoid */
4790 if (str == ref_str) {
4791 seg_idx = ref_seg_idx;
4792 seg = &str->segments[seg_idx];
4793 k_index = ref_k_index;
4794 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4795 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4797 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4798 GST_DEBUG_OBJECT (qtdemux,
4799 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4800 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4802 /* get segment and time in the segment */
4803 seg = &str->segments[seg_idx];
4804 seg_time = k_pos - seg->time;
4806 /* get the media time in the segment.
4807 * No adjustment for empty "filler" segments */
4808 if (seg->media_start != GST_CLOCK_TIME_NONE)
4809 seg_time += seg->media_start;
4811 /* get the index of the sample with media time */
4812 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4813 GST_DEBUG_OBJECT (qtdemux,
4814 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4815 GST_TIME_ARGS (seg_time), index);
4817 /* find previous keyframe */
4818 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4821 /* Remember until where we want to go */
4822 str->to_sample = str->from_sample - 1;
4823 /* Define our time position */
4825 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4826 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4827 if (seg->media_start != GST_CLOCK_TIME_NONE)
4828 str->time_position -= seg->media_start;
4830 /* Now seek back in time */
4831 gst_qtdemux_move_stream (qtdemux, str, k_index);
4832 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4833 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4834 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4840 return GST_FLOW_EOS;
4844 * Gets the current qt segment start, stop and position for the
4845 * given time offset. This is used in update_segment()
4848 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4849 QtDemuxStream * stream, GstClockTime offset,
4850 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4852 GstClockTime seg_time;
4853 GstClockTime start, stop, time;
4854 QtDemuxSegment *segment;
4856 segment = &stream->segments[stream->segment_index];
4858 /* get time in this segment */
4859 seg_time = (offset - segment->time) * segment->rate;
4861 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4862 GST_TIME_ARGS (seg_time));
4864 if (G_UNLIKELY (seg_time > segment->duration)) {
4865 GST_LOG_OBJECT (stream->pad,
4866 "seg_time > segment->duration %" GST_TIME_FORMAT,
4867 GST_TIME_ARGS (segment->duration));
4868 seg_time = segment->duration;
4871 /* qtdemux->segment.stop is in outside-time-realm, whereas
4872 * segment->media_stop is in track-time-realm.
4874 * In order to compare the two, we need to bring segment.stop
4875 * into the track-time-realm
4877 * FIXME - does this comment still hold? Don't see any conversion here */
4879 stop = qtdemux->segment.stop;
4880 if (stop == GST_CLOCK_TIME_NONE)
4881 stop = qtdemux->segment.duration;
4882 if (stop == GST_CLOCK_TIME_NONE)
4883 stop = segment->media_stop;
4886 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4888 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4889 start = segment->time + seg_time;
4891 stop = start - seg_time + segment->duration;
4892 } else if (qtdemux->segment.rate >= 0) {
4893 start = MIN (segment->media_start + seg_time, stop);
4896 if (segment->media_start >= qtdemux->segment.start) {
4897 time = segment->time;
4899 time = segment->time + (qtdemux->segment.start - segment->media_start);
4902 start = MAX (segment->media_start, qtdemux->segment.start);
4903 stop = MIN (segment->media_start + seg_time, stop);
4912 * Updates the qt segment used for the stream and pushes a new segment event
4913 * downstream on this stream's pad.
4916 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4917 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4918 GstClockTime * _stop)
4920 QtDemuxSegment *segment;
4921 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4925 /* update the current segment */
4926 stream->segment_index = seg_idx;
4928 /* get the segment */
4929 segment = &stream->segments[seg_idx];
4931 if (G_UNLIKELY (offset < segment->time)) {
4932 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4933 GST_TIME_ARGS (segment->time));
4937 /* segment lies beyond total indicated duration */
4938 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4939 segment->time > qtdemux->segment.duration)) {
4940 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4941 " < segment->time %" GST_TIME_FORMAT,
4942 GST_TIME_ARGS (qtdemux->segment.duration),
4943 GST_TIME_ARGS (segment->time));
4947 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4948 &start, &stop, &time);
4950 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4951 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4952 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4954 /* combine global rate with that of the segment */
4955 rate = segment->rate * qtdemux->segment.rate;
4957 /* Copy flags from main segment */
4958 stream->segment.flags = qtdemux->segment.flags;
4960 /* update the segment values used for clipping */
4961 stream->segment.offset = qtdemux->segment.offset;
4962 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4963 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4964 stream->segment.rate = rate;
4965 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4966 stream->cslg_shift);
4968 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4969 stream->cslg_shift);
4971 stream->segment.stop = stop;
4972 stream->segment.time = time;
4973 stream->segment.position = stream->segment.start;
4975 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4978 /* now prepare and send the segment */
4980 event = gst_event_new_segment (&stream->segment);
4981 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4982 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4984 gst_pad_push_event (stream->pad, event);
4985 /* assume we can send more data now */
4986 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4987 /* clear to send tags on this pad now */
4988 gst_qtdemux_push_tags (qtdemux, stream);
4999 /* activate the given segment number @seg_idx of @stream at time @offset.
5000 * @offset is an absolute global position over all the segments.
5002 * This will push out a NEWSEGMENT event with the right values and
5003 * position the stream index to the first decodable sample before
5007 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5008 guint32 seg_idx, GstClockTime offset)
5010 QtDemuxSegment *segment;
5011 guint32 index, kf_index;
5012 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5014 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5015 seg_idx, GST_TIME_ARGS (offset));
5017 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5021 segment = &stream->segments[stream->segment_index];
5023 /* in the fragmented case, we pick a fragment that starts before our
5024 * desired position and rely on downstream to wait for a keyframe
5025 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5026 * tfra entries tells us which trun/sample the key unit is in, but we don't
5027 * make use of this additional information at the moment) */
5028 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5029 stream->to_sample = G_MAXUINT32;
5032 /* well, it will be taken care of below */
5033 qtdemux->fragmented_seek_pending = FALSE;
5034 /* FIXME ideally the do_fragmented_seek can be done right here,
5035 * rather than at loop level
5036 * (which might even allow handling edit lists in a fragmented file) */
5039 /* We don't need to look for a sample in push-based */
5040 if (!qtdemux->pullbased)
5043 /* and move to the keyframe before the indicated media time of the
5045 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5046 if (qtdemux->segment.rate >= 0) {
5047 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5048 stream->to_sample = G_MAXUINT32;
5049 GST_DEBUG_OBJECT (stream->pad,
5050 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5051 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5052 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5054 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5055 stream->to_sample = index;
5056 GST_DEBUG_OBJECT (stream->pad,
5057 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5058 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5059 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5062 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5063 "this is an empty segment");
5067 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5068 * encountered an error and printed a message so we return appropriately */
5072 /* we're at the right spot */
5073 if (index == stream->sample_index) {
5074 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5078 /* find keyframe of the target index */
5079 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5081 /* go back two frames to provide lead-in for non-raw audio decoders */
5082 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5083 guint32 lead_in = 2;
5084 guint32 old_index = kf_index;
5085 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5087 if (gst_structure_has_name (s, "audio/mpeg")) {
5089 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5090 && mpegversion == 1) {
5091 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5096 kf_index = MAX (kf_index, lead_in) - lead_in;
5097 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5098 GST_DEBUG_OBJECT (stream->pad,
5099 "Moving backwards %u frames to ensure sufficient sound lead-in",
5100 old_index - kf_index);
5102 kf_index = old_index;
5106 /* if we move forwards, we don't have to go back to the previous
5107 * keyframe since we already sent that. We can also just jump to
5108 * the keyframe right before the target index if there is one. */
5109 if (index > stream->sample_index) {
5110 /* moving forwards check if we move past a keyframe */
5111 if (kf_index > stream->sample_index) {
5112 GST_DEBUG_OBJECT (stream->pad,
5113 "moving forwards to keyframe at %u "
5114 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5116 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5117 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5118 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5120 GST_DEBUG_OBJECT (stream->pad,
5121 "moving forwards, keyframe at %u "
5122 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5124 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5125 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5128 GST_DEBUG_OBJECT (stream->pad,
5129 "moving backwards to %sframe at %u "
5130 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5131 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5132 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5133 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5134 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5140 /* prepare to get the current sample of @stream, getting essential values.
5142 * This function will also prepare and send the segment when needed.
5144 * Return FALSE if the stream is EOS.
5149 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5150 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5151 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5152 gboolean * keyframe)
5154 QtDemuxSample *sample;
5155 GstClockTime time_position;
5158 g_return_val_if_fail (stream != NULL, FALSE);
5160 time_position = stream->time_position;
5161 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5164 seg_idx = stream->segment_index;
5165 if (G_UNLIKELY (seg_idx == -1)) {
5166 /* find segment corresponding to time_position if we are looking
5168 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5171 /* different segment, activate it, sample_index will be set. */
5172 if (G_UNLIKELY (stream->segment_index != seg_idx))
5173 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5175 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5176 segments[stream->segment_index]))) {
5177 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5179 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5180 " prepare empty sample");
5183 *pts = *dts = time_position;
5184 *duration = seg->duration - (time_position - seg->time);
5191 if (stream->sample_index == -1)
5192 stream->sample_index = 0;
5194 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5195 stream->sample_index, stream->n_samples);
5197 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5198 if (!qtdemux->fragmented)
5201 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5205 GST_OBJECT_LOCK (qtdemux);
5206 flow = qtdemux_add_fragmented_samples (qtdemux);
5207 GST_OBJECT_UNLOCK (qtdemux);
5209 if (flow != GST_FLOW_OK)
5212 while (stream->sample_index >= stream->n_samples);
5215 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5216 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5217 stream->sample_index);
5221 /* now get the info for the sample we're at */
5222 sample = &stream->samples[stream->sample_index];
5224 *dts = QTSAMPLE_DTS (stream, sample);
5225 *pts = QTSAMPLE_PTS (stream, sample);
5226 *offset = sample->offset;
5227 *size = sample->size;
5228 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5229 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5236 stream->time_position = GST_CLOCK_TIME_NONE;
5241 /* move to the next sample in @stream.
5243 * Moves to the next segment when needed.
5246 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5248 QtDemuxSample *sample;
5249 QtDemuxSegment *segment;
5251 /* get current segment */
5252 segment = &stream->segments[stream->segment_index];
5254 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5255 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5259 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5260 /* Mark the stream as EOS */
5261 GST_DEBUG_OBJECT (qtdemux,
5262 "reached max allowed sample %u, mark EOS", stream->to_sample);
5263 stream->time_position = GST_CLOCK_TIME_NONE;
5267 /* move to next sample */
5268 stream->sample_index++;
5269 stream->offset_in_sample = 0;
5271 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5274 /* reached the last sample, we need the next segment */
5275 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5278 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5279 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5280 stream->sample_index);
5284 /* get next sample */
5285 sample = &stream->samples[stream->sample_index];
5287 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5288 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5289 GST_TIME_ARGS (segment->media_stop));
5291 /* see if we are past the segment */
5292 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5295 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5296 /* inside the segment, update time_position, looks very familiar to
5297 * GStreamer segments, doesn't it? */
5298 stream->time_position =
5299 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5301 /* not yet in segment, time does not yet increment. This means
5302 * that we are still prerolling keyframes to the decoder so it can
5303 * decode the first sample of the segment. */
5304 stream->time_position = segment->time;
5308 /* move to the next segment */
5311 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5313 if (stream->segment_index == stream->n_segments - 1) {
5314 /* are we at the end of the last segment, we're EOS */
5315 stream->time_position = GST_CLOCK_TIME_NONE;
5317 /* else we're only at the end of the current segment */
5318 stream->time_position = segment->stop_time;
5320 /* make sure we select a new segment */
5322 /* accumulate previous segments */
5323 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5324 stream->accumulated_base +=
5325 (stream->segment.stop -
5326 stream->segment.start) / ABS (stream->segment.rate);
5328 stream->segment_index = -1;
5333 gst_qtdemux_sync_streams (GstQTDemux * demux)
5337 if (QTDEMUX_N_STREAMS (demux) <= 1)
5340 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5341 QtDemuxStream *stream;
5342 GstClockTime end_time;
5344 stream = QTDEMUX_NTH_STREAM (demux, i);
5349 /* TODO advance time on subtitle streams here, if any some day */
5351 /* some clips/trailers may have unbalanced streams at the end,
5352 * so send EOS on shorter stream to prevent stalling others */
5354 /* do not mess with EOS if SEGMENT seeking */
5355 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5358 if (demux->pullbased) {
5359 /* loop mode is sample time based */
5360 if (!STREAM_IS_EOS (stream))
5363 /* push mode is byte position based */
5364 if (stream->n_samples &&
5365 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5369 if (stream->sent_eos)
5372 /* only act if some gap */
5373 end_time = stream->segments[stream->n_segments - 1].stop_time;
5374 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5375 ", stream end: %" GST_TIME_FORMAT,
5376 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5377 if (GST_CLOCK_TIME_IS_VALID (end_time)
5378 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5381 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5382 GST_PAD_NAME (stream->pad));
5383 stream->sent_eos = TRUE;
5384 event = gst_event_new_eos ();
5385 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5386 gst_event_set_seqnum (event, demux->segment_seqnum);
5387 gst_pad_push_event (stream->pad, event);
5392 /* EOS and NOT_LINKED need to be combined. This means that we return:
5394 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5395 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5397 static GstFlowReturn
5398 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5401 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5404 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5407 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5409 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5413 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5414 * completely clipped
5416 * Should be used only with raw buffers */
5418 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5421 guint64 start, stop, cstart, cstop, diff;
5422 GstClockTime pts, duration;
5424 gint num_rate, denom_rate;
5429 osize = size = gst_buffer_get_size (buf);
5432 /* depending on the type, setup the clip parameters */
5433 if (stream->subtype == FOURCC_soun) {
5434 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5435 num_rate = GST_SECOND;
5436 denom_rate = (gint) CUR_STREAM (stream)->rate;
5438 } else if (stream->subtype == FOURCC_vide) {
5440 num_rate = CUR_STREAM (stream)->fps_n;
5441 denom_rate = CUR_STREAM (stream)->fps_d;
5446 if (frame_size <= 0)
5447 goto bad_frame_size;
5449 /* we can only clip if we have a valid pts */
5450 pts = GST_BUFFER_PTS (buf);
5451 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5454 duration = GST_BUFFER_DURATION (buf);
5456 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5458 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5462 stop = start + duration;
5464 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5465 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5468 /* see if some clipping happened */
5469 diff = cstart - start;
5475 /* bring clipped time to samples and to bytes */
5476 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5479 GST_DEBUG_OBJECT (qtdemux,
5480 "clipping start to %" GST_TIME_FORMAT " %"
5481 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5487 diff = stop - cstop;
5492 /* bring clipped time to samples and then to bytes */
5493 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5495 GST_DEBUG_OBJECT (qtdemux,
5496 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5497 " bytes", GST_TIME_ARGS (cstop), diff);
5502 if (offset != 0 || size != osize)
5503 gst_buffer_resize (buf, offset, size);
5505 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5506 GST_BUFFER_PTS (buf) = pts;
5507 GST_BUFFER_DURATION (buf) = duration;
5511 /* dropped buffer */
5514 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5519 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5524 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5529 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5530 gst_buffer_unref (buf);
5536 gst_qtdemux_align_buffer (GstQTDemux * demux,
5537 GstBuffer * buffer, gsize alignment)
5541 gst_buffer_map (buffer, &map, GST_MAP_READ);
5543 if (map.size < sizeof (guintptr)) {
5544 gst_buffer_unmap (buffer, &map);
5548 if (((guintptr) map.data) & (alignment - 1)) {
5549 GstBuffer *new_buffer;
5550 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5552 new_buffer = gst_buffer_new_allocate (NULL,
5553 gst_buffer_get_size (buffer), ¶ms);
5555 /* Copy data "by hand", so ensure alignment is kept: */
5556 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5558 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5559 GST_DEBUG_OBJECT (demux,
5560 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5563 gst_buffer_unmap (buffer, &map);
5564 gst_buffer_unref (buffer);
5569 gst_buffer_unmap (buffer, &map);
5574 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5580 /* We are converting from pairs to triplets */
5581 *res = ccpair_size / 2 * 3;
5582 storage = g_malloc (*res);
5583 for (i = 0; i * 2 < ccpair_size; i += 1) {
5584 /* FIXME: Use line offset 0 as we simply can't know here */
5586 storage[i * 3] = 0x80 | 0x00;
5588 storage[i * 3] = 0x00 | 0x00;
5589 storage[i * 3 + 1] = ccpair[i * 2];
5590 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5597 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5601 guint32 atom_length, fourcc;
5602 QtDemuxStreamStsdEntry *stsd_entry;
5604 GST_MEMDUMP ("caption atom", data, size);
5606 /* There might be multiple atoms */
5611 atom_length = QT_UINT32 (data);
5612 fourcc = QT_FOURCC (data + 4);
5613 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5616 GST_DEBUG_OBJECT (stream->pad, "here");
5618 /* Check if we have something compatible */
5619 stsd_entry = CUR_STREAM (stream);
5620 switch (stsd_entry->fourcc) {
5622 guint8 *cdat = NULL, *cdt2 = NULL;
5623 gsize cdat_size = 0, cdt2_size = 0;
5624 /* Should be cdat or cdt2 */
5625 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5626 GST_WARNING_OBJECT (stream->pad,
5627 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5628 GST_FOURCC_ARGS (fourcc));
5632 /* Convert to S334-1 Annex A byte triplet */
5633 if (fourcc == FOURCC_cdat)
5634 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5636 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5637 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5640 /* Check for another atom ? */
5641 if (size > atom_length + 8) {
5642 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5643 if (size >= atom_length + new_atom_length) {
5644 fourcc = QT_FOURCC (data + atom_length + 4);
5645 if (fourcc == FOURCC_cdat) {
5648 convert_to_s334_1a (data + atom_length + 8,
5649 new_atom_length - 8, 1, &cdat_size);
5651 GST_WARNING_OBJECT (stream->pad,
5652 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5656 convert_to_s334_1a (data + atom_length + 8,
5657 new_atom_length - 8, 2, &cdt2_size);
5659 GST_WARNING_OBJECT (stream->pad,
5660 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5665 *cclen = cdat_size + cdt2_size;
5666 res = g_malloc (*cclen);
5668 memcpy (res, cdat, cdat_size);
5670 memcpy (res + cdat_size, cdt2, cdt2_size);
5676 if (fourcc != FOURCC_ccdp) {
5677 GST_WARNING_OBJECT (stream->pad,
5678 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5679 GST_FOURCC_ARGS (fourcc));
5682 *cclen = atom_length - 8;
5683 res = g_memdup2 (data + 8, *cclen);
5686 /* Keep this here in case other closed caption formats are added */
5687 g_assert_not_reached ();
5691 GST_MEMDUMP ("Output", res, *cclen);
5696 GST_WARNING ("[cdat] atom is too small or invalid");
5700 /* Handle Closed Caption sample buffers.
5701 * The input buffer metadata must be writable,
5702 * but time/duration etc not yet set and need not be preserved */
5704 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5707 GstBuffer *outbuf = NULL;
5712 gst_buffer_map (buf, &map, GST_MAP_READ);
5714 /* empty buffer is sent to terminate previous subtitle */
5715 if (map.size <= 2) {
5716 gst_buffer_unmap (buf, &map);
5717 gst_buffer_unref (buf);
5721 /* For closed caption, we need to extract the information from the
5722 * [cdat],[cdt2] or [ccdp] atom */
5723 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5724 gst_buffer_unmap (buf, &map);
5726 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5727 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5729 /* Conversion failed or there's nothing */
5731 gst_buffer_unref (buf);
5736 /* DVD subpicture specific sample handling.
5737 * the input buffer metadata must be writable,
5738 * but time/duration etc not yet set and need not be preserved */
5740 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5743 /* send a one time dvd clut event */
5744 if (stream->pending_event && stream->pad)
5745 gst_pad_push_event (stream->pad, stream->pending_event);
5746 stream->pending_event = NULL;
5748 /* empty buffer is sent to terminate previous subtitle */
5749 if (gst_buffer_get_size (buf) <= 2) {
5750 gst_buffer_unref (buf);
5754 /* That's all the processing needed for subpictures */
5758 /* Timed text formats
5759 * the input buffer metadata must be writable,
5760 * but time/duration etc not yet set and need not be preserved */
5762 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5765 GstBuffer *outbuf = NULL;
5770 /* not many cases for now */
5771 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5772 stream->subtype != FOURCC_sbtl)) {
5776 gst_buffer_map (buf, &map, GST_MAP_READ);
5778 /* empty buffer is sent to terminate previous subtitle */
5779 if (map.size <= 2) {
5780 gst_buffer_unmap (buf, &map);
5781 gst_buffer_unref (buf);
5785 nsize = GST_READ_UINT16_BE (map.data);
5786 nsize = MIN (nsize, map.size - 2);
5788 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5791 /* takes care of UTF-8 validation or UTF-16 recognition,
5792 * no other encoding expected */
5793 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5794 gst_buffer_unmap (buf, &map);
5797 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5798 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5800 /* this should not really happen unless the subtitle is corrupted */
5802 gst_buffer_unref (buf);
5804 /* FIXME ? convert optional subsequent style info to markup */
5809 /* WebVTT sample handling according to 14496-30 */
5811 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5814 GstBuffer *outbuf = NULL;
5817 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5818 g_assert_not_reached (); /* The buffer must be mappable */
5821 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5822 GstEvent *gap = NULL;
5823 /* Push a gap event */
5824 stream->segment.position = GST_BUFFER_PTS (buf);
5826 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5827 gst_pad_push_event (stream->pad, gap);
5829 if (GST_BUFFER_DURATION_IS_VALID (buf))
5830 stream->segment.position += GST_BUFFER_DURATION (buf);
5833 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5834 GST_BUFFER_DURATION (buf), map.data, map.size);
5835 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5838 gst_buffer_unmap (buf, &map);
5839 gst_buffer_unref (buf);
5844 static GstFlowReturn
5845 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5848 GstFlowReturn ret = GST_FLOW_OK;
5849 GstClockTime pts, duration;
5851 if (stream->need_clip)
5852 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5854 if (G_UNLIKELY (buf == NULL))
5857 if (G_UNLIKELY (stream->discont)) {
5858 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5859 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5860 stream->discont = FALSE;
5862 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5865 GST_LOG_OBJECT (qtdemux,
5866 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5867 ", duration %" GST_TIME_FORMAT " on pad %s",
5868 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5869 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5870 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5872 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5873 GstStructure *crypto_info;
5874 QtDemuxAavdEncryptionInfo *info =
5875 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5877 crypto_info = gst_structure_copy (info->default_properties);
5878 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5879 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5882 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
5883 || stream->protection_scheme_type == FOURCC_cbcs)) {
5884 GstStructure *crypto_info;
5885 QtDemuxCencSampleSetInfo *info =
5886 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5890 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5891 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5892 GST_PTR_FORMAT, event);
5893 gst_pad_push_event (stream->pad, event);
5896 if (info->crypto_info == NULL) {
5897 if (stream->protection_scheme_type == FOURCC_cbcs) {
5898 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
5899 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
5900 GST_ERROR_OBJECT (qtdemux,
5901 "failed to attach cbcs metadata to buffer");
5902 qtdemux_gst_structure_free (crypto_info);
5904 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
5907 GST_DEBUG_OBJECT (qtdemux,
5908 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5911 /* The end of the crypto_info array matches our n_samples position,
5912 * so count backward from there */
5913 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5914 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5915 /* steal structure from array */
5916 crypto_info = g_ptr_array_index (info->crypto_info, index);
5917 g_ptr_array_index (info->crypto_info, index) = NULL;
5918 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5919 info->crypto_info->len);
5920 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5921 GST_ERROR_OBJECT (qtdemux,
5922 "failed to attach cenc metadata to buffer");
5924 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5925 index, stream->sample_index);
5930 if (stream->alignment > 1)
5931 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5933 pts = GST_BUFFER_PTS (buf);
5934 duration = GST_BUFFER_DURATION (buf);
5936 ret = gst_pad_push (stream->pad, buf);
5938 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5939 /* mark position in stream, we'll need this to know when to send GAP event */
5940 stream->segment.position = pts + duration;
5948 static GstFlowReturn
5949 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5952 GstFlowReturn ret = GST_FLOW_OK;
5954 if (stream->subtype == FOURCC_clcp
5955 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
5957 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
5958 guint n_triplets, i;
5959 guint field1_off = 0, field2_off = 0;
5961 /* We have to split CEA608 buffers so that each outgoing buffer contains
5962 * one byte pair per field according to the framerate of the video track.
5964 * If there is only a single byte pair per field we don't have to do
5968 gst_buffer_map (buf, &map, GST_MAP_READ);
5970 n_triplets = map.size / 3;
5971 for (i = 0; i < n_triplets; i++) {
5972 if (map.data[3 * i] & 0x80)
5978 g_assert (n_field1 || n_field2);
5980 /* If there's more than 1 frame we have to split, otherwise we can just
5982 if (n_field1 > 1 || n_field2 > 1) {
5984 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
5985 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
5987 for (i = 0; i < n_output_buffers; i++) {
5989 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
5993 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
5994 outptr = outmap.data;
5997 gboolean found = FALSE;
5999 while (map.data + field1_off < map.data + map.size) {
6000 if (map.data[field1_off] & 0x80) {
6001 memcpy (outptr, &map.data[field1_off], 3);
6010 const guint8 empty[] = { 0x80, 0x80, 0x80 };
6012 memcpy (outptr, empty, 3);
6019 gboolean found = FALSE;
6021 while (map.data + field2_off < map.data + map.size) {
6022 if ((map.data[field2_off] & 0x80) == 0) {
6023 memcpy (outptr, &map.data[field2_off], 3);
6032 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6034 memcpy (outptr, empty, 3);
6040 gst_buffer_unmap (outbuf, &outmap);
6042 GST_BUFFER_PTS (outbuf) =
6043 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6044 GST_SECOND * CUR_STREAM (stream)->fps_d,
6045 CUR_STREAM (stream)->fps_n);
6046 GST_BUFFER_DURATION (outbuf) =
6047 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6048 CUR_STREAM (stream)->fps_n);
6049 GST_BUFFER_OFFSET (outbuf) = -1;
6050 GST_BUFFER_OFFSET_END (outbuf) = -1;
6052 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6054 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6057 gst_buffer_unmap (buf, &map);
6058 gst_buffer_unref (buf);
6060 gst_buffer_unmap (buf, &map);
6061 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6064 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6070 /* Sets a buffer's attributes properly and pushes it downstream.
6071 * Also checks for additional actions and custom processing that may
6072 * need to be done first.
6074 static GstFlowReturn
6075 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6076 QtDemuxStream * stream, GstBuffer * buf,
6077 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6078 gboolean keyframe, GstClockTime position, guint64 byte_position)
6080 GstFlowReturn ret = GST_FLOW_OK;
6082 /* offset the timestamps according to the edit list */
6084 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6088 gst_buffer_map (buf, &map, GST_MAP_READ);
6089 url = g_strndup ((gchar *) map.data, map.size);
6090 gst_buffer_unmap (buf, &map);
6091 if (url != NULL && strlen (url) != 0) {
6092 /* we have RTSP redirect now */
6093 g_free (qtdemux->redirect_location);
6094 qtdemux->redirect_location = g_strdup (url);
6095 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6096 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6097 gst_structure_new ("redirect",
6098 "new-location", G_TYPE_STRING, url, NULL)));
6100 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6106 /* position reporting */
6107 if (qtdemux->segment.rate >= 0) {
6108 qtdemux->segment.position = position;
6109 gst_qtdemux_sync_streams (qtdemux);
6112 if (G_UNLIKELY (!stream->pad)) {
6113 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6114 gst_buffer_unref (buf);
6118 /* send out pending buffers */
6119 while (stream->buffers) {
6120 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6122 if (G_UNLIKELY (stream->discont)) {
6123 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6124 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6125 stream->discont = FALSE;
6127 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6130 if (stream->alignment > 1)
6131 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6132 gst_pad_push (stream->pad, buffer);
6134 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6137 /* we're going to modify the metadata */
6138 buf = gst_buffer_make_writable (buf);
6140 GST_BUFFER_DTS (buf) = dts;
6141 GST_BUFFER_PTS (buf) = pts;
6142 GST_BUFFER_DURATION (buf) = duration;
6143 GST_BUFFER_OFFSET (buf) = -1;
6144 GST_BUFFER_OFFSET_END (buf) = -1;
6146 if (G_UNLIKELY (stream->process_func))
6147 buf = stream->process_func (qtdemux, stream, buf);
6154 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6155 stream->on_keyframe = FALSE;
6157 stream->on_keyframe = TRUE;
6160 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6161 gst_buffer_append_memory (buf,
6162 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6164 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6165 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6168 if (G_UNLIKELY (qtdemux->element_index)) {
6169 GstClockTime stream_time;
6172 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6174 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6175 GST_LOG_OBJECT (qtdemux,
6176 "adding association %" GST_TIME_FORMAT "-> %"
6177 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6178 gst_index_add_association (qtdemux->element_index,
6180 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6181 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6182 GST_FORMAT_BYTES, byte_position, NULL);
6187 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6193 static const QtDemuxRandomAccessEntry *
6194 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6195 GstClockTime pos, gboolean after)
6197 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6198 guint n_entries = stream->n_ra_entries;
6201 /* we assume the table is sorted */
6202 for (i = 0; i < n_entries; ++i) {
6203 if (entries[i].ts > pos)
6207 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6208 * probably okay to assume that the index lists the very first fragment */
6215 return &entries[i - 1];
6219 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6221 const QtDemuxRandomAccessEntry *best_entry = NULL;
6224 GST_OBJECT_LOCK (qtdemux);
6226 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6228 /* first see if we can determine where to go to using mfra,
6229 * before we start clearing things */
6230 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6231 const QtDemuxRandomAccessEntry *entry;
6232 QtDemuxStream *stream;
6233 gboolean is_audio_or_video;
6235 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6237 if (stream->ra_entries == NULL)
6240 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6241 is_audio_or_video = TRUE;
6243 is_audio_or_video = FALSE;
6246 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6247 stream->time_position, !is_audio_or_video);
6249 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6250 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6252 stream->pending_seek = entry;
6254 /* decide position to jump to just based on audio/video tracks, not subs */
6255 if (!is_audio_or_video)
6258 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6262 /* no luck, will handle seek otherwise */
6263 if (best_entry == NULL) {
6264 GST_OBJECT_UNLOCK (qtdemux);
6268 /* ok, now we can prepare for processing as of located moof */
6269 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6270 QtDemuxStream *stream;
6272 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6274 g_free (stream->samples);
6275 stream->samples = NULL;
6276 stream->n_samples = 0;
6277 stream->stbl_index = -1; /* no samples have yet been parsed */
6278 stream->sample_index = -1;
6280 if (stream->protection_scheme_info) {
6281 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6282 if (stream->protection_scheme_type == FOURCC_cenc
6283 || stream->protection_scheme_type == FOURCC_cbcs) {
6284 QtDemuxCencSampleSetInfo *info =
6285 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6286 if (info->crypto_info) {
6287 g_ptr_array_free (info->crypto_info, TRUE);
6288 info->crypto_info = NULL;
6294 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6295 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6296 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6297 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6299 qtdemux->moof_offset = best_entry->moof_offset;
6301 qtdemux_add_fragmented_samples (qtdemux);
6303 GST_OBJECT_UNLOCK (qtdemux);
6307 static GstFlowReturn
6308 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6310 GstFlowReturn ret = GST_FLOW_OK;
6311 GstBuffer *buf = NULL;
6312 QtDemuxStream *stream, *target_stream = NULL;
6313 GstClockTime min_time;
6315 GstClockTime dts = GST_CLOCK_TIME_NONE;
6316 GstClockTime pts = GST_CLOCK_TIME_NONE;
6317 GstClockTime duration = 0;
6318 gboolean keyframe = FALSE;
6319 guint sample_size = 0;
6320 guint num_samples = 1;
6325 if (qtdemux->fragmented_seek_pending) {
6326 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6327 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6328 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6329 qtdemux->fragmented_seek_pending = FALSE;
6331 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6335 /* Figure out the next stream sample to output, min_time is expressed in
6336 * global time and runs over the edit list segments. */
6337 min_time = G_MAXUINT64;
6338 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6339 GstClockTime position;
6341 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6342 position = stream->time_position;
6344 if (!GST_CLOCK_TIME_IS_VALID (position))
6347 if (stream->segment_index != -1) {
6348 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6349 position += segment->media_start;
6352 /* position of -1 is EOS */
6353 if (position < min_time) {
6354 min_time = position;
6355 target_stream = stream;
6359 if (G_UNLIKELY (target_stream == NULL)) {
6360 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6364 /* check for segment end */
6365 if (G_UNLIKELY (qtdemux->segment.stop != -1
6366 && qtdemux->segment.rate >= 0
6367 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6368 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6369 target_stream->time_position = GST_CLOCK_TIME_NONE;
6373 /* gap events for subtitle streams */
6374 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6375 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6377 GstClockTime gap_threshold;
6379 /* Only send gap events on non-subtitle streams if lagging way behind. */
6380 if (stream->subtype == FOURCC_subp
6381 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6382 stream->subtype == FOURCC_wvtt)
6383 gap_threshold = 1 * GST_SECOND;
6385 gap_threshold = 3 * GST_SECOND;
6387 /* send gap events until the stream catches up */
6388 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6389 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6390 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6391 stream->segment.position + gap_threshold < min_time) {
6393 gst_event_new_gap (stream->segment.position, gap_threshold);
6394 gst_pad_push_event (stream->pad, gap);
6395 stream->segment.position += gap_threshold;
6400 stream = target_stream;
6401 /* fetch info for the current sample of this stream */
6402 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6403 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6406 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6407 if (stream->new_caps) {
6408 gst_qtdemux_configure_stream (qtdemux, stream);
6409 qtdemux_do_allocation (stream, qtdemux);
6412 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6413 if (G_UNLIKELY (qtdemux->segment.
6414 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6415 if (stream->subtype == FOURCC_vide) {
6417 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6420 } else if (qtdemux->trickmode_interval > 0) {
6421 GstClockTimeDiff interval;
6423 if (qtdemux->segment.rate > 0)
6424 interval = stream->time_position - stream->last_keyframe_dts;
6426 interval = stream->last_keyframe_dts - stream->time_position;
6428 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6429 && interval < qtdemux->trickmode_interval) {
6430 GST_LOG_OBJECT (qtdemux,
6431 "Skipping keyframe within interval on track-id %u",
6435 stream->last_keyframe_dts = stream->time_position;
6441 GST_DEBUG_OBJECT (qtdemux,
6442 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6443 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6444 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6445 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6446 GST_TIME_ARGS (duration));
6448 if (G_UNLIKELY (empty)) {
6449 /* empty segment, push a gap if there's a second or more
6450 * difference and move to the next one */
6451 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6452 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6453 stream->segment.position = pts + duration;
6457 /* hmm, empty sample, skip and move to next sample */
6458 if (G_UNLIKELY (sample_size <= 0))
6461 /* last pushed sample was out of boundary, goto next sample */
6462 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6465 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6466 GST_DEBUG_OBJECT (qtdemux,
6467 "size %d larger than stream max_buffer_size %d, trimming",
6468 sample_size, stream->max_buffer_size);
6470 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6471 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6472 && sample_size < stream->min_buffer_size) {
6473 guint start_sample_index = stream->sample_index;
6474 guint accumulated_size = sample_size;
6475 guint64 expected_next_offset = offset + sample_size;
6477 GST_DEBUG_OBJECT (qtdemux,
6478 "size %d smaller than stream min_buffer_size %d, combining with the next",
6479 sample_size, stream->min_buffer_size);
6481 while (stream->sample_index < stream->to_sample
6482 && stream->sample_index + 1 < stream->n_samples) {
6483 const QtDemuxSample *next_sample;
6485 /* Increment temporarily */
6486 stream->sample_index++;
6488 /* Failed to parse sample so let's go back to the previous one that was
6489 * still successful */
6490 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6491 stream->sample_index--;
6495 next_sample = &stream->samples[stream->sample_index];
6497 /* Not contiguous with the previous sample so let's go back to the
6498 * previous one that was still successful */
6499 if (next_sample->offset != expected_next_offset) {
6500 stream->sample_index--;
6504 accumulated_size += next_sample->size;
6505 expected_next_offset += next_sample->size;
6506 if (accumulated_size >= stream->min_buffer_size)
6510 num_samples = stream->sample_index + 1 - start_sample_index;
6511 stream->sample_index = start_sample_index;
6512 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6513 num_samples, accumulated_size);
6514 size = accumulated_size;
6519 if (qtdemux->cenc_aux_info_offset > 0) {
6522 GstBuffer *aux_info = NULL;
6524 /* pull the data stored before the sample */
6526 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6527 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6528 if (G_UNLIKELY (ret != GST_FLOW_OK))
6530 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6531 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6532 gst_byte_reader_init (&br, map.data + 8, map.size);
6533 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6534 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6535 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6536 gst_buffer_unmap (aux_info, &map);
6537 gst_buffer_unref (aux_info);
6538 ret = GST_FLOW_ERROR;
6541 gst_buffer_unmap (aux_info, &map);
6542 gst_buffer_unref (aux_info);
6545 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6548 if (stream->use_allocator) {
6549 /* if we have a per-stream allocator, use it */
6550 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6553 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6555 if (G_UNLIKELY (ret != GST_FLOW_OK))
6558 /* Update for both splitting and combining of samples */
6559 if (size != sample_size) {
6560 pts += gst_util_uint64_scale_int (GST_SECOND,
6561 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6564 gst_util_uint64_scale_int (GST_SECOND,
6565 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6568 gst_util_uint64_scale_int (GST_SECOND,
6569 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6572 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6573 dts, pts, duration, keyframe, min_time, offset);
6575 if (size < sample_size) {
6576 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6577 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6579 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6581 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6582 if (time_position >= segment->media_start) {
6583 /* inside the segment, update time_position, looks very familiar to
6584 * GStreamer segments, doesn't it? */
6585 stream->time_position = (time_position - segment->media_start) +
6588 /* not yet in segment, time does not yet increment. This means
6589 * that we are still prerolling keyframes to the decoder so it can
6590 * decode the first sample of the segment. */
6591 stream->time_position = segment->time;
6593 } else if (size > sample_size) {
6594 /* Increase to the last sample we already pulled so that advancing
6595 * below brings us to the next sample we need to pull */
6596 stream->sample_index += num_samples - 1;
6600 GST_OBJECT_LOCK (qtdemux);
6601 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6602 GST_OBJECT_UNLOCK (qtdemux);
6603 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6604 * we have no more data for the pad to push */
6605 if (ret == GST_FLOW_EOS)
6608 stream->offset_in_sample += size;
6609 if (stream->offset_in_sample >= sample_size) {
6610 gst_qtdemux_advance_sample (qtdemux, stream);
6615 gst_qtdemux_advance_sample (qtdemux, stream);
6623 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6629 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6630 /* EOS will be raised if all are EOS */
6637 gst_qtdemux_loop (GstPad * pad)
6639 GstQTDemux *qtdemux;
6643 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6645 cur_offset = qtdemux->offset;
6646 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6647 cur_offset, qt_demux_state_string (qtdemux->state));
6649 switch (qtdemux->state) {
6650 case QTDEMUX_STATE_INITIAL:
6651 case QTDEMUX_STATE_HEADER:
6652 ret = gst_qtdemux_loop_state_header (qtdemux);
6654 case QTDEMUX_STATE_MOVIE:
6655 ret = gst_qtdemux_loop_state_movie (qtdemux);
6656 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6657 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6665 /* if something went wrong, pause */
6666 if (ret != GST_FLOW_OK)
6670 gst_object_unref (qtdemux);
6676 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6677 (NULL), ("streaming stopped, invalid state"));
6678 gst_pad_pause_task (pad);
6679 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6684 const gchar *reason = gst_flow_get_name (ret);
6686 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6688 gst_pad_pause_task (pad);
6690 /* fatal errors need special actions */
6692 if (ret == GST_FLOW_EOS) {
6693 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6694 /* we have no streams, post an error */
6695 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6697 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6700 if ((stop = qtdemux->segment.stop) == -1)
6701 stop = qtdemux->segment.duration;
6703 if (qtdemux->segment.rate >= 0) {
6704 GstMessage *message;
6707 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6708 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6709 GST_FORMAT_TIME, stop);
6710 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6711 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6712 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6713 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6715 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6716 gst_qtdemux_push_event (qtdemux, event);
6718 GstMessage *message;
6721 /* For Reverse Playback */
6722 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6723 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6724 GST_FORMAT_TIME, qtdemux->segment.start);
6725 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6726 qtdemux->segment.start);
6727 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6728 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6729 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6731 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6732 gst_qtdemux_push_event (qtdemux, event);
6737 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6738 event = gst_event_new_eos ();
6739 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6740 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6741 gst_qtdemux_push_event (qtdemux, event);
6743 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6744 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6745 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6754 * Returns if there are samples to be played.
6757 has_next_entry (GstQTDemux * demux)
6759 QtDemuxStream *stream;
6762 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6764 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6765 stream = QTDEMUX_NTH_STREAM (demux, i);
6767 if (stream->sample_index == -1) {
6768 stream->sample_index = 0;
6769 stream->offset_in_sample = 0;
6772 if (stream->sample_index >= stream->n_samples) {
6773 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6776 GST_DEBUG_OBJECT (demux, "Found a sample");
6780 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6787 * Returns the size of the first entry at the current offset.
6788 * If -1, there are none (which means EOS or empty file).
6791 next_entry_size (GstQTDemux * demux)
6793 QtDemuxStream *stream, *target_stream = NULL;
6794 guint64 smalloffs = (guint64) - 1;
6795 QtDemuxSample *sample;
6798 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6801 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6802 stream = QTDEMUX_NTH_STREAM (demux, i);
6804 if (stream->sample_index == -1) {
6805 stream->sample_index = 0;
6806 stream->offset_in_sample = 0;
6809 if (stream->sample_index >= stream->n_samples) {
6810 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6814 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6815 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6816 stream->sample_index);
6820 sample = &stream->samples[stream->sample_index];
6822 GST_LOG_OBJECT (demux,
6823 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6824 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6825 stream->sample_index, sample->offset, sample->size);
6827 if (((smalloffs == -1)
6828 || (sample->offset < smalloffs)) && (sample->size)) {
6829 smalloffs = sample->offset;
6830 target_stream = stream;
6837 GST_LOG_OBJECT (demux,
6838 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6839 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6841 stream = target_stream;
6842 sample = &stream->samples[stream->sample_index];
6844 if (sample->offset >= demux->offset) {
6845 demux->todrop = sample->offset - demux->offset;
6846 return sample->size + demux->todrop;
6849 GST_DEBUG_OBJECT (demux,
6850 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6855 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6857 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6859 gst_element_post_message (GST_ELEMENT_CAST (demux),
6860 gst_message_new_element (GST_OBJECT_CAST (demux),
6861 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6865 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6870 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6873 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6874 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6875 GST_SEEK_TYPE_NONE, -1);
6877 /* store seqnum to drop flush events, they don't need to reach downstream */
6878 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6879 res = gst_pad_push_event (demux->sinkpad, event);
6880 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6885 /* check for seekable upstream, above and beyond a mere query */
6887 gst_qtdemux_check_seekability (GstQTDemux * demux)
6890 gboolean seekable = FALSE;
6891 gint64 start = -1, stop = -1;
6893 if (demux->upstream_size)
6896 if (demux->upstream_format_is_time)
6899 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6900 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6901 GST_DEBUG_OBJECT (demux, "seeking query failed");
6905 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6907 /* try harder to query upstream size if we didn't get it the first time */
6908 if (seekable && stop == -1) {
6909 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6910 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6913 /* if upstream doesn't know the size, it's likely that it's not seekable in
6914 * practice even if it technically may be seekable */
6915 if (seekable && (start != 0 || stop <= start)) {
6916 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6921 gst_query_unref (query);
6923 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6924 G_GUINT64_FORMAT ")", seekable, start, stop);
6925 demux->upstream_seekable = seekable;
6926 demux->upstream_size = seekable ? stop : -1;
6930 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6932 g_return_if_fail (bytes <= demux->todrop);
6934 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6935 gst_adapter_flush (demux->adapter, bytes);
6936 demux->neededbytes -= bytes;
6937 demux->offset += bytes;
6938 demux->todrop -= bytes;
6941 /* PUSH-MODE only: Send a segment, if not done already. */
6943 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6945 if (G_UNLIKELY (demux->need_segment)) {
6948 if (!demux->upstream_format_is_time) {
6949 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6951 GstEvent *segment_event;
6952 segment_event = gst_event_new_segment (&demux->segment);
6953 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6954 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6955 gst_qtdemux_push_event (demux, segment_event);
6958 demux->need_segment = FALSE;
6960 /* clear to send tags on all streams */
6961 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6962 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6963 gst_qtdemux_push_tags (demux, stream);
6964 if (CUR_STREAM (stream)->sparse) {
6965 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6966 gst_pad_push_event (stream->pad,
6967 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6973 /* Used for push mode only. */
6975 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6976 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6978 GstClockTime ts, dur;
6982 stream->segments[segment_index].duration - (pos -
6983 stream->segments[segment_index].time);
6984 stream->time_position += dur;
6986 /* Only gaps with a duration of at least one second are propagated.
6987 * Same workaround as in pull mode.
6988 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6989 if (dur >= GST_SECOND) {
6991 gap = gst_event_new_gap (ts, dur);
6993 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6994 "segment: %" GST_PTR_FORMAT, gap);
6995 gst_pad_push_event (stream->pad, gap);
6999 static GstFlowReturn
7000 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7004 demux = GST_QTDEMUX (parent);
7006 GST_DEBUG_OBJECT (demux,
7007 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7008 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7009 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7010 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7011 gst_buffer_get_size (inbuf), demux->offset);
7013 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7014 gboolean is_gap_input = FALSE;
7017 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7019 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7020 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7023 /* Check if we can land back on our feet in the case where upstream is
7024 * handling the seeking/pushing of samples with gaps in between (like
7025 * in the case of trick-mode DASH for example) */
7026 if (demux->upstream_format_is_time
7027 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7028 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7030 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7031 GST_LOG_OBJECT (demux,
7032 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7033 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7035 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7036 stream, GST_BUFFER_OFFSET (inbuf));
7038 QtDemuxSample *sample = &stream->samples[res];
7039 GST_LOG_OBJECT (demux,
7040 "Checking if sample %d from track-id %u is valid (offset:%"
7041 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7042 stream->track_id, sample->offset, sample->size);
7043 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7044 GST_LOG_OBJECT (demux,
7045 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7047 is_gap_input = TRUE;
7048 /* We can go back to standard playback mode */
7049 demux->state = QTDEMUX_STATE_MOVIE;
7050 /* Remember which sample this stream is at */
7051 stream->sample_index = res;
7052 /* Finally update all push-based values to the expected values */
7053 demux->neededbytes = stream->samples[res].size;
7054 demux->offset = GST_BUFFER_OFFSET (inbuf);
7056 demux->mdatsize - demux->offset + demux->mdatoffset;
7061 if (!is_gap_input) {
7062 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7063 /* Reset state if it's a real discont */
7064 demux->neededbytes = 16;
7065 demux->state = QTDEMUX_STATE_INITIAL;
7066 demux->offset = GST_BUFFER_OFFSET (inbuf);
7067 gst_adapter_clear (demux->adapter);
7070 /* Reverse fragmented playback, need to flush all we have before
7071 * consuming a new fragment.
7072 * The samples array have the timestamps calculated by accumulating the
7073 * durations but this won't work for reverse playback of fragments as
7074 * the timestamps of a subsequent fragment should be smaller than the
7075 * previously received one. */
7076 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7077 gst_qtdemux_process_adapter (demux, TRUE);
7078 g_ptr_array_foreach (demux->active_streams,
7079 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7083 gst_adapter_push (demux->adapter, inbuf);
7085 GST_DEBUG_OBJECT (demux,
7086 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7087 demux->neededbytes, gst_adapter_available (demux->adapter));
7089 return gst_qtdemux_process_adapter (demux, FALSE);
7092 static GstFlowReturn
7093 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7095 GstFlowReturn ret = GST_FLOW_OK;
7097 /* we never really mean to buffer that much */
7098 if (demux->neededbytes == -1) {
7102 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7103 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7105 #ifndef GST_DISABLE_GST_DEBUG
7107 guint64 discont_offset, distance_from_discont;
7109 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7110 distance_from_discont =
7111 gst_adapter_distance_from_discont (demux->adapter);
7113 GST_DEBUG_OBJECT (demux,
7114 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7115 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7116 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7117 demux->offset, discont_offset, distance_from_discont);
7121 switch (demux->state) {
7122 case QTDEMUX_STATE_INITIAL:{
7127 gst_qtdemux_check_seekability (demux);
7129 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7131 /* get fourcc/length, set neededbytes */
7132 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7134 gst_adapter_unmap (demux->adapter);
7136 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7137 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7139 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7140 (_("This file is invalid and cannot be played.")),
7141 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7142 GST_FOURCC_ARGS (fourcc)));
7143 ret = GST_FLOW_ERROR;
7146 if (fourcc == FOURCC_mdat) {
7147 gint next_entry = next_entry_size (demux);
7148 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7149 || !demux->fragmented)) {
7150 /* we have the headers, start playback */
7151 demux->state = QTDEMUX_STATE_MOVIE;
7152 demux->neededbytes = next_entry;
7153 demux->mdatleft = size;
7154 demux->mdatsize = demux->mdatleft;
7156 /* no headers yet, try to get them */
7159 guint64 old, target;
7162 old = demux->offset;
7163 target = old + size;
7165 /* try to jump over the atom with a seek */
7166 /* only bother if it seems worth doing so,
7167 * and avoids possible upstream/server problems */
7168 if (demux->upstream_seekable &&
7169 demux->upstream_size > 4 * (1 << 20)) {
7170 res = qtdemux_seek_offset (demux, target);
7172 GST_DEBUG_OBJECT (demux, "skipping seek");
7177 GST_DEBUG_OBJECT (demux, "seek success");
7178 /* remember the offset fo the first mdat so we can seek back to it
7179 * after we have the headers */
7180 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7181 demux->first_mdat = old;
7182 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7185 /* seek worked, continue reading */
7186 demux->offset = target;
7187 demux->neededbytes = 16;
7188 demux->state = QTDEMUX_STATE_INITIAL;
7190 /* seek failed, need to buffer */
7191 demux->offset = old;
7192 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7193 /* there may be multiple mdat (or alike) buffers */
7195 if (demux->mdatbuffer)
7196 bs = gst_buffer_get_size (demux->mdatbuffer);
7199 if (size + bs > 10 * (1 << 20))
7201 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7202 demux->neededbytes = size;
7203 if (!demux->mdatbuffer)
7204 demux->mdatoffset = demux->offset;
7207 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7208 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7209 (_("This file is invalid and cannot be played.")),
7210 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7211 GST_FOURCC_ARGS (fourcc), size));
7212 ret = GST_FLOW_ERROR;
7215 /* this means we already started buffering and still no moov header,
7216 * let's continue buffering everything till we get moov */
7217 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7218 || fourcc == FOURCC_moof))
7220 demux->neededbytes = size;
7221 demux->state = QTDEMUX_STATE_HEADER;
7225 case QTDEMUX_STATE_HEADER:{
7229 GST_DEBUG_OBJECT (demux, "In header");
7231 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7233 /* parse the header */
7234 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7236 if (fourcc == FOURCC_moov) {
7237 /* in usual fragmented setup we could try to scan for more
7238 * and end up at the the moov (after mdat) again */
7239 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7241 || demux->last_moov_offset == demux->offset)) {
7242 GST_DEBUG_OBJECT (demux,
7243 "Skipping moov atom as we have (this) one already");
7245 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7247 if (demux->got_moov && demux->fragmented) {
7248 GST_DEBUG_OBJECT (demux,
7249 "Got a second moov, clean up data from old one");
7250 if (demux->moov_node_compressed) {
7251 g_node_destroy (demux->moov_node_compressed);
7252 if (demux->moov_node)
7253 g_free (demux->moov_node->data);
7255 demux->moov_node_compressed = NULL;
7256 if (demux->moov_node)
7257 g_node_destroy (demux->moov_node);
7258 demux->moov_node = NULL;
7261 demux->last_moov_offset = demux->offset;
7263 /* Update streams with new moov */
7264 gst_qtdemux_stream_concat (demux,
7265 demux->old_streams, demux->active_streams);
7267 qtdemux_parse_moov (demux, data, demux->neededbytes);
7268 qtdemux_node_dump (demux, demux->moov_node);
7269 qtdemux_parse_tree (demux);
7270 qtdemux_prepare_streams (demux);
7271 QTDEMUX_EXPOSE_LOCK (demux);
7272 qtdemux_expose_streams (demux);
7273 QTDEMUX_EXPOSE_UNLOCK (demux);
7275 demux->got_moov = TRUE;
7277 gst_qtdemux_check_send_pending_segment (demux);
7279 if (demux->moov_node_compressed) {
7280 g_node_destroy (demux->moov_node_compressed);
7281 g_free (demux->moov_node->data);
7283 demux->moov_node_compressed = NULL;
7284 g_node_destroy (demux->moov_node);
7285 demux->moov_node = NULL;
7286 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7288 } else if (fourcc == FOURCC_moof) {
7289 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7291 GstClockTime prev_pts;
7292 guint64 prev_offset;
7293 guint64 adapter_discont_offset, adapter_discont_dist;
7295 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7298 * The timestamp of the moof buffer is relevant as some scenarios
7299 * won't have the initial timestamp in the atoms. Whenever a new
7300 * buffer has started, we get that buffer's PTS and use it as a base
7301 * timestamp for the trun entries.
7303 * To keep track of the current buffer timestamp and starting point
7304 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7305 * from the beginning of the buffer, with the distance and demux->offset
7306 * we know if it is still the same buffer or not.
7308 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7309 prev_offset = demux->offset - dist;
7310 if (demux->fragment_start_offset == -1
7311 || prev_offset > demux->fragment_start_offset) {
7312 demux->fragment_start_offset = prev_offset;
7313 demux->fragment_start = prev_pts;
7314 GST_DEBUG_OBJECT (demux,
7315 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7316 GST_TIME_FORMAT, demux->fragment_start_offset,
7317 GST_TIME_ARGS (demux->fragment_start));
7320 /* We can't use prev_offset() here because this would require
7321 * upstream to set consistent and correct offsets on all buffers
7322 * since the discont. Nothing ever did that in the past and we
7323 * would break backwards compatibility here then.
7324 * Instead take the offset we had at the last discont and count
7325 * the bytes from there. This works with old code as there would
7326 * be no discont between moov and moof, and also works with
7327 * adaptivedemux which correctly sets offset and will set the
7328 * DISCONT flag accordingly when needed.
7330 * We also only do this for upstream TIME segments as otherwise
7331 * there are potential backwards compatibility problems with
7332 * seeking in PUSH mode and upstream providing inconsistent
7334 adapter_discont_offset =
7335 gst_adapter_offset_at_discont (demux->adapter);
7336 adapter_discont_dist =
7337 gst_adapter_distance_from_discont (demux->adapter);
7339 GST_DEBUG_OBJECT (demux,
7340 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7341 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7342 demux->offset, adapter_discont_offset, adapter_discont_dist);
7344 if (demux->upstream_format_is_time) {
7345 demux->moof_offset = adapter_discont_offset;
7346 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7347 demux->moof_offset += adapter_discont_dist;
7348 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7349 demux->moof_offset = demux->offset;
7351 demux->moof_offset = demux->offset;
7354 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7355 demux->moof_offset, NULL)) {
7356 gst_adapter_unmap (demux->adapter);
7357 ret = GST_FLOW_ERROR;
7361 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7362 if (demux->mss_mode && !demux->exposed) {
7363 QTDEMUX_EXPOSE_LOCK (demux);
7364 qtdemux_expose_streams (demux);
7365 QTDEMUX_EXPOSE_UNLOCK (demux);
7368 gst_qtdemux_check_send_pending_segment (demux);
7370 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7372 } else if (fourcc == FOURCC_ftyp) {
7373 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7374 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7375 } else if (fourcc == FOURCC_uuid) {
7376 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7377 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7378 } else if (fourcc == FOURCC_sidx) {
7379 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7380 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7384 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7388 /* [free] and [skip] are padding atoms */
7389 GST_DEBUG_OBJECT (demux,
7390 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7391 GST_FOURCC_ARGS (fourcc));
7394 GST_WARNING_OBJECT (demux,
7395 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7396 GST_FOURCC_ARGS (fourcc));
7397 /* Let's jump that one and go back to initial state */
7401 gst_adapter_unmap (demux->adapter);
7404 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7405 gsize remaining_data_size = 0;
7407 /* the mdat was before the header */
7408 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7409 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7410 /* restore our adapter/offset view of things with upstream;
7411 * put preceding buffered data ahead of current moov data.
7412 * This should also handle evil mdat, moov, mdat cases and alike */
7413 gst_adapter_flush (demux->adapter, demux->neededbytes);
7415 /* Store any remaining data after the mdat for later usage */
7416 remaining_data_size = gst_adapter_available (demux->adapter);
7417 if (remaining_data_size > 0) {
7418 g_assert (demux->restoredata_buffer == NULL);
7419 demux->restoredata_buffer =
7420 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7421 demux->restoredata_offset = demux->offset + demux->neededbytes;
7422 GST_DEBUG_OBJECT (demux,
7423 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7424 G_GUINT64_FORMAT, remaining_data_size,
7425 demux->restoredata_offset);
7428 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7429 demux->mdatbuffer = NULL;
7430 demux->offset = demux->mdatoffset;
7431 demux->neededbytes = next_entry_size (demux);
7432 demux->state = QTDEMUX_STATE_MOVIE;
7433 demux->mdatleft = gst_adapter_available (demux->adapter);
7434 demux->mdatsize = demux->mdatleft;
7436 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7437 gst_adapter_flush (demux->adapter, demux->neededbytes);
7439 /* only go back to the mdat if there are samples to play */
7440 if (demux->got_moov && demux->first_mdat != -1
7441 && has_next_entry (demux)) {
7444 /* we need to seek back */
7445 res = qtdemux_seek_offset (demux, demux->first_mdat);
7447 demux->offset = demux->first_mdat;
7449 GST_DEBUG_OBJECT (demux, "Seek back failed");
7452 demux->offset += demux->neededbytes;
7454 demux->neededbytes = 16;
7455 demux->state = QTDEMUX_STATE_INITIAL;
7460 case QTDEMUX_STATE_BUFFER_MDAT:{
7464 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7466 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7467 gst_buffer_extract (buf, 0, fourcc, 4);
7468 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7469 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7470 if (demux->mdatbuffer)
7471 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7473 demux->mdatbuffer = buf;
7474 demux->offset += demux->neededbytes;
7475 demux->neededbytes = 16;
7476 demux->state = QTDEMUX_STATE_INITIAL;
7477 gst_qtdemux_post_progress (demux, 1, 1);
7481 case QTDEMUX_STATE_MOVIE:{
7482 QtDemuxStream *stream = NULL;
7483 QtDemuxSample *sample;
7484 GstClockTime dts, pts, duration;
7488 GST_DEBUG_OBJECT (demux,
7489 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7491 if (demux->fragmented) {
7492 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7494 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7495 /* if needed data starts within this atom,
7496 * then it should not exceed this atom */
7497 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7498 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7499 (_("This file is invalid and cannot be played.")),
7500 ("sample data crosses atom boundary"));
7501 ret = GST_FLOW_ERROR;
7504 demux->mdatleft -= demux->neededbytes;
7506 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7507 /* so we are dropping more than left in this atom */
7508 gst_qtdemux_drop_data (demux, demux->mdatleft);
7509 demux->mdatleft = 0;
7511 /* need to resume atom parsing so we do not miss any other pieces */
7512 demux->state = QTDEMUX_STATE_INITIAL;
7513 demux->neededbytes = 16;
7515 /* check if there was any stored post mdat data from previous buffers */
7516 if (demux->restoredata_buffer) {
7517 g_assert (gst_adapter_available (demux->adapter) == 0);
7519 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7520 demux->restoredata_buffer = NULL;
7521 demux->offset = demux->restoredata_offset;
7528 if (demux->todrop) {
7529 if (demux->cenc_aux_info_offset > 0) {
7533 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7534 data = gst_adapter_map (demux->adapter, demux->todrop);
7535 gst_byte_reader_init (&br, data + 8, demux->todrop);
7536 if (!qtdemux_parse_cenc_aux_info (demux,
7537 QTDEMUX_NTH_STREAM (demux, 0), &br,
7538 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7539 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7540 ret = GST_FLOW_ERROR;
7541 gst_adapter_unmap (demux->adapter);
7542 g_free (demux->cenc_aux_info_sizes);
7543 demux->cenc_aux_info_sizes = NULL;
7546 demux->cenc_aux_info_offset = 0;
7547 g_free (demux->cenc_aux_info_sizes);
7548 demux->cenc_aux_info_sizes = NULL;
7549 gst_adapter_unmap (demux->adapter);
7551 gst_qtdemux_drop_data (demux, demux->todrop);
7555 /* initial newsegment sent here after having added pads,
7556 * possible others in sink_event */
7557 gst_qtdemux_check_send_pending_segment (demux);
7559 /* Figure out which stream this packet belongs to */
7560 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7561 stream = QTDEMUX_NTH_STREAM (demux, i);
7562 if (stream->sample_index >= stream->n_samples) {
7563 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7567 GST_LOG_OBJECT (demux,
7568 "Checking track-id %u (sample_index:%d / offset:%"
7569 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7570 stream->sample_index,
7571 stream->samples[stream->sample_index].offset,
7572 stream->samples[stream->sample_index].size);
7574 if (stream->samples[stream->sample_index].offset == demux->offset)
7578 if (G_UNLIKELY (stream == NULL))
7579 goto unknown_stream;
7581 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7583 if (stream->new_caps) {
7584 gst_qtdemux_configure_stream (demux, stream);
7587 /* Put data in a buffer, set timestamps, caps, ... */
7588 sample = &stream->samples[stream->sample_index];
7590 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7591 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7592 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7594 dts = QTSAMPLE_DTS (stream, sample);
7595 pts = QTSAMPLE_PTS (stream, sample);
7596 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7597 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7599 /* check for segment end */
7600 if (G_UNLIKELY (demux->segment.stop != -1
7601 && demux->segment.stop <= pts && stream->on_keyframe)
7602 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7603 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7604 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7606 /* skip this data, stream is EOS */
7607 gst_adapter_flush (demux->adapter, demux->neededbytes);
7608 demux->offset += demux->neededbytes;
7610 /* check if all streams are eos */
7612 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7613 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7622 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7624 /* FIXME: should either be an assert or a plain check */
7625 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7627 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7628 dts, pts, duration, keyframe, dts, demux->offset);
7632 GST_OBJECT_LOCK (demux);
7633 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7634 GST_OBJECT_UNLOCK (demux);
7636 /* skip this data, stream is EOS */
7637 gst_adapter_flush (demux->adapter, demux->neededbytes);
7640 stream->sample_index++;
7641 stream->offset_in_sample = 0;
7643 /* update current offset and figure out size of next buffer */
7644 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7645 demux->offset, demux->neededbytes);
7646 demux->offset += demux->neededbytes;
7647 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7651 if (ret == GST_FLOW_EOS) {
7652 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7653 demux->neededbytes = -1;
7657 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7658 if (demux->fragmented) {
7659 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7660 /* there may be more to follow, only finish this atom */
7661 demux->todrop = demux->mdatleft;
7662 demux->neededbytes = demux->todrop;
7667 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7668 goto non_ok_unlinked_flow;
7677 /* when buffering movie data, at least show user something is happening */
7678 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7679 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7680 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7681 demux->neededbytes);
7688 non_ok_unlinked_flow:
7690 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7691 gst_flow_get_name (ret));
7696 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7697 ret = GST_FLOW_ERROR;
7702 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7708 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7709 (NULL), ("qtdemuxer invalid state %d", demux->state));
7710 ret = GST_FLOW_ERROR;
7715 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7716 (NULL), ("no 'moov' atom within the first 10 MB"));
7717 ret = GST_FLOW_ERROR;
7723 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7728 query = gst_query_new_scheduling ();
7730 if (!gst_pad_peer_query (sinkpad, query)) {
7731 gst_query_unref (query);
7735 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7736 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7737 gst_query_unref (query);
7742 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7743 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7747 GST_DEBUG_OBJECT (sinkpad, "activating push");
7748 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7753 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7754 GstPadMode mode, gboolean active)
7757 GstQTDemux *demux = GST_QTDEMUX (parent);
7760 case GST_PAD_MODE_PUSH:
7761 demux->pullbased = FALSE;
7764 case GST_PAD_MODE_PULL:
7766 demux->pullbased = TRUE;
7767 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7770 res = gst_pad_stop_task (sinkpad);
7782 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7788 memset (&z, 0, sizeof (z));
7793 if ((ret = inflateInit (&z)) != Z_OK) {
7794 GST_ERROR ("inflateInit() returned %d", ret);
7798 z.next_in = z_buffer;
7799 z.avail_in = z_length;
7801 buffer = (guint8 *) g_malloc (*length);
7802 z.avail_out = *length;
7803 z.next_out = (Bytef *) buffer;
7805 ret = inflate (&z, Z_NO_FLUSH);
7806 if (ret == Z_STREAM_END) {
7808 } else if (ret != Z_OK) {
7809 GST_WARNING ("inflate() returned %d", ret);
7814 buffer = (guint8 *) g_realloc (buffer, *length);
7815 z.next_out = (Bytef *) (buffer + z.total_out);
7816 z.avail_out += 4096;
7817 } while (z.avail_in > 0);
7819 if (ret != Z_STREAM_END) {
7824 *length = z.total_out;
7831 #endif /* HAVE_ZLIB */
7834 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7838 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7840 /* counts as header data */
7841 qtdemux->header_size += length;
7843 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7844 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7846 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7853 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7854 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7855 if (dcom == NULL || cmvd == NULL)
7856 goto invalid_compression;
7858 dcom_len = QT_UINT32 (dcom->data);
7860 goto invalid_compression;
7862 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7866 guint uncompressed_length;
7867 guint compressed_length;
7871 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7873 goto invalid_compression;
7875 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7876 compressed_length = cmvd_len - 12;
7877 GST_LOG ("length = %u", uncompressed_length);
7880 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7881 compressed_length, &uncompressed_length);
7884 qtdemux->moov_node_compressed = qtdemux->moov_node;
7885 qtdemux->moov_node = g_node_new (buf);
7887 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7888 uncompressed_length);
7892 #endif /* HAVE_ZLIB */
7894 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7895 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7902 invalid_compression:
7904 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7910 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7913 while (G_UNLIKELY (buf < end)) {
7917 if (G_UNLIKELY (buf + 4 > end)) {
7918 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7921 len = QT_UINT32 (buf);
7922 if (G_UNLIKELY (len == 0)) {
7923 GST_LOG_OBJECT (qtdemux, "empty container");
7926 if (G_UNLIKELY (len < 8)) {
7927 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7930 if (G_UNLIKELY (len > (end - buf))) {
7931 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7932 (gint) (end - buf));
7936 child = g_node_new ((guint8 *) buf);
7937 g_node_append (node, child);
7938 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7939 qtdemux_parse_node (qtdemux, child, buf, len);
7947 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7950 int len = QT_UINT32 (xdxt->data);
7951 guint8 *buf = xdxt->data;
7952 guint8 *end = buf + len;
7955 /* skip size and type */
7963 size = QT_UINT32 (buf);
7964 type = QT_FOURCC (buf + 4);
7966 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7968 if (buf + size > end || size <= 0)
7974 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7975 GST_FOURCC_ARGS (type));
7979 buffer = gst_buffer_new_and_alloc (size);
7980 gst_buffer_fill (buffer, 0, buf, size);
7981 stream->buffers = g_slist_append (stream->buffers, buffer);
7982 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7985 buffer = gst_buffer_new_and_alloc (size);
7986 gst_buffer_fill (buffer, 0, buf, size);
7987 stream->buffers = g_slist_append (stream->buffers, buffer);
7988 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7991 buffer = gst_buffer_new_and_alloc (size);
7992 gst_buffer_fill (buffer, 0, buf, size);
7993 stream->buffers = g_slist_append (stream->buffers, buffer);
7994 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7997 GST_WARNING_OBJECT (qtdemux,
7998 "unknown theora cookie %" GST_FOURCC_FORMAT,
7999 GST_FOURCC_ARGS (type));
8008 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8012 guint32 node_length = 0;
8013 const QtNodeType *type;
8016 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8018 if (G_UNLIKELY (length < 8))
8019 goto not_enough_data;
8021 node_length = QT_UINT32 (buffer);
8022 fourcc = QT_FOURCC (buffer + 4);
8024 /* ignore empty nodes */
8025 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8028 type = qtdemux_type_get (fourcc);
8030 end = buffer + length;
8032 GST_LOG_OBJECT (qtdemux,
8033 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8034 GST_FOURCC_ARGS (fourcc), node_length, type->name);
8036 if (node_length > length)
8037 goto broken_atom_size;
8039 if (type->flags & QT_FLAG_CONTAINER) {
8040 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8045 if (node_length < 20) {
8046 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8049 GST_DEBUG_OBJECT (qtdemux,
8050 "parsing stsd (sample table, sample description) atom");
8051 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8052 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8064 /* also read alac (or whatever) in stead of mp4a in the following,
8065 * since a similar layout is used in other cases as well */
8066 if (fourcc == FOURCC_mp4a)
8068 else if (fourcc == FOURCC_fLaC)
8073 /* There are two things we might encounter here: a true mp4a atom, and
8074 an mp4a entry in an stsd atom. The latter is what we're interested
8075 in, and it looks like an atom, but isn't really one. The true mp4a
8076 atom is short, so we detect it based on length here. */
8077 if (length < min_size) {
8078 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8079 GST_FOURCC_ARGS (fourcc));
8083 /* 'version' here is the sound sample description version. Types 0 and
8084 1 are documented in the QTFF reference, but type 2 is not: it's
8085 described in Apple header files instead (struct SoundDescriptionV2
8087 version = QT_UINT16 (buffer + 16);
8089 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8090 GST_FOURCC_ARGS (fourcc), version);
8092 /* parse any esds descriptors */
8104 GST_WARNING_OBJECT (qtdemux,
8105 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8106 GST_FOURCC_ARGS (fourcc), version);
8111 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8139 /* codec_data is contained inside these atoms, which all have
8140 * the same format. */
8141 /* video sample description size is 86 bytes without extension.
8142 * node_length have to be bigger than 86 bytes because video sample
8143 * description can include extensions such as esds, fiel, glbl, etc. */
8144 if (node_length < 86) {
8145 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8146 " sample description length too short (%u < 86)",
8147 GST_FOURCC_ARGS (fourcc), node_length);
8151 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8152 GST_FOURCC_ARGS (fourcc));
8154 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8156 * revision level (2 bytes) : must be set to 0. */
8157 version = QT_UINT32 (buffer + 16);
8158 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8160 /* compressor name : PASCAL string and informative purposes
8161 * first byte : the number of bytes to be displayed.
8162 * it has to be less than 32 because it is reserved
8163 * space of 32 bytes total including itself. */
8164 str_len = QT_UINT8 (buffer + 50);
8166 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8167 (char *) buffer + 51);
8169 GST_WARNING_OBJECT (qtdemux,
8170 "compressorname length too big (%u > 31)", str_len);
8172 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8174 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8179 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8181 /* You are reading this correctly. QTFF specifies that the
8182 * metadata atom is a short atom, whereas ISO BMFF specifies
8183 * it's a full atom. But since so many people are doing things
8184 * differently, we actually peek into the atom to see which
8187 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8188 GST_FOURCC_ARGS (fourcc));
8191 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8192 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8193 * starts with a 'hdlr' atom */
8194 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8195 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8196 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8197 * with version/flags both set to zero */
8198 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8200 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8205 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8206 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8207 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8216 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8217 GST_FOURCC_ARGS (fourcc));
8221 version = QT_UINT32 (buffer + 12);
8222 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8229 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8234 if (length < offset) {
8235 GST_WARNING_OBJECT (qtdemux,
8236 "skipping too small %" GST_FOURCC_FORMAT " box",
8237 GST_FOURCC_ARGS (fourcc));
8240 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8246 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8251 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8256 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8260 if (!strcmp (type->name, "unknown"))
8261 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8265 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8266 GST_FOURCC_ARGS (fourcc));
8272 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8273 (_("This file is corrupt and cannot be played.")),
8274 ("Not enough data for an atom header, got only %u bytes", length));
8279 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8280 (_("This file is corrupt and cannot be played.")),
8281 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8282 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8289 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8291 /* FIXME: This can only reliably work if demuxers have a
8292 * separate streaming thread per srcpad. This should be
8293 * done in a demuxer base class, which integrates parts
8296 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8301 query = gst_query_new_allocation (stream->caps, FALSE);
8303 if (!gst_pad_peer_query (stream->pad, query)) {
8304 /* not a problem, just debug a little */
8305 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8308 if (stream->allocator)
8309 gst_object_unref (stream->allocator);
8311 if (gst_query_get_n_allocation_params (query) > 0) {
8312 /* try the allocator */
8313 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8315 stream->use_allocator = TRUE;
8317 stream->allocator = NULL;
8318 gst_allocation_params_init (&stream->params);
8319 stream->use_allocator = FALSE;
8321 gst_query_unref (query);
8326 pad_query (const GValue * item, GValue * value, gpointer user_data)
8328 GstPad *pad = g_value_get_object (item);
8329 GstQuery *query = user_data;
8332 res = gst_pad_peer_query (pad, query);
8335 g_value_set_boolean (value, TRUE);
8339 GST_INFO_OBJECT (pad, "pad peer query failed");
8344 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8345 GstPadDirection direction)
8348 GstIteratorFoldFunction func = pad_query;
8349 GValue res = { 0, };
8351 g_value_init (&res, G_TYPE_BOOLEAN);
8352 g_value_set_boolean (&res, FALSE);
8355 if (direction == GST_PAD_SRC)
8356 it = gst_element_iterate_src_pads (element);
8358 it = gst_element_iterate_sink_pads (element);
8360 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8361 gst_iterator_resync (it);
8363 gst_iterator_free (it);
8365 return g_value_get_boolean (&res);
8369 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8370 QtDemuxStream * stream)
8374 GstElement *element = GST_ELEMENT (qtdemux);
8376 gchar **filtered_sys_ids;
8377 GValue event_list = G_VALUE_INIT;
8380 /* 1. Check if we already have the context. */
8381 if (qtdemux->preferred_protection_system_id != NULL) {
8382 GST_LOG_OBJECT (element,
8383 "already have the protection context, no need to request it again");
8387 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8388 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8389 (const gchar **) qtdemux->protection_system_ids->pdata);
8391 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8392 qtdemux->protection_system_ids->len - 1);
8393 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8394 "decryptors for %u of them, running context request",
8395 qtdemux->protection_system_ids->len,
8396 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8399 if (stream->protection_scheme_event_queue.length) {
8400 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8401 stream->protection_scheme_event_queue.length);
8402 walk = stream->protection_scheme_event_queue.tail;
8404 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8405 qtdemux->protection_event_queue.length);
8406 walk = qtdemux->protection_event_queue.tail;
8409 g_value_init (&event_list, GST_TYPE_LIST);
8410 for (; walk; walk = g_list_previous (walk)) {
8411 GValue *event_value = g_new0 (GValue, 1);
8412 g_value_init (event_value, GST_TYPE_EVENT);
8413 g_value_set_boxed (event_value, walk->data);
8414 gst_value_list_append_and_take_value (&event_list, event_value);
8417 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8418 * check if downstream already has a context of the specific type
8419 * 2b) Query upstream as above.
8421 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8422 st = gst_query_writable_structure (query);
8423 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8424 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8426 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8427 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8428 gst_query_parse_context (query, &ctxt);
8429 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8430 gst_element_set_context (element, ctxt);
8431 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8432 gst_query_parse_context (query, &ctxt);
8433 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8434 gst_element_set_context (element, ctxt);
8436 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8437 * the required context type and afterwards check if a
8438 * usable context was set now as in 1). The message could
8439 * be handled by the parent bins of the element and the
8444 GST_INFO_OBJECT (element, "posting need context message");
8445 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8446 "drm-preferred-decryption-system-id");
8447 st = (GstStructure *) gst_message_get_structure (msg);
8448 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8449 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8452 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8453 gst_element_post_message (element, msg);
8456 g_strfreev (filtered_sys_ids);
8457 g_value_unset (&event_list);
8458 gst_query_unref (query);
8462 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8463 QtDemuxStream * stream)
8466 const gchar *selected_system = NULL;
8468 g_return_val_if_fail (qtdemux != NULL, FALSE);
8469 g_return_val_if_fail (stream != NULL, FALSE);
8470 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8473 if (stream->protection_scheme_type == FOURCC_aavd) {
8474 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8475 if (!gst_structure_has_name (s, "application/x-aavd")) {
8476 gst_structure_set (s,
8477 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8479 gst_structure_set_name (s, "application/x-aavd");
8484 if (stream->protection_scheme_type != FOURCC_cenc
8485 && stream->protection_scheme_type != FOURCC_cbcs) {
8486 GST_ERROR_OBJECT (qtdemux,
8487 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8488 GST_FOURCC_ARGS (stream->protection_scheme_type));
8492 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8493 if (!gst_structure_has_name (s, "application/x-cenc")) {
8494 gst_structure_set (s,
8495 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8496 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8497 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8499 gst_structure_set_name (s, "application/x-cenc");
8502 if (qtdemux->protection_system_ids == NULL) {
8503 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8504 "cenc protection system information has been found, not setting a "
8505 "protection system UUID");
8509 gst_qtdemux_request_protection_context (qtdemux, stream);
8510 if (qtdemux->preferred_protection_system_id != NULL) {
8511 const gchar *preferred_system_array[] =
8512 { qtdemux->preferred_protection_system_id, NULL };
8514 selected_system = gst_protection_select_system (preferred_system_array);
8516 if (selected_system) {
8517 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8518 qtdemux->preferred_protection_system_id);
8520 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8521 "because there is no available decryptor",
8522 qtdemux->preferred_protection_system_id);
8526 if (!selected_system) {
8527 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8528 selected_system = gst_protection_select_system ((const gchar **)
8529 qtdemux->protection_system_ids->pdata);
8530 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8531 qtdemux->protection_system_ids->len - 1);
8534 if (!selected_system) {
8535 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8536 "suitable decryptor element has been found");
8540 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8543 gst_structure_set (s,
8544 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8551 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8553 /* fps is calculated base on the duration of the average framerate since
8554 * qt does not have a fixed framerate. */
8555 gboolean fps_available = TRUE;
8556 guint32 first_duration = 0;
8558 if (stream->n_samples > 0)
8559 first_duration = stream->samples[0].duration;
8561 if ((stream->n_samples == 1 && first_duration == 0)
8562 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8564 CUR_STREAM (stream)->fps_n = 0;
8565 CUR_STREAM (stream)->fps_d = 1;
8567 if (stream->duration == 0 || stream->n_samples < 2) {
8568 CUR_STREAM (stream)->fps_n = stream->timescale;
8569 CUR_STREAM (stream)->fps_d = 1;
8570 fps_available = FALSE;
8572 GstClockTime avg_duration;
8576 /* duration and n_samples can be updated for fragmented format
8577 * so, framerate of fragmented format is calculated using data in a moof */
8578 if (qtdemux->fragmented && stream->n_samples_moof > 0
8579 && stream->duration_moof > 0) {
8580 n_samples = stream->n_samples_moof;
8581 duration = stream->duration_moof;
8583 n_samples = stream->n_samples;
8584 duration = stream->duration;
8587 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8588 /* stream->duration is guint64, timescale, n_samples are guint32 */
8590 gst_util_uint64_scale_round (duration -
8591 first_duration, GST_SECOND,
8592 (guint64) (stream->timescale) * (n_samples - 1));
8594 GST_LOG_OBJECT (qtdemux,
8595 "Calculating avg sample duration based on stream (or moof) duration %"
8597 " minus first sample %u, leaving %d samples gives %"
8598 GST_TIME_FORMAT, duration, first_duration,
8599 n_samples - 1, GST_TIME_ARGS (avg_duration));
8602 gst_video_guess_framerate (avg_duration,
8603 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8605 GST_DEBUG_OBJECT (qtdemux,
8606 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8607 stream->timescale, CUR_STREAM (stream)->fps_n,
8608 CUR_STREAM (stream)->fps_d);
8612 return fps_available;
8616 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8618 if (stream->subtype == FOURCC_vide) {
8619 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8621 if (CUR_STREAM (stream)->caps) {
8622 CUR_STREAM (stream)->caps =
8623 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8625 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8626 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8627 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8628 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8630 /* set framerate if calculated framerate is reliable */
8631 if (fps_available) {
8632 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8633 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8634 CUR_STREAM (stream)->fps_d, NULL);
8637 /* calculate pixel-aspect-ratio using display width and height */
8638 GST_DEBUG_OBJECT (qtdemux,
8639 "video size %dx%d, target display size %dx%d",
8640 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8641 stream->display_width, stream->display_height);
8642 /* qt file might have pasp atom */
8643 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8644 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8645 CUR_STREAM (stream)->par_h);
8646 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8647 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8648 CUR_STREAM (stream)->par_h, NULL);
8649 } else if (stream->display_width > 0 && stream->display_height > 0
8650 && CUR_STREAM (stream)->width > 0
8651 && CUR_STREAM (stream)->height > 0) {
8654 /* calculate the pixel aspect ratio using the display and pixel w/h */
8655 n = stream->display_width * CUR_STREAM (stream)->height;
8656 d = stream->display_height * CUR_STREAM (stream)->width;
8659 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8660 CUR_STREAM (stream)->par_w = n;
8661 CUR_STREAM (stream)->par_h = d;
8662 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8663 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8664 CUR_STREAM (stream)->par_h, NULL);
8667 if (CUR_STREAM (stream)->interlace_mode > 0) {
8668 if (CUR_STREAM (stream)->interlace_mode == 1) {
8669 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8670 G_TYPE_STRING, "progressive", NULL);
8671 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8672 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8673 G_TYPE_STRING, "interleaved", NULL);
8674 if (CUR_STREAM (stream)->field_order == 9) {
8675 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8676 G_TYPE_STRING, "top-field-first", NULL);
8677 } else if (CUR_STREAM (stream)->field_order == 14) {
8678 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8679 G_TYPE_STRING, "bottom-field-first", NULL);
8684 /* Create incomplete colorimetry here if needed */
8685 if (CUR_STREAM (stream)->colorimetry.range ||
8686 CUR_STREAM (stream)->colorimetry.matrix ||
8687 CUR_STREAM (stream)->colorimetry.transfer
8688 || CUR_STREAM (stream)->colorimetry.primaries) {
8689 gchar *colorimetry =
8690 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8691 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8692 G_TYPE_STRING, colorimetry, NULL);
8693 g_free (colorimetry);
8696 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8697 guint par_w = 1, par_h = 1;
8699 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8700 par_w = CUR_STREAM (stream)->par_w;
8701 par_h = CUR_STREAM (stream)->par_h;
8704 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8705 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8707 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8710 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8711 "multiview-mode", G_TYPE_STRING,
8712 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8713 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8714 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8719 else if (stream->subtype == FOURCC_soun) {
8720 if (CUR_STREAM (stream)->caps) {
8721 CUR_STREAM (stream)->caps =
8722 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8723 if (CUR_STREAM (stream)->rate > 0)
8724 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8725 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8726 if (CUR_STREAM (stream)->n_channels > 0)
8727 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8728 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8729 if (CUR_STREAM (stream)->n_channels > 2) {
8730 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8731 * correctly; this is just the minimum we can do - assume
8732 * we don't actually have any channel positions. */
8733 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8734 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8739 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8740 const GstStructure *s;
8741 QtDemuxStream *fps_stream = NULL;
8742 gboolean fps_available = FALSE;
8744 /* CEA608 closed caption tracks are a bit special in that each sample
8745 * can contain CCs for multiple frames, and CCs can be omitted and have to
8746 * be inferred from the duration of the sample then.
8748 * As such we take the framerate from the (first) video track here for
8749 * CEA608 as there must be one CC byte pair for every video frame
8750 * according to the spec.
8752 * For CEA708 all is fine and there is one sample per frame.
8755 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8756 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8759 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8760 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8762 if (tmp->subtype == FOURCC_vide) {
8769 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8770 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8771 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8774 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8775 fps_stream = stream;
8778 CUR_STREAM (stream)->caps =
8779 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8781 /* set framerate if calculated framerate is reliable */
8782 if (fps_available) {
8783 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8784 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8785 CUR_STREAM (stream)->fps_d, NULL);
8790 GstCaps *prev_caps = NULL;
8792 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8793 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8794 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8795 gst_pad_set_active (stream->pad, TRUE);
8797 gst_pad_use_fixed_caps (stream->pad);
8799 if (stream->protected) {
8800 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8801 GST_ERROR_OBJECT (qtdemux,
8802 "Failed to configure protected stream caps.");
8807 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8808 CUR_STREAM (stream)->caps);
8809 if (stream->new_stream) {
8811 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8814 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8817 gst_event_parse_stream_flags (event, &stream_flags);
8818 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8819 qtdemux->have_group_id = TRUE;
8821 qtdemux->have_group_id = FALSE;
8822 gst_event_unref (event);
8823 } else if (!qtdemux->have_group_id) {
8824 qtdemux->have_group_id = TRUE;
8825 qtdemux->group_id = gst_util_group_id_next ();
8828 stream->new_stream = FALSE;
8829 event = gst_event_new_stream_start (stream->stream_id);
8830 if (qtdemux->have_group_id)
8831 gst_event_set_group_id (event, qtdemux->group_id);
8832 if (stream->disabled)
8833 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8834 if (CUR_STREAM (stream)->sparse) {
8835 stream_flags |= GST_STREAM_FLAG_SPARSE;
8837 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8839 gst_event_set_stream_flags (event, stream_flags);
8840 gst_pad_push_event (stream->pad, event);
8843 prev_caps = gst_pad_get_current_caps (stream->pad);
8845 if (CUR_STREAM (stream)->caps) {
8847 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8848 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8849 CUR_STREAM (stream)->caps);
8850 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8852 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8855 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8859 gst_caps_unref (prev_caps);
8860 stream->new_caps = FALSE;
8866 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8867 QtDemuxStream * stream)
8869 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8872 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8873 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8874 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8875 stream->stsd_entries_length)) {
8876 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8877 (_("This file is invalid and cannot be played.")),
8878 ("New sample description id is out of bounds (%d >= %d)",
8879 stream->stsd_sample_description_id, stream->stsd_entries_length));
8881 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8882 stream->new_caps = TRUE;
8887 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8888 QtDemuxStream * stream, GstTagList * list)
8890 gboolean ret = TRUE;
8892 if (stream->subtype == FOURCC_vide) {
8893 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8896 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8899 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8900 gst_object_unref (stream->pad);
8906 qtdemux->n_video_streams++;
8907 } else if (stream->subtype == FOURCC_soun) {
8908 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8911 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8913 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8914 gst_object_unref (stream->pad);
8919 qtdemux->n_audio_streams++;
8920 } else if (stream->subtype == FOURCC_strm) {
8921 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8922 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8923 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8924 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
8925 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8928 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8930 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8931 gst_object_unref (stream->pad);
8936 qtdemux->n_sub_streams++;
8937 } else if (CUR_STREAM (stream)->caps) {
8938 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8941 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8943 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8944 gst_object_unref (stream->pad);
8949 qtdemux->n_video_streams++;
8951 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8958 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8959 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8960 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8961 GST_OBJECT_LOCK (qtdemux);
8962 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8963 GST_OBJECT_UNLOCK (qtdemux);
8965 if (stream->stream_tags)
8966 gst_tag_list_unref (stream->stream_tags);
8967 stream->stream_tags = list;
8969 /* global tags go on each pad anyway */
8970 stream->send_global_tags = TRUE;
8971 /* send upstream GST_EVENT_PROTECTION events that were received before
8972 this source pad was created */
8973 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8974 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8978 gst_tag_list_unref (list);
8982 /* find next atom with @fourcc starting at @offset */
8983 static GstFlowReturn
8984 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8985 guint64 * length, guint32 fourcc)
8991 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8992 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8998 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8999 if (G_UNLIKELY (ret != GST_FLOW_OK))
9001 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9004 gst_buffer_unref (buf);
9007 gst_buffer_map (buf, &map, GST_MAP_READ);
9008 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9009 gst_buffer_unmap (buf, &map);
9010 gst_buffer_unref (buf);
9012 if (G_UNLIKELY (*length == 0)) {
9013 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9014 ret = GST_FLOW_ERROR;
9018 if (lfourcc == fourcc) {
9019 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9020 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9023 GST_LOG_OBJECT (qtdemux,
9024 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9025 GST_FOURCC_ARGS (lfourcc), *offset);
9026 if (*offset == G_MAXUINT64)
9036 /* might simply have had last one */
9037 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9042 /* should only do something in pull mode */
9043 /* call with OBJECT lock */
9044 static GstFlowReturn
9045 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9047 guint64 length, offset;
9048 GstBuffer *buf = NULL;
9049 GstFlowReturn ret = GST_FLOW_OK;
9050 GstFlowReturn res = GST_FLOW_OK;
9053 offset = qtdemux->moof_offset;
9054 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9057 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9058 return GST_FLOW_EOS;
9061 /* best not do pull etc with lock held */
9062 GST_OBJECT_UNLOCK (qtdemux);
9064 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9065 if (ret != GST_FLOW_OK)
9068 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9069 if (G_UNLIKELY (ret != GST_FLOW_OK))
9071 gst_buffer_map (buf, &map, GST_MAP_READ);
9072 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9073 gst_buffer_unmap (buf, &map);
9074 gst_buffer_unref (buf);
9079 gst_buffer_unmap (buf, &map);
9080 gst_buffer_unref (buf);
9084 /* look for next moof */
9085 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9086 if (G_UNLIKELY (ret != GST_FLOW_OK))
9090 GST_OBJECT_LOCK (qtdemux);
9092 qtdemux->moof_offset = offset;
9098 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9100 res = GST_FLOW_ERROR;
9105 /* maybe upstream temporarily flushing */
9106 if (ret != GST_FLOW_FLUSHING) {
9107 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9110 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9111 /* resume at current position next time */
9119 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9123 gint32 stts_duration;
9124 GstByteWriter stsc, stts, stsz;
9126 /* Each sample has a different size, which we don't support for merging */
9127 if (stream->sample_size == 0) {
9128 GST_DEBUG_OBJECT (qtdemux,
9129 "Not all samples have the same size, not merging");
9133 /* The stream has a ctts table, we don't support that */
9134 if (stream->ctts_present) {
9135 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9139 /* If there's a sync sample table also ignore this stream */
9140 if (stream->stps_present || stream->stss_present) {
9141 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9145 /* If chunks are considered samples already ignore this stream */
9146 if (stream->chunks_are_samples) {
9147 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9151 /* Require that all samples have the same duration */
9152 if (stream->n_sample_times > 1) {
9153 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9157 /* Parse the stts to get the sample duration and number of samples */
9158 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9159 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9161 /* Parse the number of chunks from the stco manually because the
9162 * reader is already behind that */
9163 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9165 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9168 /* Now parse stsc, convert chunks into single samples and generate a
9169 * new stsc, stts and stsz from this information */
9170 gst_byte_writer_init (&stsc);
9171 gst_byte_writer_init (&stts);
9172 gst_byte_writer_init (&stsz);
9174 /* Note: we skip fourccs, size, version, flags and other fields of the new
9175 * atoms as the byte readers with them are already behind that position
9176 * anyway and only update the values of those inside the stream directly.
9178 stream->n_sample_times = 0;
9179 stream->n_samples = 0;
9180 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9182 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9184 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9185 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9186 sample_description_id =
9187 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9189 if (i == stream->n_samples_per_chunk - 1) {
9190 /* +1 because first_chunk is 1-based */
9191 last_chunk = num_chunks + 1;
9193 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9196 GST_DEBUG_OBJECT (qtdemux,
9197 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9198 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9200 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9201 /* One sample in this chunk */
9202 gst_byte_writer_put_uint32_be (&stsc, 1);
9203 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9205 /* For each chunk write a stts and stsz entry now */
9206 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9207 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9208 for (j = first_chunk; j < last_chunk; j++) {
9209 gst_byte_writer_put_uint32_be (&stsz,
9210 stream->sample_size * samples_per_chunk);
9213 stream->n_sample_times += 1;
9214 stream->n_samples += last_chunk - first_chunk;
9217 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9219 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9220 stream->n_samples, stream->n_sample_times);
9222 /* We don't have a fixed sample size anymore */
9223 stream->sample_size = 0;
9225 /* Free old data for the atoms */
9226 g_free ((gpointer) stream->stsz.data);
9227 stream->stsz.data = NULL;
9228 g_free ((gpointer) stream->stsc.data);
9229 stream->stsc.data = NULL;
9230 g_free ((gpointer) stream->stts.data);
9231 stream->stts.data = NULL;
9233 /* Store new data and replace byte readers */
9234 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9235 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9236 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9237 stream->stts.size = gst_byte_writer_get_size (&stts);
9238 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9239 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9240 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9241 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9242 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9245 /* initialise bytereaders for stbl sub-atoms */
9247 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9249 stream->stbl_index = -1; /* no samples have yet been parsed */
9250 stream->sample_index = -1;
9252 /* time-to-sample atom */
9253 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9256 /* copy atom data into a new buffer for later use */
9257 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9259 /* skip version + flags */
9260 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9261 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9263 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9265 /* make sure there's enough data */
9266 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9267 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9268 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9269 stream->n_sample_times);
9270 if (!stream->n_sample_times)
9274 /* sync sample atom */
9275 stream->stps_present = FALSE;
9276 if ((stream->stss_present =
9277 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9278 &stream->stss) ? TRUE : FALSE) == TRUE) {
9279 /* copy atom data into a new buffer for later use */
9280 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9282 /* skip version + flags */
9283 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9284 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9287 if (stream->n_sample_syncs) {
9288 /* make sure there's enough data */
9289 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9293 /* partial sync sample atom */
9294 if ((stream->stps_present =
9295 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9296 &stream->stps) ? TRUE : FALSE) == TRUE) {
9297 /* copy atom data into a new buffer for later use */
9298 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9300 /* skip version + flags */
9301 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9302 !gst_byte_reader_get_uint32_be (&stream->stps,
9303 &stream->n_sample_partial_syncs))
9306 /* if there are no entries, the stss table contains the real
9308 if (stream->n_sample_partial_syncs) {
9309 /* make sure there's enough data */
9310 if (!qt_atom_parser_has_chunks (&stream->stps,
9311 stream->n_sample_partial_syncs, 4))
9318 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9321 /* copy atom data into a new buffer for later use */
9322 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9324 /* skip version + flags */
9325 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9326 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9329 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9332 if (!stream->n_samples)
9335 /* sample-to-chunk atom */
9336 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9339 /* copy atom data into a new buffer for later use */
9340 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9342 /* skip version + flags */
9343 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9344 !gst_byte_reader_get_uint32_be (&stream->stsc,
9345 &stream->n_samples_per_chunk))
9348 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9349 stream->n_samples_per_chunk);
9351 /* make sure there's enough data */
9352 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9358 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9359 stream->co_size = sizeof (guint32);
9360 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9362 stream->co_size = sizeof (guint64);
9366 /* copy atom data into a new buffer for later use */
9367 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9369 /* skip version + flags */
9370 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9373 /* chunks_are_samples == TRUE means treat chunks as samples */
9374 stream->chunks_are_samples = stream->sample_size
9375 && !CUR_STREAM (stream)->sampled;
9376 if (stream->chunks_are_samples) {
9377 /* treat chunks as samples */
9378 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9381 /* skip number of entries */
9382 if (!gst_byte_reader_skip (&stream->stco, 4))
9385 /* make sure there are enough data in the stsz atom */
9386 if (!stream->sample_size) {
9387 /* different sizes for each sample */
9388 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9393 /* composition time-to-sample */
9394 if ((stream->ctts_present =
9395 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9396 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9397 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9398 guint8 ctts_version;
9399 gboolean checked_ctts = FALSE;
9401 /* copy atom data into a new buffer for later use */
9402 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9404 /* version 1 has signed offsets */
9405 if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9409 if (!gst_byte_reader_skip (&stream->ctts, 3)
9410 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9411 &stream->n_composition_times))
9414 /* make sure there's enough data */
9415 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9419 /* This is optional, if missing we iterate the ctts */
9420 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9421 guint8 cslg_version;
9423 /* cslg version 1 has 64 bit fields */
9424 if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9428 if (!gst_byte_reader_skip (&cslg, 3))
9431 if (cslg_version == 0) {
9432 gint32 composition_to_dts_shift;
9434 if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9437 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9439 gint64 composition_to_dts_shift;
9441 if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9444 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9447 gint32 cslg_least = 0;
9448 guint num_entries, pos;
9451 pos = gst_byte_reader_get_pos (&stream->ctts);
9452 num_entries = stream->n_composition_times;
9454 checked_ctts = TRUE;
9456 stream->cslg_shift = 0;
9458 for (i = 0; i < num_entries; i++) {
9461 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9462 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9463 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9464 * slightly inaccurate PTS could be more usable than corrupted one */
9465 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9466 && ABS (offset) / 2 > stream->duration)) {
9467 GST_WARNING_OBJECT (qtdemux,
9468 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9469 " larger than duration %" G_GUINT64_FORMAT, offset,
9472 stream->cslg_shift = 0;
9473 stream->ctts_present = FALSE;
9477 /* Don't consider "no decode samples" with offset G_MININT32
9478 * for the DTS/PTS shift */
9479 if (offset != G_MININT32 && offset < cslg_least)
9480 cslg_least = offset;
9484 stream->cslg_shift = -cslg_least;
9486 stream->cslg_shift = 0;
9488 /* reset the reader so we can generate sample table */
9489 gst_byte_reader_set_pos (&stream->ctts, pos);
9492 /* Check if ctts values are looking reasonable if that didn't happen above */
9493 if (!checked_ctts) {
9494 guint num_entries, pos;
9497 pos = gst_byte_reader_get_pos (&stream->ctts);
9498 num_entries = stream->n_composition_times;
9500 for (i = 0; i < num_entries; i++) {
9503 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9504 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9505 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9506 * slightly inaccurate PTS could be more usable than corrupted one */
9507 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9508 && ABS (offset) / 2 > stream->duration)) {
9509 GST_WARNING_OBJECT (qtdemux,
9510 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9511 " larger than duration %" G_GUINT64_FORMAT, offset,
9514 stream->cslg_shift = 0;
9515 stream->ctts_present = FALSE;
9520 /* reset the reader so we can generate sample table */
9521 gst_byte_reader_set_pos (&stream->ctts, pos);
9524 /* Ensure the cslg_shift value is consistent so we can use it
9525 * unconditionally to produce TS and Segment */
9526 stream->cslg_shift = 0;
9529 /* For raw audio streams especially we might want to merge the samples
9530 * to not output one audio sample per buffer. We're doing this here
9531 * before allocating the sample tables so that from this point onwards
9532 * the number of container samples are static */
9533 if (stream->min_buffer_size > 0) {
9534 qtdemux_merge_sample_table (qtdemux, stream);
9538 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9539 stream->n_samples, (guint) sizeof (QtDemuxSample),
9540 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9542 if (stream->n_samples >=
9543 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9544 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9545 "be larger than %uMB (broken file?)", stream->n_samples,
9546 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9550 g_assert (stream->samples == NULL);
9551 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9552 if (!stream->samples) {
9553 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9562 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9563 (_("This file is corrupt and cannot be played.")), (NULL));
9568 gst_qtdemux_stbl_free (stream);
9569 if (!qtdemux->fragmented) {
9570 /* not quite good */
9571 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9574 /* may pick up samples elsewhere */
9580 /* collect samples from the next sample to be parsed up to sample @n for @stream
9581 * by reading the info from @stbl
9583 * This code can be executed from both the streaming thread and the seeking
9584 * thread so it takes the object lock to protect itself
9587 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9590 QtDemuxSample *samples, *first, *cur, *last;
9591 guint32 n_samples_per_chunk;
9594 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9595 GST_FOURCC_FORMAT ", pad %s",
9596 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9597 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9599 n_samples = stream->n_samples;
9602 goto out_of_samples;
9604 GST_OBJECT_LOCK (qtdemux);
9605 if (n <= stream->stbl_index)
9606 goto already_parsed;
9608 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9610 if (!stream->stsz.data) {
9611 /* so we already parsed and passed all the moov samples;
9612 * onto fragmented ones */
9613 g_assert (qtdemux->fragmented);
9617 /* pointer to the sample table */
9618 samples = stream->samples;
9620 /* starts from -1, moves to the next sample index to parse */
9621 stream->stbl_index++;
9623 /* keep track of the first and last sample to fill */
9624 first = &samples[stream->stbl_index];
9627 if (!stream->chunks_are_samples) {
9628 /* set the sample sizes */
9629 if (stream->sample_size == 0) {
9630 /* different sizes for each sample */
9631 for (cur = first; cur <= last; cur++) {
9632 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9633 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9634 (guint) (cur - samples), cur->size);
9637 /* samples have the same size */
9638 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9639 for (cur = first; cur <= last; cur++)
9640 cur->size = stream->sample_size;
9644 n_samples_per_chunk = stream->n_samples_per_chunk;
9647 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9650 if (stream->stsc_chunk_index >= stream->last_chunk
9651 || stream->stsc_chunk_index < stream->first_chunk) {
9652 stream->first_chunk =
9653 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9654 stream->samples_per_chunk =
9655 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9657 stream->stsd_sample_description_id =
9658 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9660 /* chunk numbers are counted from 1 it seems */
9661 if (G_UNLIKELY (stream->first_chunk == 0))
9664 --stream->first_chunk;
9666 /* the last chunk of each entry is calculated by taking the first chunk
9667 * of the next entry; except if there is no next, where we fake it with
9669 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9670 stream->last_chunk = G_MAXUINT32;
9672 stream->last_chunk =
9673 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9674 if (G_UNLIKELY (stream->last_chunk == 0))
9677 --stream->last_chunk;
9680 GST_LOG_OBJECT (qtdemux,
9681 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9682 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9683 stream->samples_per_chunk, stream->stsd_sample_description_id);
9685 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9688 if (stream->last_chunk != G_MAXUINT32) {
9689 if (!qt_atom_parser_peek_sub (&stream->stco,
9690 stream->first_chunk * stream->co_size,
9691 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9696 stream->co_chunk = stream->stco;
9697 if (!gst_byte_reader_skip (&stream->co_chunk,
9698 stream->first_chunk * stream->co_size))
9702 stream->stsc_chunk_index = stream->first_chunk;
9705 last_chunk = stream->last_chunk;
9707 if (stream->chunks_are_samples) {
9708 cur = &samples[stream->stsc_chunk_index];
9710 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9713 stream->stsc_chunk_index = j;
9718 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9721 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9722 "%" G_GUINT64_FORMAT, j, cur->offset);
9724 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9725 CUR_STREAM (stream)->bytes_per_frame > 0) {
9727 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9728 CUR_STREAM (stream)->samples_per_frame *
9729 CUR_STREAM (stream)->bytes_per_frame;
9731 cur->size = stream->samples_per_chunk;
9734 GST_DEBUG_OBJECT (qtdemux,
9735 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9736 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9737 stream->stco_sample_index)), cur->size);
9739 cur->timestamp = stream->stco_sample_index;
9740 cur->duration = stream->samples_per_chunk;
9741 cur->keyframe = TRUE;
9744 stream->stco_sample_index += stream->samples_per_chunk;
9746 stream->stsc_chunk_index = j;
9748 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9749 guint32 samples_per_chunk;
9750 guint64 chunk_offset;
9752 if (!stream->stsc_sample_index
9753 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9754 &stream->chunk_offset))
9757 samples_per_chunk = stream->samples_per_chunk;
9758 chunk_offset = stream->chunk_offset;
9760 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9761 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9762 G_GUINT64_FORMAT " and size %d",
9763 (guint) (cur - samples), chunk_offset, cur->size);
9765 cur->offset = chunk_offset;
9766 chunk_offset += cur->size;
9769 if (G_UNLIKELY (cur > last)) {
9771 stream->stsc_sample_index = k + 1;
9772 stream->chunk_offset = chunk_offset;
9773 stream->stsc_chunk_index = j;
9777 stream->stsc_sample_index = 0;
9779 stream->stsc_chunk_index = j;
9781 stream->stsc_index++;
9784 if (stream->chunks_are_samples)
9788 guint32 n_sample_times;
9790 n_sample_times = stream->n_sample_times;
9793 for (i = stream->stts_index; i < n_sample_times; i++) {
9794 guint32 stts_samples;
9795 gint32 stts_duration;
9798 if (stream->stts_sample_index >= stream->stts_samples
9799 || !stream->stts_sample_index) {
9801 stream->stts_samples =
9802 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9803 stream->stts_duration =
9804 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9806 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9807 i, stream->stts_samples, stream->stts_duration);
9809 stream->stts_sample_index = 0;
9812 stts_samples = stream->stts_samples;
9813 stts_duration = stream->stts_duration;
9814 stts_time = stream->stts_time;
9816 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9817 GST_DEBUG_OBJECT (qtdemux,
9818 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9819 (guint) (cur - samples), j,
9820 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9822 cur->timestamp = stts_time;
9823 cur->duration = stts_duration;
9825 /* avoid 32-bit wrap-around,
9826 * but still mind possible 'negative' duration */
9827 stts_time += (gint64) stts_duration;
9830 if (G_UNLIKELY (cur > last)) {
9832 stream->stts_time = stts_time;
9833 stream->stts_sample_index = j + 1;
9834 if (stream->stts_sample_index >= stream->stts_samples)
9835 stream->stts_index++;
9839 stream->stts_sample_index = 0;
9840 stream->stts_time = stts_time;
9841 stream->stts_index++;
9843 /* fill up empty timestamps with the last timestamp, this can happen when
9844 * the last samples do not decode and so we don't have timestamps for them.
9845 * We however look at the last timestamp to estimate the track length so we
9846 * need something in here. */
9847 for (; cur < last; cur++) {
9848 GST_DEBUG_OBJECT (qtdemux,
9849 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9850 (guint) (cur - samples),
9851 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9852 cur->timestamp = stream->stts_time;
9858 /* sample sync, can be NULL */
9859 if (stream->stss_present == TRUE) {
9860 guint32 n_sample_syncs;
9862 n_sample_syncs = stream->n_sample_syncs;
9864 if (!n_sample_syncs) {
9865 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9866 stream->all_keyframe = TRUE;
9868 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9869 /* note that the first sample is index 1, not 0 */
9872 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9874 if (G_LIKELY (index > 0 && index <= n_samples)) {
9876 samples[index].keyframe = TRUE;
9877 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9878 /* and exit if we have enough samples */
9879 if (G_UNLIKELY (index >= n)) {
9886 stream->stss_index = i;
9889 /* stps marks partial sync frames like open GOP I-Frames */
9890 if (stream->stps_present == TRUE) {
9891 guint32 n_sample_partial_syncs;
9893 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9895 /* if there are no entries, the stss table contains the real
9897 if (n_sample_partial_syncs) {
9898 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9899 /* note that the first sample is index 1, not 0 */
9902 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9904 if (G_LIKELY (index > 0 && index <= n_samples)) {
9906 samples[index].keyframe = TRUE;
9907 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9908 /* and exit if we have enough samples */
9909 if (G_UNLIKELY (index >= n)) {
9916 stream->stps_index = i;
9920 /* no stss, all samples are keyframes */
9921 stream->all_keyframe = TRUE;
9922 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9927 /* composition time to sample */
9928 if (stream->ctts_present == TRUE) {
9929 guint32 n_composition_times;
9931 gint32 ctts_soffset;
9933 /* Fill in the pts_offsets */
9935 n_composition_times = stream->n_composition_times;
9937 for (i = stream->ctts_index; i < n_composition_times; i++) {
9938 if (stream->ctts_sample_index >= stream->ctts_count
9939 || !stream->ctts_sample_index) {
9940 stream->ctts_count =
9941 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9942 stream->ctts_soffset =
9943 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9944 stream->ctts_sample_index = 0;
9947 ctts_count = stream->ctts_count;
9948 ctts_soffset = stream->ctts_soffset;
9950 /* FIXME: Set offset to 0 for "no decode samples". This needs
9951 * to be handled in a codec specific manner ideally. */
9952 if (ctts_soffset == G_MININT32)
9955 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9956 cur->pts_offset = ctts_soffset;
9959 if (G_UNLIKELY (cur > last)) {
9961 stream->ctts_sample_index = j + 1;
9965 stream->ctts_sample_index = 0;
9966 stream->ctts_index++;
9970 stream->stbl_index = n;
9971 /* if index has been completely parsed, free data that is no-longer needed */
9972 if (n + 1 == stream->n_samples) {
9973 gst_qtdemux_stbl_free (stream);
9974 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9975 if (qtdemux->pullbased) {
9976 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9977 while (n + 1 == stream->n_samples)
9978 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9982 GST_OBJECT_UNLOCK (qtdemux);
9989 GST_LOG_OBJECT (qtdemux,
9990 "Tried to parse up to sample %u but this sample has already been parsed",
9992 /* if fragmented, there may be more */
9993 if (qtdemux->fragmented && n == stream->stbl_index)
9995 GST_OBJECT_UNLOCK (qtdemux);
10001 GST_LOG_OBJECT (qtdemux,
10002 "Tried to parse up to sample %u but there are only %u samples", n + 1,
10003 stream->n_samples);
10004 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10005 (_("This file is corrupt and cannot be played.")), (NULL));
10010 GST_OBJECT_UNLOCK (qtdemux);
10011 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10012 (_("This file is corrupt and cannot be played.")), (NULL));
10017 /* collect all segment info for @stream.
10020 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10024 /* accept edts if they contain gaps at start and there is only
10025 * one media segment */
10026 gboolean allow_pushbased_edts = TRUE;
10027 gint media_segments_count = 0;
10029 /* parse and prepare segment info from the edit list */
10030 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10031 stream->n_segments = 0;
10032 stream->segments = NULL;
10033 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10036 gint segment_number, entry_size;
10038 GstClockTime stime;
10039 const guint8 *buffer;
10043 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10044 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10047 buffer = elst->data;
10049 size = QT_UINT32 (buffer);
10050 /* version, flags, n_segments */
10052 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10055 version = QT_UINT8 (buffer + 8);
10056 entry_size = (version == 1) ? 20 : 12;
10058 n_segments = QT_UINT32 (buffer + 12);
10060 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10061 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10065 /* we might allocate a bit too much, at least allocate 1 segment */
10066 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10068 /* segments always start from 0 */
10072 for (segment_number = 0; segment_number < n_segments; segment_number++) {
10074 guint64 media_time;
10075 gboolean empty_edit = FALSE;
10076 QtDemuxSegment *segment;
10078 GstClockTime media_start = GST_CLOCK_TIME_NONE;
10080 if (version == 1) {
10081 media_time = QT_UINT64 (buffer + 8);
10082 duration = QT_UINT64 (buffer);
10083 if (media_time == G_MAXUINT64)
10086 media_time = QT_UINT32 (buffer + 4);
10087 duration = QT_UINT32 (buffer);
10088 if (media_time == G_MAXUINT32)
10093 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10095 segment = &stream->segments[segment_number];
10097 /* time and duration expressed in global timescale */
10098 segment->time = stime;
10099 if (duration != 0 || empty_edit) {
10100 /* edge case: empty edits with duration=zero are treated here.
10101 * (files should not have these anyway). */
10103 /* add non scaled values so we don't cause roundoff errors */
10105 stime = QTTIME_TO_GSTTIME (qtdemux, time);
10106 segment->duration = stime - segment->time;
10108 /* zero duration does not imply media_start == media_stop
10109 * but, only specify media_start. The edit ends with the track. */
10110 stime = segment->duration = GST_CLOCK_TIME_NONE;
10111 /* Don't allow more edits after this one. */
10112 n_segments = segment_number + 1;
10114 segment->stop_time = stime;
10116 segment->trak_media_start = media_time;
10117 /* media_time expressed in stream timescale */
10119 segment->media_start = media_start;
10120 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10121 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10122 media_segments_count++;
10124 segment->media_start = GST_CLOCK_TIME_NONE;
10125 segment->media_stop = GST_CLOCK_TIME_NONE;
10127 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10129 if (rate_int <= 1) {
10130 /* 0 is not allowed, some programs write 1 instead of the floating point
10132 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10136 segment->rate = rate_int / 65536.0;
10139 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10140 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10141 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10142 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10143 segment_number, GST_TIME_ARGS (segment->time),
10144 GST_TIME_ARGS (segment->duration),
10145 GST_TIME_ARGS (segment->media_start), media_time,
10146 GST_TIME_ARGS (segment->media_stop),
10147 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10148 stream->timescale);
10149 if (segment->stop_time > qtdemux->segment.stop &&
10150 !qtdemux->upstream_format_is_time) {
10151 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10152 " extends to %" GST_TIME_FORMAT
10153 " past the end of the declared movie duration %" GST_TIME_FORMAT
10154 " movie segment will be extended", segment_number,
10155 GST_TIME_ARGS (segment->stop_time),
10156 GST_TIME_ARGS (qtdemux->segment.stop));
10157 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10160 buffer += entry_size;
10162 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10163 stream->n_segments = n_segments;
10164 if (media_segments_count != 1)
10165 allow_pushbased_edts = FALSE;
10169 /* push based does not handle segments, so act accordingly here,
10170 * and warn if applicable */
10171 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10172 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10173 /* remove and use default one below, we stream like it anyway */
10174 g_free (stream->segments);
10175 stream->segments = NULL;
10176 stream->n_segments = 0;
10179 /* no segments, create one to play the complete trak */
10180 if (stream->n_segments == 0) {
10181 GstClockTime stream_duration =
10182 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10184 if (stream->segments == NULL)
10185 stream->segments = g_new (QtDemuxSegment, 1);
10187 /* represent unknown our way */
10188 if (stream_duration == 0)
10189 stream_duration = GST_CLOCK_TIME_NONE;
10191 stream->segments[0].time = 0;
10192 stream->segments[0].stop_time = stream_duration;
10193 stream->segments[0].duration = stream_duration;
10194 stream->segments[0].media_start = 0;
10195 stream->segments[0].media_stop = stream_duration;
10196 stream->segments[0].rate = 1.0;
10197 stream->segments[0].trak_media_start = 0;
10199 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10200 GST_TIME_ARGS (stream_duration));
10201 stream->n_segments = 1;
10202 stream->dummy_segment = TRUE;
10204 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10210 * Parses the stsd atom of a svq3 trak looking for
10211 * the SMI and gama atoms.
10214 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10215 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10217 const guint8 *_gamma = NULL;
10218 GstBuffer *_seqh = NULL;
10219 const guint8 *stsd_data = stsd_entry_data;
10220 guint32 length = QT_UINT32 (stsd_data);
10224 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10230 version = QT_UINT16 (stsd_data);
10231 if (version == 3) {
10232 if (length >= 70) {
10235 while (length > 8) {
10236 guint32 fourcc, size;
10237 const guint8 *data;
10238 size = QT_UINT32 (stsd_data);
10239 fourcc = QT_FOURCC (stsd_data + 4);
10240 data = stsd_data + 8;
10243 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10244 "svq3 atom parsing");
10253 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10254 " for gama atom, expected 12", size);
10259 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10261 if (_seqh != NULL) {
10262 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10263 " found, ignoring");
10265 seqh_size = QT_UINT32 (data + 4);
10266 if (seqh_size > 0) {
10267 _seqh = gst_buffer_new_and_alloc (seqh_size);
10268 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10275 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10276 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10280 if (size <= length) {
10286 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10289 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10290 G_GUINT16_FORMAT, version);
10300 } else if (_seqh) {
10301 gst_buffer_unref (_seqh);
10306 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10309 GstByteReader dref;
10313 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10314 * atom that might contain a 'data' atom with the rtsp uri.
10315 * This case was reported in bug #597497, some info about
10316 * the hndl atom can be found in TN1195
10318 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10319 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10322 guint32 dref_num_entries = 0;
10323 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10324 gst_byte_reader_skip (&dref, 4) &&
10325 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10328 /* search dref entries for hndl atom */
10329 for (i = 0; i < dref_num_entries; i++) {
10330 guint32 size = 0, type;
10331 guint8 string_len = 0;
10332 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10333 qt_atom_parser_get_fourcc (&dref, &type)) {
10334 if (type == FOURCC_hndl) {
10335 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10337 /* skip data reference handle bytes and the
10338 * following pascal string and some extra 4
10339 * bytes I have no idea what are */
10340 if (!gst_byte_reader_skip (&dref, 4) ||
10341 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10342 !gst_byte_reader_skip (&dref, string_len + 4)) {
10343 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10347 /* iterate over the atoms to find the data atom */
10348 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10352 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10353 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10354 if (atom_type == FOURCC_data) {
10355 const guint8 *uri_aux = NULL;
10357 /* found the data atom that might contain the rtsp uri */
10358 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10359 "hndl atom, interpreting it as an URI");
10360 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10362 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10363 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10365 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10366 "didn't contain a rtsp address");
10368 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10373 /* skipping to the next entry */
10374 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10377 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10384 /* skip to the next entry */
10385 if (!gst_byte_reader_skip (&dref, size - 8))
10388 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10391 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10397 #define AMR_NB_ALL_MODES 0x81ff
10398 #define AMR_WB_ALL_MODES 0x83ff
10400 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10402 /* The 'damr' atom is of the form:
10404 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10405 * 32 b 8 b 16 b 8 b 8 b
10407 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10408 * represents the highest mode used in the stream (and thus the maximum
10409 * bitrate), with a couple of special cases as seen below.
10412 /* Map of frame type ID -> bitrate */
10413 static const guint nb_bitrates[] = {
10414 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10416 static const guint wb_bitrates[] = {
10417 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10423 gst_buffer_map (buf, &map, GST_MAP_READ);
10425 if (map.size != 0x11) {
10426 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10430 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10431 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10432 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10436 mode_set = QT_UINT16 (map.data + 13);
10438 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10439 max_mode = 7 + (wb ? 1 : 0);
10441 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10442 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10444 if (max_mode == -1) {
10445 GST_DEBUG ("No mode indication was found (mode set) = %x",
10450 gst_buffer_unmap (buf, &map);
10451 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10454 gst_buffer_unmap (buf, &map);
10459 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10460 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10463 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10469 if (gst_byte_reader_get_remaining (reader) < 36)
10472 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10473 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10474 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10475 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10476 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10477 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10478 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10479 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10480 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10482 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10483 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10484 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10486 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10487 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10489 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10490 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10497 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10498 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10505 * This macro will only compare value abdegh, it expects cfi to have already
10508 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10509 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10511 /* only handle the cases where the last column has standard values */
10512 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10513 const gchar *rotation_tag = NULL;
10515 /* no rotation needed */
10516 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10518 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10519 rotation_tag = "rotate-90";
10520 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10521 rotation_tag = "rotate-180";
10522 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10523 rotation_tag = "rotate-270";
10525 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10528 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10529 GST_STR_NULL (rotation_tag));
10530 if (rotation_tag != NULL) {
10531 if (*taglist == NULL)
10532 *taglist = gst_tag_list_new_empty ();
10533 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10534 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10537 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10542 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10543 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10547 GstBuffer *adrm_buf = NULL;
10548 QtDemuxAavdEncryptionInfo *info;
10550 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10551 if (G_UNLIKELY (!adrm)) {
10552 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10555 adrm_size = QT_UINT32 (adrm->data);
10556 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10558 stream->protection_scheme_type = FOURCC_aavd;
10560 if (!stream->protection_scheme_info)
10561 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10563 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10565 if (info->default_properties)
10566 gst_structure_free (info->default_properties);
10567 info->default_properties = gst_structure_new ("application/x-aavd",
10568 "encrypted", G_TYPE_BOOLEAN, TRUE,
10569 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10570 gst_buffer_unref (adrm_buf);
10572 *original_fmt = FOURCC_mp4a;
10576 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10577 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10578 * Common Encryption (cenc), the function will also parse the tenc box (defined
10579 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10580 * (typically an enc[v|a|t|s] sample entry); the function will set
10581 * @original_fmt to the fourcc of the original unencrypted stream format.
10582 * Returns TRUE if successful; FALSE otherwise. */
10584 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10585 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10591 QtDemuxCencSampleSetInfo *info;
10593 const guint8 *tenc_data;
10595 g_return_val_if_fail (qtdemux != NULL, FALSE);
10596 g_return_val_if_fail (stream != NULL, FALSE);
10597 g_return_val_if_fail (container != NULL, FALSE);
10598 g_return_val_if_fail (original_fmt != NULL, FALSE);
10600 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10601 if (G_UNLIKELY (!sinf)) {
10602 if (stream->protection_scheme_type == FOURCC_cenc
10603 || stream->protection_scheme_type == FOURCC_cbcs) {
10604 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10605 "mandatory for Common Encryption");
10611 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10612 if (G_UNLIKELY (!frma)) {
10613 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10617 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10618 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10619 GST_FOURCC_ARGS (*original_fmt));
10621 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10623 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10626 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10627 stream->protection_scheme_version =
10628 QT_UINT32 ((const guint8 *) schm->data + 16);
10630 GST_DEBUG_OBJECT (qtdemux,
10631 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10632 "protection_scheme_version: %#010x",
10633 GST_FOURCC_ARGS (stream->protection_scheme_type),
10634 stream->protection_scheme_version);
10636 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10638 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10641 if (stream->protection_scheme_type != FOURCC_cenc &&
10642 stream->protection_scheme_type != FOURCC_piff &&
10643 stream->protection_scheme_type != FOURCC_cbcs) {
10644 GST_ERROR_OBJECT (qtdemux,
10645 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10646 GST_FOURCC_ARGS (stream->protection_scheme_type));
10650 if (G_UNLIKELY (!stream->protection_scheme_info))
10651 stream->protection_scheme_info =
10652 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10654 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10656 if (stream->protection_scheme_type == FOURCC_cenc
10657 || stream->protection_scheme_type == FOURCC_cbcs) {
10658 guint8 is_encrypted;
10660 guint8 constant_iv_size = 0;
10661 const guint8 *default_kid;
10662 guint8 crypt_byte_block = 0;
10663 guint8 skip_byte_block = 0;
10664 const guint8 *constant_iv = NULL;
10666 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10668 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10669 "which is mandatory for Common Encryption");
10672 tenc_data = (const guint8 *) tenc->data + 12;
10673 is_encrypted = QT_UINT8 (tenc_data + 2);
10674 iv_size = QT_UINT8 (tenc_data + 3);
10675 default_kid = (tenc_data + 4);
10676 if (stream->protection_scheme_type == FOURCC_cbcs) {
10677 guint8 possible_pattern_info;
10678 if (iv_size == 0) {
10679 constant_iv_size = QT_UINT8 (tenc_data + 20);
10680 if (constant_iv_size != 8 && constant_iv_size != 16) {
10681 GST_ERROR_OBJECT (qtdemux,
10682 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10685 constant_iv = (tenc_data + 21);
10687 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10688 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10689 skip_byte_block = possible_pattern_info & 0x0f;
10691 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10692 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10693 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10694 } else if (stream->protection_scheme_type == FOURCC_piff) {
10696 static const guint8 piff_track_encryption_uuid[] = {
10697 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10698 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10701 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10703 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10704 "which is mandatory for Common Encryption");
10708 tenc_data = (const guint8 *) tenc->data + 8;
10709 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10710 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10711 GST_ERROR_OBJECT (qtdemux,
10712 "Unsupported track encryption box with uuid: %s", box_uuid);
10716 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10717 gst_byte_reader_init (&br, tenc_data, 20);
10718 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10719 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10722 stream->protection_scheme_type = FOURCC_cenc;
10729 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10730 QtDemuxStream ** stream2)
10732 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10736 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10741 /*parse svmi header if existing */
10742 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10744 guint len = QT_UINT32 ((guint8 *) svmi->data);
10745 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10747 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10748 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10749 guint8 frame_type, frame_layout;
10750 guint32 stereo_mono_change_count;
10755 /* MPEG-A stereo video */
10756 if (qtdemux->major_brand == FOURCC_ss02)
10757 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10759 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10760 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10761 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10763 switch (frame_type) {
10765 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10768 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10771 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10774 /* mode 3 is primary/secondary view sequence, ie
10775 * left/right views in separate tracks. See section 7.2
10776 * of ISO/IEC 23000-11:2009 */
10777 /* In the future this might be supported using related
10778 * streams, like an enhancement track - if files like this
10780 GST_FIXME_OBJECT (qtdemux,
10781 "Implement stereo video in separate streams");
10784 if ((frame_layout & 0x1) == 0)
10785 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10787 GST_LOG_OBJECT (qtdemux,
10788 "StereoVideo: composition type: %u, is_left_first: %u",
10789 frame_type, frame_layout);
10791 if (stereo_mono_change_count > 1) {
10792 GST_FIXME_OBJECT (qtdemux,
10793 "Mixed-mono flags are not yet supported in qtdemux.");
10796 stream->multiview_mode = mode;
10797 stream->multiview_flags = flags;
10804 /* parse the traks.
10805 * With each track we associate a new QtDemuxStream that contains all the info
10807 * traks that do not decode to something (like strm traks) will not have a pad.
10810 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10812 GstByteReader tkhd;
10826 QtDemuxStream *stream = NULL;
10827 const guint8 *stsd_data;
10828 const guint8 *stsd_entry_data;
10829 guint remaining_stsd_len;
10830 guint stsd_entry_count;
10832 guint16 lang_code; /* quicktime lang code or packed iso code */
10834 guint32 tkhd_flags = 0;
10835 guint8 tkhd_version = 0;
10836 guint32 w = 0, h = 0;
10837 guint value_size, stsd_len, len;
10841 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10843 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10844 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10845 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10848 /* pick between 64 or 32 bits */
10849 value_size = tkhd_version == 1 ? 8 : 4;
10850 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10851 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10854 /* Check if current moov has duplicated track_id */
10855 if (qtdemux_find_stream (qtdemux, track_id))
10856 goto existing_stream;
10858 stream = _create_stream (qtdemux, track_id);
10859 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10861 /* need defaults for fragments */
10862 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10864 if ((tkhd_flags & 1) == 0)
10865 stream->disabled = TRUE;
10867 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10868 tkhd_version, tkhd_flags, stream->track_id);
10870 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10873 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10874 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10875 if (qtdemux->major_brand != FOURCC_mjp2 ||
10876 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10880 len = QT_UINT32 ((guint8 *) mdhd->data);
10881 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10882 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10883 if (version == 0x01000000) {
10886 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10887 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10888 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
10892 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10893 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10894 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10897 if (lang_code < 0x400) {
10898 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10899 } else if (lang_code == 0x7fff) {
10900 stream->lang_id[0] = 0; /* unspecified */
10902 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10903 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10904 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10905 stream->lang_id[3] = 0;
10908 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10909 stream->timescale);
10910 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10912 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10913 lang_code, stream->lang_id);
10915 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10918 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10919 /* chapters track reference */
10920 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10922 gsize length = GST_READ_UINT32_BE (chap->data);
10923 if (qtdemux->chapters_track_id)
10924 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10926 if (length >= 12) {
10927 qtdemux->chapters_track_id =
10928 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10933 /* fragmented files may have bogus duration in moov */
10934 if (!qtdemux->fragmented &&
10935 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10936 guint64 tdur1, tdur2;
10938 /* don't overflow */
10939 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10940 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10943 * some of those trailers, nowadays, have prologue images that are
10944 * themselves video tracks as well. I haven't really found a way to
10945 * identify those yet, except for just looking at their duration. */
10946 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10947 GST_WARNING_OBJECT (qtdemux,
10948 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10949 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10950 "found, assuming preview image or something; skipping track",
10951 stream->duration, stream->timescale, qtdemux->duration,
10952 qtdemux->timescale);
10953 gst_qtdemux_stream_unref (stream);
10958 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10961 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10962 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10964 len = QT_UINT32 ((guint8 *) hdlr->data);
10966 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10967 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10968 GST_FOURCC_ARGS (stream->subtype));
10970 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10973 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10976 /* Parse out svmi (and later st3d/sv3d) atoms */
10977 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
10980 /* parse rest of tkhd */
10981 if (stream->subtype == FOURCC_vide) {
10984 /* version 1 uses some 64-bit ints */
10985 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10988 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10991 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10992 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10995 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10996 &stream->stream_tags);
11000 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11002 stsd_data = (const guint8 *) stsd->data;
11004 /* stsd should at least have one entry */
11005 stsd_len = QT_UINT32 (stsd_data);
11006 if (stsd_len < 24) {
11007 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11008 if (stream->subtype == FOURCC_vivo) {
11009 gst_qtdemux_stream_unref (stream);
11016 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11017 /* each stsd entry must contain at least 8 bytes */
11018 if (stream->stsd_entries_length == 0
11019 || stream->stsd_entries_length > stsd_len / 8) {
11020 stream->stsd_entries_length = 0;
11023 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11024 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
11025 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
11027 stsd_entry_data = stsd_data + 16;
11028 remaining_stsd_len = stsd_len - 16;
11029 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11031 gchar *codec = NULL;
11032 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11034 /* and that entry should fit within stsd */
11035 len = QT_UINT32 (stsd_entry_data);
11036 if (len > remaining_stsd_len)
11039 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11040 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
11041 GST_FOURCC_ARGS (entry->fourcc));
11042 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
11044 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11045 goto error_encrypted;
11047 if (fourcc == FOURCC_aavd) {
11048 if (stream->subtype != FOURCC_soun) {
11049 GST_ERROR_OBJECT (qtdemux,
11050 "Unexpeced stsd type 'aavd' outside 'soun' track");
11052 /* encrypted audio with sound sample description v0 */
11053 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11054 stream->protected = TRUE;
11055 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11056 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11060 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11061 /* FIXME this looks wrong, there might be multiple children
11062 * with the same type */
11063 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11064 stream->protected = TRUE;
11065 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11066 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11069 if (stream->subtype == FOURCC_vide) {
11074 gint depth, palette_size, palette_count;
11075 guint32 *palette_data = NULL;
11077 entry->sampled = TRUE;
11079 stream->display_width = w >> 16;
11080 stream->display_height = h >> 16;
11083 if (len < 86) /* TODO verify */
11086 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11087 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11088 entry->fps_n = 0; /* this is filled in later */
11089 entry->fps_d = 0; /* this is filled in later */
11090 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11091 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11093 /* if color_table_id is 0, ctab atom must follow; however some files
11094 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11095 * if color table is not present we'll correct the value */
11096 if (entry->color_table_id == 0 &&
11098 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11099 entry->color_table_id = -1;
11102 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11103 entry->width, entry->height, entry->bits_per_sample,
11104 entry->color_table_id);
11106 depth = entry->bits_per_sample;
11108 /* more than 32 bits means grayscale */
11109 gray = (depth > 32);
11110 /* low 32 bits specify the depth */
11113 /* different number of palette entries is determined by depth. */
11115 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11116 palette_count = (1 << depth);
11117 palette_size = palette_count * 4;
11119 if (entry->color_table_id) {
11120 switch (palette_count) {
11124 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11127 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11132 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11134 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11139 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11142 g_memdup2 (ff_qt_default_palette_256, palette_size);
11145 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11146 (_("The video in this file might not play correctly.")),
11147 ("unsupported palette depth %d", depth));
11151 gint i, j, start, end;
11157 start = QT_UINT32 (stsd_entry_data + offset + 70);
11158 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11159 end = QT_UINT16 (stsd_entry_data + offset + 76);
11161 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11162 start, end, palette_count);
11169 if (len < 94 + (end - start) * 8)
11172 /* palette is always the same size */
11173 palette_data = g_malloc0 (256 * 4);
11174 palette_size = 256 * 4;
11176 for (j = 0, i = start; i <= end; j++, i++) {
11177 guint32 a, r, g, b;
11179 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11180 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11181 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11182 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11184 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11185 (g & 0xff00) | (b >> 8);
11190 gst_caps_unref (entry->caps);
11193 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11195 if (G_UNLIKELY (!entry->caps)) {
11196 g_free (palette_data);
11197 goto unknown_stream;
11201 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11202 GST_TAG_VIDEO_CODEC, codec, NULL);
11207 if (palette_data) {
11210 if (entry->rgb8_palette)
11211 gst_memory_unref (entry->rgb8_palette);
11212 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11213 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11215 s = gst_caps_get_structure (entry->caps, 0);
11217 /* non-raw video has a palette_data property. raw video has the palette as
11218 * an extra plane that we append to the output buffers before we push
11220 if (!gst_structure_has_name (s, "video/x-raw")) {
11221 GstBuffer *palette;
11223 palette = gst_buffer_new ();
11224 gst_buffer_append_memory (palette, entry->rgb8_palette);
11225 entry->rgb8_palette = NULL;
11227 gst_caps_set_simple (entry->caps, "palette_data",
11228 GST_TYPE_BUFFER, palette, NULL);
11229 gst_buffer_unref (palette);
11231 } else if (palette_count != 0) {
11232 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11233 (NULL), ("Unsupported palette depth %d", depth));
11236 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11237 QT_UINT16 (stsd_entry_data + offset + 32));
11243 /* pick 'the' stsd child */
11244 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11245 // We should skip parsing the stsd for non-protected streams if
11246 // the entry doesn't match the fourcc, since they don't change
11247 // format. However, for protected streams we can have partial
11248 // encryption, where parts of the stream are encrypted and parts
11249 // not. For both parts of such streams, we should ensure the
11250 // esds overrides are parsed for both from the stsd.
11251 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11252 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11254 else if (!stream->protected)
11259 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11260 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11261 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11262 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11266 const guint8 *pasp_data = (const guint8 *) pasp->data;
11267 gint len = QT_UINT32 (pasp_data);
11270 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11271 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11273 CUR_STREAM (stream)->par_w = 0;
11274 CUR_STREAM (stream)->par_h = 0;
11277 CUR_STREAM (stream)->par_w = 0;
11278 CUR_STREAM (stream)->par_h = 0;
11282 const guint8 *fiel_data = (const guint8 *) fiel->data;
11283 gint len = QT_UINT32 (fiel_data);
11286 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11287 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11292 const guint8 *colr_data = (const guint8 *) colr->data;
11293 gint len = QT_UINT32 (colr_data);
11295 if (len == 19 || len == 18) {
11296 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11298 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11299 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11300 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11301 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11302 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11304 CUR_STREAM (stream)->colorimetry.primaries =
11305 gst_video_color_primaries_from_iso (primaries);
11306 CUR_STREAM (stream)->colorimetry.transfer =
11307 gst_video_transfer_function_from_iso (transfer_function);
11308 CUR_STREAM (stream)->colorimetry.matrix =
11309 gst_video_color_matrix_from_iso (matrix);
11310 CUR_STREAM (stream)->colorimetry.range =
11311 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11312 GST_VIDEO_COLOR_RANGE_16_235;
11314 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11317 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11322 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11323 stream->stream_tags);
11330 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11331 const guint8 *avc_data = stsd_entry_data + 0x56;
11334 while (len >= 0x8) {
11337 if (QT_UINT32 (avc_data) <= len)
11338 size = QT_UINT32 (avc_data) - 0x8;
11343 /* No real data, so break out */
11346 switch (QT_FOURCC (avc_data + 0x4)) {
11349 /* parse, if found */
11352 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11354 /* First 4 bytes are the length of the atom, the next 4 bytes
11355 * are the fourcc, the next 1 byte is the version, and the
11356 * subsequent bytes are profile_tier_level structure like data. */
11357 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11358 avc_data + 8 + 1, size - 1);
11359 buf = gst_buffer_new_and_alloc (size);
11360 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11361 gst_caps_set_simple (entry->caps,
11362 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11363 gst_buffer_unref (buf);
11371 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11373 /* First 4 bytes are the length of the atom, the next 4 bytes
11374 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11375 * next 1 byte is the version, and the
11376 * subsequent bytes are sequence parameter set like data. */
11378 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11380 gst_codec_utils_h264_caps_set_level_and_profile
11381 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11383 buf = gst_buffer_new_and_alloc (size);
11384 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11385 gst_caps_set_simple (entry->caps,
11386 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11387 gst_buffer_unref (buf);
11393 guint avg_bitrate, max_bitrate;
11395 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11399 max_bitrate = QT_UINT32 (avc_data + 0xc);
11400 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11402 if (!max_bitrate && !avg_bitrate)
11405 /* Some muxers seem to swap the average and maximum bitrates
11406 * (I'm looking at you, YouTube), so we swap for sanity. */
11407 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11408 guint temp = avg_bitrate;
11410 avg_bitrate = max_bitrate;
11411 max_bitrate = temp;
11414 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11415 gst_tag_list_add (stream->stream_tags,
11416 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11417 max_bitrate, NULL);
11419 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11420 gst_tag_list_add (stream->stream_tags,
11421 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11433 avc_data += size + 8;
11444 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11445 const guint8 *hevc_data = stsd_entry_data + 0x56;
11448 while (len >= 0x8) {
11451 if (QT_UINT32 (hevc_data) <= len)
11452 size = QT_UINT32 (hevc_data) - 0x8;
11457 /* No real data, so break out */
11460 switch (QT_FOURCC (hevc_data + 0x4)) {
11463 /* parse, if found */
11466 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11468 /* First 4 bytes are the length of the atom, the next 4 bytes
11469 * are the fourcc, the next 1 byte is the version, and the
11470 * subsequent bytes are sequence parameter set like data. */
11471 gst_codec_utils_h265_caps_set_level_tier_and_profile
11472 (entry->caps, hevc_data + 8 + 1, size - 1);
11474 buf = gst_buffer_new_and_alloc (size);
11475 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11476 gst_caps_set_simple (entry->caps,
11477 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11478 gst_buffer_unref (buf);
11485 hevc_data += size + 8;
11498 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11499 GST_FOURCC_ARGS (fourcc));
11501 /* codec data might be in glbl extension atom */
11503 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11509 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11511 len = QT_UINT32 (data);
11514 buf = gst_buffer_new_and_alloc (len);
11515 gst_buffer_fill (buf, 0, data + 8, len);
11516 gst_caps_set_simple (entry->caps,
11517 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11518 gst_buffer_unref (buf);
11525 /* see annex I of the jpeg2000 spec */
11526 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11527 const guint8 *data;
11528 const gchar *colorspace = NULL;
11530 guint32 ncomp_map = 0;
11531 gint32 *comp_map = NULL;
11532 guint32 nchan_def = 0;
11533 gint32 *chan_def = NULL;
11535 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11536 /* some required atoms */
11537 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11540 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11544 /* number of components; redundant with info in codestream, but useful
11546 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11547 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11549 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11551 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11554 GST_DEBUG_OBJECT (qtdemux, "found colr");
11555 /* extract colour space info */
11556 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11557 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11559 colorspace = "sRGB";
11562 colorspace = "GRAY";
11565 colorspace = "sYUV";
11573 /* colr is required, and only values 16, 17, and 18 are specified,
11574 so error if we have no colorspace */
11577 /* extract component mapping */
11578 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11580 guint32 cmap_len = 0;
11582 cmap_len = QT_UINT32 (cmap->data);
11583 if (cmap_len >= 8) {
11584 /* normal box, subtract off header */
11586 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11587 if (cmap_len % 4 == 0) {
11588 ncomp_map = (cmap_len / 4);
11589 comp_map = g_new0 (gint32, ncomp_map);
11590 for (i = 0; i < ncomp_map; i++) {
11593 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11594 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11595 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11596 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11601 /* extract channel definitions */
11602 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11604 guint32 cdef_len = 0;
11606 cdef_len = QT_UINT32 (cdef->data);
11607 if (cdef_len >= 10) {
11608 /* normal box, subtract off header and len */
11610 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11611 if (cdef_len % 6 == 0) {
11612 nchan_def = (cdef_len / 6);
11613 chan_def = g_new0 (gint32, nchan_def);
11614 for (i = 0; i < nchan_def; i++)
11616 for (i = 0; i < nchan_def; i++) {
11617 guint16 cn, typ, asoc;
11618 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11619 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11620 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11621 if (cn < nchan_def) {
11624 chan_def[cn] = asoc;
11627 chan_def[cn] = 0; /* alpha */
11630 chan_def[cn] = -typ;
11638 gst_caps_set_simple (entry->caps,
11639 "num-components", G_TYPE_INT, ncomp, NULL);
11640 gst_caps_set_simple (entry->caps,
11641 "colorspace", G_TYPE_STRING, colorspace, NULL);
11644 GValue arr = { 0, };
11645 GValue elt = { 0, };
11647 g_value_init (&arr, GST_TYPE_ARRAY);
11648 g_value_init (&elt, G_TYPE_INT);
11649 for (i = 0; i < ncomp_map; i++) {
11650 g_value_set_int (&elt, comp_map[i]);
11651 gst_value_array_append_value (&arr, &elt);
11653 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11654 "component-map", &arr);
11655 g_value_unset (&elt);
11656 g_value_unset (&arr);
11661 GValue arr = { 0, };
11662 GValue elt = { 0, };
11664 g_value_init (&arr, GST_TYPE_ARRAY);
11665 g_value_init (&elt, G_TYPE_INT);
11666 for (i = 0; i < nchan_def; i++) {
11667 g_value_set_int (&elt, chan_def[i]);
11668 gst_value_array_append_value (&arr, &elt);
11670 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11671 "channel-definitions", &arr);
11672 g_value_unset (&elt);
11673 g_value_unset (&arr);
11677 /* some optional atoms */
11678 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11679 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11681 /* indicate possible fields in caps */
11683 data = (guint8 *) field->data + 8;
11685 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11686 (gint) * data, NULL);
11688 /* add codec_data if provided */
11693 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11694 data = prefix->data;
11695 len = QT_UINT32 (data);
11698 buf = gst_buffer_new_and_alloc (len);
11699 gst_buffer_fill (buf, 0, data + 8, len);
11700 gst_caps_set_simple (entry->caps,
11701 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11702 gst_buffer_unref (buf);
11711 GstBuffer *seqh = NULL;
11712 const guint8 *gamma_data = NULL;
11713 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11715 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11718 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11719 QT_FP32 (gamma_data), NULL);
11722 /* sorry for the bad name, but we don't know what this is, other
11723 * than its own fourcc */
11724 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11726 gst_buffer_unref (seqh);
11729 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11730 buf = gst_buffer_new_and_alloc (len);
11731 gst_buffer_fill (buf, 0, stsd_data, len);
11732 gst_caps_set_simple (entry->caps,
11733 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11734 gst_buffer_unref (buf);
11739 /* https://developer.apple.com/standards/qtff-2001.pdf,
11740 * page 92, "Video Sample Description", under table 3.1 */
11743 const gint compressor_offset =
11744 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11745 const gint min_size = compressor_offset + 32 + 2 + 2;
11748 guint16 color_table_id = 0;
11751 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11753 /* recover information on interlaced/progressive */
11754 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11758 len = QT_UINT32 (jpeg->data);
11759 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11761 if (len >= min_size) {
11762 gst_byte_reader_init (&br, jpeg->data, len);
11764 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11765 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11766 if (color_table_id != 0) {
11767 /* the spec says there can be concatenated chunks in the data, and we want
11768 * to find one called field. Walk through them. */
11769 gint offset = min_size;
11770 while (offset + 8 < len) {
11771 guint32 size = 0, tag;
11772 ok = gst_byte_reader_get_uint32_le (&br, &size);
11773 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11774 if (!ok || size < 8) {
11775 GST_WARNING_OBJECT (qtdemux,
11776 "Failed to walk optional chunk list");
11779 GST_DEBUG_OBJECT (qtdemux,
11780 "Found optional %4.4s chunk, size %u",
11781 (const char *) &tag, size);
11782 if (tag == FOURCC_fiel) {
11783 guint8 n_fields = 0, ordering = 0;
11784 gst_byte_reader_get_uint8 (&br, &n_fields);
11785 gst_byte_reader_get_uint8 (&br, &ordering);
11786 if (n_fields == 1 || n_fields == 2) {
11787 GST_DEBUG_OBJECT (qtdemux,
11788 "Found fiel tag with %u fields, ordering %u",
11789 n_fields, ordering);
11791 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11792 "interlace-mode", G_TYPE_STRING, "interleaved",
11795 GST_WARNING_OBJECT (qtdemux,
11796 "Found fiel tag with invalid fields (%u)", n_fields);
11802 GST_DEBUG_OBJECT (qtdemux,
11803 "Color table ID is 0, not trying to get interlacedness");
11806 GST_WARNING_OBJECT (qtdemux,
11807 "Length of jpeg chunk is too small, not trying to get interlacedness");
11815 gst_caps_set_simple (entry->caps,
11816 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11822 GNode *xith, *xdxt;
11824 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11825 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11829 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11833 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11834 /* collect the headers and store them in a stream list so that we can
11835 * send them out first */
11836 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11846 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11847 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11850 ovc1_data = ovc1->data;
11851 ovc1_len = QT_UINT32 (ovc1_data);
11852 if (ovc1_len <= 198) {
11853 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11856 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11857 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11858 gst_caps_set_simple (entry->caps,
11859 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11860 gst_buffer_unref (buf);
11865 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11866 const guint8 *vc1_data = stsd_entry_data + 0x56;
11872 if (QT_UINT32 (vc1_data) <= len)
11873 size = QT_UINT32 (vc1_data) - 8;
11878 /* No real data, so break out */
11881 switch (QT_FOURCC (vc1_data + 0x4)) {
11882 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11886 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11887 buf = gst_buffer_new_and_alloc (size);
11888 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11889 gst_caps_set_simple (entry->caps,
11890 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11891 gst_buffer_unref (buf);
11898 vc1_data += size + 8;
11904 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11905 const guint8 *av1_data = stsd_entry_data + 0x56;
11908 while (len >= 0x8) {
11911 if (QT_UINT32 (av1_data) <= len)
11912 size = QT_UINT32 (av1_data) - 0x8;
11917 /* No real data, so break out */
11920 switch (QT_FOURCC (av1_data + 0x4)) {
11923 /* parse, if found */
11925 guint8 pres_delay_field;
11927 GST_DEBUG_OBJECT (qtdemux,
11928 "found av1C codec_data in stsd of size %d", size);
11930 /* not enough data, just ignore and hope for the best */
11935 * 4 bytes: atom length
11940 * 1 bits: initial_presentation_delay_present
11941 * 4 bits: initial_presentation_delay (if present else reserved
11945 if (av1_data[9] != 0) {
11946 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11950 /* We skip initial_presentation_delay* for now */
11951 pres_delay_field = *(av1_data + 12);
11952 if (pres_delay_field & (1 << 5)) {
11953 gst_caps_set_simple (entry->caps,
11954 "presentation-delay", G_TYPE_INT,
11955 (gint) (pres_delay_field & 0x0F) + 1, NULL);
11958 buf = gst_buffer_new_and_alloc (size - 5);
11959 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11960 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
11961 gst_caps_set_simple (entry->caps,
11962 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11963 gst_buffer_unref (buf);
11972 av1_data += size + 8;
11978 /* TODO: Need to parse vpcC for VP8 codec too.
11979 * Note that VPCodecConfigurationBox (vpcC) is defined for
11980 * vp08, vp09, and vp10 fourcc. */
11983 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11984 const guint8 *vpcc_data = stsd_entry_data + 0x56;
11987 while (len >= 0x8) {
11990 if (QT_UINT32 (vpcc_data) <= len)
11991 size = QT_UINT32 (vpcc_data) - 0x8;
11996 /* No real data, so break out */
11999 switch (QT_FOURCC (vpcc_data + 0x4)) {
12002 const gchar *profile_str = NULL;
12003 const gchar *chroma_format_str = NULL;
12006 guint8 chroma_format;
12007 GstVideoColorimetry cinfo;
12009 /* parse, if found */
12010 GST_DEBUG_OBJECT (qtdemux,
12011 "found vp codec_data in stsd of size %d", size);
12013 /* the meaning of "size" is length of the atom body, excluding
12014 * atom length and fourcc fields */
12019 * 4 bytes: atom length
12026 * 3 bits: chromaSubsampling
12027 * 1 bit: videoFullRangeFlag
12028 * 1 byte: colourPrimaries
12029 * 1 byte: transferCharacteristics
12030 * 1 byte: matrixCoefficients
12031 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
12032 * rest: codecIntializationData (not used for vp8 and vp9)
12035 if (vpcc_data[8] != 1) {
12036 GST_WARNING_OBJECT (qtdemux,
12037 "unknown vpcC version %d", vpcc_data[8]);
12041 profile = vpcc_data[12];
12060 gst_caps_set_simple (entry->caps,
12061 "profile", G_TYPE_STRING, profile_str, NULL);
12064 /* skip level, the VP9 spec v0.6 defines only one level atm,
12065 * but webm spec define various ones. Add level to caps
12066 * if we really need it then */
12068 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12069 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12070 gst_caps_set_simple (entry->caps,
12071 "bit-depth-luma", G_TYPE_UINT, bitdepth,
12072 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12075 chroma_format = (vpcc_data[14] & 0xe) >> 1;
12076 switch (chroma_format) {
12079 chroma_format_str = "4:2:0";
12082 chroma_format_str = "4:2:2";
12085 chroma_format_str = "4:4:4";
12091 if (chroma_format_str) {
12092 gst_caps_set_simple (entry->caps,
12093 "chroma-format", G_TYPE_STRING, chroma_format_str,
12097 if ((vpcc_data[14] & 0x1) != 0)
12098 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12100 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12102 gst_video_color_primaries_from_iso (vpcc_data[15]);
12104 gst_video_transfer_function_from_iso (vpcc_data[16]);
12106 gst_video_color_matrix_from_iso (vpcc_data[17]);
12108 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12109 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12110 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12111 /* set this only if all values are known, otherwise this
12112 * might overwrite valid ones parsed from other color box */
12113 CUR_STREAM (stream)->colorimetry = cinfo;
12122 vpcc_data += size + 8;
12132 GST_INFO_OBJECT (qtdemux,
12133 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12134 GST_FOURCC_ARGS (fourcc), entry->caps);
12136 } else if (stream->subtype == FOURCC_soun) {
12138 int version, samplesize;
12139 guint16 compression_id;
12140 gboolean amrwb = FALSE;
12143 /* sample description entry (16) + sound sample description v0 (20) */
12147 version = QT_UINT32 (stsd_entry_data + offset);
12148 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12149 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12150 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12151 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12153 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12154 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12155 QT_UINT32 (stsd_entry_data + offset + 4));
12156 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12157 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12158 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12159 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12160 QT_UINT16 (stsd_entry_data + offset + 14));
12161 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12163 if (compression_id == 0xfffe)
12164 entry->sampled = TRUE;
12166 /* first assume uncompressed audio */
12167 entry->bytes_per_sample = samplesize / 8;
12168 entry->samples_per_frame = entry->n_channels;
12169 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12170 entry->samples_per_packet = entry->samples_per_frame;
12171 entry->bytes_per_packet = entry->bytes_per_sample;
12175 if (version == 0x00010000) {
12176 /* sample description entry (16) + sound sample description v1 (20+16) */
12180 /* take information from here over the normal sample description */
12181 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12182 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12183 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12184 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12186 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12187 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12188 entry->samples_per_packet);
12189 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12190 entry->bytes_per_packet);
12191 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12192 entry->bytes_per_frame);
12193 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12194 entry->bytes_per_sample);
12196 if (!entry->sampled && entry->bytes_per_packet) {
12197 entry->samples_per_frame = (entry->bytes_per_frame /
12198 entry->bytes_per_packet) * entry->samples_per_packet;
12199 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12200 entry->samples_per_frame);
12202 } else if (version == 0x00020000) {
12203 /* sample description entry (16) + sound sample description v2 (56) */
12207 /* take information from here over the normal sample description */
12208 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12209 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12210 entry->samples_per_frame = entry->n_channels;
12211 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12212 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12213 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12214 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12216 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12217 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12218 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12219 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12220 entry->bytes_per_sample * 8);
12221 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12222 QT_UINT32 (stsd_entry_data + offset + 24));
12223 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12224 entry->bytes_per_packet);
12225 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12226 entry->samples_per_packet);
12227 } else if (version != 0x00000) {
12228 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12233 /* Yes, these have to be hard-coded */
12236 entry->samples_per_packet = 6;
12237 entry->bytes_per_packet = 1;
12238 entry->bytes_per_frame = 1 * entry->n_channels;
12239 entry->bytes_per_sample = 1;
12240 entry->samples_per_frame = 6 * entry->n_channels;
12245 entry->samples_per_packet = 3;
12246 entry->bytes_per_packet = 1;
12247 entry->bytes_per_frame = 1 * entry->n_channels;
12248 entry->bytes_per_sample = 1;
12249 entry->samples_per_frame = 3 * entry->n_channels;
12254 entry->samples_per_packet = 64;
12255 entry->bytes_per_packet = 34;
12256 entry->bytes_per_frame = 34 * entry->n_channels;
12257 entry->bytes_per_sample = 2;
12258 entry->samples_per_frame = 64 * entry->n_channels;
12264 entry->samples_per_packet = 1;
12265 entry->bytes_per_packet = 1;
12266 entry->bytes_per_frame = 1 * entry->n_channels;
12267 entry->bytes_per_sample = 1;
12268 entry->samples_per_frame = 1 * entry->n_channels;
12273 entry->samples_per_packet = 160;
12274 entry->bytes_per_packet = 33;
12275 entry->bytes_per_frame = 33 * entry->n_channels;
12276 entry->bytes_per_sample = 2;
12277 entry->samples_per_frame = 160 * entry->n_channels;
12280 /* fix up any invalid header information from above */
12285 /* Sometimes these are set to 0 in the sound sample descriptions so
12286 * let's try to infer useful values from the other information we
12287 * have available */
12288 if (entry->bytes_per_sample == 0)
12289 entry->bytes_per_sample =
12290 entry->bytes_per_frame / entry->n_channels;
12291 if (entry->bytes_per_sample == 0)
12292 entry->bytes_per_sample = samplesize / 8;
12294 if (entry->bytes_per_frame == 0)
12295 entry->bytes_per_frame =
12296 entry->bytes_per_sample * entry->n_channels;
12298 if (entry->bytes_per_packet == 0)
12299 entry->bytes_per_packet = entry->bytes_per_sample;
12301 if (entry->samples_per_frame == 0)
12302 entry->samples_per_frame = entry->n_channels;
12304 if (entry->samples_per_packet == 0)
12305 entry->samples_per_packet = entry->samples_per_frame;
12315 entry->bytes_per_sample = 3;
12319 entry->bytes_per_sample = 4;
12322 entry->bytes_per_sample = 8;
12325 entry->bytes_per_sample = 2;
12328 g_assert_not_reached ();
12331 entry->samples_per_frame = entry->n_channels;
12332 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12333 entry->samples_per_packet = entry->samples_per_frame;
12334 entry->bytes_per_packet = entry->bytes_per_sample;
12342 gst_caps_unref (entry->caps);
12344 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12345 stsd_entry_data + 32, len - 16, &codec);
12356 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12358 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12360 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12362 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12365 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12366 const gchar *format_str;
12370 format_str = (enda_value) ? "S24LE" : "S24BE";
12373 format_str = (enda_value) ? "S32LE" : "S32BE";
12376 format_str = (enda_value) ? "F32LE" : "F32BE";
12379 format_str = (enda_value) ? "F64LE" : "F64BE";
12382 g_assert_not_reached ();
12385 gst_caps_set_simple (entry->caps,
12386 "format", G_TYPE_STRING, format_str, NULL);
12392 const guint8 *owma_data;
12393 const gchar *codec_name = NULL;
12397 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12398 /* FIXME this should also be gst_riff_strf_auds,
12399 * but the latter one is actually missing bits-per-sample :( */
12404 gint32 nSamplesPerSec;
12405 gint32 nAvgBytesPerSec;
12406 gint16 nBlockAlign;
12407 gint16 wBitsPerSample;
12410 WAVEFORMATEX *wfex;
12412 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12413 owma_data = stsd_entry_data;
12414 owma_len = QT_UINT32 (owma_data);
12415 if (owma_len <= 54) {
12416 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12419 wfex = (WAVEFORMATEX *) (owma_data + 36);
12420 buf = gst_buffer_new_and_alloc (owma_len - 54);
12421 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12422 if (wfex->wFormatTag == 0x0161) {
12423 codec_name = "Windows Media Audio";
12425 } else if (wfex->wFormatTag == 0x0162) {
12426 codec_name = "Windows Media Audio 9 Pro";
12428 } else if (wfex->wFormatTag == 0x0163) {
12429 codec_name = "Windows Media Audio 9 Lossless";
12430 /* is that correct? gstffmpegcodecmap.c is missing it, but
12431 * fluendo codec seems to support it */
12435 gst_caps_set_simple (entry->caps,
12436 "codec_data", GST_TYPE_BUFFER, buf,
12437 "wmaversion", G_TYPE_INT, version,
12438 "block_align", G_TYPE_INT,
12439 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12440 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12441 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12442 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12443 gst_buffer_unref (buf);
12447 codec = g_strdup (codec_name);
12453 gint len = QT_UINT32 (stsd_entry_data) - offset;
12454 const guint8 *wfex_data = stsd_entry_data + offset;
12455 const gchar *codec_name = NULL;
12457 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12458 /* FIXME this should also be gst_riff_strf_auds,
12459 * but the latter one is actually missing bits-per-sample :( */
12464 gint32 nSamplesPerSec;
12465 gint32 nAvgBytesPerSec;
12466 gint16 nBlockAlign;
12467 gint16 wBitsPerSample;
12472 /* FIXME: unify with similar wavformatex parsing code above */
12473 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12479 if (QT_UINT32 (wfex_data) <= len)
12480 size = QT_UINT32 (wfex_data) - 8;
12485 /* No real data, so break out */
12488 switch (QT_FOURCC (wfex_data + 4)) {
12489 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12491 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12496 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12497 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12498 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12499 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12500 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12501 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12502 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12504 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12505 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12506 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12507 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12508 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12509 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12511 if (wfex.wFormatTag == 0x0161) {
12512 codec_name = "Windows Media Audio";
12514 } else if (wfex.wFormatTag == 0x0162) {
12515 codec_name = "Windows Media Audio 9 Pro";
12517 } else if (wfex.wFormatTag == 0x0163) {
12518 codec_name = "Windows Media Audio 9 Lossless";
12519 /* is that correct? gstffmpegcodecmap.c is missing it, but
12520 * fluendo codec seems to support it */
12524 gst_caps_set_simple (entry->caps,
12525 "wmaversion", G_TYPE_INT, version,
12526 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12527 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12528 "width", G_TYPE_INT, wfex.wBitsPerSample,
12529 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12531 if (size > wfex.cbSize) {
12534 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12535 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12536 size - wfex.cbSize);
12537 gst_caps_set_simple (entry->caps,
12538 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12539 gst_buffer_unref (buf);
12541 GST_WARNING_OBJECT (qtdemux, "no codec data");
12546 codec = g_strdup (codec_name);
12554 wfex_data += size + 8;
12560 const guint8 *dops_data;
12561 guint8 *channel_mapping = NULL;
12564 guint8 channel_mapping_family;
12565 guint8 stream_count;
12566 guint8 coupled_count;
12569 version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12571 dops_data = stsd_entry_data + 51;
12573 dops_data = stsd_entry_data + 35;
12575 channels = GST_READ_UINT8 (dops_data + 10);
12576 rate = GST_READ_UINT32_LE (dops_data + 13);
12577 channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12578 stream_count = GST_READ_UINT8 (dops_data + 20);
12579 coupled_count = GST_READ_UINT8 (dops_data + 21);
12581 if (channels > 0) {
12582 channel_mapping = g_malloc (channels * sizeof (guint8));
12583 for (i = 0; i < channels; i++)
12584 channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12587 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12588 channel_mapping_family, stream_count, coupled_count,
12600 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12601 GST_TAG_AUDIO_CODEC, codec, NULL);
12605 /* some bitrate info may have ended up in caps */
12606 s = gst_caps_get_structure (entry->caps, 0);
12607 gst_structure_get_int (s, "bitrate", &bitrate);
12609 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12610 GST_TAG_BITRATE, bitrate, NULL);
12614 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12615 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12616 if (stream->protected) {
12617 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12618 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12620 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12630 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12632 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12634 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12638 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12639 16 bits is a byte-swapped wave-style codec identifier,
12640 and we can find a WAVE header internally to a 'wave' atom here.
12641 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12642 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12645 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12646 if (len < offset + 20) {
12647 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12649 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12650 const guint8 *data = stsd_entry_data + offset + 16;
12652 GNode *waveheadernode;
12654 wavenode = g_node_new ((guint8 *) data);
12655 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12656 const guint8 *waveheader;
12659 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12660 if (waveheadernode) {
12661 waveheader = (const guint8 *) waveheadernode->data;
12662 headerlen = QT_UINT32 (waveheader);
12664 if (headerlen > 8) {
12665 gst_riff_strf_auds *header = NULL;
12666 GstBuffer *headerbuf;
12672 headerbuf = gst_buffer_new_and_alloc (headerlen);
12673 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12675 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12676 headerbuf, &header, &extra)) {
12677 gst_caps_unref (entry->caps);
12678 /* FIXME: Need to do something with the channel reorder map */
12680 gst_riff_create_audio_caps (header->format, NULL, header,
12681 extra, NULL, NULL, NULL);
12684 gst_buffer_unref (extra);
12689 GST_DEBUG ("Didn't find waveheadernode for this codec");
12691 g_node_destroy (wavenode);
12694 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12695 stream->stream_tags);
12699 /* FIXME: what is in the chunk? */
12702 gint len = QT_UINT32 (stsd_data);
12704 /* seems to be always = 116 = 0x74 */
12710 gint len = QT_UINT32 (stsd_entry_data);
12713 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12715 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12716 gst_caps_set_simple (entry->caps,
12717 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12718 gst_buffer_unref (buf);
12720 gst_caps_set_simple (entry->caps,
12721 "samplesize", G_TYPE_INT, samplesize, NULL);
12726 GNode *alac, *wave = NULL;
12728 /* apparently, m4a has this atom appended directly in the stsd entry,
12729 * while mov has it in a wave atom */
12730 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12732 /* alac now refers to stsd entry atom */
12733 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12735 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12737 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12740 const guint8 *alac_data = alac->data;
12741 gint len = QT_UINT32 (alac->data);
12745 GST_DEBUG_OBJECT (qtdemux,
12746 "discarding alac atom with unexpected len %d", len);
12748 /* codec-data contains alac atom size and prefix,
12749 * ffmpeg likes it that way, not quite gst-ish though ...*/
12750 buf = gst_buffer_new_and_alloc (len);
12751 gst_buffer_fill (buf, 0, alac->data, len);
12752 gst_caps_set_simple (entry->caps,
12753 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12754 gst_buffer_unref (buf);
12756 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12757 entry->n_channels = QT_UINT8 (alac_data + 21);
12758 entry->rate = QT_UINT32 (alac_data + 32);
12759 samplesize = QT_UINT8 (alac_data + 16 + 1);
12762 gst_caps_set_simple (entry->caps,
12763 "samplesize", G_TYPE_INT, samplesize, NULL);
12768 /* The codingname of the sample entry is 'fLaC' */
12769 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12772 /* The 'dfLa' box is added to the sample entry to convey
12773 initializing information for the decoder. */
12774 const GNode *dfla =
12775 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12778 const guint32 len = QT_UINT32 (dfla->data);
12780 /* Must contain at least dfLa box header (12),
12781 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12783 GST_DEBUG_OBJECT (qtdemux,
12784 "discarding dfla atom with unexpected len %d", len);
12786 /* skip dfLa header to get the METADATA_BLOCKs */
12787 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12788 const guint32 metadata_blocks_len = len - 12;
12790 gchar *stream_marker = g_strdup ("fLaC");
12791 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12792 strlen (stream_marker));
12795 guint32 remainder = 0;
12796 guint32 block_size = 0;
12797 gboolean is_last = FALSE;
12799 GValue array = G_VALUE_INIT;
12800 GValue value = G_VALUE_INIT;
12802 g_value_init (&array, GST_TYPE_ARRAY);
12803 g_value_init (&value, GST_TYPE_BUFFER);
12805 gst_value_set_buffer (&value, block);
12806 gst_value_array_append_value (&array, &value);
12807 g_value_reset (&value);
12809 gst_buffer_unref (block);
12811 /* check there's at least one METADATA_BLOCK_HEADER's worth
12812 * of data, and we haven't already finished parsing */
12813 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12814 remainder = metadata_blocks_len - index;
12816 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12818 (metadata_blocks[index + 1] << 16) +
12819 (metadata_blocks[index + 2] << 8) +
12820 metadata_blocks[index + 3];
12822 /* be careful not to read off end of box */
12823 if (block_size > remainder) {
12827 is_last = metadata_blocks[index] >> 7;
12829 block = gst_buffer_new_and_alloc (block_size);
12831 gst_buffer_fill (block, 0, &metadata_blocks[index],
12834 gst_value_set_buffer (&value, block);
12835 gst_value_array_append_value (&array, &value);
12836 g_value_reset (&value);
12838 gst_buffer_unref (block);
12840 index += block_size;
12843 /* only append the metadata if we successfully read all of it */
12845 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12846 (stream)->caps, 0), "streamheader", &array);
12848 GST_WARNING_OBJECT (qtdemux,
12849 "discarding all METADATA_BLOCKs due to invalid "
12850 "block_size %d at idx %d, rem %d", block_size, index,
12854 g_value_unset (&value);
12855 g_value_unset (&array);
12857 /* The sample rate obtained from the stsd may not be accurate
12858 * since it cannot represent rates greater than 65535Hz, so
12859 * override that value with the sample rate from the
12860 * METADATA_BLOCK_STREAMINFO block */
12861 CUR_STREAM (stream)->rate =
12862 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12873 gint len = QT_UINT32 (stsd_entry_data);
12876 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12879 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12881 /* If we have enough data, let's try to get the 'damr' atom. See
12882 * the 3GPP container spec (26.244) for more details. */
12883 if ((len - 0x34) > 8 &&
12884 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12885 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12886 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12889 gst_caps_set_simple (entry->caps,
12890 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12891 gst_buffer_unref (buf);
12897 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12898 gint len = QT_UINT32 (stsd_entry_data);
12899 guint16 sound_version = 0;
12900 /* FIXME: Can this be determined somehow? There doesn't seem to be
12901 * anything in mp4a atom that specifis compression */
12903 guint16 channels = entry->n_channels;
12904 guint32 time_scale = (guint32) entry->rate;
12905 gint sample_rate_index = -1;
12908 sound_version = QT_UINT16 (stsd_entry_data + 16);
12910 if (sound_version == 1) {
12911 channels = QT_UINT16 (stsd_entry_data + 24);
12912 time_scale = QT_UINT32 (stsd_entry_data + 30);
12914 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
12918 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
12922 sample_rate_index =
12923 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12924 if (sample_rate_index >= 0 && channels > 0) {
12925 guint8 codec_data[2];
12928 /* build AAC codec data */
12929 codec_data[0] = profile << 3;
12930 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12931 codec_data[1] = (sample_rate_index & 0x01) << 7;
12932 codec_data[1] |= (channels & 0xF) << 3;
12934 buf = gst_buffer_new_and_alloc (2);
12935 gst_buffer_fill (buf, 0, codec_data, 2);
12936 gst_caps_set_simple (entry->caps,
12937 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12938 gst_buffer_unref (buf);
12948 /* Fully handled elsewhere */
12951 GST_INFO_OBJECT (qtdemux,
12952 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12956 GST_INFO_OBJECT (qtdemux,
12957 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12958 GST_FOURCC_ARGS (fourcc), entry->caps);
12960 } else if (stream->subtype == FOURCC_strm) {
12961 if (fourcc == FOURCC_rtsp) {
12962 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12964 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12965 GST_FOURCC_ARGS (fourcc));
12966 goto unknown_stream;
12968 entry->sampled = TRUE;
12969 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12970 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12971 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
12973 entry->sampled = TRUE;
12974 entry->sparse = TRUE;
12977 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12980 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12981 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12986 /* hunt for sort-of codec data */
12990 GNode *mp4s = NULL;
12991 GNode *esds = NULL;
12993 /* look for palette in a stsd->mp4s->esds sub-atom */
12994 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12996 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12997 if (esds == NULL) {
12999 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13003 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13004 stream->stream_tags);
13008 GST_INFO_OBJECT (qtdemux,
13009 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13012 GST_INFO_OBJECT (qtdemux,
13013 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13014 GST_FOURCC_ARGS (fourcc), entry->caps);
13016 /* everything in 1 sample */
13017 entry->sampled = TRUE;
13020 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13023 if (entry->caps == NULL)
13024 goto unknown_stream;
13027 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13028 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13034 /* promote to sampled format */
13035 if (entry->fourcc == FOURCC_samr) {
13036 /* force mono 8000 Hz for AMR */
13037 entry->sampled = TRUE;
13038 entry->n_channels = 1;
13039 entry->rate = 8000;
13040 } else if (entry->fourcc == FOURCC_sawb) {
13041 /* force mono 16000 Hz for AMR-WB */
13042 entry->sampled = TRUE;
13043 entry->n_channels = 1;
13044 entry->rate = 16000;
13045 } else if (entry->fourcc == FOURCC_mp4a) {
13046 entry->sampled = TRUE;
13050 stsd_entry_data += len;
13051 remaining_stsd_len -= len;
13055 /* collect sample information */
13056 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13057 goto samples_failed;
13059 if (qtdemux->fragmented) {
13062 /* need all moov samples as basis; probably not many if any at all */
13063 /* prevent moof parsing taking of at this time */
13064 offset = qtdemux->moof_offset;
13065 qtdemux->moof_offset = 0;
13066 if (stream->n_samples &&
13067 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13068 qtdemux->moof_offset = offset;
13069 goto samples_failed;
13071 qtdemux->moof_offset = offset;
13072 /* movie duration more reliable in this case (e.g. mehd) */
13073 if (qtdemux->segment.duration &&
13074 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13076 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13079 /* configure segments */
13080 if (!qtdemux_parse_segments (qtdemux, stream, trak))
13081 goto segments_failed;
13083 /* add some language tag, if useful */
13084 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13085 strcmp (stream->lang_id, "und")) {
13086 const gchar *lang_code;
13088 /* convert ISO 639-2 code to ISO 639-1 */
13089 lang_code = gst_tag_get_language_code (stream->lang_id);
13090 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13091 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13094 /* Check for UDTA tags */
13095 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13096 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13099 /* Insert and sort new stream in track-id order.
13100 * This will help in comparing old/new streams during stream update check */
13101 g_ptr_array_add (qtdemux->active_streams, stream);
13102 g_ptr_array_sort (qtdemux->active_streams,
13103 (GCompareFunc) qtdemux_track_id_compare_func);
13104 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13105 QTDEMUX_N_STREAMS (qtdemux));
13112 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13113 (_("This file is corrupt and cannot be played.")), (NULL));
13115 gst_qtdemux_stream_unref (stream);
13120 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13121 gst_qtdemux_stream_unref (stream);
13127 /* we posted an error already */
13128 /* free stbl sub-atoms */
13129 gst_qtdemux_stbl_free (stream);
13130 gst_qtdemux_stream_unref (stream);
13135 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13141 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13142 GST_FOURCC_ARGS (stream->subtype));
13143 gst_qtdemux_stream_unref (stream);
13148 /* If we can estimate the overall bitrate, and don't have information about the
13149 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13150 * the overall bitrate minus the sum of the bitrates of all other streams. This
13151 * should be useful for the common case where we have one audio and one video
13152 * stream and can estimate the bitrate of one, but not the other. */
13154 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13156 QtDemuxStream *stream = NULL;
13157 gint64 size, sys_bitrate, sum_bitrate = 0;
13158 GstClockTime duration;
13162 if (qtdemux->fragmented)
13165 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13167 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13169 GST_DEBUG_OBJECT (qtdemux,
13170 "Size in bytes of the stream not known - bailing");
13174 /* Subtract the header size */
13175 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13176 size, qtdemux->header_size);
13178 if (size < qtdemux->header_size)
13181 size = size - qtdemux->header_size;
13183 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13184 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13188 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13189 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13190 switch (str->subtype) {
13193 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13194 CUR_STREAM (str)->caps);
13195 /* retrieve bitrate, prefer avg then max */
13197 if (str->stream_tags) {
13198 if (gst_tag_list_get_uint (str->stream_tags,
13199 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13200 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13201 if (gst_tag_list_get_uint (str->stream_tags,
13202 GST_TAG_NOMINAL_BITRATE, &bitrate))
13203 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13204 if (gst_tag_list_get_uint (str->stream_tags,
13205 GST_TAG_BITRATE, &bitrate))
13206 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13209 sum_bitrate += bitrate;
13212 GST_DEBUG_OBJECT (qtdemux,
13213 ">1 stream with unknown bitrate - bailing");
13220 /* For other subtypes, we assume no significant impact on bitrate */
13226 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13230 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13232 if (sys_bitrate < sum_bitrate) {
13233 /* This can happen, since sum_bitrate might be derived from maximum
13234 * bitrates and not average bitrates */
13235 GST_DEBUG_OBJECT (qtdemux,
13236 "System bitrate less than sum bitrate - bailing");
13240 bitrate = sys_bitrate - sum_bitrate;
13241 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13242 ", Stream bitrate = %u", sys_bitrate, bitrate);
13244 if (!stream->stream_tags)
13245 stream->stream_tags = gst_tag_list_new_empty ();
13247 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13249 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13250 GST_TAG_BITRATE, bitrate, NULL);
13253 static GstFlowReturn
13254 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13256 GstFlowReturn ret = GST_FLOW_OK;
13259 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13261 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13262 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13263 guint32 sample_num = 0;
13265 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13266 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13268 if (qtdemux->fragmented && qtdemux->pullbased) {
13269 /* need all moov samples first */
13270 GST_OBJECT_LOCK (qtdemux);
13271 while (stream->n_samples == 0)
13272 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13274 GST_OBJECT_UNLOCK (qtdemux);
13276 /* discard any stray moof */
13277 qtdemux->moof_offset = 0;
13280 /* prepare braking */
13281 if (ret != GST_FLOW_ERROR)
13284 /* in pull mode, we should have parsed some sample info by now;
13285 * and quite some code will not handle no samples.
13286 * in push mode, we'll just have to deal with it */
13287 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13288 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13289 g_ptr_array_remove_index (qtdemux->active_streams, i);
13292 } else if (stream->track_id == qtdemux->chapters_track_id &&
13293 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13294 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13295 so that it doesn't look like a subtitle track */
13296 g_ptr_array_remove_index (qtdemux->active_streams, i);
13301 /* parse the initial sample for use in setting the frame rate cap */
13302 while (sample_num == 0 && sample_num < stream->n_samples) {
13303 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13313 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13315 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13319 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13323 /* Different length, updated */
13324 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13327 /* streams in list are sorted in track-id order */
13328 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13329 /* Different stream-id, updated */
13330 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13331 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13339 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13340 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13342 /* Connect old stream's srcpad to new stream */
13343 newstream->pad = oldstream->pad;
13344 oldstream->pad = NULL;
13346 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13347 * case we need to force one through */
13348 newstream->new_stream = GST_PAD_IS_EOS (newstream->pad);
13350 return gst_qtdemux_configure_stream (qtdemux, newstream);
13354 qtdemux_update_streams (GstQTDemux * qtdemux)
13357 g_assert (qtdemux->streams_aware);
13359 /* At below, figure out which stream in active_streams has identical stream-id
13360 * with that of in old_streams. If there is matching stream-id,
13361 * corresponding newstream will not be exposed again,
13362 * but demux will reuse srcpad of matched old stream
13364 * active_streams : newly created streams from the latest moov
13365 * old_streams : existing streams (belong to previous moov)
13368 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13369 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13370 QtDemuxStream *oldstream = NULL;
13373 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13374 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13376 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13377 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13378 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13380 /* null pad stream cannot be reused */
13381 if (oldstream->pad == NULL)
13386 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13388 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13391 /* we don't need to preserve order of old streams */
13392 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13396 /* now we have all info and can expose */
13397 list = stream->stream_tags;
13398 stream->stream_tags = NULL;
13399 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13407 /* Must be called with expose lock */
13408 static GstFlowReturn
13409 qtdemux_expose_streams (GstQTDemux * qtdemux)
13413 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13415 if (!qtdemux_is_streams_update (qtdemux)) {
13416 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13417 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13418 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13419 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13420 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13421 return GST_FLOW_ERROR;
13424 g_ptr_array_set_size (qtdemux->old_streams, 0);
13425 qtdemux->need_segment = TRUE;
13427 return GST_FLOW_OK;
13430 if (qtdemux->streams_aware) {
13431 if (!qtdemux_update_streams (qtdemux))
13432 return GST_FLOW_ERROR;
13434 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13435 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13438 /* now we have all info and can expose */
13439 list = stream->stream_tags;
13440 stream->stream_tags = NULL;
13441 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13442 return GST_FLOW_ERROR;
13447 gst_qtdemux_guess_bitrate (qtdemux);
13449 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13451 /* If we have still old_streams, it's no more used stream */
13452 for (i = 0; i < qtdemux->old_streams->len; i++) {
13453 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13458 event = gst_event_new_eos ();
13459 if (qtdemux->segment_seqnum)
13460 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13462 gst_pad_push_event (stream->pad, event);
13466 g_ptr_array_set_size (qtdemux->old_streams, 0);
13468 /* check if we should post a redirect in case there is a single trak
13469 * and it is a redirecting trak */
13470 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13471 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13474 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13475 "an external content");
13476 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13477 gst_structure_new ("redirect",
13478 "new-location", G_TYPE_STRING,
13479 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13480 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13481 g_free (qtdemux->redirect_location);
13482 qtdemux->redirect_location =
13483 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13486 g_ptr_array_foreach (qtdemux->active_streams,
13487 (GFunc) qtdemux_do_allocation, qtdemux);
13489 qtdemux->need_segment = TRUE;
13491 qtdemux->exposed = TRUE;
13492 return GST_FLOW_OK;
13497 GstStructure *structure; /* helper for sort function */
13499 guint min_req_bitrate;
13500 guint min_req_qt_version;
13504 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13506 GstQtReference *ref_a = (GstQtReference *) a;
13507 GstQtReference *ref_b = (GstQtReference *) b;
13509 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13510 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13512 /* known bitrates go before unknown; higher bitrates go first */
13513 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13516 /* sort the redirects and post a message for the application.
13519 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13521 GstQtReference *best;
13524 GValue list_val = { 0, };
13527 g_assert (references != NULL);
13529 references = g_list_sort (references, qtdemux_redirects_sort_func);
13531 best = (GstQtReference *) references->data;
13533 g_value_init (&list_val, GST_TYPE_LIST);
13535 for (l = references; l != NULL; l = l->next) {
13536 GstQtReference *ref = (GstQtReference *) l->data;
13537 GValue struct_val = { 0, };
13539 ref->structure = gst_structure_new ("redirect",
13540 "new-location", G_TYPE_STRING, ref->location, NULL);
13542 if (ref->min_req_bitrate > 0) {
13543 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13544 ref->min_req_bitrate, NULL);
13547 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13548 g_value_set_boxed (&struct_val, ref->structure);
13549 gst_value_list_append_value (&list_val, &struct_val);
13550 g_value_unset (&struct_val);
13551 /* don't free anything here yet, since we need best->structure below */
13554 g_assert (best != NULL);
13555 s = gst_structure_copy (best->structure);
13557 if (g_list_length (references) > 1) {
13558 gst_structure_set_value (s, "locations", &list_val);
13561 g_value_unset (&list_val);
13563 for (l = references; l != NULL; l = l->next) {
13564 GstQtReference *ref = (GstQtReference *) l->data;
13566 gst_structure_free (ref->structure);
13567 g_free (ref->location);
13570 g_list_free (references);
13572 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13573 g_free (qtdemux->redirect_location);
13574 qtdemux->redirect_location =
13575 g_strdup (gst_structure_get_string (s, "new-location"));
13576 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13577 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13580 /* look for redirect nodes, collect all redirect information and
13584 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13586 GNode *rmra, *rmda, *rdrf;
13588 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13590 GList *redirects = NULL;
13592 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13594 GstQtReference ref = { NULL, NULL, 0, 0 };
13595 GNode *rmdr, *rmvc;
13597 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13598 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13599 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13600 ref.min_req_bitrate);
13603 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13604 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13605 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13607 #ifndef GST_DISABLE_GST_DEBUG
13608 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13610 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13612 GST_LOG_OBJECT (qtdemux,
13613 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13614 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13615 bitmask, check_type);
13616 if (package == FOURCC_qtim && check_type == 0) {
13617 ref.min_req_qt_version = version;
13621 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13627 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13628 if (ref_len > 20) {
13629 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13630 ref_data = (guint8 *) rdrf->data + 20;
13631 if (ref_type == FOURCC_alis) {
13632 guint record_len, record_version, fn_len;
13634 if (ref_len > 70) {
13635 /* MacOSX alias record, google for alias-layout.txt */
13636 record_len = QT_UINT16 (ref_data + 4);
13637 record_version = QT_UINT16 (ref_data + 4 + 2);
13638 fn_len = QT_UINT8 (ref_data + 50);
13639 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13640 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13643 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13646 } else if (ref_type == FOURCC_url_) {
13647 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13649 GST_DEBUG_OBJECT (qtdemux,
13650 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13651 GST_FOURCC_ARGS (ref_type));
13653 if (ref.location != NULL) {
13654 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13656 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13658 GST_WARNING_OBJECT (qtdemux,
13659 "Failed to extract redirect location from rdrf atom");
13662 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13666 /* look for others */
13667 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13670 if (redirects != NULL) {
13671 qtdemux_process_redirects (qtdemux, redirects);
13677 static GstTagList *
13678 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13682 if (tags == NULL) {
13683 tags = gst_tag_list_new_empty ();
13684 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13687 if (qtdemux->major_brand == FOURCC_mjp2)
13688 fmt = "Motion JPEG 2000";
13689 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13691 else if (qtdemux->major_brand == FOURCC_qt__)
13693 else if (qtdemux->fragmented)
13696 fmt = "ISO MP4/M4A";
13698 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13699 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13701 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13707 /* we have read the complete moov node now.
13708 * This function parses all of the relevant info, creates the traks and
13709 * prepares all data structures for playback
13712 qtdemux_parse_tree (GstQTDemux * qtdemux)
13719 guint64 creation_time;
13720 GstDateTime *datetime = NULL;
13723 /* make sure we have a usable taglist */
13724 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13726 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13727 if (mvhd == NULL) {
13728 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13729 return qtdemux_parse_redirects (qtdemux);
13732 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13733 if (version == 1) {
13734 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13735 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13736 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13737 } else if (version == 0) {
13738 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13739 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13740 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13742 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13746 /* Moving qt creation time (secs since 1904) to unix time */
13747 if (creation_time != 0) {
13748 /* Try to use epoch first as it should be faster and more commonly found */
13749 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13752 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13753 /* some data cleansing sanity */
13754 now_s = g_get_real_time () / G_USEC_PER_SEC;
13755 if (now_s + 24 * 3600 < creation_time) {
13756 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13758 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13761 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13762 GDateTime *dt, *dt_local;
13764 dt = g_date_time_add_seconds (base_dt, creation_time);
13765 dt_local = g_date_time_to_local (dt);
13766 datetime = gst_date_time_new_from_g_date_time (dt_local);
13768 g_date_time_unref (base_dt);
13769 g_date_time_unref (dt);
13773 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13774 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13776 gst_date_time_unref (datetime);
13779 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13780 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13782 /* check for fragmented file and get some (default) data */
13783 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13786 GstByteReader mehd_data;
13788 /* let track parsing or anyone know weird stuff might happen ... */
13789 qtdemux->fragmented = TRUE;
13791 /* compensate for total duration */
13792 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13794 qtdemux_parse_mehd (qtdemux, &mehd_data);
13797 /* Update the movie segment duration, unless it was directly given to us
13798 * by upstream. Otherwise let it as is, as we don't want to mangle the
13799 * duration provided by upstream that may come e.g. from a MPD file. */
13800 if (!qtdemux->upstream_format_is_time) {
13801 GstClockTime duration;
13802 /* set duration in the segment info */
13803 gst_qtdemux_get_duration (qtdemux, &duration);
13804 qtdemux->segment.duration = duration;
13805 /* also do not exceed duration; stop is set that way post seek anyway,
13806 * and segment activation falls back to duration,
13807 * whereas loop only checks stop, so let's align this here as well */
13808 qtdemux->segment.stop = duration;
13811 /* parse all traks */
13812 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13814 qtdemux_parse_trak (qtdemux, trak);
13815 /* iterate all siblings */
13816 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13819 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13822 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13824 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13826 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13829 /* maybe also some tags in meta box */
13830 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13832 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13833 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13835 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13838 /* parse any protection system info */
13839 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13841 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13842 qtdemux_parse_pssh (qtdemux, pssh);
13843 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13846 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13851 /* taken from ffmpeg */
13853 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13865 len = (len << 7) | (c & 0x7f);
13874 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13875 gsize codec_data_size)
13877 GList *list = NULL;
13878 guint8 *p = codec_data;
13879 gint i, offset, num_packets;
13880 guint *length, last;
13882 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13884 if (codec_data == NULL || codec_data_size == 0)
13887 /* start of the stream and vorbis audio or theora video, need to
13888 * send the codec_priv data as first three packets */
13889 num_packets = p[0] + 1;
13890 GST_DEBUG_OBJECT (qtdemux,
13891 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13892 (guint) num_packets, codec_data_size);
13894 /* Let's put some limits, Don't think there even is a xiph codec
13895 * with more than 3-4 headers */
13896 if (G_UNLIKELY (num_packets > 16)) {
13897 GST_WARNING_OBJECT (qtdemux,
13898 "Unlikely number of xiph headers, most likely not valid");
13902 length = g_alloca (num_packets * sizeof (guint));
13906 /* first packets, read length values */
13907 for (i = 0; i < num_packets - 1; i++) {
13909 while (offset < codec_data_size) {
13910 length[i] += p[offset];
13911 if (p[offset++] != 0xff)
13916 if (offset + last > codec_data_size)
13919 /* last packet is the remaining size */
13920 length[i] = codec_data_size - offset - last;
13922 for (i = 0; i < num_packets; i++) {
13925 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
13927 if (offset + length[i] > codec_data_size)
13930 hdr = gst_buffer_new_memdup (p + offset, length[i]);
13931 list = g_list_append (list, hdr);
13933 offset += length[i];
13942 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
13948 /* this can change the codec originally present in @list */
13950 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13951 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13953 int len = QT_UINT32 (esds->data);
13954 guint8 *ptr = esds->data;
13955 guint8 *end = ptr + len;
13957 guint8 *data_ptr = NULL;
13959 guint8 object_type_id = 0;
13960 guint8 stream_type = 0;
13961 const char *codec_name = NULL;
13962 GstCaps *caps = NULL;
13964 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13966 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13968 while (ptr + 1 < end) {
13969 tag = QT_UINT8 (ptr);
13970 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13972 len = read_descr_size (ptr, end, &ptr);
13973 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13975 /* Check the stated amount of data is available for reading */
13976 if (len < 0 || ptr + len > end)
13980 case ES_DESCRIPTOR_TAG:
13981 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
13982 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
13985 case DECODER_CONFIG_DESC_TAG:{
13986 guint max_bitrate, avg_bitrate;
13988 object_type_id = QT_UINT8 (ptr);
13989 stream_type = QT_UINT8 (ptr + 1) >> 2;
13990 max_bitrate = QT_UINT32 (ptr + 5);
13991 avg_bitrate = QT_UINT32 (ptr + 9);
13992 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13993 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
13994 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13995 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13996 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13997 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13998 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13999 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14001 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14002 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14003 avg_bitrate, NULL);
14008 case DECODER_SPECIFIC_INFO_TAG:
14009 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14010 if (object_type_id == 0xe0 && len == 0x40) {
14016 GST_DEBUG_OBJECT (qtdemux,
14017 "Have VOBSUB palette. Creating palette event");
14018 /* move to decConfigDescr data and read palette */
14020 for (i = 0; i < 16; i++) {
14021 clut[i] = QT_UINT32 (data);
14025 s = gst_structure_new ("application/x-gst-dvd", "event",
14026 G_TYPE_STRING, "dvd-spu-clut-change",
14027 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14028 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14029 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14030 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14031 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14032 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14033 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14034 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14037 /* store event and trigger custom processing */
14038 stream->pending_event =
14039 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14041 /* Generic codec_data handler puts it on the caps */
14048 case SL_CONFIG_DESC_TAG:
14049 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14053 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14055 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14061 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14062 * in use, and should also be used to override some other parameters for some
14064 switch (object_type_id) {
14065 case 0x20: /* MPEG-4 */
14066 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14067 * profile_and_level_indication */
14068 if (data_ptr != NULL && data_len >= 5 &&
14069 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14070 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14071 data_ptr + 4, data_len - 4);
14073 break; /* Nothing special needed here */
14074 case 0x21: /* H.264 */
14075 codec_name = "H.264 / AVC";
14076 caps = gst_caps_new_simple ("video/x-h264",
14077 "stream-format", G_TYPE_STRING, "avc",
14078 "alignment", G_TYPE_STRING, "au", NULL);
14080 case 0x40: /* AAC (any) */
14081 case 0x66: /* AAC Main */
14082 case 0x67: /* AAC LC */
14083 case 0x68: /* AAC SSR */
14084 /* Override channels and rate based on the codec_data, as it's often
14086 /* Only do so for basic setup without HE-AAC extension */
14087 if (data_ptr && data_len == 2) {
14088 guint channels, rate;
14090 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14092 entry->n_channels = channels;
14094 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14096 entry->rate = rate;
14099 /* Set level and profile if possible */
14100 if (data_ptr != NULL && data_len >= 2) {
14101 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14102 data_ptr, data_len);
14104 const gchar *profile_str = NULL;
14107 guint8 *codec_data;
14108 gint rate_idx, profile;
14110 /* No codec_data, let's invent something.
14111 * FIXME: This is wrong for SBR! */
14113 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14115 buffer = gst_buffer_new_and_alloc (2);
14116 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14117 codec_data = map.data;
14120 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14123 switch (object_type_id) {
14125 profile_str = "main";
14129 profile_str = "lc";
14133 profile_str = "ssr";
14141 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14143 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14145 gst_buffer_unmap (buffer, &map);
14146 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14147 GST_TYPE_BUFFER, buffer, NULL);
14148 gst_buffer_unref (buffer);
14151 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14152 G_TYPE_STRING, profile_str, NULL);
14156 case 0x60: /* MPEG-2, various profiles */
14162 codec_name = "MPEG-2 video";
14163 caps = gst_caps_new_simple ("video/mpeg",
14164 "mpegversion", G_TYPE_INT, 2,
14165 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14167 case 0x69: /* MPEG-2 BC audio */
14168 case 0x6B: /* MPEG-1 audio */
14169 caps = gst_caps_new_simple ("audio/mpeg",
14170 "mpegversion", G_TYPE_INT, 1, NULL);
14171 codec_name = "MPEG-1 audio";
14173 case 0x6A: /* MPEG-1 */
14174 codec_name = "MPEG-1 video";
14175 caps = gst_caps_new_simple ("video/mpeg",
14176 "mpegversion", G_TYPE_INT, 1,
14177 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14179 case 0x6C: /* MJPEG */
14181 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14183 codec_name = "Motion-JPEG";
14185 case 0x6D: /* PNG */
14187 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14189 codec_name = "PNG still images";
14191 case 0x6E: /* JPEG2000 */
14192 codec_name = "JPEG-2000";
14193 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14195 case 0xA4: /* Dirac */
14196 codec_name = "Dirac";
14197 caps = gst_caps_new_empty_simple ("video/x-dirac");
14199 case 0xA5: /* AC3 */
14200 codec_name = "AC-3 audio";
14201 caps = gst_caps_new_simple ("audio/x-ac3",
14202 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14204 case 0xA9: /* AC3 */
14205 codec_name = "DTS audio";
14206 caps = gst_caps_new_simple ("audio/x-dts",
14207 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14210 if (stream_type == 0x05 && data_ptr) {
14212 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14215 GValue arr_val = G_VALUE_INIT;
14216 GValue buf_val = G_VALUE_INIT;
14219 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14220 codec_name = "Vorbis";
14221 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14222 g_value_init (&arr_val, GST_TYPE_ARRAY);
14223 g_value_init (&buf_val, GST_TYPE_BUFFER);
14224 for (tmp = headers; tmp; tmp = tmp->next) {
14225 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14226 gst_value_array_append_value (&arr_val, &buf_val);
14228 s = gst_caps_get_structure (caps, 0);
14229 gst_structure_take_value (s, "streamheader", &arr_val);
14230 g_value_unset (&buf_val);
14231 g_list_free (headers);
14238 case 0xE1: /* QCELP */
14239 /* QCELP, the codec_data is a riff tag (little endian) with
14240 * 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). */
14241 caps = gst_caps_new_empty_simple ("audio/qcelp");
14242 codec_name = "QCELP";
14248 /* If we have a replacement caps, then change our caps for this stream */
14250 gst_caps_unref (entry->caps);
14251 entry->caps = caps;
14254 if (codec_name && list)
14255 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14256 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14258 /* Add the codec_data attribute to caps, if we have it */
14262 buffer = gst_buffer_new_and_alloc (data_len);
14263 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14265 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14266 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14268 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14270 gst_buffer_unref (buffer);
14275 static inline GstCaps *
14276 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14280 char *s, fourstr[5];
14282 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14283 for (i = 0; i < 4; i++) {
14284 if (!g_ascii_isalnum (fourstr[i]))
14287 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14288 caps = gst_caps_new_empty_simple (s);
14293 #define _codec(name) \
14295 if (codec_name) { \
14296 *codec_name = g_strdup (name); \
14301 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14302 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14303 const guint8 * stsd_entry_data, gchar ** codec_name)
14305 GstCaps *caps = NULL;
14306 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14310 _codec ("PNG still images");
14311 caps = gst_caps_new_empty_simple ("image/png");
14314 _codec ("JPEG still images");
14316 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14319 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14320 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14321 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14322 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14323 _codec ("Motion-JPEG");
14325 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14328 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14329 _codec ("Motion-JPEG format B");
14330 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14333 _codec ("JPEG-2000");
14334 /* override to what it should be according to spec, avoid palette_data */
14335 entry->bits_per_sample = 24;
14336 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14339 _codec ("Sorensen video v.3");
14340 caps = gst_caps_new_simple ("video/x-svq",
14341 "svqversion", G_TYPE_INT, 3, NULL);
14343 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14344 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14345 _codec ("Sorensen video v.1");
14346 caps = gst_caps_new_simple ("video/x-svq",
14347 "svqversion", G_TYPE_INT, 1, NULL);
14349 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14350 caps = gst_caps_new_empty_simple ("video/x-raw");
14351 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14352 _codec ("Windows Raw RGB");
14353 stream->alignment = 32;
14359 bps = QT_UINT16 (stsd_entry_data + 82);
14362 format = GST_VIDEO_FORMAT_RGB15;
14365 format = GST_VIDEO_FORMAT_RGB16;
14368 format = GST_VIDEO_FORMAT_RGB;
14371 format = GST_VIDEO_FORMAT_ARGB;
14379 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14380 format = GST_VIDEO_FORMAT_I420;
14382 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14383 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14384 format = GST_VIDEO_FORMAT_I420;
14387 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14388 format = GST_VIDEO_FORMAT_UYVY;
14390 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14391 format = GST_VIDEO_FORMAT_v308;
14393 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14394 format = GST_VIDEO_FORMAT_v216;
14397 format = GST_VIDEO_FORMAT_v210;
14399 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14400 format = GST_VIDEO_FORMAT_r210;
14402 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14403 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14404 format = GST_VIDEO_FORMAT_v410;
14407 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14408 * but different order than AYUV
14409 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14410 format = GST_VIDEO_FORMAT_v408;
14413 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14414 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14415 _codec ("MPEG-1 video");
14416 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14417 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14419 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14420 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14421 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14422 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14423 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14424 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14425 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14426 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14427 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14428 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14429 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14430 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14431 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14432 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14433 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14434 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14435 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14436 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14437 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14438 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14439 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14440 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14441 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14442 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14443 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14444 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14445 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14446 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14447 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14448 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14449 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14450 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14451 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14452 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14453 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14454 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14455 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14456 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14457 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14458 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14459 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14460 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14461 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14462 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14463 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14464 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14465 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14466 _codec ("MPEG-2 video");
14467 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14468 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14470 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14471 _codec ("GIF still images");
14472 caps = gst_caps_new_empty_simple ("image/gif");
14475 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14477 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14479 /* ffmpeg uses the height/width props, don't know why */
14480 caps = gst_caps_new_simple ("video/x-h263",
14481 "variant", G_TYPE_STRING, "itu", NULL);
14485 _codec ("MPEG-4 video");
14486 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14487 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14489 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14490 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14491 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14492 caps = gst_caps_new_simple ("video/x-msmpeg",
14493 "msmpegversion", G_TYPE_INT, 43, NULL);
14495 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14497 caps = gst_caps_new_simple ("video/x-divx",
14498 "divxversion", G_TYPE_INT, 3, NULL);
14500 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14501 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14503 caps = gst_caps_new_simple ("video/x-divx",
14504 "divxversion", G_TYPE_INT, 4, NULL);
14506 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14508 caps = gst_caps_new_simple ("video/x-divx",
14509 "divxversion", G_TYPE_INT, 5, NULL);
14512 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14514 caps = gst_caps_new_simple ("video/x-ffv",
14515 "ffvversion", G_TYPE_INT, 1, NULL);
14518 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14519 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14524 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14525 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14526 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14530 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14531 _codec ("Cinepak");
14532 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14534 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14535 _codec ("Apple QuickDraw");
14536 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14538 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14539 _codec ("Apple video");
14540 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14545 _codec ("H.264 / AVC");
14546 caps = gst_caps_new_simple ("video/x-h264",
14547 "stream-format", G_TYPE_STRING, "avc",
14548 "alignment", G_TYPE_STRING, "au", NULL);
14552 _codec ("H.264 / AVC");
14553 caps = gst_caps_new_simple ("video/x-h264",
14554 "stream-format", G_TYPE_STRING, "avc3",
14555 "alignment", G_TYPE_STRING, "au", NULL);
14560 _codec ("H.265 / HEVC");
14561 caps = gst_caps_new_simple ("video/x-h265",
14562 "stream-format", G_TYPE_STRING, "hvc1",
14563 "alignment", G_TYPE_STRING, "au", NULL);
14567 _codec ("H.265 / HEVC");
14568 caps = gst_caps_new_simple ("video/x-h265",
14569 "stream-format", G_TYPE_STRING, "hev1",
14570 "alignment", G_TYPE_STRING, "au", NULL);
14573 _codec ("Run-length encoding");
14574 caps = gst_caps_new_simple ("video/x-rle",
14575 "layout", G_TYPE_STRING, "quicktime", NULL);
14578 _codec ("Run-length encoding");
14579 caps = gst_caps_new_simple ("video/x-rle",
14580 "layout", G_TYPE_STRING, "microsoft", NULL);
14582 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14583 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14584 _codec ("Indeo Video 3");
14585 caps = gst_caps_new_simple ("video/x-indeo",
14586 "indeoversion", G_TYPE_INT, 3, NULL);
14588 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14589 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14590 _codec ("Intel Video 4");
14591 caps = gst_caps_new_simple ("video/x-indeo",
14592 "indeoversion", G_TYPE_INT, 4, NULL);
14596 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14597 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14598 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14599 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14600 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14601 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14602 _codec ("DV Video");
14603 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14604 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14606 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14607 case FOURCC_dv5p: /* DVCPRO50 PAL */
14608 _codec ("DVCPro50 Video");
14609 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14610 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14612 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14613 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14614 _codec ("DVCProHD Video");
14615 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14616 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14618 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14619 _codec ("Apple Graphics (SMC)");
14620 caps = gst_caps_new_empty_simple ("video/x-smc");
14622 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14624 caps = gst_caps_new_empty_simple ("video/x-vp3");
14626 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14627 _codec ("VP6 Flash");
14628 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14632 caps = gst_caps_new_empty_simple ("video/x-theora");
14633 /* theora uses one byte of padding in the data stream because it does not
14634 * allow 0 sized packets while theora does */
14635 entry->padding = 1;
14639 caps = gst_caps_new_empty_simple ("video/x-dirac");
14641 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14642 _codec ("TIFF still images");
14643 caps = gst_caps_new_empty_simple ("image/tiff");
14645 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14646 _codec ("Apple Intermediate Codec");
14647 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14649 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14650 _codec ("AVID DNxHD");
14651 caps = gst_caps_from_string ("video/x-dnxhd");
14655 _codec ("On2 VP8");
14656 caps = gst_caps_from_string ("video/x-vp8");
14659 _codec ("Google VP9");
14660 caps = gst_caps_from_string ("video/x-vp9");
14663 _codec ("Apple ProRes LT");
14665 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14669 _codec ("Apple ProRes HQ");
14671 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14675 _codec ("Apple ProRes");
14677 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14681 _codec ("Apple ProRes Proxy");
14683 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14687 _codec ("Apple ProRes 4444");
14689 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14692 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14693 if (entry->bits_per_sample > 0) {
14694 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14699 _codec ("Apple ProRes 4444 XQ");
14701 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14704 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14705 if (entry->bits_per_sample > 0) {
14706 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14711 _codec ("GoPro CineForm");
14712 caps = gst_caps_from_string ("video/x-cineform");
14717 caps = gst_caps_new_simple ("video/x-wmv",
14718 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14722 caps = gst_caps_new_empty_simple ("video/x-av1");
14724 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14727 caps = _get_unknown_codec_name ("video", fourcc);
14732 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14735 gst_video_info_init (&info);
14736 gst_video_info_set_format (&info, format, entry->width, entry->height);
14738 caps = gst_video_info_to_caps (&info);
14739 *codec_name = gst_pb_utils_get_codec_description (caps);
14741 /* enable clipping for raw video streams */
14742 stream->need_clip = TRUE;
14743 stream->alignment = 32;
14750 round_up_pow2 (guint n)
14762 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14763 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14764 int len, gchar ** codec_name)
14767 const GstStructure *s;
14770 GstAudioFormat format = 0;
14773 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14775 depth = entry->bytes_per_packet * 8;
14778 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14780 /* 8-bit audio is unsigned */
14782 format = GST_AUDIO_FORMAT_U8;
14783 /* otherwise it's signed and big-endian just like 'twos' */
14785 endian = G_BIG_ENDIAN;
14792 endian = G_LITTLE_ENDIAN;
14795 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14797 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14801 caps = gst_caps_new_simple ("audio/x-raw",
14802 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14803 "layout", G_TYPE_STRING, "interleaved", NULL);
14804 stream->alignment = GST_ROUND_UP_8 (depth);
14805 stream->alignment = round_up_pow2 (stream->alignment);
14809 _codec ("Raw 64-bit floating-point audio");
14810 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14812 caps = gst_caps_new_simple ("audio/x-raw",
14813 "format", G_TYPE_STRING, "F64BE",
14814 "layout", G_TYPE_STRING, "interleaved", NULL);
14815 stream->alignment = 8;
14818 _codec ("Raw 32-bit floating-point audio");
14819 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14821 caps = gst_caps_new_simple ("audio/x-raw",
14822 "format", G_TYPE_STRING, "F32BE",
14823 "layout", G_TYPE_STRING, "interleaved", NULL);
14824 stream->alignment = 4;
14827 _codec ("Raw 24-bit PCM audio");
14828 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14830 caps = gst_caps_new_simple ("audio/x-raw",
14831 "format", G_TYPE_STRING, "S24BE",
14832 "layout", G_TYPE_STRING, "interleaved", NULL);
14833 stream->alignment = 4;
14836 _codec ("Raw 32-bit PCM audio");
14837 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14839 caps = gst_caps_new_simple ("audio/x-raw",
14840 "format", G_TYPE_STRING, "S32BE",
14841 "layout", G_TYPE_STRING, "interleaved", NULL);
14842 stream->alignment = 4;
14845 _codec ("Raw 16-bit PCM audio");
14846 caps = gst_caps_new_simple ("audio/x-raw",
14847 "format", G_TYPE_STRING, "S16LE",
14848 "layout", G_TYPE_STRING, "interleaved", NULL);
14849 stream->alignment = 2;
14852 _codec ("Mu-law audio");
14853 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14856 _codec ("A-law audio");
14857 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14861 _codec ("Microsoft ADPCM");
14862 /* Microsoft ADPCM-ACM code 2 */
14863 caps = gst_caps_new_simple ("audio/x-adpcm",
14864 "layout", G_TYPE_STRING, "microsoft", NULL);
14868 _codec ("DVI/IMA ADPCM");
14869 caps = gst_caps_new_simple ("audio/x-adpcm",
14870 "layout", G_TYPE_STRING, "dvi", NULL);
14874 _codec ("DVI/Intel IMA ADPCM");
14875 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14876 caps = gst_caps_new_simple ("audio/x-adpcm",
14877 "layout", G_TYPE_STRING, "quicktime", NULL);
14881 /* MPEG layer 3, CBR only (pre QT4.1) */
14884 _codec ("MPEG-1 layer 3");
14885 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14886 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14887 "mpegversion", G_TYPE_INT, 1, NULL);
14889 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14890 _codec ("MPEG-1 layer 2");
14892 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14893 "mpegversion", G_TYPE_INT, 1, NULL);
14896 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14897 _codec ("EAC-3 audio");
14898 caps = gst_caps_new_simple ("audio/x-eac3",
14899 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14900 entry->sampled = TRUE;
14902 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14904 _codec ("AC-3 audio");
14905 caps = gst_caps_new_simple ("audio/x-ac3",
14906 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14907 entry->sampled = TRUE;
14909 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14910 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14911 _codec ("DTS audio");
14912 caps = gst_caps_new_simple ("audio/x-dts",
14913 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14914 entry->sampled = TRUE;
14916 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14917 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14918 _codec ("DTS-HD audio");
14919 caps = gst_caps_new_simple ("audio/x-dts",
14920 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14921 entry->sampled = TRUE;
14925 caps = gst_caps_new_simple ("audio/x-mace",
14926 "maceversion", G_TYPE_INT, 3, NULL);
14930 caps = gst_caps_new_simple ("audio/x-mace",
14931 "maceversion", G_TYPE_INT, 6, NULL);
14933 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14935 caps = gst_caps_new_empty_simple ("application/ogg");
14937 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14938 _codec ("DV audio");
14939 caps = gst_caps_new_empty_simple ("audio/x-dv");
14942 _codec ("MPEG-4 AAC audio");
14943 caps = gst_caps_new_simple ("audio/mpeg",
14944 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14945 "stream-format", G_TYPE_STRING, "raw", NULL);
14947 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14948 _codec ("QDesign Music");
14949 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14952 _codec ("QDesign Music v.2");
14953 /* FIXME: QDesign music version 2 (no constant) */
14954 if (FALSE && data) {
14955 caps = gst_caps_new_simple ("audio/x-qdm2",
14956 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14957 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14958 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14960 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14964 _codec ("GSM audio");
14965 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14968 _codec ("AMR audio");
14969 caps = gst_caps_new_empty_simple ("audio/AMR");
14972 _codec ("AMR-WB audio");
14973 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14976 _codec ("Quicktime IMA ADPCM");
14977 caps = gst_caps_new_simple ("audio/x-adpcm",
14978 "layout", G_TYPE_STRING, "quicktime", NULL);
14981 _codec ("Apple lossless audio");
14982 caps = gst_caps_new_empty_simple ("audio/x-alac");
14985 _codec ("Free Lossless Audio Codec");
14986 caps = gst_caps_new_simple ("audio/x-flac",
14987 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14989 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14990 _codec ("QualComm PureVoice");
14991 caps = gst_caps_from_string ("audio/qcelp");
14996 caps = gst_caps_new_empty_simple ("audio/x-wma");
15000 caps = gst_caps_new_empty_simple ("audio/x-opus");
15007 GstAudioFormat format;
15010 FLAG_IS_FLOAT = 0x1,
15011 FLAG_IS_BIG_ENDIAN = 0x2,
15012 FLAG_IS_SIGNED = 0x4,
15013 FLAG_IS_PACKED = 0x8,
15014 FLAG_IS_ALIGNED_HIGH = 0x10,
15015 FLAG_IS_NON_INTERLEAVED = 0x20
15017 _codec ("Raw LPCM audio");
15019 if (data && len >= 36) {
15020 depth = QT_UINT32 (data + 24);
15021 flags = QT_UINT32 (data + 28);
15022 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15024 if ((flags & FLAG_IS_FLOAT) == 0) {
15029 if ((flags & FLAG_IS_ALIGNED_HIGH))
15032 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15033 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15034 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15035 caps = gst_caps_new_simple ("audio/x-raw",
15036 "format", G_TYPE_STRING,
15038 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15039 "UNKNOWN", "layout", G_TYPE_STRING,
15040 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15041 "interleaved", NULL);
15042 stream->alignment = GST_ROUND_UP_8 (depth);
15043 stream->alignment = round_up_pow2 (stream->alignment);
15048 if (flags & FLAG_IS_BIG_ENDIAN)
15049 format = GST_AUDIO_FORMAT_F64BE;
15051 format = GST_AUDIO_FORMAT_F64LE;
15053 if (flags & FLAG_IS_BIG_ENDIAN)
15054 format = GST_AUDIO_FORMAT_F32BE;
15056 format = GST_AUDIO_FORMAT_F32LE;
15058 caps = gst_caps_new_simple ("audio/x-raw",
15059 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15060 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15061 "non-interleaved" : "interleaved", NULL);
15062 stream->alignment = width / 8;
15066 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15069 caps = gst_caps_new_empty_simple ("audio/x-ac4");
15072 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15076 caps = _get_unknown_codec_name ("audio", fourcc);
15082 GstCaps *templ_caps =
15083 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15084 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15085 gst_caps_unref (caps);
15086 gst_caps_unref (templ_caps);
15087 caps = intersection;
15090 /* enable clipping for raw audio streams */
15091 s = gst_caps_get_structure (caps, 0);
15092 name = gst_structure_get_name (s);
15093 if (g_str_has_prefix (name, "audio/x-raw")) {
15094 stream->need_clip = TRUE;
15095 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15096 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15097 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15098 stream->max_buffer_size);
15104 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15105 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15106 const guint8 * stsd_entry_data, gchar ** codec_name)
15110 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15114 _codec ("DVD subtitle");
15115 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15116 stream->process_func = gst_qtdemux_process_buffer_dvd;
15119 _codec ("Quicktime timed text");
15122 _codec ("3GPP timed text");
15124 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15126 /* actual text piece needs to be extracted */
15127 stream->process_func = gst_qtdemux_process_buffer_text;
15130 _codec ("XML subtitles");
15131 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15136 const gchar *buf = "WEBVTT\n\n";
15138 _codec ("WebVTT subtitles");
15139 caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15140 stream->process_func = gst_qtdemux_process_buffer_wvtt;
15142 /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15143 buffer = gst_buffer_new_and_alloc (8);
15144 gst_buffer_fill (buffer, 0, buf, 8);
15145 stream->buffers = g_slist_append (stream->buffers, buffer);
15150 _codec ("CEA 608 Closed Caption");
15152 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15153 G_TYPE_STRING, "s334-1a", NULL);
15154 stream->process_func = gst_qtdemux_process_buffer_clcp;
15155 stream->need_split = TRUE;
15158 _codec ("CEA 708 Closed Caption");
15160 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15161 G_TYPE_STRING, "cdp", NULL);
15162 stream->process_func = gst_qtdemux_process_buffer_clcp;
15167 caps = _get_unknown_codec_name ("text", fourcc);
15175 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15176 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15177 const guint8 * stsd_entry_data, gchar ** codec_name)
15183 _codec ("MPEG 1 video");
15184 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15185 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15195 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15196 const gchar * system_id)
15200 if (!qtdemux->protection_system_ids)
15201 qtdemux->protection_system_ids =
15202 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15203 /* Check whether we already have an entry for this system ID. */
15204 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15205 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15206 if (g_ascii_strcasecmp (system_id, id) == 0) {
15210 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15211 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,