2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
12 * Copyright (C) <2016> British Broadcasting Corporation
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with this library; if not, write to the
26 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
31 * SECTION:element-qtdemux
34 * Demuxes a .mov file into raw or compressed audio and/or video streams.
36 * This element supports both push and pull-based scheduling, depending on the
37 * capabilities of the upstream elements.
39 * ## Example launch line
41 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
42 * ]| Play (parse and decode) a .mov file and try to output it to
43 * an automatically detected soundcard and videosink. If the MOV file contains
44 * compressed audio or video data, this will only work if you have the
45 * right decoder elements/plugins installed.
53 #include <glib/gi18n-lib.h>
55 #include <glib/gprintf.h>
56 #include <gst/base/base.h>
57 #include <gst/tag/tag.h>
58 #include <gst/audio/audio.h>
59 #include <gst/riff/riff.h>
60 #include <gst/pbutils/pbutils.h>
62 #include "gstisomp4elements.h"
63 #include "qtatomparser.h"
64 #include "qtdemux_types.h"
65 #include "qtdemux_dump.h"
67 #include "descriptors.h"
68 #include "qtdemux_lang.h"
70 #include "qtpalette.h"
71 #include "qtdemux_tags.h"
72 #include "qtdemux_tree.h"
73 #include "qtdemux-webvtt.h"
79 #include <gst/math-compat.h>
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
97 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
99 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
101 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
103 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
104 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
105 #define QTDEMUX_NTH_STREAM(demux,idx) \
106 QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
107 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
108 QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
110 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
112 GST_DEBUG_CATEGORY (qtdemux_debug);
113 #define GST_CAT_DEFAULT qtdemux_debug
115 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
116 typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
118 /* Macros for converting to/from timescale */
119 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
120 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
122 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
123 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
125 /* timestamp is the DTS */
126 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
127 /* timestamp + offset + cslg_shift is the outgoing PTS */
128 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
129 /* timestamp + offset is the PTS used for internal seek calculations */
130 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
131 /* timestamp + duration - dts is the duration */
132 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
134 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
136 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
137 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
138 GST_TRACE("Locking from thread %p", g_thread_self()); \
139 g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
140 GST_TRACE("Locked from thread %p", g_thread_self()); \
143 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
144 GST_TRACE("Unlocking from thread %p", g_thread_self()); \
145 g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
149 * Quicktime has tracks and segments. A track is a continuous piece of
150 * multimedia content. The track is not always played from start to finish but
151 * instead, pieces of the track are 'cut out' and played in sequence. This is
152 * what the segments do.
154 * Inside the track we have keyframes (K) and delta frames. The track has its
155 * own timing, which starts from 0 and extends to end. The position in the track
156 * is called the media_time.
158 * The segments now describe the pieces that should be played from this track
159 * and are basically tuples of media_time/duration/rate entries. We can have
160 * multiple segments and they are all played after one another. An example:
162 * segment 1: media_time: 1 second, duration: 1 second, rate 1
163 * segment 2: media_time: 3 second, duration: 2 second, rate 2
165 * To correctly play back this track, one must play: 1 second of media starting
166 * from media_time 1 followed by 2 seconds of media starting from media_time 3
169 * Each of the segments will be played at a specific time, the first segment at
170 * time 0, the second one after the duration of the first one, etc.. Note that
171 * the time in resulting playback is not identical to the media_time of the
174 * Visually, assuming the track has 4 second of media_time:
177 * .-----------------------------------------------------------.
178 * track: | K.....K.........K........K.......K.......K...........K... |
179 * '-----------------------------------------------------------'
181 * .------------^ ^ .----------^ ^
182 * / .-------------' / .------------------'
184 * .--------------. .--------------.
185 * | segment 1 | | segment 2 |
186 * '--------------' '--------------'
188 * The challenge here is to cut out the right pieces of the track for each of
189 * the playback segments. This fortunately can easily be done with the SEGMENT
190 * events of GStreamer.
192 * For playback of segment 1, we need to provide the decoder with the keyframe
193 * (a), in the above figure, but we must instruct it only to output the decoded
194 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
195 * position set to the time of the segment: 0.
197 * We then proceed to push data from keyframe (a) to frame (b). The decoder
198 * decodes but clips all before media_time 1.
200 * After finishing a segment, we push out a new SEGMENT event with the clipping
201 * boundaries of the new data.
203 * This is a good usecase for the GStreamer accumulated SEGMENT events.
206 struct _QtDemuxSegment
208 /* global time and duration, all gst time */
210 GstClockTime stop_time;
211 GstClockTime duration;
212 /* media time of trak, all gst time */
213 GstClockTime media_start;
214 GstClockTime media_stop;
216 /* Media start time in trak timescale units */
217 guint32 trak_media_start;
220 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
222 /* Used with fragmented MP4 files (mfra atom) */
223 struct _QtDemuxRandomAccessEntry
230 /* Contains properties and cryptographic info for a set of samples from a
231 * track protected using Common Encryption (cenc) */
232 struct _QtDemuxCencSampleSetInfo
234 GstStructure *default_properties;
236 /* @crypto_info holds one GstStructure per sample */
237 GPtrArray *crypto_info;
240 struct _QtDemuxAavdEncryptionInfo
242 GstStructure *default_properties;
246 qt_demux_state_string (enum QtDemuxState state)
249 case QTDEMUX_STATE_INITIAL:
251 case QTDEMUX_STATE_HEADER:
253 case QTDEMUX_STATE_MOVIE:
255 case QTDEMUX_STATE_BUFFER_MDAT:
256 return "<BUFFER_MDAT>";
262 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
264 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
266 static GstStaticPadTemplate gst_qtdemux_sink_template =
267 GST_STATIC_PAD_TEMPLATE ("sink",
270 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
274 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
275 GST_STATIC_PAD_TEMPLATE ("video_%u",
278 GST_STATIC_CAPS_ANY);
280 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
281 GST_STATIC_PAD_TEMPLATE ("audio_%u",
284 GST_STATIC_CAPS_ANY);
286 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
287 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
290 GST_STATIC_CAPS_ANY);
292 #define gst_qtdemux_parent_class parent_class
293 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
294 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
295 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
297 static void gst_qtdemux_dispose (GObject * object);
298 static void gst_qtdemux_finalize (GObject * object);
301 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
302 GstClockTime media_time);
304 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
305 QtDemuxStream * str, gint64 media_offset);
308 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
309 static GstIndex *gst_qtdemux_get_index (GstElement * element);
311 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
312 GstStateChange transition);
313 static void gst_qtdemux_set_context (GstElement * element,
314 GstContext * context);
315 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
316 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
317 GstObject * parent, GstPadMode mode, gboolean active);
319 static void gst_qtdemux_loop (GstPad * pad);
320 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
322 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
324 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
326 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
327 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
328 QtDemuxStream * stream);
329 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
330 QtDemuxStream * stream);
331 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
334 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
336 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
337 const guint8 * buffer, guint length);
338 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
339 const guint8 * buffer, guint length);
340 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
342 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
343 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
345 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
346 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
347 const guint8 * stsd_entry_data, gchar ** codec_name);
348 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
349 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
350 const guint8 * data, int len, gchar ** codec_name);
351 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
352 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
353 gchar ** codec_name);
354 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
355 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
356 const guint8 * stsd_entry_data, gchar ** codec_name);
358 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
359 QtDemuxStream * stream, guint32 n);
360 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
361 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
362 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
363 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
364 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
365 static void qtdemux_do_allocation (QtDemuxStream * stream,
366 GstQTDemux * qtdemux);
367 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
368 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
369 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
370 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
371 GstClockTime * _start, GstClockTime * _stop);
372 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
373 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
375 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
376 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
378 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
380 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
381 QtDemuxStream * stream, guint sample_index);
382 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
384 static void qtdemux_gst_structure_free (GstStructure * gststructure);
385 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
388 gst_qtdemux_class_init (GstQTDemuxClass * klass)
390 GObjectClass *gobject_class;
391 GstElementClass *gstelement_class;
393 gobject_class = (GObjectClass *) klass;
394 gstelement_class = (GstElementClass *) klass;
396 parent_class = g_type_class_peek_parent (klass);
398 gobject_class->dispose = gst_qtdemux_dispose;
399 gobject_class->finalize = gst_qtdemux_finalize;
401 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
403 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
404 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
406 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
408 gst_tag_register_musicbrainz_tags ();
410 gst_element_class_add_static_pad_template (gstelement_class,
411 &gst_qtdemux_sink_template);
412 gst_element_class_add_static_pad_template (gstelement_class,
413 &gst_qtdemux_videosrc_template);
414 gst_element_class_add_static_pad_template (gstelement_class,
415 &gst_qtdemux_audiosrc_template);
416 gst_element_class_add_static_pad_template (gstelement_class,
417 &gst_qtdemux_subsrc_template);
418 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
420 "Demultiplex a QuickTime file into audio and video streams",
421 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
423 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
428 gst_qtdemux_init (GstQTDemux * qtdemux)
431 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
432 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
433 gst_pad_set_activatemode_function (qtdemux->sinkpad,
434 qtdemux_sink_activate_mode);
435 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
436 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
437 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
438 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
440 qtdemux->adapter = gst_adapter_new ();
441 g_queue_init (&qtdemux->protection_event_queue);
442 qtdemux->flowcombiner = gst_flow_combiner_new ();
443 g_mutex_init (&qtdemux->expose_lock);
445 qtdemux->active_streams = g_ptr_array_new_with_free_func
446 ((GDestroyNotify) gst_qtdemux_stream_unref);
447 qtdemux->old_streams = g_ptr_array_new_with_free_func
448 ((GDestroyNotify) gst_qtdemux_stream_unref);
450 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
452 gst_qtdemux_reset (qtdemux, TRUE);
456 gst_qtdemux_finalize (GObject * object)
458 GstQTDemux *qtdemux = GST_QTDEMUX (object);
460 g_free (qtdemux->redirect_location);
462 G_OBJECT_CLASS (parent_class)->finalize (object);
466 gst_qtdemux_dispose (GObject * object)
468 GstQTDemux *qtdemux = GST_QTDEMUX (object);
470 if (qtdemux->adapter) {
471 g_object_unref (G_OBJECT (qtdemux->adapter));
472 qtdemux->adapter = NULL;
474 gst_tag_list_unref (qtdemux->tag_list);
475 gst_flow_combiner_free (qtdemux->flowcombiner);
476 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
478 g_queue_clear (&qtdemux->protection_event_queue);
480 g_free (qtdemux->cenc_aux_info_sizes);
481 qtdemux->cenc_aux_info_sizes = NULL;
482 g_mutex_clear (&qtdemux->expose_lock);
484 g_ptr_array_free (qtdemux->active_streams, TRUE);
485 g_ptr_array_free (qtdemux->old_streams, TRUE);
487 G_OBJECT_CLASS (parent_class)->dispose (object);
491 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
493 if (qtdemux->redirect_location) {
494 GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
495 (_("This file contains no playable streams.")),
496 ("no known streams found, a redirect message has been posted"),
497 ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
499 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
500 (_("This file contains no playable streams.")),
501 ("no known streams found"));
506 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
508 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
509 mem, size, 0, size, mem, free_func);
513 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
520 if (G_UNLIKELY (size == 0)) {
522 GstBuffer *tmp = NULL;
524 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
525 if (ret != GST_FLOW_OK)
528 gst_buffer_map (tmp, &map, GST_MAP_READ);
529 size = QT_UINT32 (map.data);
530 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
532 gst_buffer_unmap (tmp, &map);
533 gst_buffer_unref (tmp);
536 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
537 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
538 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
539 /* we're pulling header but already got most interesting bits,
540 * so never mind the rest (e.g. tags) (that much) */
541 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
545 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
546 (_("This file is invalid and cannot be played.")),
547 ("atom has bogus size %" G_GUINT64_FORMAT, size));
548 return GST_FLOW_ERROR;
552 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
554 if (G_UNLIKELY (flow != GST_FLOW_OK))
557 bsize = gst_buffer_get_size (*buf);
558 /* Catch short reads - we don't want any partial atoms */
559 if (G_UNLIKELY (bsize < size)) {
560 GST_WARNING_OBJECT (qtdemux,
561 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
562 gst_buffer_unref (*buf);
572 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
573 GstFormat src_format, gint64 src_value, GstFormat dest_format,
577 QtDemuxStream *stream = gst_pad_get_element_private (pad);
580 if (stream->subtype != FOURCC_vide) {
585 switch (src_format) {
586 case GST_FORMAT_TIME:
587 switch (dest_format) {
588 case GST_FORMAT_BYTES:{
589 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
595 *dest_value = stream->samples[index].offset;
597 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
598 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
599 GST_TIME_ARGS (src_value), *dest_value);
607 case GST_FORMAT_BYTES:
608 switch (dest_format) {
609 case GST_FORMAT_TIME:{
611 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
620 QTSTREAMTIME_TO_GSTTIME (stream,
621 stream->samples[index].timestamp);
622 GST_DEBUG_OBJECT (qtdemux,
623 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
624 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
643 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
645 gboolean res = FALSE;
647 *duration = GST_CLOCK_TIME_NONE;
649 if (qtdemux->duration != 0 &&
650 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
651 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
654 *duration = GST_CLOCK_TIME_NONE;
661 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
664 gboolean res = FALSE;
665 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
667 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
669 switch (GST_QUERY_TYPE (query)) {
670 case GST_QUERY_POSITION:{
673 gst_query_parse_position (query, &fmt, NULL);
674 if (fmt == GST_FORMAT_TIME
675 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
676 gst_query_set_position (query, GST_FORMAT_TIME,
677 qtdemux->segment.position);
682 case GST_QUERY_DURATION:{
685 gst_query_parse_duration (query, &fmt, NULL);
686 if (fmt == GST_FORMAT_TIME) {
687 /* First try to query upstream */
688 res = gst_pad_query_default (pad, parent, query);
690 GstClockTime duration;
691 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
692 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
699 case GST_QUERY_CONVERT:{
700 GstFormat src_fmt, dest_fmt;
701 gint64 src_value, dest_value = 0;
703 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
705 res = gst_qtdemux_src_convert (qtdemux, pad,
706 src_fmt, src_value, dest_fmt, &dest_value);
708 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
712 case GST_QUERY_FORMATS:
713 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
716 case GST_QUERY_SEEKING:{
720 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
722 if (fmt == GST_FORMAT_BYTES) {
723 /* We always refuse BYTES seeks from downstream */
727 /* try upstream first */
728 res = gst_pad_query_default (pad, parent, query);
731 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
732 if (fmt == GST_FORMAT_TIME) {
733 GstClockTime duration;
735 gst_qtdemux_get_duration (qtdemux, &duration);
737 if (!qtdemux->pullbased) {
740 /* we might be able with help from upstream */
742 q = gst_query_new_seeking (GST_FORMAT_BYTES);
743 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
744 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
745 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
749 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
755 case GST_QUERY_SEGMENT:
760 format = qtdemux->segment.format;
763 gst_segment_to_stream_time (&qtdemux->segment, format,
764 qtdemux->segment.start);
765 if ((stop = qtdemux->segment.stop) == -1)
766 stop = qtdemux->segment.duration;
768 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
770 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
775 res = gst_pad_query_default (pad, parent, query);
783 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
785 if (G_LIKELY (stream->pad)) {
786 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
787 GST_DEBUG_PAD_NAME (stream->pad));
789 if (!gst_tag_list_is_empty (stream->stream_tags)) {
790 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
791 stream->stream_tags);
792 gst_pad_push_event (stream->pad,
793 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
796 if (G_UNLIKELY (stream->send_global_tags)) {
797 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
799 gst_pad_push_event (stream->pad,
800 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
801 stream->send_global_tags = FALSE;
806 /* push event on all source pads; takes ownership of the event */
808 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
810 gboolean has_valid_stream = FALSE;
811 GstEventType etype = GST_EVENT_TYPE (event);
814 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
815 GST_EVENT_TYPE_NAME (event));
817 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
819 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
820 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
822 if ((pad = stream->pad)) {
823 has_valid_stream = TRUE;
825 if (etype == GST_EVENT_EOS) {
826 /* let's not send twice */
827 if (stream->sent_eos)
829 stream->sent_eos = TRUE;
832 gst_pad_push_event (pad, gst_event_ref (event));
836 gst_event_unref (event);
838 /* if it is EOS and there are no pads, post an error */
839 if (!has_valid_stream && etype == GST_EVENT_EOS) {
840 gst_qtdemux_post_no_playable_stream_error (qtdemux);
850 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
852 if ((gint64) s1->timestamp > *media_time)
854 if ((gint64) s1->timestamp == *media_time)
860 /* find the index of the sample that includes the data for @media_time using a
861 * binary search. Only to be called in optimized cases of linear search below.
863 * Returns the index of the sample with the corresponding *DTS*.
866 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
869 QtDemuxSample *result;
872 /* convert media_time to mov format */
874 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
876 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
877 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
878 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
880 if (G_LIKELY (result))
881 index = result - str->samples;
890 /* find the index of the sample that includes the data for @media_offset using a
893 * Returns the index of the sample.
896 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
897 QtDemuxStream * str, gint64 media_offset)
899 QtDemuxSample *result = str->samples;
902 if (result == NULL || str->n_samples == 0)
905 if (media_offset == result->offset)
909 while (index < str->n_samples - 1) {
910 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
913 if (media_offset < result->offset)
924 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
929 /* find the index of the sample that includes the data for @media_time using a
930 * linear search, and keeping in mind that not all samples may have been parsed
931 * yet. If possible, it will delegate to binary search.
933 * Returns the index of the sample.
936 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
937 GstClockTime media_time)
941 QtDemuxSample *sample;
943 /* convert media_time to mov format */
945 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
947 sample = str->samples;
948 if (mov_time == sample->timestamp + sample->pts_offset)
951 /* use faster search if requested time in already parsed range */
952 sample = str->samples + str->stbl_index;
953 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
954 index = gst_qtdemux_find_index (qtdemux, str, media_time);
955 sample = str->samples + index;
957 while (index < str->n_samples - 1) {
958 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
961 sample = str->samples + index + 1;
962 if (mov_time < sample->timestamp) {
963 sample = str->samples + index;
971 /* sample->timestamp is now <= media_time, need to find the corresponding
972 * PTS now by looking backwards */
973 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
975 sample = str->samples + index;
983 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
988 /* find the index of the keyframe needed to decode the sample at @index
989 * of stream @str, or of a subsequent keyframe (depending on @next)
991 * Returns the index of the keyframe.
994 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
995 guint32 index, gboolean next)
997 guint32 new_index = index;
999 if (index >= str->n_samples) {
1000 new_index = str->n_samples;
1004 /* all keyframes, return index */
1005 if (str->all_keyframe) {
1010 /* else search until we have a keyframe */
1011 while (new_index < str->n_samples) {
1012 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1015 if (str->samples[new_index].keyframe)
1027 if (new_index == str->n_samples) {
1028 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1033 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1034 "gave %u", next ? "after" : "before", index, new_index);
1041 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1046 /* find the segment for @time_position for @stream
1048 * Returns the index of the segment containing @time_position.
1049 * Returns the last segment and sets the @eos variable to TRUE
1050 * if the time is beyond the end. @eos may be NULL
1053 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1054 GstClockTime time_position)
1059 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1060 GST_TIME_ARGS (time_position));
1063 for (i = 0; i < stream->n_segments; i++) {
1064 QtDemuxSegment *segment = &stream->segments[i];
1066 GST_LOG_OBJECT (stream->pad,
1067 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1068 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1070 /* For the last segment we include stop_time in the last segment */
1071 if (i < stream->n_segments - 1) {
1072 if (segment->time <= time_position && time_position < segment->stop_time) {
1073 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1078 /* Last segment always matches */
1086 /* move the stream @str to the sample position @index.
1088 * Updates @str->sample_index and marks discontinuity if needed.
1091 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1094 /* no change needed */
1095 if (index == str->sample_index)
1098 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1101 /* position changed, we have a discont */
1102 str->sample_index = index;
1103 str->offset_in_sample = 0;
1104 /* Each time we move in the stream we store the position where we are
1106 str->from_sample = index;
1107 str->discont = TRUE;
1111 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1112 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1115 gint64 min_byte_offset = -1;
1118 min_offset = desired_time;
1120 /* for each stream, find the index of the sample in the segment
1121 * and move back to the previous keyframe. */
1122 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1124 guint32 index, kindex;
1126 GstClockTime media_start;
1127 GstClockTime media_time;
1128 GstClockTime seg_time;
1129 QtDemuxSegment *seg;
1130 gboolean empty_segment = FALSE;
1132 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1134 if (CUR_STREAM (str)->sparse && !use_sparse)
1137 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1138 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1140 /* get segment and time in the segment */
1141 seg = &str->segments[seg_idx];
1142 seg_time = (desired_time - seg->time) * seg->rate;
1144 while (QTSEGMENT_IS_EMPTY (seg)) {
1146 empty_segment = TRUE;
1147 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1150 if (seg_idx == str->n_segments)
1152 seg = &str->segments[seg_idx];
1155 if (seg_idx == str->n_segments) {
1156 /* FIXME track shouldn't have the last segment as empty, but if it
1157 * happens we better handle it */
1161 /* get the media time in the segment */
1162 media_start = seg->media_start + seg_time;
1164 /* get the index of the sample with media time */
1165 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1166 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1167 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1168 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1171 /* shift to next frame if we are looking for next keyframe */
1172 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1173 && index < str->stbl_index)
1176 if (!empty_segment) {
1177 /* find previous keyframe */
1178 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1180 /* we will settle for one before if none found after */
1181 if (next && kindex == -1)
1182 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1184 /* Update the requested time whenever a keyframe was found, to make it
1185 * accurate and avoid having the first buffer fall outside of the segment
1190 /* get timestamp of keyframe */
1191 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1192 GST_DEBUG_OBJECT (qtdemux,
1193 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1194 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1195 str->samples[kindex].offset);
1197 /* keyframes in the segment get a chance to change the
1198 * desired_offset. keyframes out of the segment are
1200 if (media_time >= seg->media_start) {
1201 GstClockTime seg_time;
1203 /* this keyframe is inside the segment, convert back to
1205 seg_time = (media_time - seg->media_start) + seg->time;
1206 if ((!next && (seg_time < min_offset)) ||
1207 (next && (seg_time > min_offset)))
1208 min_offset = seg_time;
1213 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1214 min_byte_offset = str->samples[index].offset;
1218 *key_time = min_offset;
1220 *key_offset = min_byte_offset;
1224 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1225 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1229 g_return_val_if_fail (format != NULL, FALSE);
1230 g_return_val_if_fail (cur != NULL, FALSE);
1231 g_return_val_if_fail (stop != NULL, FALSE);
1233 if (*format == GST_FORMAT_TIME)
1237 if (cur_type != GST_SEEK_TYPE_NONE)
1238 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1239 if (res && stop_type != GST_SEEK_TYPE_NONE)
1240 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1243 *format = GST_FORMAT_TIME;
1248 /* perform seek in push based mode:
1249 find BYTE position to move to based on time and delegate to upstream
1252 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1257 GstSeekType cur_type, stop_type;
1258 gint64 cur, stop, key_cur;
1261 gint64 original_stop;
1264 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1266 gst_event_parse_seek (event, &rate, &format, &flags,
1267 &cur_type, &cur, &stop_type, &stop);
1268 seqnum = gst_event_get_seqnum (event);
1270 /* Directly send the instant-rate-change event here before taking the
1271 * stream-lock so that it can be applied as soon as possible */
1272 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1275 /* instant rate change only supported if direction does not change. All
1276 * other requirements are already checked before creating the seek event
1277 * but let's double-check here to be sure */
1278 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1279 (qtdemux->segment.rate < 0 && rate > 0) ||
1280 cur_type != GST_SEEK_TYPE_NONE ||
1281 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1282 GST_ERROR_OBJECT (qtdemux,
1283 "Instant rate change seeks only supported in the "
1284 "same direction, without flushing and position change");
1288 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1289 (GstSegmentFlags) flags);
1290 gst_event_set_seqnum (ev, seqnum);
1291 gst_qtdemux_push_event (qtdemux, ev);
1295 /* only forward streaming and seeking is possible */
1297 goto unsupported_seek;
1299 /* convert to TIME if needed and possible */
1300 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1304 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1305 * the original stop position to use when upstream pushes the new segment
1307 original_stop = stop;
1310 /* find reasonable corresponding BYTE position,
1311 * also try to mind about keyframes, since we can not go back a bit for them
1313 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1314 * mostly just work, but let's not yet boldly go there ... */
1315 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1320 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1321 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1324 GST_OBJECT_LOCK (qtdemux);
1325 qtdemux->seek_offset = byte_cur;
1326 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1327 qtdemux->push_seek_start = cur;
1329 qtdemux->push_seek_start = key_cur;
1332 if (stop_type == GST_SEEK_TYPE_NONE) {
1333 qtdemux->push_seek_stop = qtdemux->segment.stop;
1335 qtdemux->push_seek_stop = original_stop;
1337 GST_OBJECT_UNLOCK (qtdemux);
1339 qtdemux->segment_seqnum = seqnum;
1340 /* BYTE seek event */
1341 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1343 gst_event_set_seqnum (event, seqnum);
1344 res = gst_pad_push_event (qtdemux->sinkpad, event);
1351 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1357 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1362 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1367 /* perform the seek.
1369 * We set all segment_indexes in the streams to unknown and
1370 * adjust the time_position to the desired position. this is enough
1371 * to trigger a segment switch in the streaming thread to start
1372 * streaming from the desired position.
1374 * Keyframe seeking is a little more complicated when dealing with
1375 * segments. Ideally we want to move to the previous keyframe in
1376 * the segment but there might not be a keyframe in the segment. In
1377 * fact, none of the segments could contain a keyframe. We take a
1378 * practical approach: seek to the previous keyframe in the segment,
1379 * if there is none, seek to the beginning of the segment.
1381 * Called with STREAM_LOCK
1384 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1385 guint32 seqnum, GstSeekFlags flags)
1387 gint64 desired_offset;
1390 desired_offset = segment->position;
1392 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1393 GST_TIME_ARGS (desired_offset));
1395 /* may not have enough fragmented info to do this adjustment,
1396 * and we can't scan (and probably should not) at this time with
1397 * possibly flushing upstream */
1398 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1400 gboolean next, before, after;
1402 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1403 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1404 next = after && !before;
1405 if (segment->rate < 0)
1408 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1410 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1411 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1412 desired_offset = min_offset;
1415 /* and set all streams to the final position */
1416 GST_OBJECT_LOCK (qtdemux);
1417 gst_flow_combiner_reset (qtdemux->flowcombiner);
1418 GST_OBJECT_UNLOCK (qtdemux);
1419 qtdemux->segment_seqnum = seqnum;
1420 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1421 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1423 stream->time_position = desired_offset;
1424 stream->accumulated_base = 0;
1425 stream->sample_index = -1;
1426 stream->offset_in_sample = 0;
1427 stream->segment_index = -1;
1428 stream->sent_eos = FALSE;
1429 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1431 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1432 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1434 segment->position = desired_offset;
1435 if (segment->rate >= 0) {
1436 segment->start = desired_offset;
1437 /* We need to update time as we update start in that direction */
1438 segment->time = desired_offset;
1440 /* we stop at the end */
1441 if (segment->stop == -1)
1442 segment->stop = segment->duration;
1444 segment->stop = desired_offset;
1447 if (qtdemux->fragmented)
1448 qtdemux->fragmented_seek_pending = TRUE;
1453 /* do a seek in pull based mode */
1455 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1460 GstSeekType cur_type, stop_type;
1462 gboolean flush, instant_rate_change;
1464 GstSegment seeksegment;
1465 guint32 seqnum = GST_SEQNUM_INVALID;
1466 GstEvent *flush_event;
1469 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1471 gst_event_parse_seek (event, &rate, &format, &flags,
1472 &cur_type, &cur, &stop_type, &stop);
1473 seqnum = gst_event_get_seqnum (event);
1475 /* we have to have a format as the segment format. Try to convert
1477 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1481 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1483 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1484 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1486 /* Directly send the instant-rate-change event here before taking the
1487 * stream-lock so that it can be applied as soon as possible */
1488 if (instant_rate_change) {
1491 /* instant rate change only supported if direction does not change. All
1492 * other requirements are already checked before creating the seek event
1493 * but let's double-check here to be sure */
1494 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1495 (qtdemux->segment.rate < 0 && rate > 0) ||
1496 cur_type != GST_SEEK_TYPE_NONE ||
1497 stop_type != GST_SEEK_TYPE_NONE || flush) {
1498 GST_ERROR_OBJECT (qtdemux,
1499 "Instant rate change seeks only supported in the "
1500 "same direction, without flushing and position change");
1504 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1505 (GstSegmentFlags) flags);
1506 gst_event_set_seqnum (ev, seqnum);
1507 gst_qtdemux_push_event (qtdemux, ev);
1511 /* stop streaming, either by flushing or by pausing the task */
1513 flush_event = gst_event_new_flush_start ();
1514 if (seqnum != GST_SEQNUM_INVALID)
1515 gst_event_set_seqnum (flush_event, seqnum);
1516 /* unlock upstream pull_range */
1517 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1518 /* make sure out loop function exits */
1519 gst_qtdemux_push_event (qtdemux, flush_event);
1521 /* non flushing seek, pause the task */
1522 gst_pad_pause_task (qtdemux->sinkpad);
1525 /* wait for streaming to finish */
1526 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1528 /* copy segment, we need this because we still need the old
1529 * segment when we close the current segment. */
1530 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1532 /* configure the segment with the seek variables */
1533 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1534 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1535 cur_type, cur, stop_type, stop, &update)) {
1537 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1539 /* now do the seek */
1540 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1543 /* prepare for streaming again */
1545 flush_event = gst_event_new_flush_stop (TRUE);
1546 if (seqnum != GST_SEQNUM_INVALID)
1547 gst_event_set_seqnum (flush_event, seqnum);
1549 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1550 gst_qtdemux_push_event (qtdemux, flush_event);
1553 /* commit the new segment */
1554 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1556 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1557 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1558 qtdemux->segment.format, qtdemux->segment.position);
1559 if (seqnum != GST_SEQNUM_INVALID)
1560 gst_message_set_seqnum (msg, seqnum);
1561 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1564 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1565 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1566 qtdemux->sinkpad, NULL);
1568 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1575 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1581 qtdemux_ensure_index (GstQTDemux * qtdemux)
1585 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1587 /* Build complete index */
1588 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1589 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1591 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1592 GST_LOG_OBJECT (qtdemux,
1593 "Building complete index of track-id %u for seeking failed!",
1603 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1606 gboolean res = TRUE;
1607 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1609 switch (GST_EVENT_TYPE (event)) {
1610 case GST_EVENT_RECONFIGURE:
1611 GST_OBJECT_LOCK (qtdemux);
1612 gst_flow_combiner_reset (qtdemux->flowcombiner);
1613 GST_OBJECT_UNLOCK (qtdemux);
1614 res = gst_pad_event_default (pad, parent, event);
1616 case GST_EVENT_SEEK:
1618 GstSeekFlags flags = 0;
1619 GstFormat seek_format;
1620 gboolean instant_rate_change;
1622 #ifndef GST_DISABLE_GST_DEBUG
1623 GstClockTime ts = gst_util_get_timestamp ();
1625 guint32 seqnum = gst_event_get_seqnum (event);
1627 qtdemux->received_seek = TRUE;
1629 gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1631 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1633 if (seqnum == qtdemux->segment_seqnum) {
1634 GST_LOG_OBJECT (pad,
1635 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1636 gst_event_unref (event);
1640 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1641 /* seek should be handled by upstream, we might need to re-download fragments */
1642 GST_DEBUG_OBJECT (qtdemux,
1643 "let upstream handle seek for fragmented playback");
1647 if (seek_format == GST_FORMAT_BYTES) {
1648 GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1649 gst_event_unref (event);
1653 gst_event_parse_seek_trickmode_interval (event,
1654 &qtdemux->trickmode_interval);
1656 /* Build complete index for seeking;
1657 * if not a fragmented file at least and we're really doing a seek,
1658 * not just an instant-rate-change */
1659 if (!qtdemux->fragmented && !instant_rate_change) {
1660 if (!qtdemux_ensure_index (qtdemux))
1663 #ifndef GST_DISABLE_GST_DEBUG
1664 ts = gst_util_get_timestamp () - ts;
1665 GST_INFO_OBJECT (qtdemux,
1666 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1668 if (qtdemux->pullbased) {
1669 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1670 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1671 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1673 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1674 && QTDEMUX_N_STREAMS (qtdemux)
1675 && !qtdemux->fragmented) {
1676 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1678 GST_DEBUG_OBJECT (qtdemux,
1679 "ignoring seek in push mode in current state");
1682 gst_event_unref (event);
1687 res = gst_pad_event_default (pad, parent, event);
1697 GST_ERROR_OBJECT (qtdemux, "Index failed");
1698 gst_event_unref (event);
1704 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1706 * If @fw is false, the coding order is explored backwards.
1708 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1709 * sample is found for that track.
1711 * The stream and sample index of the sample with the minimum offset in the direction explored
1712 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1714 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1715 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1716 * @_stream and @_index. */
1718 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1719 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1722 gint64 time, min_time;
1723 QtDemuxStream *stream;
1730 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1733 gboolean set_sample;
1735 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1742 i = str->n_samples - 1;
1746 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1747 if (str->samples[i].size == 0)
1750 if (fw && (str->samples[i].offset < byte_pos))
1753 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1756 /* move stream to first available sample */
1758 gst_qtdemux_move_stream (qtdemux, str, i);
1762 /* avoid index from sparse streams since they might be far away */
1763 if (!CUR_STREAM (str)->sparse) {
1764 /* determine min/max time */
1765 time = QTSAMPLE_PTS (str, &str->samples[i]);
1766 if (min_time == -1 || (!fw && time > min_time) ||
1767 (fw && time < min_time)) {
1771 /* determine stream with leading sample, to get its position */
1773 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1774 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1782 /* no sample for this stream, mark eos */
1784 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1795 /* Copied from mpegtsbase code */
1796 /* FIXME: replace this function when we add new util function for stream-id creation */
1798 _get_upstream_id (GstQTDemux * demux)
1800 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1803 /* Try to create one from the upstream URI, else use a randome number */
1807 /* Try to generate one from the URI query and
1808 * if it fails take a random number instead */
1809 query = gst_query_new_uri ();
1810 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1811 gst_query_parse_uri (query, &uri);
1817 /* And then generate an SHA256 sum of the URI */
1818 cs = g_checksum_new (G_CHECKSUM_SHA256);
1819 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1821 upstream_id = g_strdup (g_checksum_get_string (cs));
1822 g_checksum_free (cs);
1824 /* Just get some random number if the URI query fails */
1825 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1826 "implementing a deterministic way of creating a stream-id");
1828 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1829 g_random_int (), g_random_int ());
1832 gst_query_unref (query);
1837 static QtDemuxStream *
1838 _create_stream (GstQTDemux * demux, guint32 track_id)
1840 QtDemuxStream *stream;
1843 stream = g_new0 (QtDemuxStream, 1);
1844 stream->demux = demux;
1845 stream->track_id = track_id;
1846 upstream_id = _get_upstream_id (demux);
1847 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1848 g_free (upstream_id);
1849 /* new streams always need a discont */
1850 stream->discont = TRUE;
1851 /* we enable clipping for raw audio/video streams */
1852 stream->need_clip = FALSE;
1853 stream->process_func = NULL;
1854 stream->segment_index = -1;
1855 stream->time_position = 0;
1856 stream->sample_index = -1;
1857 stream->offset_in_sample = 0;
1858 stream->new_stream = TRUE;
1859 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1860 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1861 stream->protected = FALSE;
1862 stream->protection_scheme_type = 0;
1863 stream->protection_scheme_version = 0;
1864 stream->protection_scheme_info = NULL;
1865 stream->n_samples_moof = 0;
1866 stream->duration_moof = 0;
1867 stream->duration_last_moof = 0;
1868 stream->alignment = 1;
1869 stream->stream_tags = gst_tag_list_new_empty ();
1870 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1871 g_queue_init (&stream->protection_scheme_event_queue);
1872 stream->ref_count = 1;
1873 /* consistent default for push based mode */
1874 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1879 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1881 GstStructure *structure;
1882 const gchar *variant;
1883 const GstCaps *mediacaps = NULL;
1885 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1887 structure = gst_caps_get_structure (caps, 0);
1888 variant = gst_structure_get_string (structure, "variant");
1890 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1891 QtDemuxStream *stream;
1892 const GValue *value;
1894 demux->fragmented = TRUE;
1895 demux->mss_mode = TRUE;
1897 if (QTDEMUX_N_STREAMS (demux) > 1) {
1898 /* can't do this, we can only renegotiate for another mss format */
1902 value = gst_structure_get_value (structure, "media-caps");
1905 const GValue *timescale_v;
1907 /* TODO update when stream changes during playback */
1909 if (QTDEMUX_N_STREAMS (demux) == 0) {
1910 stream = _create_stream (demux, 1);
1911 g_ptr_array_add (demux->active_streams, stream);
1912 /* mss has no stsd/stsd entry, use id 0 as default */
1913 stream->stsd_entries_length = 1;
1914 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1915 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1917 stream = QTDEMUX_NTH_STREAM (demux, 0);
1920 timescale_v = gst_structure_get_value (structure, "timescale");
1922 stream->timescale = g_value_get_uint64 (timescale_v);
1924 /* default mss timescale */
1925 stream->timescale = 10000000;
1927 demux->timescale = stream->timescale;
1929 mediacaps = gst_value_get_caps (value);
1930 if (!CUR_STREAM (stream)->caps
1931 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1932 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1934 stream->new_caps = TRUE;
1936 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1937 structure = gst_caps_get_structure (mediacaps, 0);
1938 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1939 stream->subtype = FOURCC_vide;
1941 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1942 gst_structure_get_int (structure, "height",
1943 &CUR_STREAM (stream)->height);
1944 gst_structure_get_fraction (structure, "framerate",
1945 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1946 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1948 stream->subtype = FOURCC_soun;
1949 gst_structure_get_int (structure, "channels",
1950 &CUR_STREAM (stream)->n_channels);
1951 gst_structure_get_int (structure, "rate", &rate);
1952 CUR_STREAM (stream)->rate = rate;
1953 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1954 if (gst_structure_has_field (structure, "original-media-type")) {
1955 const gchar *media_type =
1956 gst_structure_get_string (structure, "original-media-type");
1957 if (g_str_has_prefix (media_type, "video")) {
1958 stream->subtype = FOURCC_vide;
1959 } else if (g_str_has_prefix (media_type, "audio")) {
1960 stream->subtype = FOURCC_soun;
1965 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1967 demux->mss_mode = FALSE;
1974 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1978 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1979 gst_pad_stop_task (qtdemux->sinkpad);
1981 if (hard || qtdemux->upstream_format_is_time) {
1982 qtdemux->state = QTDEMUX_STATE_INITIAL;
1983 qtdemux->neededbytes = 16;
1984 qtdemux->todrop = 0;
1985 qtdemux->pullbased = FALSE;
1986 g_clear_pointer (&qtdemux->redirect_location, g_free);
1987 qtdemux->first_mdat = -1;
1988 qtdemux->header_size = 0;
1989 qtdemux->mdatoffset = -1;
1990 qtdemux->restoredata_offset = -1;
1991 if (qtdemux->mdatbuffer)
1992 gst_buffer_unref (qtdemux->mdatbuffer);
1993 if (qtdemux->restoredata_buffer)
1994 gst_buffer_unref (qtdemux->restoredata_buffer);
1995 qtdemux->mdatbuffer = NULL;
1996 qtdemux->restoredata_buffer = NULL;
1997 qtdemux->mdatleft = 0;
1998 qtdemux->mdatsize = 0;
1999 if (qtdemux->comp_brands)
2000 gst_buffer_unref (qtdemux->comp_brands);
2001 qtdemux->comp_brands = NULL;
2002 qtdemux->last_moov_offset = -1;
2003 if (qtdemux->moov_node_compressed) {
2004 g_node_destroy (qtdemux->moov_node_compressed);
2005 if (qtdemux->moov_node)
2006 g_free (qtdemux->moov_node->data);
2008 qtdemux->moov_node_compressed = NULL;
2009 if (qtdemux->moov_node)
2010 g_node_destroy (qtdemux->moov_node);
2011 qtdemux->moov_node = NULL;
2012 if (qtdemux->tag_list)
2013 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2014 qtdemux->tag_list = gst_tag_list_new_empty ();
2015 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2017 if (qtdemux->element_index)
2018 gst_object_unref (qtdemux->element_index);
2019 qtdemux->element_index = NULL;
2021 qtdemux->major_brand = 0;
2022 qtdemux->upstream_format_is_time = FALSE;
2023 qtdemux->upstream_seekable = FALSE;
2024 qtdemux->upstream_size = 0;
2026 qtdemux->fragment_start = -1;
2027 qtdemux->fragment_start_offset = -1;
2028 qtdemux->duration = 0;
2029 qtdemux->moof_offset = 0;
2030 qtdemux->chapters_track_id = 0;
2031 qtdemux->have_group_id = FALSE;
2032 qtdemux->group_id = G_MAXUINT;
2034 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2036 g_queue_clear (&qtdemux->protection_event_queue);
2038 qtdemux->received_seek = FALSE;
2039 qtdemux->first_moof_already_parsed = FALSE;
2041 qtdemux->offset = 0;
2042 gst_adapter_clear (qtdemux->adapter);
2043 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2044 qtdemux->need_segment = TRUE;
2047 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2048 qtdemux->trickmode_interval = 0;
2049 g_ptr_array_set_size (qtdemux->active_streams, 0);
2050 g_ptr_array_set_size (qtdemux->old_streams, 0);
2051 qtdemux->n_video_streams = 0;
2052 qtdemux->n_audio_streams = 0;
2053 qtdemux->n_sub_streams = 0;
2054 qtdemux->exposed = FALSE;
2055 qtdemux->fragmented = FALSE;
2056 qtdemux->mss_mode = FALSE;
2057 gst_caps_replace (&qtdemux->media_caps, NULL);
2058 qtdemux->timescale = 0;
2059 qtdemux->got_moov = FALSE;
2060 qtdemux->cenc_aux_info_offset = 0;
2061 qtdemux->cenc_aux_info_sizes = NULL;
2062 qtdemux->cenc_aux_sample_count = 0;
2063 if (qtdemux->protection_system_ids) {
2064 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2065 qtdemux->protection_system_ids = NULL;
2067 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2068 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2069 GST_BIN_FLAG_STREAMS_AWARE);
2071 if (qtdemux->preferred_protection_system_id) {
2072 g_free (qtdemux->preferred_protection_system_id);
2073 qtdemux->preferred_protection_system_id = NULL;
2075 } else if (qtdemux->mss_mode) {
2076 gst_flow_combiner_reset (qtdemux->flowcombiner);
2077 g_ptr_array_foreach (qtdemux->active_streams,
2078 (GFunc) gst_qtdemux_stream_clear, NULL);
2080 gst_flow_combiner_reset (qtdemux->flowcombiner);
2081 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2082 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2083 stream->sent_eos = FALSE;
2084 stream->time_position = 0;
2085 stream->accumulated_base = 0;
2086 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2092 /* Maps the @segment to the qt edts internal segments and pushes
2093 * the corresponding segment event.
2095 * If it ends up being at a empty segment, a gap will be pushed and the next
2096 * edts segment will be activated in sequence.
2098 * To be used in push-mode only */
2100 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2104 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2105 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2107 stream->time_position = segment->start;
2109 /* in push mode we should be guaranteed that we will have empty segments
2110 * at the beginning and then one segment after, other scenarios are not
2111 * supported and are discarded when parsing the edts */
2112 for (i = 0; i < stream->n_segments; i++) {
2113 if (stream->segments[i].stop_time > segment->start) {
2114 /* push the empty segment and move to the next one */
2115 gst_qtdemux_activate_segment (qtdemux, stream, i,
2116 stream->time_position);
2117 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2118 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2119 stream->time_position);
2121 /* accumulate previous segments */
2122 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2123 stream->accumulated_base +=
2124 (stream->segment.stop -
2125 stream->segment.start) / ABS (stream->segment.rate);
2129 g_assert (i == stream->n_segments - 1);
2136 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2147 for (i = 0; i < len; i++) {
2148 QtDemuxStream *stream = g_ptr_array_index (src, i);
2150 #ifndef GST_DISABLE_GST_DEBUG
2151 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2152 stream, GST_STR_NULL (stream->stream_id), dest);
2154 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2157 g_ptr_array_set_size (src, 0);
2161 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2164 GstQTDemux *demux = GST_QTDEMUX (parent);
2165 gboolean res = TRUE;
2167 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2169 switch (GST_EVENT_TYPE (event)) {
2170 case GST_EVENT_SEGMENT:
2173 QtDemuxStream *stream;
2177 /* some debug output */
2178 gst_event_copy_segment (event, &segment);
2179 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2182 if (segment.format == GST_FORMAT_TIME) {
2183 demux->upstream_format_is_time = TRUE;
2184 demux->segment_seqnum = gst_event_get_seqnum (event);
2186 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2187 "not in time format");
2189 /* chain will send initial newsegment after pads have been added */
2190 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2191 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2196 /* check if this matches a time seek we received previously
2197 * FIXME for backwards compatibility reasons we use the
2198 * seek_offset here to compare. In the future we might want to
2199 * change this to use the seqnum as it uniquely should identify
2200 * the segment that corresponds to the seek. */
2201 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2202 ", received segment offset %" G_GINT64_FORMAT,
2203 demux->seek_offset, segment.start);
2204 if (segment.format == GST_FORMAT_BYTES
2205 && demux->seek_offset == segment.start) {
2206 GST_OBJECT_LOCK (demux);
2207 offset = segment.start;
2209 segment.format = GST_FORMAT_TIME;
2210 segment.start = demux->push_seek_start;
2211 segment.stop = demux->push_seek_stop;
2212 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2213 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2214 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2215 GST_OBJECT_UNLOCK (demux);
2218 /* we only expect a BYTE segment, e.g. following a seek */
2219 if (segment.format == GST_FORMAT_BYTES) {
2220 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2221 offset = segment.start;
2223 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2224 NULL, (gint64 *) & segment.start);
2225 if ((gint64) segment.start < 0)
2228 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2229 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2230 NULL, (gint64 *) & segment.stop);
2231 /* keyframe seeking should already arrange for start >= stop,
2232 * but make sure in other rare cases */
2233 segment.stop = MAX (segment.stop, segment.start);
2235 } else if (segment.format == GST_FORMAT_TIME) {
2236 /* push all data on the adapter before starting this
2238 gst_qtdemux_process_adapter (demux, TRUE);
2240 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2244 /* We shouldn't modify upstream driven TIME FORMAT segment */
2245 if (!demux->upstream_format_is_time) {
2246 /* accept upstream's notion of segment and distribute along */
2247 segment.format = GST_FORMAT_TIME;
2248 segment.position = segment.time = segment.start;
2249 segment.duration = demux->segment.duration;
2250 segment.base = gst_segment_to_running_time (&demux->segment,
2251 GST_FORMAT_TIME, demux->segment.position);
2254 gst_segment_copy_into (&segment, &demux->segment);
2255 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2257 /* map segment to internal qt segments and push on each stream */
2258 if (QTDEMUX_N_STREAMS (demux)) {
2259 demux->need_segment = TRUE;
2260 gst_qtdemux_check_send_pending_segment (demux);
2263 /* clear leftover in current segment, if any */
2264 gst_adapter_clear (demux->adapter);
2266 /* set up streaming thread */
2267 demux->offset = offset;
2268 if (demux->upstream_format_is_time) {
2269 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2270 "set values to restart reading from a new atom");
2271 demux->neededbytes = 16;
2274 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2277 demux->todrop = stream->samples[idx].offset - offset;
2278 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2280 /* set up for EOS */
2281 demux->neededbytes = -1;
2286 gst_event_unref (event);
2290 case GST_EVENT_FLUSH_START:
2292 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2293 gst_event_unref (event);
2296 QTDEMUX_EXPOSE_LOCK (demux);
2297 res = gst_pad_event_default (demux->sinkpad, parent, event);
2298 QTDEMUX_EXPOSE_UNLOCK (demux);
2301 case GST_EVENT_FLUSH_STOP:
2305 dur = demux->segment.duration;
2306 gst_qtdemux_reset (demux, FALSE);
2307 demux->segment.duration = dur;
2309 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2310 gst_event_unref (event);
2316 /* If we are in push mode, and get an EOS before we've seen any streams,
2317 * then error out - we have nowhere to send the EOS */
2318 if (!demux->pullbased) {
2320 gboolean has_valid_stream = FALSE;
2321 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2322 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2323 has_valid_stream = TRUE;
2327 if (!has_valid_stream)
2328 gst_qtdemux_post_no_playable_stream_error (demux);
2330 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2331 (guint) gst_adapter_available (demux->adapter));
2332 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2338 case GST_EVENT_CAPS:{
2339 GstCaps *caps = NULL;
2341 gst_event_parse_caps (event, &caps);
2342 gst_qtdemux_setcaps (demux, caps);
2344 gst_event_unref (event);
2347 case GST_EVENT_PROTECTION:
2349 const gchar *system_id = NULL;
2351 gst_event_parse_protection (event, &system_id, NULL, NULL);
2352 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2354 gst_qtdemux_append_protection_system_id (demux, system_id);
2355 /* save the event for later, for source pads that have not been created */
2356 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2357 /* send it to all pads that already exist */
2358 gst_qtdemux_push_event (demux, event);
2362 case GST_EVENT_STREAM_START:
2365 gst_event_unref (event);
2367 /* Drain all the buffers */
2368 gst_qtdemux_process_adapter (demux, TRUE);
2369 gst_qtdemux_reset (demux, FALSE);
2370 /* We expect new moov box after new stream-start event */
2371 if (demux->exposed) {
2372 gst_qtdemux_stream_concat (demux,
2373 demux->old_streams, demux->active_streams);
2382 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2389 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2392 GstQTDemux *demux = GST_QTDEMUX (parent);
2393 gboolean res = FALSE;
2395 switch (GST_QUERY_TYPE (query)) {
2396 case GST_QUERY_BITRATE:
2398 GstClockTime duration;
2400 /* populate demux->upstream_size if not done yet */
2401 gst_qtdemux_check_seekability (demux);
2403 if (demux->upstream_size != -1
2404 && gst_qtdemux_get_duration (demux, &duration)) {
2406 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2409 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2410 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2411 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2413 /* TODO: better results based on ranges/index tables */
2414 gst_query_set_bitrate (query, bitrate);
2420 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2430 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2432 GstQTDemux *demux = GST_QTDEMUX (element);
2434 GST_OBJECT_LOCK (demux);
2435 if (demux->element_index)
2436 gst_object_unref (demux->element_index);
2438 demux->element_index = gst_object_ref (index);
2440 demux->element_index = NULL;
2442 GST_OBJECT_UNLOCK (demux);
2443 /* object lock might be taken again */
2445 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2446 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2447 demux->element_index, demux->index_id);
2451 gst_qtdemux_get_index (GstElement * element)
2453 GstIndex *result = NULL;
2454 GstQTDemux *demux = GST_QTDEMUX (element);
2456 GST_OBJECT_LOCK (demux);
2457 if (demux->element_index)
2458 result = gst_object_ref (demux->element_index);
2459 GST_OBJECT_UNLOCK (demux);
2461 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2468 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2470 g_free ((gpointer) stream->stco.data);
2471 stream->stco.data = NULL;
2472 g_free ((gpointer) stream->stsz.data);
2473 stream->stsz.data = NULL;
2474 g_free ((gpointer) stream->stsc.data);
2475 stream->stsc.data = NULL;
2476 g_free ((gpointer) stream->stts.data);
2477 stream->stts.data = NULL;
2478 g_free ((gpointer) stream->stss.data);
2479 stream->stss.data = NULL;
2480 g_free ((gpointer) stream->stps.data);
2481 stream->stps.data = NULL;
2482 g_free ((gpointer) stream->ctts.data);
2483 stream->ctts.data = NULL;
2487 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2489 g_free (stream->segments);
2490 stream->segments = NULL;
2491 stream->segment_index = -1;
2492 stream->accumulated_base = 0;
2496 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2498 g_free (stream->samples);
2499 stream->samples = NULL;
2500 gst_qtdemux_stbl_free (stream);
2503 g_free (stream->ra_entries);
2504 stream->ra_entries = NULL;
2505 stream->n_ra_entries = 0;
2507 stream->sample_index = -1;
2508 stream->stbl_index = -1;
2509 stream->n_samples = 0;
2510 stream->time_position = 0;
2512 stream->n_samples_moof = 0;
2513 stream->duration_moof = 0;
2514 stream->duration_last_moof = 0;
2518 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2521 if (stream->allocator)
2522 gst_object_unref (stream->allocator);
2523 while (stream->buffers) {
2524 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2525 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2527 for (i = 0; i < stream->stsd_entries_length; i++) {
2528 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2529 if (entry->rgb8_palette) {
2530 gst_memory_unref (entry->rgb8_palette);
2531 entry->rgb8_palette = NULL;
2533 entry->sparse = FALSE;
2536 if (stream->stream_tags)
2537 gst_tag_list_unref (stream->stream_tags);
2539 stream->stream_tags = gst_tag_list_new_empty ();
2540 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2541 g_free (stream->redirect_uri);
2542 stream->redirect_uri = NULL;
2543 stream->sent_eos = FALSE;
2544 stream->protected = FALSE;
2545 if (stream->protection_scheme_info) {
2546 if (stream->protection_scheme_type == FOURCC_cenc
2547 || stream->protection_scheme_type == FOURCC_cbcs) {
2548 QtDemuxCencSampleSetInfo *info =
2549 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2550 if (info->default_properties)
2551 gst_structure_free (info->default_properties);
2552 if (info->crypto_info)
2553 g_ptr_array_free (info->crypto_info, TRUE);
2555 if (stream->protection_scheme_type == FOURCC_aavd) {
2556 QtDemuxAavdEncryptionInfo *info =
2557 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2558 if (info->default_properties)
2559 gst_structure_free (info->default_properties);
2561 g_free (stream->protection_scheme_info);
2562 stream->protection_scheme_info = NULL;
2564 stream->protection_scheme_type = 0;
2565 stream->protection_scheme_version = 0;
2566 g_queue_foreach (&stream->protection_scheme_event_queue,
2567 (GFunc) gst_event_unref, NULL);
2568 g_queue_clear (&stream->protection_scheme_event_queue);
2569 gst_qtdemux_stream_flush_segments_data (stream);
2570 gst_qtdemux_stream_flush_samples_data (stream);
2574 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2577 gst_qtdemux_stream_clear (stream);
2578 for (i = 0; i < stream->stsd_entries_length; i++) {
2579 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2581 gst_caps_unref (entry->caps);
2585 g_free (stream->stsd_entries);
2586 stream->stsd_entries = NULL;
2587 stream->stsd_entries_length = 0;
2590 static QtDemuxStream *
2591 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2593 g_atomic_int_add (&stream->ref_count, 1);
2599 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2601 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2602 gst_qtdemux_stream_reset (stream);
2603 gst_tag_list_unref (stream->stream_tags);
2605 GstQTDemux *demux = stream->demux;
2606 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2607 GST_OBJECT_LOCK (demux);
2608 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2609 GST_OBJECT_UNLOCK (demux);
2611 g_free (stream->stream_id);
2616 static GstStateChangeReturn
2617 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2619 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2620 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2622 switch (transition) {
2623 case GST_STATE_CHANGE_READY_TO_PAUSED:
2624 gst_qtdemux_reset (qtdemux, TRUE);
2630 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2632 switch (transition) {
2633 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2634 gst_qtdemux_reset (qtdemux, TRUE);
2645 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2647 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2649 g_return_if_fail (GST_IS_CONTEXT (context));
2651 if (gst_context_has_context_type (context,
2652 "drm-preferred-decryption-system-id")) {
2653 const GstStructure *s;
2655 s = gst_context_get_structure (context);
2656 g_free (qtdemux->preferred_protection_system_id);
2657 qtdemux->preferred_protection_system_id =
2658 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2659 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2660 qtdemux->preferred_protection_system_id);
2663 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2667 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2669 /* counts as header data */
2670 qtdemux->header_size += length;
2672 /* only consider at least a sufficiently complete ftyp atom */
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 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
3467 stream->cslg_shift);
3469 /* Update total duration if needed */
3470 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3472 /* Pre-emptively figure out size of mdat based on trun information.
3473 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3474 * size, else we will still be able to use this when dealing with gap'ed
3476 qtdemux->mdatleft = *running_offset - initial_offset;
3477 qtdemux->mdatoffset = initial_offset;
3478 qtdemux->mdatsize = qtdemux->mdatleft;
3480 stream->n_samples += samples_count;
3481 stream->n_samples_moof += samples_count;
3483 if (stream->pending_seek != NULL)
3484 stream->pending_seek = NULL;
3490 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3495 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3501 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3502 "be larger than %uMB (broken file?)", stream->n_samples,
3503 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3508 /* find stream with @id */
3509 static inline QtDemuxStream *
3510 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3512 QtDemuxStream *stream;
3516 if (G_UNLIKELY (!id)) {
3517 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3521 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3522 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3523 if (stream->track_id == id)
3526 if (qtdemux->mss_mode) {
3527 /* mss should have only 1 stream anyway */
3528 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3535 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3536 guint32 * fragment_number)
3538 if (!gst_byte_reader_skip (mfhd, 4))
3540 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3545 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3551 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3552 QtDemuxStream ** stream, guint32 * default_sample_duration,
3553 guint32 * default_sample_size, guint32 * default_sample_flags,
3554 gint64 * base_offset)
3557 guint32 track_id = 0;
3559 if (!gst_byte_reader_skip (tfhd, 1) ||
3560 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3563 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3566 *stream = qtdemux_find_stream (qtdemux, track_id);
3567 if (G_UNLIKELY (!*stream))
3568 goto unknown_stream;
3570 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3571 *base_offset = qtdemux->moof_offset;
3573 if (flags & TF_BASE_DATA_OFFSET)
3574 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3577 /* obtain stream defaults */
3578 qtdemux_parse_trex (qtdemux, *stream,
3579 default_sample_duration, default_sample_size, default_sample_flags);
3581 (*stream)->stsd_sample_description_id =
3582 (*stream)->def_sample_description_index - 1;
3584 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3585 guint32 sample_description_index;
3586 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3588 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3591 if (qtdemux->mss_mode) {
3592 /* mss has no stsd entry */
3593 (*stream)->stsd_sample_description_id = 0;
3596 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3597 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3600 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3601 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3604 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3605 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3612 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3617 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3623 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3624 guint64 * decode_time)
3626 guint32 version = 0;
3628 if (!gst_byte_reader_get_uint32_be (br, &version))
3633 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3636 guint32 dec_time = 0;
3637 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3639 *decode_time = dec_time;
3642 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3649 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3654 /* Returns a pointer to a GstStructure containing the properties of
3655 * the stream sample identified by @sample_index. The caller must unref
3656 * the returned object after use. Returns NULL if unsuccessful. */
3657 static GstStructure *
3658 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3659 QtDemuxStream * stream, guint sample_index)
3661 QtDemuxCencSampleSetInfo *info = NULL;
3663 g_return_val_if_fail (stream != NULL, NULL);
3664 g_return_val_if_fail (stream->protected, NULL);
3665 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3667 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3669 /* Currently, cenc properties for groups of samples are not supported, so
3670 * simply return a copy of the default sample properties */
3671 return gst_structure_copy (info->default_properties);
3674 /* Parses the sizes of sample auxiliary information contained within a stream,
3675 * as given in a saiz box. Returns array of sample_count guint8 size values,
3676 * or NULL on failure */
3678 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3679 GstByteReader * br, guint32 * sample_count)
3683 guint8 default_info_size;
3685 g_return_val_if_fail (qtdemux != NULL, NULL);
3686 g_return_val_if_fail (stream != NULL, NULL);
3687 g_return_val_if_fail (br != NULL, NULL);
3688 g_return_val_if_fail (sample_count != NULL, NULL);
3690 if (!gst_byte_reader_get_uint32_be (br, &flags))
3694 /* aux_info_type and aux_info_type_parameter are ignored */
3695 if (!gst_byte_reader_skip (br, 8))
3699 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3701 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3703 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3705 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3708 if (default_info_size == 0) {
3709 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3713 info_sizes = g_new (guint8, *sample_count);
3714 memset (info_sizes, default_info_size, *sample_count);
3720 /* Parses the offset of sample auxiliary information contained within a stream,
3721 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3723 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3724 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3729 guint32 aux_info_type = 0;
3730 guint32 aux_info_type_parameter = 0;
3731 guint32 entry_count;
3734 const guint8 *aux_info_type_data = NULL;
3736 g_return_val_if_fail (qtdemux != NULL, FALSE);
3737 g_return_val_if_fail (stream != NULL, FALSE);
3738 g_return_val_if_fail (br != NULL, FALSE);
3739 g_return_val_if_fail (offset != NULL, FALSE);
3741 if (!gst_byte_reader_get_uint8 (br, &version))
3744 if (!gst_byte_reader_get_uint24_be (br, &flags))
3749 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3751 aux_info_type = QT_FOURCC (aux_info_type_data);
3753 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3755 } else if (stream->protected) {
3756 aux_info_type = stream->protection_scheme_type;
3758 aux_info_type = CUR_STREAM (stream)->fourcc;
3762 *info_type = aux_info_type;
3763 if (info_type_parameter)
3764 *info_type_parameter = aux_info_type_parameter;
3766 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3767 "aux_info_type_parameter: %#06x",
3768 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3770 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3773 if (entry_count != 1) {
3774 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3779 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3781 *offset = (guint64) off_32;
3783 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3788 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3793 qtdemux_gst_structure_free (GstStructure * gststructure)
3796 gst_structure_free (gststructure);
3800 /* Parses auxiliary information relating to samples protected using
3801 * Common Encryption (cenc); the format of this information
3802 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3805 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3806 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3808 QtDemuxCencSampleSetInfo *ss_info = NULL;
3811 GPtrArray *old_crypto_info = NULL;
3812 guint old_entries = 0;
3814 g_return_val_if_fail (qtdemux != NULL, FALSE);
3815 g_return_val_if_fail (stream != NULL, FALSE);
3816 g_return_val_if_fail (br != NULL, FALSE);
3817 g_return_val_if_fail (stream->protected, FALSE);
3818 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3820 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3822 if (ss_info->crypto_info) {
3823 old_crypto_info = ss_info->crypto_info;
3824 /* Count number of non-null entries remaining at the tail end */
3825 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3826 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3832 ss_info->crypto_info =
3833 g_ptr_array_new_full (sample_count + old_entries,
3834 (GDestroyNotify) qtdemux_gst_structure_free);
3836 /* We preserve old entries because we parse the next moof in advance
3837 * of consuming all samples from the previous moof, and otherwise
3838 * we'd discard the corresponding crypto info for the samples
3839 * from the previous fragment. */
3841 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3843 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3844 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3846 g_ptr_array_index (old_crypto_info, i) = NULL;
3850 if (old_crypto_info) {
3851 /* Everything now belongs to the new array */
3852 g_ptr_array_free (old_crypto_info, TRUE);
3855 for (i = 0; i < sample_count; ++i) {
3856 GstStructure *properties;
3857 guint16 n_subsamples = 0;
3861 gboolean could_read_iv;
3863 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3864 if (properties == NULL) {
3865 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3868 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3869 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3870 gst_structure_free (properties);
3874 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3875 if (could_read_iv) {
3876 buf = gst_buffer_new_wrapped (data, iv_size);
3877 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3878 gst_buffer_unref (buf);
3879 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3880 const GValue *constant_iv_size_value =
3881 gst_structure_get_value (properties, "constant_iv_size");
3882 const GValue *constant_iv_value =
3883 gst_structure_get_value (properties, "iv");
3884 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3885 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3886 gst_structure_free (properties);
3889 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3890 gst_structure_remove_field (properties, "constant_iv_size");
3891 } else if (stream->protection_scheme_type == FOURCC_cenc) {
3892 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3893 gst_structure_free (properties);
3896 size = info_sizes[i];
3897 if (size > iv_size) {
3898 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3899 || !(n_subsamples > 0)) {
3900 gst_structure_free (properties);
3901 GST_ERROR_OBJECT (qtdemux,
3902 "failed to get subsample count for sample %u", i);
3905 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3906 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3907 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3909 gst_structure_free (properties);
3912 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3914 gst_structure_free (properties);
3917 gst_structure_set (properties,
3918 "subsample_count", G_TYPE_UINT, n_subsamples,
3919 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3920 gst_buffer_unref (buf);
3922 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3924 g_ptr_array_add (ss_info->crypto_info, properties);
3929 /* Converts a UUID in raw byte form to a string representation, as defined in
3930 * RFC 4122. The caller takes ownership of the returned string and is
3931 * responsible for freeing it after use. */
3933 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3935 const guint8 *uuid = (const guint8 *) uuid_bytes;
3937 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3938 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3939 uuid[0], uuid[1], uuid[2], uuid[3],
3940 uuid[4], uuid[5], uuid[6], uuid[7],
3941 uuid[8], uuid[9], uuid[10], uuid[11],
3942 uuid[12], uuid[13], uuid[14], uuid[15]);
3945 /* Parses a Protection System Specific Header box (pssh), as defined in the
3946 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3947 * information needed by a specific content protection system in order to
3948 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3951 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3953 gchar *sysid_string;
3954 guint32 pssh_size = QT_UINT32 (node->data);
3955 GstBuffer *pssh = NULL;
3956 GstEvent *event = NULL;
3957 guint32 parent_box_type;
3960 if (G_UNLIKELY (pssh_size < 32U)) {
3961 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3966 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3968 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3970 pssh = gst_buffer_new_memdup (node->data, pssh_size);
3971 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3972 gst_buffer_get_size (pssh));
3974 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3976 /* Push an event containing the pssh box onto the queues of all streams. */
3977 event = gst_event_new_protection (sysid_string, pssh,
3978 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3979 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3980 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3981 GST_TRACE_OBJECT (qtdemux,
3982 "adding protection event for stream %s and system %s",
3983 stream->stream_id, sysid_string);
3984 g_queue_push_tail (&stream->protection_scheme_event_queue,
3985 gst_event_ref (event));
3987 g_free (sysid_string);
3988 gst_event_unref (event);
3989 gst_buffer_unref (pssh);
3994 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3995 guint64 moof_offset, QtDemuxStream * stream)
3997 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3999 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4000 GNode *saiz_node, *saio_node, *pssh_node;
4001 GstByteReader saiz_data, saio_data;
4002 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4003 gint64 base_offset, running_offset;
4005 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4007 /* NOTE @stream ignored */
4009 moof_node = g_node_new ((guint8 *) buffer);
4010 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4011 qtdemux_node_dump (qtdemux, moof_node);
4013 /* Get fragment number from mfhd and check it's valid */
4015 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4016 if (mfhd_node == NULL)
4018 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4020 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4022 /* unknown base_offset to start with */
4023 base_offset = running_offset = -1;
4024 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4026 guint64 decode_time = 0;
4028 /* Fragment Header node */
4030 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4034 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4035 &ds_size, &ds_flags, &base_offset))
4038 /* The following code assumes at most a single set of sample auxiliary
4039 * data in the fragment (consisting of a saiz box and a corresponding saio
4040 * box); in theory, however, there could be multiple sets of sample
4041 * auxiliary data in a fragment. */
4043 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4046 guint32 info_type = 0;
4048 guint32 info_type_parameter = 0;
4050 g_free (qtdemux->cenc_aux_info_sizes);
4052 qtdemux->cenc_aux_info_sizes =
4053 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4054 &qtdemux->cenc_aux_sample_count);
4055 if (qtdemux->cenc_aux_info_sizes == NULL) {
4056 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4060 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4063 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4064 g_free (qtdemux->cenc_aux_info_sizes);
4065 qtdemux->cenc_aux_info_sizes = NULL;
4069 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4070 &info_type, &info_type_parameter, &offset))) {
4071 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4072 g_free (qtdemux->cenc_aux_info_sizes);
4073 qtdemux->cenc_aux_info_sizes = NULL;
4076 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4077 offset += (guint64) (base_offset - qtdemux->moof_offset);
4078 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4079 && info_type_parameter == 0U) {
4081 if (offset > length) {
4082 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4083 qtdemux->cenc_aux_info_offset = offset;
4085 gst_byte_reader_init (&br, buffer + offset, length - offset);
4086 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4087 qtdemux->cenc_aux_info_sizes,
4088 qtdemux->cenc_aux_sample_count)) {
4089 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4090 g_free (qtdemux->cenc_aux_info_sizes);
4091 qtdemux->cenc_aux_info_sizes = NULL;
4099 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4102 /* We'll use decode_time to interpolate timestamps
4103 * in case the input timestamps are missing */
4104 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4106 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4107 " (%" GST_TIME_FORMAT ")", decode_time,
4108 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4109 decode_time) : GST_CLOCK_TIME_NONE));
4111 /* Discard the fragment buffer timestamp info to avoid using it.
4112 * Rely on tfdt instead as it is more accurate than the timestamp
4113 * that is fetched from a manifest/playlist and is usually
4115 qtdemux->fragment_start = -1;
4118 if (G_UNLIKELY (!stream)) {
4119 /* we lost track of offset, we'll need to regain it,
4120 * but can delay complaining until later or avoid doing so altogether */
4124 if (G_UNLIKELY (base_offset < -1))
4127 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4129 if (!qtdemux->pullbased) {
4130 /* Sample tables can grow enough to be problematic if the system memory
4131 * is very low (e.g. embedded devices) and the videos very long
4132 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4133 * Fortunately, we can easily discard them for each new fragment when
4134 * we know qtdemux will not receive seeks outside of the current fragment.
4135 * adaptivedemux honors this assumption.
4136 * This optimization is also useful for applications that use qtdemux as
4137 * a push-based simple demuxer, like Media Source Extensions. */
4138 gst_qtdemux_stream_flush_samples_data (stream);
4141 /* initialise moof sample data */
4142 stream->n_samples_moof = 0;
4143 stream->duration_last_moof = stream->duration_moof;
4144 stream->duration_moof = 0;
4146 /* Track Run node */
4148 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4151 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4152 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4153 &running_offset, decode_time, (tfdt_node != NULL));
4154 /* iterate all siblings */
4155 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4159 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4161 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4162 guint32 box_length = QT_UINT32 (uuid_buffer);
4164 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4167 /* if no new base_offset provided for next traf,
4168 * base is end of current traf */
4169 base_offset = running_offset;
4170 running_offset = -1;
4172 if (stream->n_samples_moof && stream->duration_moof)
4173 stream->new_caps = TRUE;
4176 /* iterate all siblings */
4177 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4180 /* parse any protection system info */
4181 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4183 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4184 qtdemux_parse_pssh (qtdemux, pssh_node);
4185 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4188 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4189 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4191 /* Unless the user has explicitly requested another seek, perform an
4192 * internal seek to the time specified in the tfdt.
4194 * This way if the user opens a file where the first tfdt is 1 hour
4195 * into the presentation, they will not have to wait 1 hour for run
4196 * time to catch up and actual playback to start. */
4199 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4200 "performing an internal seek to %" GST_TIME_FORMAT,
4201 GST_TIME_ARGS (min_dts));
4203 qtdemux->segment.start = min_dts;
4204 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4206 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4207 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4208 stream->time_position = min_dts;
4211 /* Before this code was run a segment was already sent when the moov was
4212 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4213 * be emitted after a moov, and we can emit a second segment anyway for
4214 * special cases like this. */
4215 qtdemux->need_segment = TRUE;
4218 qtdemux->first_moof_already_parsed = TRUE;
4220 g_node_destroy (moof_node);
4225 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4230 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4235 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4240 g_node_destroy (moof_node);
4241 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4242 (_("This file is corrupt and cannot be played.")), (NULL));
4248 /* might be used if some day we actually use mfra & co
4249 * for random access to fragments,
4250 * but that will require quite some modifications and much less relying
4251 * on a sample array */
4255 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4257 QtDemuxStream *stream;
4258 guint32 ver_flags, track_id, len, num_entries, i;
4259 guint value_size, traf_size, trun_size, sample_size;
4260 guint64 time = 0, moof_offset = 0;
4262 GstBuffer *buf = NULL;
4267 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4269 if (!gst_byte_reader_skip (&tfra, 8))
4272 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4275 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4276 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4277 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4280 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4282 stream = qtdemux_find_stream (qtdemux, track_id);
4284 goto unknown_trackid;
4286 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4287 sample_size = (len & 3) + 1;
4288 trun_size = ((len & 12) >> 2) + 1;
4289 traf_size = ((len & 48) >> 4) + 1;
4291 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4292 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4294 if (num_entries == 0)
4297 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4298 value_size + value_size + traf_size + trun_size + sample_size))
4301 g_free (stream->ra_entries);
4302 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4303 stream->n_ra_entries = num_entries;
4305 for (i = 0; i < num_entries; i++) {
4306 qt_atom_parser_get_offset (&tfra, value_size, &time);
4307 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4308 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4309 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4310 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4312 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4314 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4315 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4317 stream->ra_entries[i].ts = time;
4318 stream->ra_entries[i].moof_offset = moof_offset;
4320 /* don't want to go through the entire file and read all moofs at startup */
4322 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4323 if (ret != GST_FLOW_OK)
4325 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4326 moof_offset, stream);
4327 gst_buffer_unref (buf);
4331 check_update_duration (qtdemux, time);
4338 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4343 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4348 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4354 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4356 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4357 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4358 GstBuffer *mfro = NULL, *mfra = NULL;
4360 gboolean ret = FALSE;
4361 GNode *mfra_node, *tfra_node;
4362 guint64 mfra_offset = 0;
4363 guint32 fourcc, mfra_size;
4366 /* query upstream size in bytes */
4367 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4368 goto size_query_failed;
4370 /* mfro box should be at the very end of the file */
4371 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4372 if (flow != GST_FLOW_OK)
4375 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4377 fourcc = QT_FOURCC (mfro_map.data + 4);
4378 if (fourcc != FOURCC_mfro)
4381 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4382 if (mfro_map.size < 16)
4383 goto invalid_mfro_size;
4385 mfra_size = QT_UINT32 (mfro_map.data + 12);
4386 if (mfra_size >= len)
4387 goto invalid_mfra_size;
4389 mfra_offset = len - mfra_size;
4391 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4392 mfra_offset, mfra_size);
4394 /* now get and parse mfra box */
4395 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4396 if (flow != GST_FLOW_OK)
4399 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4401 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4402 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4404 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4407 qtdemux_parse_tfra (qtdemux, tfra_node);
4408 /* iterate all siblings */
4409 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4411 g_node_destroy (mfra_node);
4413 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4419 if (mfro_map.memory != NULL)
4420 gst_buffer_unmap (mfro, &mfro_map);
4421 gst_buffer_unref (mfro);
4424 if (mfra_map.memory != NULL)
4425 gst_buffer_unmap (mfra, &mfra_map);
4426 gst_buffer_unref (mfra);
4433 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4438 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4443 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4448 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4454 add_offset (guint64 offset, guint64 advance)
4456 /* Avoid 64-bit overflow by clamping */
4457 if (offset > G_MAXUINT64 - advance)
4459 return offset + advance;
4462 static GstFlowReturn
4463 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4467 GstBuffer *buf = NULL;
4468 GstFlowReturn ret = GST_FLOW_OK;
4469 guint64 cur_offset = qtdemux->offset;
4472 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4473 if (G_UNLIKELY (ret != GST_FLOW_OK))
4475 gst_buffer_map (buf, &map, GST_MAP_READ);
4476 if (G_LIKELY (map.size >= 8))
4477 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4478 gst_buffer_unmap (buf, &map);
4479 gst_buffer_unref (buf);
4481 /* maybe we already got most we needed, so only consider this eof */
4482 if (G_UNLIKELY (length == 0)) {
4483 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4484 (_("Invalid atom size.")),
4485 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4486 GST_FOURCC_ARGS (fourcc)));
4493 /* record for later parsing when needed */
4494 if (!qtdemux->moof_offset) {
4495 qtdemux->moof_offset = qtdemux->offset;
4497 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4500 qtdemux->offset += length; /* skip moof and keep going */
4502 if (qtdemux->got_moov) {
4503 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4515 GST_LOG_OBJECT (qtdemux,
4516 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4517 GST_FOURCC_ARGS (fourcc), cur_offset);
4518 qtdemux->offset = add_offset (qtdemux->offset, length);
4523 GstBuffer *moov = NULL;
4525 if (qtdemux->got_moov) {
4526 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4527 qtdemux->offset = add_offset (qtdemux->offset, length);
4531 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4532 if (ret != GST_FLOW_OK)
4534 gst_buffer_map (moov, &map, GST_MAP_READ);
4536 if (length != map.size) {
4537 /* Some files have a 'moov' atom at the end of the file which contains
4538 * a terminal 'free' atom where the body of the atom is missing.
4539 * Check for, and permit, this special case.
4541 if (map.size >= 8) {
4542 guint8 *final_data = map.data + (map.size - 8);
4543 guint32 final_length = QT_UINT32 (final_data);
4544 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4546 if (final_fourcc == FOURCC_free
4547 && map.size + final_length - 8 == length) {
4548 /* Ok, we've found that special case. Allocate a new buffer with
4549 * that free atom actually present. */
4550 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4551 gst_buffer_fill (newmoov, 0, map.data, map.size);
4552 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4553 gst_buffer_unmap (moov, &map);
4554 gst_buffer_unref (moov);
4556 gst_buffer_map (moov, &map, GST_MAP_READ);
4561 if (length != map.size) {
4562 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4563 (_("This file is incomplete and cannot be played.")),
4564 ("We got less than expected (received %" G_GSIZE_FORMAT
4565 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4566 (guint) length, cur_offset));
4567 gst_buffer_unmap (moov, &map);
4568 gst_buffer_unref (moov);
4569 ret = GST_FLOW_ERROR;
4572 qtdemux->offset += length;
4574 qtdemux_parse_moov (qtdemux, map.data, length);
4575 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4577 qtdemux_parse_tree (qtdemux);
4578 if (qtdemux->moov_node_compressed) {
4579 g_node_destroy (qtdemux->moov_node_compressed);
4580 g_free (qtdemux->moov_node->data);
4582 qtdemux->moov_node_compressed = NULL;
4583 g_node_destroy (qtdemux->moov_node);
4584 qtdemux->moov_node = NULL;
4585 gst_buffer_unmap (moov, &map);
4586 gst_buffer_unref (moov);
4587 qtdemux->got_moov = TRUE;
4593 GstBuffer *ftyp = NULL;
4595 /* extract major brand; might come in handy for ISO vs QT issues */
4596 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4597 if (ret != GST_FLOW_OK)
4599 qtdemux->offset += length;
4600 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4601 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4602 gst_buffer_unmap (ftyp, &map);
4603 gst_buffer_unref (ftyp);
4608 GstBuffer *uuid = NULL;
4610 /* uuid are extension atoms */
4611 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4612 if (ret != GST_FLOW_OK)
4614 qtdemux->offset += length;
4615 gst_buffer_map (uuid, &map, GST_MAP_READ);
4616 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4617 gst_buffer_unmap (uuid, &map);
4618 gst_buffer_unref (uuid);
4623 GstBuffer *sidx = NULL;
4624 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4625 if (ret != GST_FLOW_OK)
4627 qtdemux->offset += length;
4628 gst_buffer_map (sidx, &map, GST_MAP_READ);
4629 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4630 gst_buffer_unmap (sidx, &map);
4631 gst_buffer_unref (sidx);
4636 GstBuffer *unknown = NULL;
4638 GST_LOG_OBJECT (qtdemux,
4639 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4640 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4642 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4643 if (ret != GST_FLOW_OK)
4645 gst_buffer_map (unknown, &map, GST_MAP_READ);
4646 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4647 gst_buffer_unmap (unknown, &map);
4648 gst_buffer_unref (unknown);
4649 qtdemux->offset += length;
4655 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4656 /* digested all data, show what we have */
4657 qtdemux_prepare_streams (qtdemux);
4658 QTDEMUX_EXPOSE_LOCK (qtdemux);
4659 ret = qtdemux_expose_streams (qtdemux);
4660 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4662 qtdemux->state = QTDEMUX_STATE_MOVIE;
4663 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4670 /* Seeks to the previous keyframe of the indexed stream and
4671 * aligns other streams with respect to the keyframe timestamp
4672 * of indexed stream. Only called in case of Reverse Playback
4674 static GstFlowReturn
4675 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4677 guint32 seg_idx = 0, k_index = 0;
4678 guint32 ref_seg_idx, ref_k_index;
4679 GstClockTime k_pos = 0, last_stop = 0;
4680 QtDemuxSegment *seg = NULL;
4681 QtDemuxStream *ref_str = NULL;
4682 guint64 seg_media_start_mov; /* segment media start time in mov format */
4686 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4687 * and finally align all the other streams on that timestamp with their
4688 * respective keyframes */
4689 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4690 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4692 /* No candidate yet, take the first stream */
4698 /* So that stream has a segment, we prefer video streams */
4699 if (str->subtype == FOURCC_vide) {
4705 if (G_UNLIKELY (!ref_str)) {
4706 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4710 if (G_UNLIKELY (!ref_str->from_sample)) {
4711 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4715 /* So that stream has been playing from from_sample to to_sample. We will
4716 * get the timestamp of the previous sample and search for a keyframe before
4717 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4718 if (ref_str->subtype == FOURCC_vide) {
4719 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4720 ref_str->from_sample - 1, FALSE);
4722 if (ref_str->from_sample >= 10)
4723 k_index = ref_str->from_sample - 10;
4729 ref_str->samples[k_index].timestamp +
4730 ref_str->samples[k_index].pts_offset;
4732 /* get current segment for that stream */
4733 seg = &ref_str->segments[ref_str->segment_index];
4734 /* Use segment start in original timescale for comparisons */
4735 seg_media_start_mov = seg->trak_media_start;
4737 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4738 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4739 k_index, target_ts, seg_media_start_mov,
4740 GST_TIME_ARGS (seg->media_start));
4742 /* Crawl back through segments to find the one containing this I frame */
4743 while (target_ts < seg_media_start_mov) {
4744 GST_DEBUG_OBJECT (qtdemux,
4745 "keyframe position (sample %u) is out of segment %u " " target %"
4746 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4747 ref_str->segment_index, target_ts, seg_media_start_mov);
4749 if (G_UNLIKELY (!ref_str->segment_index)) {
4750 /* Reached first segment, let's consider it's EOS */
4753 ref_str->segment_index--;
4754 seg = &ref_str->segments[ref_str->segment_index];
4755 /* Use segment start in original timescale for comparisons */
4756 seg_media_start_mov = seg->trak_media_start;
4758 /* Calculate time position of the keyframe and where we should stop */
4760 QTSTREAMTIME_TO_GSTTIME (ref_str,
4761 target_ts - seg->trak_media_start) + seg->time;
4763 QTSTREAMTIME_TO_GSTTIME (ref_str,
4764 ref_str->samples[ref_str->from_sample].timestamp -
4765 seg->trak_media_start) + seg->time;
4767 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4768 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4769 k_index, GST_TIME_ARGS (k_pos));
4771 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4772 qtdemux->segment.position = last_stop;
4773 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4774 GST_TIME_ARGS (last_stop));
4776 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4777 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4781 ref_seg_idx = ref_str->segment_index;
4782 ref_k_index = k_index;
4784 /* Align them all on this */
4785 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4787 GstClockTime seg_time = 0;
4788 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4790 /* aligning reference stream again might lead to backing up to yet another
4791 * keyframe (due to timestamp rounding issues),
4792 * potentially putting more load on downstream; so let's try to avoid */
4793 if (str == ref_str) {
4794 seg_idx = ref_seg_idx;
4795 seg = &str->segments[seg_idx];
4796 k_index = ref_k_index;
4797 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4798 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4800 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4801 GST_DEBUG_OBJECT (qtdemux,
4802 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4803 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4805 /* get segment and time in the segment */
4806 seg = &str->segments[seg_idx];
4807 seg_time = k_pos - seg->time;
4809 /* get the media time in the segment.
4810 * No adjustment for empty "filler" segments */
4811 if (seg->media_start != GST_CLOCK_TIME_NONE)
4812 seg_time += seg->media_start;
4814 /* get the index of the sample with media time */
4815 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4816 GST_DEBUG_OBJECT (qtdemux,
4817 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4818 GST_TIME_ARGS (seg_time), index);
4820 /* find previous keyframe */
4821 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4824 /* Remember until where we want to go */
4825 str->to_sample = str->from_sample - 1;
4826 /* Define our time position */
4828 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4829 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4830 if (seg->media_start != GST_CLOCK_TIME_NONE)
4831 str->time_position -= seg->media_start;
4833 /* Now seek back in time */
4834 gst_qtdemux_move_stream (qtdemux, str, k_index);
4835 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4836 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4837 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4843 return GST_FLOW_EOS;
4847 * Gets the current qt segment start, stop and position for the
4848 * given time offset. This is used in update_segment()
4851 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4852 QtDemuxStream * stream, GstClockTime offset,
4853 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4855 GstClockTime seg_time;
4856 GstClockTime start, stop, time;
4857 QtDemuxSegment *segment;
4859 segment = &stream->segments[stream->segment_index];
4861 /* get time in this segment */
4862 seg_time = (offset - segment->time) * segment->rate;
4864 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4865 GST_TIME_ARGS (seg_time));
4867 if (G_UNLIKELY (seg_time > segment->duration)) {
4868 GST_LOG_OBJECT (stream->pad,
4869 "seg_time > segment->duration %" GST_TIME_FORMAT,
4870 GST_TIME_ARGS (segment->duration));
4871 seg_time = segment->duration;
4874 /* qtdemux->segment.stop is in outside-time-realm, whereas
4875 * segment->media_stop is in track-time-realm.
4877 * In order to compare the two, we need to bring segment.stop
4878 * into the track-time-realm
4880 * FIXME - does this comment still hold? Don't see any conversion here */
4882 stop = qtdemux->segment.stop;
4883 if (stop == GST_CLOCK_TIME_NONE)
4884 stop = qtdemux->segment.duration;
4885 if (stop == GST_CLOCK_TIME_NONE)
4886 stop = segment->media_stop;
4889 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4891 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4892 start = segment->time + seg_time;
4894 stop = start - seg_time + segment->duration;
4895 } else if (qtdemux->segment.rate >= 0) {
4896 start = MIN (segment->media_start + seg_time, stop);
4899 if (segment->media_start >= qtdemux->segment.start) {
4900 time = segment->time;
4902 time = segment->time + (qtdemux->segment.start - segment->media_start);
4905 start = MAX (segment->media_start, qtdemux->segment.start);
4906 stop = MIN (segment->media_start + seg_time, stop);
4915 * Updates the qt segment used for the stream and pushes a new segment event
4916 * downstream on this stream's pad.
4919 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4920 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4921 GstClockTime * _stop)
4923 QtDemuxSegment *segment;
4924 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4928 /* update the current segment */
4929 stream->segment_index = seg_idx;
4931 /* get the segment */
4932 segment = &stream->segments[seg_idx];
4934 if (G_UNLIKELY (offset < segment->time)) {
4935 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4936 GST_TIME_ARGS (segment->time));
4940 /* segment lies beyond total indicated duration */
4941 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4942 segment->time > qtdemux->segment.duration)) {
4943 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4944 " < segment->time %" GST_TIME_FORMAT,
4945 GST_TIME_ARGS (qtdemux->segment.duration),
4946 GST_TIME_ARGS (segment->time));
4950 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4951 &start, &stop, &time);
4953 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4954 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4955 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4957 /* combine global rate with that of the segment */
4958 rate = segment->rate * qtdemux->segment.rate;
4960 /* Copy flags from main segment */
4961 stream->segment.flags = qtdemux->segment.flags;
4963 /* update the segment values used for clipping */
4964 stream->segment.offset = qtdemux->segment.offset;
4965 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4966 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4967 stream->segment.rate = rate;
4968 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4969 stream->cslg_shift);
4971 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4972 stream->cslg_shift);
4974 stream->segment.stop = stop;
4975 stream->segment.time = time;
4976 stream->segment.position = stream->segment.start;
4978 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4981 /* now prepare and send the segment */
4983 event = gst_event_new_segment (&stream->segment);
4984 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4985 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4987 gst_pad_push_event (stream->pad, event);
4988 /* assume we can send more data now */
4989 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4990 /* clear to send tags on this pad now */
4991 gst_qtdemux_push_tags (qtdemux, stream);
5002 /* activate the given segment number @seg_idx of @stream at time @offset.
5003 * @offset is an absolute global position over all the segments.
5005 * This will push out a NEWSEGMENT event with the right values and
5006 * position the stream index to the first decodable sample before
5010 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5011 guint32 seg_idx, GstClockTime offset)
5013 QtDemuxSegment *segment;
5014 guint32 index, kf_index;
5015 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5017 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5018 seg_idx, GST_TIME_ARGS (offset));
5020 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5024 segment = &stream->segments[stream->segment_index];
5026 /* in the fragmented case, we pick a fragment that starts before our
5027 * desired position and rely on downstream to wait for a keyframe
5028 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5029 * tfra entries tells us which trun/sample the key unit is in, but we don't
5030 * make use of this additional information at the moment) */
5031 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5032 stream->to_sample = G_MAXUINT32;
5035 /* well, it will be taken care of below */
5036 qtdemux->fragmented_seek_pending = FALSE;
5037 /* FIXME ideally the do_fragmented_seek can be done right here,
5038 * rather than at loop level
5039 * (which might even allow handling edit lists in a fragmented file) */
5042 /* We don't need to look for a sample in push-based */
5043 if (!qtdemux->pullbased)
5046 /* and move to the keyframe before the indicated media time of the
5048 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5049 if (qtdemux->segment.rate >= 0) {
5050 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5051 stream->to_sample = G_MAXUINT32;
5052 GST_DEBUG_OBJECT (stream->pad,
5053 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5054 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5055 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5057 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5058 stream->to_sample = index;
5059 GST_DEBUG_OBJECT (stream->pad,
5060 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5061 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5062 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5065 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5066 "this is an empty segment");
5070 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5071 * encountered an error and printed a message so we return appropriately */
5075 /* we're at the right spot */
5076 if (index == stream->sample_index) {
5077 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5081 /* find keyframe of the target index */
5082 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5084 /* go back two frames to provide lead-in for non-raw audio decoders */
5085 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5086 guint32 lead_in = 2;
5087 guint32 old_index = kf_index;
5088 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5090 if (gst_structure_has_name (s, "audio/mpeg")) {
5092 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5093 && mpegversion == 1) {
5094 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5099 kf_index = MAX (kf_index, lead_in) - lead_in;
5100 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5101 GST_DEBUG_OBJECT (stream->pad,
5102 "Moving backwards %u frames to ensure sufficient sound lead-in",
5103 old_index - kf_index);
5105 kf_index = old_index;
5109 /* if we move forwards, we don't have to go back to the previous
5110 * keyframe since we already sent that. We can also just jump to
5111 * the keyframe right before the target index if there is one. */
5112 if (index > stream->sample_index) {
5113 /* moving forwards check if we move past a keyframe */
5114 if (kf_index > stream->sample_index) {
5115 GST_DEBUG_OBJECT (stream->pad,
5116 "moving forwards to keyframe at %u "
5117 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5119 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5120 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5121 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5123 GST_DEBUG_OBJECT (stream->pad,
5124 "moving forwards, keyframe at %u "
5125 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5127 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5128 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5131 GST_DEBUG_OBJECT (stream->pad,
5132 "moving backwards to %sframe at %u "
5133 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5134 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5135 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5136 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5137 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5143 /* prepare to get the current sample of @stream, getting essential values.
5145 * This function will also prepare and send the segment when needed.
5147 * Return FALSE if the stream is EOS.
5152 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5153 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5154 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5155 gboolean * keyframe)
5157 QtDemuxSample *sample;
5158 GstClockTime time_position;
5161 g_return_val_if_fail (stream != NULL, FALSE);
5163 time_position = stream->time_position;
5164 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5167 seg_idx = stream->segment_index;
5168 if (G_UNLIKELY (seg_idx == -1)) {
5169 /* find segment corresponding to time_position if we are looking
5171 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5174 /* different segment, activate it, sample_index will be set. */
5175 if (G_UNLIKELY (stream->segment_index != seg_idx))
5176 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5178 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5179 segments[stream->segment_index]))) {
5180 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5182 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5183 " prepare empty sample");
5186 *pts = *dts = time_position;
5187 *duration = seg->duration - (time_position - seg->time);
5194 if (stream->sample_index == -1)
5195 stream->sample_index = 0;
5197 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5198 stream->sample_index, stream->n_samples);
5200 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5201 if (!qtdemux->fragmented)
5204 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5208 GST_OBJECT_LOCK (qtdemux);
5209 flow = qtdemux_add_fragmented_samples (qtdemux);
5210 GST_OBJECT_UNLOCK (qtdemux);
5212 if (flow != GST_FLOW_OK)
5215 while (stream->sample_index >= stream->n_samples);
5218 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5219 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5220 stream->sample_index);
5224 /* now get the info for the sample we're at */
5225 sample = &stream->samples[stream->sample_index];
5227 *dts = QTSAMPLE_DTS (stream, sample);
5228 *pts = QTSAMPLE_PTS (stream, sample);
5229 *offset = sample->offset;
5230 *size = sample->size;
5231 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5232 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5239 stream->time_position = GST_CLOCK_TIME_NONE;
5244 /* move to the next sample in @stream.
5246 * Moves to the next segment when needed.
5249 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5251 QtDemuxSample *sample;
5252 QtDemuxSegment *segment;
5254 /* get current segment */
5255 segment = &stream->segments[stream->segment_index];
5257 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5258 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5262 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5263 /* Mark the stream as EOS */
5264 GST_DEBUG_OBJECT (qtdemux,
5265 "reached max allowed sample %u, mark EOS", stream->to_sample);
5266 stream->time_position = GST_CLOCK_TIME_NONE;
5270 /* move to next sample */
5271 stream->sample_index++;
5272 stream->offset_in_sample = 0;
5274 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5277 /* reached the last sample, we need the next segment */
5278 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5281 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5282 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5283 stream->sample_index);
5287 /* get next sample */
5288 sample = &stream->samples[stream->sample_index];
5290 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5291 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5292 GST_TIME_ARGS (segment->media_stop));
5294 /* see if we are past the segment */
5295 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5298 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5299 /* inside the segment, update time_position, looks very familiar to
5300 * GStreamer segments, doesn't it? */
5301 stream->time_position =
5302 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5304 /* not yet in segment, time does not yet increment. This means
5305 * that we are still prerolling keyframes to the decoder so it can
5306 * decode the first sample of the segment. */
5307 stream->time_position = segment->time;
5311 /* move to the next segment */
5314 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5316 if (stream->segment_index == stream->n_segments - 1) {
5317 /* are we at the end of the last segment, we're EOS */
5318 stream->time_position = GST_CLOCK_TIME_NONE;
5320 /* else we're only at the end of the current segment */
5321 stream->time_position = segment->stop_time;
5323 /* make sure we select a new segment */
5325 /* accumulate previous segments */
5326 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5327 stream->accumulated_base +=
5328 (stream->segment.stop -
5329 stream->segment.start) / ABS (stream->segment.rate);
5331 stream->segment_index = -1;
5336 gst_qtdemux_sync_streams (GstQTDemux * demux)
5340 if (QTDEMUX_N_STREAMS (demux) <= 1)
5343 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5344 QtDemuxStream *stream;
5345 GstClockTime end_time;
5347 stream = QTDEMUX_NTH_STREAM (demux, i);
5352 /* TODO advance time on subtitle streams here, if any some day */
5354 /* some clips/trailers may have unbalanced streams at the end,
5355 * so send EOS on shorter stream to prevent stalling others */
5357 /* do not mess with EOS if SEGMENT seeking */
5358 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5361 if (demux->pullbased) {
5362 /* loop mode is sample time based */
5363 if (!STREAM_IS_EOS (stream))
5366 /* push mode is byte position based */
5367 if (stream->n_samples &&
5368 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5372 if (stream->sent_eos)
5375 /* only act if some gap */
5376 end_time = stream->segments[stream->n_segments - 1].stop_time;
5377 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5378 ", stream end: %" GST_TIME_FORMAT,
5379 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5380 if (GST_CLOCK_TIME_IS_VALID (end_time)
5381 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5384 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5385 GST_PAD_NAME (stream->pad));
5386 stream->sent_eos = TRUE;
5387 event = gst_event_new_eos ();
5388 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5389 gst_event_set_seqnum (event, demux->segment_seqnum);
5390 gst_pad_push_event (stream->pad, event);
5395 /* EOS and NOT_LINKED need to be combined. This means that we return:
5397 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5398 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5400 static GstFlowReturn
5401 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5404 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5407 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5410 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5412 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5416 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5417 * completely clipped
5419 * Should be used only with raw buffers */
5421 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5424 guint64 start, stop, cstart, cstop, diff;
5425 GstClockTime pts, duration;
5427 gint num_rate, denom_rate;
5432 osize = size = gst_buffer_get_size (buf);
5435 /* depending on the type, setup the clip parameters */
5436 if (stream->subtype == FOURCC_soun) {
5437 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5438 num_rate = GST_SECOND;
5439 denom_rate = (gint) CUR_STREAM (stream)->rate;
5441 } else if (stream->subtype == FOURCC_vide) {
5443 num_rate = CUR_STREAM (stream)->fps_n;
5444 denom_rate = CUR_STREAM (stream)->fps_d;
5449 if (frame_size <= 0)
5450 goto bad_frame_size;
5452 /* we can only clip if we have a valid pts */
5453 pts = GST_BUFFER_PTS (buf);
5454 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5457 duration = GST_BUFFER_DURATION (buf);
5459 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5461 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5465 stop = start + duration;
5467 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5468 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5471 /* see if some clipping happened */
5472 diff = cstart - start;
5478 /* bring clipped time to samples and to bytes */
5479 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5482 GST_DEBUG_OBJECT (qtdemux,
5483 "clipping start to %" GST_TIME_FORMAT " %"
5484 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5490 diff = stop - cstop;
5495 /* bring clipped time to samples and then to bytes */
5496 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5498 GST_DEBUG_OBJECT (qtdemux,
5499 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5500 " bytes", GST_TIME_ARGS (cstop), diff);
5505 if (offset != 0 || size != osize)
5506 gst_buffer_resize (buf, offset, size);
5508 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5509 GST_BUFFER_PTS (buf) = pts;
5510 GST_BUFFER_DURATION (buf) = duration;
5514 /* dropped buffer */
5517 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5522 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5527 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5532 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5533 gst_buffer_unref (buf);
5539 gst_qtdemux_align_buffer (GstQTDemux * demux,
5540 GstBuffer * buffer, gsize alignment)
5544 gst_buffer_map (buffer, &map, GST_MAP_READ);
5546 if (map.size < sizeof (guintptr)) {
5547 gst_buffer_unmap (buffer, &map);
5551 if (((guintptr) map.data) & (alignment - 1)) {
5552 GstBuffer *new_buffer;
5553 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5555 new_buffer = gst_buffer_new_allocate (NULL,
5556 gst_buffer_get_size (buffer), ¶ms);
5558 /* Copy data "by hand", so ensure alignment is kept: */
5559 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5561 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5562 GST_DEBUG_OBJECT (demux,
5563 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5566 gst_buffer_unmap (buffer, &map);
5567 gst_buffer_unref (buffer);
5572 gst_buffer_unmap (buffer, &map);
5577 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5583 /* We are converting from pairs to triplets */
5584 *res = ccpair_size / 2 * 3;
5585 storage = g_malloc (*res);
5586 for (i = 0; i * 2 < ccpair_size; i += 1) {
5587 /* FIXME: Use line offset 0 as we simply can't know here */
5589 storage[i * 3] = 0x80 | 0x00;
5591 storage[i * 3] = 0x00 | 0x00;
5592 storage[i * 3 + 1] = ccpair[i * 2];
5593 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5600 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5604 guint32 atom_length, fourcc;
5605 QtDemuxStreamStsdEntry *stsd_entry;
5607 GST_MEMDUMP ("caption atom", data, size);
5609 /* There might be multiple atoms */
5614 atom_length = QT_UINT32 (data);
5615 fourcc = QT_FOURCC (data + 4);
5616 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5619 GST_DEBUG_OBJECT (stream->pad, "here");
5621 /* Check if we have something compatible */
5622 stsd_entry = CUR_STREAM (stream);
5623 switch (stsd_entry->fourcc) {
5625 guint8 *cdat = NULL, *cdt2 = NULL;
5626 gsize cdat_size = 0, cdt2_size = 0;
5627 /* Should be cdat or cdt2 */
5628 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5629 GST_WARNING_OBJECT (stream->pad,
5630 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5631 GST_FOURCC_ARGS (fourcc));
5635 /* Convert to S334-1 Annex A byte triplet */
5636 if (fourcc == FOURCC_cdat)
5637 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5639 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5640 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5643 /* Check for another atom ? */
5644 if (size > atom_length + 8) {
5645 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5646 if (size >= atom_length + new_atom_length) {
5647 fourcc = QT_FOURCC (data + atom_length + 4);
5648 if (fourcc == FOURCC_cdat) {
5651 convert_to_s334_1a (data + atom_length + 8,
5652 new_atom_length - 8, 1, &cdat_size);
5654 GST_WARNING_OBJECT (stream->pad,
5655 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5659 convert_to_s334_1a (data + atom_length + 8,
5660 new_atom_length - 8, 2, &cdt2_size);
5662 GST_WARNING_OBJECT (stream->pad,
5663 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5668 *cclen = cdat_size + cdt2_size;
5669 res = g_malloc (*cclen);
5671 memcpy (res, cdat, cdat_size);
5673 memcpy (res + cdat_size, cdt2, cdt2_size);
5679 if (fourcc != FOURCC_ccdp) {
5680 GST_WARNING_OBJECT (stream->pad,
5681 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5682 GST_FOURCC_ARGS (fourcc));
5685 *cclen = atom_length - 8;
5686 res = g_memdup2 (data + 8, *cclen);
5689 /* Keep this here in case other closed caption formats are added */
5690 g_assert_not_reached ();
5694 GST_MEMDUMP ("Output", res, *cclen);
5699 GST_WARNING ("[cdat] atom is too small or invalid");
5703 /* Handle Closed Caption sample buffers.
5704 * The input buffer metadata must be writable,
5705 * but time/duration etc not yet set and need not be preserved */
5707 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5710 GstBuffer *outbuf = NULL;
5715 gst_buffer_map (buf, &map, GST_MAP_READ);
5717 /* empty buffer is sent to terminate previous subtitle */
5718 if (map.size <= 2) {
5719 gst_buffer_unmap (buf, &map);
5720 gst_buffer_unref (buf);
5724 /* For closed caption, we need to extract the information from the
5725 * [cdat],[cdt2] or [ccdp] atom */
5726 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5727 gst_buffer_unmap (buf, &map);
5729 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5730 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5732 /* Conversion failed or there's nothing */
5734 gst_buffer_unref (buf);
5739 /* DVD subpicture specific sample handling.
5740 * the input buffer metadata must be writable,
5741 * but time/duration etc not yet set and need not be preserved */
5743 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5746 /* send a one time dvd clut event */
5747 if (stream->pending_event && stream->pad)
5748 gst_pad_push_event (stream->pad, stream->pending_event);
5749 stream->pending_event = NULL;
5751 /* empty buffer is sent to terminate previous subtitle */
5752 if (gst_buffer_get_size (buf) <= 2) {
5753 gst_buffer_unref (buf);
5757 /* That's all the processing needed for subpictures */
5761 /* Timed text formats
5762 * the input buffer metadata must be writable,
5763 * but time/duration etc not yet set and need not be preserved */
5765 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5768 GstBuffer *outbuf = NULL;
5773 /* not many cases for now */
5774 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5775 stream->subtype != FOURCC_sbtl)) {
5779 gst_buffer_map (buf, &map, GST_MAP_READ);
5781 /* empty buffer is sent to terminate previous subtitle */
5782 if (map.size <= 2) {
5783 gst_buffer_unmap (buf, &map);
5784 gst_buffer_unref (buf);
5788 nsize = GST_READ_UINT16_BE (map.data);
5789 nsize = MIN (nsize, map.size - 2);
5791 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5794 /* takes care of UTF-8 validation or UTF-16 recognition,
5795 * no other encoding expected */
5796 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5797 gst_buffer_unmap (buf, &map);
5800 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5801 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5803 /* this should not really happen unless the subtitle is corrupted */
5805 gst_buffer_unref (buf);
5807 /* FIXME ? convert optional subsequent style info to markup */
5812 /* WebVTT sample handling according to 14496-30 */
5814 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5817 GstBuffer *outbuf = NULL;
5820 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5821 g_assert_not_reached (); /* The buffer must be mappable */
5824 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5825 GstEvent *gap = NULL;
5826 /* Push a gap event */
5827 stream->segment.position = GST_BUFFER_PTS (buf);
5829 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5830 gst_pad_push_event (stream->pad, gap);
5832 if (GST_BUFFER_DURATION_IS_VALID (buf))
5833 stream->segment.position += GST_BUFFER_DURATION (buf);
5836 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5837 GST_BUFFER_DURATION (buf), map.data, map.size);
5838 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5841 gst_buffer_unmap (buf, &map);
5842 gst_buffer_unref (buf);
5847 static GstFlowReturn
5848 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5851 GstFlowReturn ret = GST_FLOW_OK;
5852 GstClockTime pts, duration;
5854 if (stream->need_clip)
5855 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5857 if (G_UNLIKELY (buf == NULL))
5860 if (G_UNLIKELY (stream->discont)) {
5861 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5862 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5863 stream->discont = FALSE;
5865 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5868 GST_LOG_OBJECT (qtdemux,
5869 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5870 ", duration %" GST_TIME_FORMAT " on pad %s",
5871 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5872 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5873 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5875 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5876 GstStructure *crypto_info;
5877 QtDemuxAavdEncryptionInfo *info =
5878 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5880 crypto_info = gst_structure_copy (info->default_properties);
5881 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5882 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5885 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
5886 || stream->protection_scheme_type == FOURCC_cbcs)) {
5887 GstStructure *crypto_info;
5888 QtDemuxCencSampleSetInfo *info =
5889 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5893 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5894 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5895 GST_PTR_FORMAT, event);
5896 gst_pad_push_event (stream->pad, event);
5899 if (info->crypto_info == NULL) {
5900 if (stream->protection_scheme_type == FOURCC_cbcs) {
5901 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
5902 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
5903 GST_ERROR_OBJECT (qtdemux,
5904 "failed to attach cbcs metadata to buffer");
5905 qtdemux_gst_structure_free (crypto_info);
5907 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
5910 GST_DEBUG_OBJECT (qtdemux,
5911 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5914 /* The end of the crypto_info array matches our n_samples position,
5915 * so count backward from there */
5916 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5917 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5918 /* steal structure from array */
5919 crypto_info = g_ptr_array_index (info->crypto_info, index);
5920 g_ptr_array_index (info->crypto_info, index) = NULL;
5921 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5922 info->crypto_info->len);
5923 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5924 GST_ERROR_OBJECT (qtdemux,
5925 "failed to attach cenc metadata to buffer");
5927 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5928 index, stream->sample_index);
5933 if (stream->alignment > 1)
5934 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5936 pts = GST_BUFFER_PTS (buf);
5937 duration = GST_BUFFER_DURATION (buf);
5939 ret = gst_pad_push (stream->pad, buf);
5941 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5942 /* mark position in stream, we'll need this to know when to send GAP event */
5943 stream->segment.position = pts + duration;
5951 static GstFlowReturn
5952 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5955 GstFlowReturn ret = GST_FLOW_OK;
5957 if (stream->subtype == FOURCC_clcp
5958 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
5960 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
5961 guint n_triplets, i;
5962 guint field1_off = 0, field2_off = 0;
5964 /* We have to split CEA608 buffers so that each outgoing buffer contains
5965 * one byte pair per field according to the framerate of the video track.
5967 * If there is only a single byte pair per field we don't have to do
5971 gst_buffer_map (buf, &map, GST_MAP_READ);
5973 n_triplets = map.size / 3;
5974 for (i = 0; i < n_triplets; i++) {
5975 if (map.data[3 * i] & 0x80)
5981 g_assert (n_field1 || n_field2);
5983 /* If there's more than 1 frame we have to split, otherwise we can just
5985 if (n_field1 > 1 || n_field2 > 1) {
5987 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
5988 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
5990 for (i = 0; i < n_output_buffers; i++) {
5992 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
5996 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
5997 outptr = outmap.data;
6000 gboolean found = FALSE;
6002 while (map.data + field1_off < map.data + map.size) {
6003 if (map.data[field1_off] & 0x80) {
6004 memcpy (outptr, &map.data[field1_off], 3);
6013 const guint8 empty[] = { 0x80, 0x80, 0x80 };
6015 memcpy (outptr, empty, 3);
6022 gboolean found = FALSE;
6024 while (map.data + field2_off < map.data + map.size) {
6025 if ((map.data[field2_off] & 0x80) == 0) {
6026 memcpy (outptr, &map.data[field2_off], 3);
6035 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6037 memcpy (outptr, empty, 3);
6043 gst_buffer_unmap (outbuf, &outmap);
6045 GST_BUFFER_PTS (outbuf) =
6046 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6047 GST_SECOND * CUR_STREAM (stream)->fps_d,
6048 CUR_STREAM (stream)->fps_n);
6049 GST_BUFFER_DURATION (outbuf) =
6050 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6051 CUR_STREAM (stream)->fps_n);
6052 GST_BUFFER_OFFSET (outbuf) = -1;
6053 GST_BUFFER_OFFSET_END (outbuf) = -1;
6055 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6057 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6060 gst_buffer_unmap (buf, &map);
6061 gst_buffer_unref (buf);
6063 gst_buffer_unmap (buf, &map);
6064 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6067 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6073 /* Sets a buffer's attributes properly and pushes it downstream.
6074 * Also checks for additional actions and custom processing that may
6075 * need to be done first.
6077 static GstFlowReturn
6078 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6079 QtDemuxStream * stream, GstBuffer * buf,
6080 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6081 gboolean keyframe, GstClockTime position, guint64 byte_position)
6083 GstFlowReturn ret = GST_FLOW_OK;
6085 /* offset the timestamps according to the edit list */
6087 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6091 gst_buffer_map (buf, &map, GST_MAP_READ);
6092 url = g_strndup ((gchar *) map.data, map.size);
6093 gst_buffer_unmap (buf, &map);
6094 if (url != NULL && strlen (url) != 0) {
6095 /* we have RTSP redirect now */
6096 g_free (qtdemux->redirect_location);
6097 qtdemux->redirect_location = g_strdup (url);
6098 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6099 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6100 gst_structure_new ("redirect",
6101 "new-location", G_TYPE_STRING, url, NULL)));
6103 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6109 /* position reporting */
6110 if (qtdemux->segment.rate >= 0) {
6111 qtdemux->segment.position = position;
6112 gst_qtdemux_sync_streams (qtdemux);
6115 if (G_UNLIKELY (!stream->pad)) {
6116 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6117 gst_buffer_unref (buf);
6121 /* send out pending buffers */
6122 while (stream->buffers) {
6123 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6125 if (G_UNLIKELY (stream->discont)) {
6126 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6127 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6128 stream->discont = FALSE;
6130 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6133 if (stream->alignment > 1)
6134 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6135 gst_pad_push (stream->pad, buffer);
6137 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6140 /* we're going to modify the metadata */
6141 buf = gst_buffer_make_writable (buf);
6143 GST_BUFFER_DTS (buf) = dts;
6144 GST_BUFFER_PTS (buf) = pts;
6145 GST_BUFFER_DURATION (buf) = duration;
6146 GST_BUFFER_OFFSET (buf) = -1;
6147 GST_BUFFER_OFFSET_END (buf) = -1;
6149 if (G_UNLIKELY (stream->process_func))
6150 buf = stream->process_func (qtdemux, stream, buf);
6157 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6158 stream->on_keyframe = FALSE;
6160 stream->on_keyframe = TRUE;
6163 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6164 gst_buffer_append_memory (buf,
6165 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6167 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6168 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6171 if (G_UNLIKELY (qtdemux->element_index)) {
6172 GstClockTime stream_time;
6175 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6177 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6178 GST_LOG_OBJECT (qtdemux,
6179 "adding association %" GST_TIME_FORMAT "-> %"
6180 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6181 gst_index_add_association (qtdemux->element_index,
6183 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6184 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6185 GST_FORMAT_BYTES, byte_position, NULL);
6190 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6196 static const QtDemuxRandomAccessEntry *
6197 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6198 GstClockTime pos, gboolean after)
6200 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6201 guint n_entries = stream->n_ra_entries;
6204 /* we assume the table is sorted */
6205 for (i = 0; i < n_entries; ++i) {
6206 if (entries[i].ts > pos)
6210 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6211 * probably okay to assume that the index lists the very first fragment */
6218 return &entries[i - 1];
6222 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6224 const QtDemuxRandomAccessEntry *best_entry = NULL;
6227 GST_OBJECT_LOCK (qtdemux);
6229 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6231 /* first see if we can determine where to go to using mfra,
6232 * before we start clearing things */
6233 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6234 const QtDemuxRandomAccessEntry *entry;
6235 QtDemuxStream *stream;
6236 gboolean is_audio_or_video;
6238 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6240 if (stream->ra_entries == NULL)
6243 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6244 is_audio_or_video = TRUE;
6246 is_audio_or_video = FALSE;
6249 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6250 stream->time_position, !is_audio_or_video);
6252 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6253 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6255 stream->pending_seek = entry;
6257 /* decide position to jump to just based on audio/video tracks, not subs */
6258 if (!is_audio_or_video)
6261 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6265 /* no luck, will handle seek otherwise */
6266 if (best_entry == NULL) {
6267 GST_OBJECT_UNLOCK (qtdemux);
6271 /* ok, now we can prepare for processing as of located moof */
6272 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6273 QtDemuxStream *stream;
6275 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6277 g_free (stream->samples);
6278 stream->samples = NULL;
6279 stream->n_samples = 0;
6280 stream->stbl_index = -1; /* no samples have yet been parsed */
6281 stream->sample_index = -1;
6283 if (stream->protection_scheme_info) {
6284 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6285 if (stream->protection_scheme_type == FOURCC_cenc
6286 || stream->protection_scheme_type == FOURCC_cbcs) {
6287 QtDemuxCencSampleSetInfo *info =
6288 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6289 if (info->crypto_info) {
6290 g_ptr_array_free (info->crypto_info, TRUE);
6291 info->crypto_info = NULL;
6297 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6298 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6299 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6300 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6302 qtdemux->moof_offset = best_entry->moof_offset;
6304 qtdemux_add_fragmented_samples (qtdemux);
6306 GST_OBJECT_UNLOCK (qtdemux);
6310 static GstFlowReturn
6311 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6313 GstFlowReturn ret = GST_FLOW_OK;
6314 GstBuffer *buf = NULL;
6315 QtDemuxStream *stream, *target_stream = NULL;
6316 GstClockTime min_time;
6318 GstClockTime dts = GST_CLOCK_TIME_NONE;
6319 GstClockTime pts = GST_CLOCK_TIME_NONE;
6320 GstClockTime duration = 0;
6321 gboolean keyframe = FALSE;
6322 guint sample_size = 0;
6323 guint num_samples = 1;
6328 if (qtdemux->fragmented_seek_pending) {
6329 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6330 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6331 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6332 qtdemux->fragmented_seek_pending = FALSE;
6334 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6338 /* Figure out the next stream sample to output, min_time is expressed in
6339 * global time and runs over the edit list segments. */
6340 min_time = G_MAXUINT64;
6341 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6342 GstClockTime position;
6344 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6345 position = stream->time_position;
6347 if (!GST_CLOCK_TIME_IS_VALID (position))
6350 if (stream->segment_index != -1) {
6351 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6352 position += segment->media_start;
6355 /* position of -1 is EOS */
6356 if (position < min_time) {
6357 min_time = position;
6358 target_stream = stream;
6362 if (G_UNLIKELY (target_stream == NULL)) {
6363 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6367 /* check for segment end */
6368 if (G_UNLIKELY (qtdemux->segment.stop != -1
6369 && qtdemux->segment.rate >= 0
6370 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6371 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6372 target_stream->time_position = GST_CLOCK_TIME_NONE;
6376 /* fetch info for the current sample of this stream */
6377 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, target_stream,
6378 &empty, &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6381 /* Send catche-up GAP event for each other stream if required.
6382 * This logic will be applied only for positive rate */
6383 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux) &&
6384 qtdemux->segment.rate >= 0; i++) {
6385 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6387 if (stream == target_stream ||
6388 !GST_CLOCK_TIME_IS_VALID (stream->segment.stop) ||
6389 !GST_CLOCK_TIME_IS_VALID (stream->segment.position))
6393 GstClockTime gap_threshold;
6394 /* kind of running time with offset segment.base and segment.start */
6395 GstClockTime pseudo_target_time = target_stream->segment.base;
6396 GstClockTime pseudo_cur_time = stream->segment.base;
6398 /* make sure positive offset, segment.position can be smallr than
6399 * segment.start for some reasons */
6400 if (target_stream->segment.position >= target_stream->segment.start) {
6401 pseudo_target_time +=
6402 (target_stream->segment.position - target_stream->segment.start);
6405 if (stream->segment.position >= stream->segment.start)
6406 pseudo_cur_time += (stream->segment.position - stream->segment.start);
6408 /* Only send gap events on non-subtitle streams if lagging way behind. */
6409 if (stream->subtype == FOURCC_subp
6410 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6411 stream->subtype == FOURCC_wvtt)
6412 gap_threshold = 1 * GST_SECOND;
6414 gap_threshold = 3 * GST_SECOND;
6416 /* send gap events until the stream catches up */
6417 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6418 while (GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6419 pseudo_cur_time + gap_threshold < pseudo_target_time) {
6421 gst_event_new_gap (stream->segment.position, gap_threshold);
6422 GST_LOG_OBJECT (stream->pad, "Sending %" GST_PTR_FORMAT, gap);
6424 gst_pad_push_event (stream->pad, gap);
6425 stream->segment.position += gap_threshold;
6426 pseudo_cur_time += gap_threshold;
6431 stream = target_stream;
6433 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6434 if (stream->new_caps) {
6435 gst_qtdemux_configure_stream (qtdemux, stream);
6436 qtdemux_do_allocation (stream, qtdemux);
6439 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6440 if (G_UNLIKELY (qtdemux->segment.
6441 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6442 if (stream->subtype == FOURCC_vide) {
6444 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6447 } else if (qtdemux->trickmode_interval > 0) {
6448 GstClockTimeDiff interval;
6450 if (qtdemux->segment.rate > 0)
6451 interval = stream->time_position - stream->last_keyframe_dts;
6453 interval = stream->last_keyframe_dts - stream->time_position;
6455 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6456 && interval < qtdemux->trickmode_interval) {
6457 GST_LOG_OBJECT (qtdemux,
6458 "Skipping keyframe within interval on track-id %u",
6462 stream->last_keyframe_dts = stream->time_position;
6468 GST_DEBUG_OBJECT (qtdemux,
6469 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6470 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6471 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6472 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6473 GST_TIME_ARGS (duration));
6475 if (G_UNLIKELY (empty)) {
6476 /* empty segment, push a gap if there's a second or more
6477 * difference and move to the next one */
6478 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6479 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6480 stream->segment.position = pts + duration;
6484 /* hmm, empty sample, skip and move to next sample */
6485 if (G_UNLIKELY (sample_size <= 0))
6488 /* last pushed sample was out of boundary, goto next sample */
6489 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6492 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6493 GST_DEBUG_OBJECT (qtdemux,
6494 "size %d larger than stream max_buffer_size %d, trimming",
6495 sample_size, stream->max_buffer_size);
6497 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6498 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6499 && sample_size < stream->min_buffer_size) {
6500 guint start_sample_index = stream->sample_index;
6501 guint accumulated_size = sample_size;
6502 guint64 expected_next_offset = offset + sample_size;
6504 GST_DEBUG_OBJECT (qtdemux,
6505 "size %d smaller than stream min_buffer_size %d, combining with the next",
6506 sample_size, stream->min_buffer_size);
6508 while (stream->sample_index < stream->to_sample
6509 && stream->sample_index + 1 < stream->n_samples) {
6510 const QtDemuxSample *next_sample;
6512 /* Increment temporarily */
6513 stream->sample_index++;
6515 /* Failed to parse sample so let's go back to the previous one that was
6516 * still successful */
6517 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6518 stream->sample_index--;
6522 next_sample = &stream->samples[stream->sample_index];
6524 /* Not contiguous with the previous sample so let's go back to the
6525 * previous one that was still successful */
6526 if (next_sample->offset != expected_next_offset) {
6527 stream->sample_index--;
6531 accumulated_size += next_sample->size;
6532 expected_next_offset += next_sample->size;
6533 if (accumulated_size >= stream->min_buffer_size)
6537 num_samples = stream->sample_index + 1 - start_sample_index;
6538 stream->sample_index = start_sample_index;
6539 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6540 num_samples, accumulated_size);
6541 size = accumulated_size;
6546 if (qtdemux->cenc_aux_info_offset > 0) {
6549 GstBuffer *aux_info = NULL;
6551 /* pull the data stored before the sample */
6553 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6554 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6555 if (G_UNLIKELY (ret != GST_FLOW_OK))
6557 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6558 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6559 gst_byte_reader_init (&br, map.data + 8, map.size);
6560 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6561 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6562 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6563 gst_buffer_unmap (aux_info, &map);
6564 gst_buffer_unref (aux_info);
6565 ret = GST_FLOW_ERROR;
6568 gst_buffer_unmap (aux_info, &map);
6569 gst_buffer_unref (aux_info);
6572 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6575 if (stream->use_allocator) {
6576 /* if we have a per-stream allocator, use it */
6577 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6580 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6582 if (G_UNLIKELY (ret != GST_FLOW_OK))
6585 /* Update for both splitting and combining of samples */
6586 if (size != sample_size) {
6587 pts += gst_util_uint64_scale_int (GST_SECOND,
6588 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6591 gst_util_uint64_scale_int (GST_SECOND,
6592 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6595 gst_util_uint64_scale_int (GST_SECOND,
6596 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6599 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6600 dts, pts, duration, keyframe, min_time, offset);
6602 if (size < sample_size) {
6603 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6604 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6606 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6608 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6609 if (time_position >= segment->media_start) {
6610 /* inside the segment, update time_position, looks very familiar to
6611 * GStreamer segments, doesn't it? */
6612 stream->time_position = (time_position - segment->media_start) +
6615 /* not yet in segment, time does not yet increment. This means
6616 * that we are still prerolling keyframes to the decoder so it can
6617 * decode the first sample of the segment. */
6618 stream->time_position = segment->time;
6620 } else if (size > sample_size) {
6621 /* Increase to the last sample we already pulled so that advancing
6622 * below brings us to the next sample we need to pull */
6623 stream->sample_index += num_samples - 1;
6627 GST_OBJECT_LOCK (qtdemux);
6628 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6629 GST_OBJECT_UNLOCK (qtdemux);
6630 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6631 * we have no more data for the pad to push */
6632 if (ret == GST_FLOW_EOS)
6635 stream->offset_in_sample += size;
6636 if (stream->offset_in_sample >= sample_size) {
6637 gst_qtdemux_advance_sample (qtdemux, stream);
6642 gst_qtdemux_advance_sample (qtdemux, stream);
6650 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6656 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6657 /* EOS will be raised if all are EOS */
6664 gst_qtdemux_loop (GstPad * pad)
6666 GstQTDemux *qtdemux;
6670 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6672 cur_offset = qtdemux->offset;
6673 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6674 cur_offset, qt_demux_state_string (qtdemux->state));
6676 switch (qtdemux->state) {
6677 case QTDEMUX_STATE_INITIAL:
6678 case QTDEMUX_STATE_HEADER:
6679 ret = gst_qtdemux_loop_state_header (qtdemux);
6681 case QTDEMUX_STATE_MOVIE:
6682 ret = gst_qtdemux_loop_state_movie (qtdemux);
6683 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6684 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6692 /* if something went wrong, pause */
6693 if (ret != GST_FLOW_OK)
6697 gst_object_unref (qtdemux);
6703 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6704 (NULL), ("streaming stopped, invalid state"));
6705 gst_pad_pause_task (pad);
6706 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6711 const gchar *reason = gst_flow_get_name (ret);
6713 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6715 gst_pad_pause_task (pad);
6717 /* fatal errors need special actions */
6719 if (ret == GST_FLOW_EOS) {
6720 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6721 /* we have no streams, post an error */
6722 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6724 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6727 if ((stop = qtdemux->segment.stop) == -1)
6728 stop = qtdemux->segment.duration;
6730 if (qtdemux->segment.rate >= 0) {
6731 GstMessage *message;
6734 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6735 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6736 GST_FORMAT_TIME, stop);
6737 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6738 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6739 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6740 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6742 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6743 gst_qtdemux_push_event (qtdemux, event);
6745 GstMessage *message;
6748 /* For Reverse Playback */
6749 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6750 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6751 GST_FORMAT_TIME, qtdemux->segment.start);
6752 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6753 qtdemux->segment.start);
6754 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6755 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6756 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6758 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6759 gst_qtdemux_push_event (qtdemux, event);
6764 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6765 event = gst_event_new_eos ();
6766 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6767 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6768 gst_qtdemux_push_event (qtdemux, event);
6770 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6771 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6772 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6781 * Returns if there are samples to be played.
6784 has_next_entry (GstQTDemux * demux)
6786 QtDemuxStream *stream;
6789 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6791 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6792 stream = QTDEMUX_NTH_STREAM (demux, i);
6794 if (stream->sample_index == -1) {
6795 stream->sample_index = 0;
6796 stream->offset_in_sample = 0;
6799 if (stream->sample_index >= stream->n_samples) {
6800 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6803 GST_DEBUG_OBJECT (demux, "Found a sample");
6807 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6814 * Returns the size of the first entry at the current offset.
6815 * If -1, there are none (which means EOS or empty file).
6818 next_entry_size (GstQTDemux * demux)
6820 QtDemuxStream *stream, *target_stream = NULL;
6821 guint64 smalloffs = (guint64) - 1;
6822 QtDemuxSample *sample;
6825 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6828 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6829 stream = QTDEMUX_NTH_STREAM (demux, i);
6831 if (stream->sample_index == -1) {
6832 stream->sample_index = 0;
6833 stream->offset_in_sample = 0;
6836 if (stream->sample_index >= stream->n_samples) {
6837 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6841 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6842 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6843 stream->sample_index);
6847 sample = &stream->samples[stream->sample_index];
6849 GST_LOG_OBJECT (demux,
6850 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6851 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6852 stream->sample_index, sample->offset, sample->size);
6854 if (((smalloffs == -1)
6855 || (sample->offset < smalloffs)) && (sample->size)) {
6856 smalloffs = sample->offset;
6857 target_stream = stream;
6864 GST_LOG_OBJECT (demux,
6865 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6866 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6868 stream = target_stream;
6869 sample = &stream->samples[stream->sample_index];
6871 if (sample->offset >= demux->offset) {
6872 demux->todrop = sample->offset - demux->offset;
6873 return sample->size + demux->todrop;
6876 GST_DEBUG_OBJECT (demux,
6877 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6882 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6884 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6886 gst_element_post_message (GST_ELEMENT_CAST (demux),
6887 gst_message_new_element (GST_OBJECT_CAST (demux),
6888 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6892 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6897 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6900 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6901 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6902 GST_SEEK_TYPE_NONE, -1);
6904 /* store seqnum to drop flush events, they don't need to reach downstream */
6905 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6906 res = gst_pad_push_event (demux->sinkpad, event);
6907 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6912 /* check for seekable upstream, above and beyond a mere query */
6914 gst_qtdemux_check_seekability (GstQTDemux * demux)
6917 gboolean seekable = FALSE;
6918 gint64 start = -1, stop = -1;
6920 if (demux->upstream_size)
6923 if (demux->upstream_format_is_time)
6926 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6927 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6928 GST_DEBUG_OBJECT (demux, "seeking query failed");
6932 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6934 /* try harder to query upstream size if we didn't get it the first time */
6935 if (seekable && stop == -1) {
6936 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6937 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6940 /* if upstream doesn't know the size, it's likely that it's not seekable in
6941 * practice even if it technically may be seekable */
6942 if (seekable && (start != 0 || stop <= start)) {
6943 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6948 gst_query_unref (query);
6950 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6951 G_GUINT64_FORMAT ")", seekable, start, stop);
6952 demux->upstream_seekable = seekable;
6953 demux->upstream_size = seekable ? stop : -1;
6957 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6959 g_return_if_fail (bytes <= demux->todrop);
6961 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6962 gst_adapter_flush (demux->adapter, bytes);
6963 demux->neededbytes -= bytes;
6964 demux->offset += bytes;
6965 demux->todrop -= bytes;
6968 /* PUSH-MODE only: Send a segment, if not done already. */
6970 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6972 if (G_UNLIKELY (demux->need_segment)) {
6975 if (!demux->upstream_format_is_time) {
6976 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6978 GstEvent *segment_event;
6979 segment_event = gst_event_new_segment (&demux->segment);
6980 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6981 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6982 gst_qtdemux_push_event (demux, segment_event);
6985 demux->need_segment = FALSE;
6987 /* clear to send tags on all streams */
6988 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6989 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6990 gst_qtdemux_push_tags (demux, stream);
6991 if (CUR_STREAM (stream)->sparse) {
6992 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6993 gst_pad_push_event (stream->pad,
6994 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7000 /* Used for push mode only. */
7002 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7003 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7005 GstClockTime ts, dur;
7009 stream->segments[segment_index].duration - (pos -
7010 stream->segments[segment_index].time);
7011 stream->time_position += dur;
7013 /* Only gaps with a duration of at least one second are propagated.
7014 * Same workaround as in pull mode.
7015 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7016 if (dur >= GST_SECOND) {
7018 gap = gst_event_new_gap (ts, dur);
7020 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7021 "segment: %" GST_PTR_FORMAT, gap);
7022 gst_pad_push_event (stream->pad, gap);
7026 static GstFlowReturn
7027 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7031 demux = GST_QTDEMUX (parent);
7033 GST_DEBUG_OBJECT (demux,
7034 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7035 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7036 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7037 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7038 gst_buffer_get_size (inbuf), demux->offset);
7040 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7041 gboolean is_gap_input = FALSE;
7044 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7046 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7047 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7050 /* Check if we can land back on our feet in the case where upstream is
7051 * handling the seeking/pushing of samples with gaps in between (like
7052 * in the case of trick-mode DASH for example) */
7053 if (demux->upstream_format_is_time
7054 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7055 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7057 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7058 GST_LOG_OBJECT (demux,
7059 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7060 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7062 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7063 stream, GST_BUFFER_OFFSET (inbuf));
7065 QtDemuxSample *sample = &stream->samples[res];
7066 GST_LOG_OBJECT (demux,
7067 "Checking if sample %d from track-id %u is valid (offset:%"
7068 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7069 stream->track_id, sample->offset, sample->size);
7070 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7071 GST_LOG_OBJECT (demux,
7072 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7074 is_gap_input = TRUE;
7075 /* We can go back to standard playback mode */
7076 demux->state = QTDEMUX_STATE_MOVIE;
7077 /* Remember which sample this stream is at */
7078 stream->sample_index = res;
7079 /* Finally update all push-based values to the expected values */
7080 demux->neededbytes = stream->samples[res].size;
7081 demux->offset = GST_BUFFER_OFFSET (inbuf);
7083 demux->mdatsize - demux->offset + demux->mdatoffset;
7088 if (!is_gap_input) {
7089 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7090 /* Reset state if it's a real discont */
7091 demux->neededbytes = 16;
7092 demux->state = QTDEMUX_STATE_INITIAL;
7093 demux->offset = GST_BUFFER_OFFSET (inbuf);
7094 gst_adapter_clear (demux->adapter);
7097 /* Reverse fragmented playback, need to flush all we have before
7098 * consuming a new fragment.
7099 * The samples array have the timestamps calculated by accumulating the
7100 * durations but this won't work for reverse playback of fragments as
7101 * the timestamps of a subsequent fragment should be smaller than the
7102 * previously received one. */
7103 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7104 gst_qtdemux_process_adapter (demux, TRUE);
7105 g_ptr_array_foreach (demux->active_streams,
7106 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7110 gst_adapter_push (demux->adapter, inbuf);
7112 GST_DEBUG_OBJECT (demux,
7113 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7114 demux->neededbytes, gst_adapter_available (demux->adapter));
7116 return gst_qtdemux_process_adapter (demux, FALSE);
7119 static GstFlowReturn
7120 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7122 GstFlowReturn ret = GST_FLOW_OK;
7124 /* we never really mean to buffer that much */
7125 if (demux->neededbytes == -1) {
7129 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7130 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7132 #ifndef GST_DISABLE_GST_DEBUG
7134 guint64 discont_offset, distance_from_discont;
7136 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7137 distance_from_discont =
7138 gst_adapter_distance_from_discont (demux->adapter);
7140 GST_DEBUG_OBJECT (demux,
7141 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7142 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7143 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7144 demux->offset, discont_offset, distance_from_discont);
7148 switch (demux->state) {
7149 case QTDEMUX_STATE_INITIAL:{
7154 gst_qtdemux_check_seekability (demux);
7156 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7158 /* get fourcc/length, set neededbytes */
7159 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7161 gst_adapter_unmap (demux->adapter);
7163 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7164 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7166 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7167 (_("This file is invalid and cannot be played.")),
7168 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7169 GST_FOURCC_ARGS (fourcc)));
7170 ret = GST_FLOW_ERROR;
7173 if (fourcc == FOURCC_mdat) {
7174 gint next_entry = next_entry_size (demux);
7175 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7176 || !demux->fragmented)) {
7177 /* we have the headers, start playback */
7178 demux->state = QTDEMUX_STATE_MOVIE;
7179 demux->neededbytes = next_entry;
7180 demux->mdatleft = size;
7181 demux->mdatsize = demux->mdatleft;
7183 /* no headers yet, try to get them */
7186 guint64 old, target;
7189 old = demux->offset;
7190 target = old + size;
7192 /* try to jump over the atom with a seek */
7193 /* only bother if it seems worth doing so,
7194 * and avoids possible upstream/server problems */
7195 if (demux->upstream_seekable &&
7196 demux->upstream_size > 4 * (1 << 20)) {
7197 res = qtdemux_seek_offset (demux, target);
7199 GST_DEBUG_OBJECT (demux, "skipping seek");
7204 GST_DEBUG_OBJECT (demux, "seek success");
7205 /* remember the offset fo the first mdat so we can seek back to it
7206 * after we have the headers */
7207 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7208 demux->first_mdat = old;
7209 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7212 /* seek worked, continue reading */
7213 demux->offset = target;
7214 demux->neededbytes = 16;
7215 demux->state = QTDEMUX_STATE_INITIAL;
7217 /* seek failed, need to buffer */
7218 demux->offset = old;
7219 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7220 /* there may be multiple mdat (or alike) buffers */
7222 if (demux->mdatbuffer)
7223 bs = gst_buffer_get_size (demux->mdatbuffer);
7226 if (size + bs > 10 * (1 << 20))
7228 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7229 demux->neededbytes = size;
7230 if (!demux->mdatbuffer)
7231 demux->mdatoffset = demux->offset;
7234 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7235 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7236 (_("This file is invalid and cannot be played.")),
7237 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7238 GST_FOURCC_ARGS (fourcc), size));
7239 ret = GST_FLOW_ERROR;
7242 /* this means we already started buffering and still no moov header,
7243 * let's continue buffering everything till we get moov */
7244 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7245 || fourcc == FOURCC_moof))
7247 demux->neededbytes = size;
7248 demux->state = QTDEMUX_STATE_HEADER;
7252 case QTDEMUX_STATE_HEADER:{
7256 GST_DEBUG_OBJECT (demux, "In header");
7258 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7260 /* parse the header */
7261 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7263 if (fourcc == FOURCC_moov) {
7264 /* in usual fragmented setup we could try to scan for more
7265 * and end up at the the moov (after mdat) again */
7266 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7268 || demux->last_moov_offset == demux->offset)) {
7269 GST_DEBUG_OBJECT (demux,
7270 "Skipping moov atom as we have (this) one already");
7272 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7274 if (demux->got_moov && demux->fragmented) {
7275 GST_DEBUG_OBJECT (demux,
7276 "Got a second moov, clean up data from old one");
7277 if (demux->moov_node_compressed) {
7278 g_node_destroy (demux->moov_node_compressed);
7279 if (demux->moov_node)
7280 g_free (demux->moov_node->data);
7282 demux->moov_node_compressed = NULL;
7283 if (demux->moov_node)
7284 g_node_destroy (demux->moov_node);
7285 demux->moov_node = NULL;
7288 demux->last_moov_offset = demux->offset;
7290 /* Update streams with new moov */
7291 gst_qtdemux_stream_concat (demux,
7292 demux->old_streams, demux->active_streams);
7294 qtdemux_parse_moov (demux, data, demux->neededbytes);
7295 qtdemux_node_dump (demux, demux->moov_node);
7296 qtdemux_parse_tree (demux);
7297 qtdemux_prepare_streams (demux);
7298 QTDEMUX_EXPOSE_LOCK (demux);
7299 qtdemux_expose_streams (demux);
7300 QTDEMUX_EXPOSE_UNLOCK (demux);
7302 demux->got_moov = TRUE;
7304 gst_qtdemux_check_send_pending_segment (demux);
7306 if (demux->moov_node_compressed) {
7307 g_node_destroy (demux->moov_node_compressed);
7308 g_free (demux->moov_node->data);
7310 demux->moov_node_compressed = NULL;
7311 g_node_destroy (demux->moov_node);
7312 demux->moov_node = NULL;
7313 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7315 } else if (fourcc == FOURCC_moof) {
7316 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7318 GstClockTime prev_pts;
7319 guint64 prev_offset;
7320 guint64 adapter_discont_offset, adapter_discont_dist;
7322 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7325 * The timestamp of the moof buffer is relevant as some scenarios
7326 * won't have the initial timestamp in the atoms. Whenever a new
7327 * buffer has started, we get that buffer's PTS and use it as a base
7328 * timestamp for the trun entries.
7330 * To keep track of the current buffer timestamp and starting point
7331 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7332 * from the beginning of the buffer, with the distance and demux->offset
7333 * we know if it is still the same buffer or not.
7335 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7336 prev_offset = demux->offset - dist;
7337 if (demux->fragment_start_offset == -1
7338 || prev_offset > demux->fragment_start_offset) {
7339 demux->fragment_start_offset = prev_offset;
7340 demux->fragment_start = prev_pts;
7341 GST_DEBUG_OBJECT (demux,
7342 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7343 GST_TIME_FORMAT, demux->fragment_start_offset,
7344 GST_TIME_ARGS (demux->fragment_start));
7347 /* We can't use prev_offset() here because this would require
7348 * upstream to set consistent and correct offsets on all buffers
7349 * since the discont. Nothing ever did that in the past and we
7350 * would break backwards compatibility here then.
7351 * Instead take the offset we had at the last discont and count
7352 * the bytes from there. This works with old code as there would
7353 * be no discont between moov and moof, and also works with
7354 * adaptivedemux which correctly sets offset and will set the
7355 * DISCONT flag accordingly when needed.
7357 * We also only do this for upstream TIME segments as otherwise
7358 * there are potential backwards compatibility problems with
7359 * seeking in PUSH mode and upstream providing inconsistent
7361 adapter_discont_offset =
7362 gst_adapter_offset_at_discont (demux->adapter);
7363 adapter_discont_dist =
7364 gst_adapter_distance_from_discont (demux->adapter);
7366 GST_DEBUG_OBJECT (demux,
7367 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7368 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7369 demux->offset, adapter_discont_offset, adapter_discont_dist);
7371 if (demux->upstream_format_is_time) {
7372 demux->moof_offset = adapter_discont_offset;
7373 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7374 demux->moof_offset += adapter_discont_dist;
7375 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7376 demux->moof_offset = demux->offset;
7378 demux->moof_offset = demux->offset;
7381 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7382 demux->moof_offset, NULL)) {
7383 gst_adapter_unmap (demux->adapter);
7384 ret = GST_FLOW_ERROR;
7388 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7389 if (demux->mss_mode && !demux->exposed) {
7390 QTDEMUX_EXPOSE_LOCK (demux);
7391 qtdemux_expose_streams (demux);
7392 QTDEMUX_EXPOSE_UNLOCK (demux);
7395 gst_qtdemux_check_send_pending_segment (demux);
7397 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7399 } else if (fourcc == FOURCC_ftyp) {
7400 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7401 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7402 } else if (fourcc == FOURCC_uuid) {
7403 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7404 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7405 } else if (fourcc == FOURCC_sidx) {
7406 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7407 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7411 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7415 /* [free] and [skip] are padding atoms */
7416 GST_DEBUG_OBJECT (demux,
7417 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7418 GST_FOURCC_ARGS (fourcc));
7421 GST_WARNING_OBJECT (demux,
7422 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7423 GST_FOURCC_ARGS (fourcc));
7424 /* Let's jump that one and go back to initial state */
7428 gst_adapter_unmap (demux->adapter);
7431 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7432 gsize remaining_data_size = 0;
7434 /* the mdat was before the header */
7435 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7436 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7437 /* restore our adapter/offset view of things with upstream;
7438 * put preceding buffered data ahead of current moov data.
7439 * This should also handle evil mdat, moov, mdat cases and alike */
7440 gst_adapter_flush (demux->adapter, demux->neededbytes);
7442 /* Store any remaining data after the mdat for later usage */
7443 remaining_data_size = gst_adapter_available (demux->adapter);
7444 if (remaining_data_size > 0) {
7445 g_assert (demux->restoredata_buffer == NULL);
7446 demux->restoredata_buffer =
7447 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7448 demux->restoredata_offset = demux->offset + demux->neededbytes;
7449 GST_DEBUG_OBJECT (demux,
7450 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7451 G_GUINT64_FORMAT, remaining_data_size,
7452 demux->restoredata_offset);
7455 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7456 demux->mdatbuffer = NULL;
7457 demux->offset = demux->mdatoffset;
7458 demux->neededbytes = next_entry_size (demux);
7459 demux->state = QTDEMUX_STATE_MOVIE;
7460 demux->mdatleft = gst_adapter_available (demux->adapter);
7461 demux->mdatsize = demux->mdatleft;
7463 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7464 gst_adapter_flush (demux->adapter, demux->neededbytes);
7466 /* only go back to the mdat if there are samples to play */
7467 if (demux->got_moov && demux->first_mdat != -1
7468 && has_next_entry (demux)) {
7471 /* we need to seek back */
7472 res = qtdemux_seek_offset (demux, demux->first_mdat);
7474 demux->offset = demux->first_mdat;
7476 GST_DEBUG_OBJECT (demux, "Seek back failed");
7479 demux->offset += demux->neededbytes;
7481 demux->neededbytes = 16;
7482 demux->state = QTDEMUX_STATE_INITIAL;
7487 case QTDEMUX_STATE_BUFFER_MDAT:{
7491 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7493 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7494 gst_buffer_extract (buf, 0, fourcc, 4);
7495 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7496 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7497 if (demux->mdatbuffer)
7498 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7500 demux->mdatbuffer = buf;
7501 demux->offset += demux->neededbytes;
7502 demux->neededbytes = 16;
7503 demux->state = QTDEMUX_STATE_INITIAL;
7504 gst_qtdemux_post_progress (demux, 1, 1);
7508 case QTDEMUX_STATE_MOVIE:{
7509 QtDemuxStream *stream = NULL;
7510 QtDemuxSample *sample;
7511 GstClockTime dts, pts, duration;
7515 GST_DEBUG_OBJECT (demux,
7516 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7518 if (demux->fragmented) {
7519 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7521 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7522 /* if needed data starts within this atom,
7523 * then it should not exceed this atom */
7524 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7525 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7526 (_("This file is invalid and cannot be played.")),
7527 ("sample data crosses atom boundary"));
7528 ret = GST_FLOW_ERROR;
7531 demux->mdatleft -= demux->neededbytes;
7533 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7534 /* so we are dropping more than left in this atom */
7535 gst_qtdemux_drop_data (demux, demux->mdatleft);
7536 demux->mdatleft = 0;
7538 /* need to resume atom parsing so we do not miss any other pieces */
7539 demux->state = QTDEMUX_STATE_INITIAL;
7540 demux->neededbytes = 16;
7542 /* check if there was any stored post mdat data from previous buffers */
7543 if (demux->restoredata_buffer) {
7544 g_assert (gst_adapter_available (demux->adapter) == 0);
7546 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7547 demux->restoredata_buffer = NULL;
7548 demux->offset = demux->restoredata_offset;
7555 if (demux->todrop) {
7556 if (demux->cenc_aux_info_offset > 0) {
7560 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7561 data = gst_adapter_map (demux->adapter, demux->todrop);
7562 gst_byte_reader_init (&br, data + 8, demux->todrop);
7563 if (!qtdemux_parse_cenc_aux_info (demux,
7564 QTDEMUX_NTH_STREAM (demux, 0), &br,
7565 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7566 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7567 ret = GST_FLOW_ERROR;
7568 gst_adapter_unmap (demux->adapter);
7569 g_free (demux->cenc_aux_info_sizes);
7570 demux->cenc_aux_info_sizes = NULL;
7573 demux->cenc_aux_info_offset = 0;
7574 g_free (demux->cenc_aux_info_sizes);
7575 demux->cenc_aux_info_sizes = NULL;
7576 gst_adapter_unmap (demux->adapter);
7578 gst_qtdemux_drop_data (demux, demux->todrop);
7582 /* initial newsegment sent here after having added pads,
7583 * possible others in sink_event */
7584 gst_qtdemux_check_send_pending_segment (demux);
7586 /* Figure out which stream this packet belongs to */
7587 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7588 stream = QTDEMUX_NTH_STREAM (demux, i);
7589 if (stream->sample_index >= stream->n_samples) {
7590 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7594 GST_LOG_OBJECT (demux,
7595 "Checking track-id %u (sample_index:%d / offset:%"
7596 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7597 stream->sample_index,
7598 stream->samples[stream->sample_index].offset,
7599 stream->samples[stream->sample_index].size);
7601 if (stream->samples[stream->sample_index].offset == demux->offset)
7605 if (G_UNLIKELY (stream == NULL))
7606 goto unknown_stream;
7608 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7610 if (stream->new_caps) {
7611 gst_qtdemux_configure_stream (demux, stream);
7614 /* Put data in a buffer, set timestamps, caps, ... */
7615 sample = &stream->samples[stream->sample_index];
7617 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7618 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7619 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7621 dts = QTSAMPLE_DTS (stream, sample);
7622 pts = QTSAMPLE_PTS (stream, sample);
7623 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7624 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7626 /* check for segment end */
7627 if (G_UNLIKELY (demux->segment.stop != -1
7628 && demux->segment.stop <= pts && stream->on_keyframe)
7629 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7630 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7631 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7633 /* skip this data, stream is EOS */
7634 gst_adapter_flush (demux->adapter, demux->neededbytes);
7635 demux->offset += demux->neededbytes;
7637 /* check if all streams are eos */
7639 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7640 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7649 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7651 /* FIXME: should either be an assert or a plain check */
7652 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7654 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7655 dts, pts, duration, keyframe, dts, demux->offset);
7659 GST_OBJECT_LOCK (demux);
7660 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7661 GST_OBJECT_UNLOCK (demux);
7663 /* skip this data, stream is EOS */
7664 gst_adapter_flush (demux->adapter, demux->neededbytes);
7667 stream->sample_index++;
7668 stream->offset_in_sample = 0;
7670 /* update current offset and figure out size of next buffer */
7671 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7672 demux->offset, demux->neededbytes);
7673 demux->offset += demux->neededbytes;
7674 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7678 if (ret == GST_FLOW_EOS) {
7679 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7680 demux->neededbytes = -1;
7684 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7685 if (demux->fragmented) {
7686 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7687 /* there may be more to follow, only finish this atom */
7688 demux->todrop = demux->mdatleft;
7689 demux->neededbytes = demux->todrop;
7694 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7695 goto non_ok_unlinked_flow;
7704 /* when buffering movie data, at least show user something is happening */
7705 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7706 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7707 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7708 demux->neededbytes);
7715 non_ok_unlinked_flow:
7717 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7718 gst_flow_get_name (ret));
7723 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7724 ret = GST_FLOW_ERROR;
7729 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7735 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7736 (NULL), ("qtdemuxer invalid state %d", demux->state));
7737 ret = GST_FLOW_ERROR;
7742 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7743 (NULL), ("no 'moov' atom within the first 10 MB"));
7744 ret = GST_FLOW_ERROR;
7750 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7755 query = gst_query_new_scheduling ();
7757 if (!gst_pad_peer_query (sinkpad, query)) {
7758 gst_query_unref (query);
7762 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7763 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7764 gst_query_unref (query);
7769 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7770 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7774 GST_DEBUG_OBJECT (sinkpad, "activating push");
7775 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7780 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7781 GstPadMode mode, gboolean active)
7784 GstQTDemux *demux = GST_QTDEMUX (parent);
7787 case GST_PAD_MODE_PUSH:
7788 demux->pullbased = FALSE;
7791 case GST_PAD_MODE_PULL:
7793 demux->pullbased = TRUE;
7794 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7797 res = gst_pad_stop_task (sinkpad);
7809 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7815 memset (&z, 0, sizeof (z));
7820 if ((ret = inflateInit (&z)) != Z_OK) {
7821 GST_ERROR ("inflateInit() returned %d", ret);
7825 z.next_in = z_buffer;
7826 z.avail_in = z_length;
7828 buffer = (guint8 *) g_malloc (*length);
7829 z.avail_out = *length;
7830 z.next_out = (Bytef *) buffer;
7832 ret = inflate (&z, Z_NO_FLUSH);
7833 if (ret == Z_STREAM_END) {
7835 } else if (ret != Z_OK) {
7836 GST_WARNING ("inflate() returned %d", ret);
7841 buffer = (guint8 *) g_realloc (buffer, *length);
7842 z.next_out = (Bytef *) (buffer + z.total_out);
7843 z.avail_out += 4096;
7844 } while (z.avail_in > 0);
7846 if (ret != Z_STREAM_END) {
7851 *length = z.total_out;
7858 #endif /* HAVE_ZLIB */
7861 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7865 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7867 /* counts as header data */
7868 qtdemux->header_size += length;
7870 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7871 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7873 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7880 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7881 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7882 if (dcom == NULL || cmvd == NULL)
7883 goto invalid_compression;
7885 dcom_len = QT_UINT32 (dcom->data);
7887 goto invalid_compression;
7889 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7893 guint uncompressed_length;
7894 guint compressed_length;
7898 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7900 goto invalid_compression;
7902 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7903 compressed_length = cmvd_len - 12;
7904 GST_LOG ("length = %u", uncompressed_length);
7907 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7908 compressed_length, &uncompressed_length);
7911 qtdemux->moov_node_compressed = qtdemux->moov_node;
7912 qtdemux->moov_node = g_node_new (buf);
7914 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7915 uncompressed_length);
7919 #endif /* HAVE_ZLIB */
7921 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7922 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7929 invalid_compression:
7931 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7937 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7940 while (G_UNLIKELY (buf < end)) {
7944 if (G_UNLIKELY (buf + 4 > end)) {
7945 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7948 len = QT_UINT32 (buf);
7949 if (G_UNLIKELY (len == 0)) {
7950 GST_LOG_OBJECT (qtdemux, "empty container");
7953 if (G_UNLIKELY (len < 8)) {
7954 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7957 if (G_UNLIKELY (len > (end - buf))) {
7958 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7959 (gint) (end - buf));
7963 child = g_node_new ((guint8 *) buf);
7964 g_node_append (node, child);
7965 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7966 qtdemux_parse_node (qtdemux, child, buf, len);
7974 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7977 int len = QT_UINT32 (xdxt->data);
7978 guint8 *buf = xdxt->data;
7979 guint8 *end = buf + len;
7982 /* skip size and type */
7990 size = QT_UINT32 (buf);
7991 type = QT_FOURCC (buf + 4);
7993 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7995 if (buf + size > end || size <= 0)
8001 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8002 GST_FOURCC_ARGS (type));
8006 buffer = gst_buffer_new_and_alloc (size);
8007 gst_buffer_fill (buffer, 0, buf, size);
8008 stream->buffers = g_slist_append (stream->buffers, buffer);
8009 GST_LOG_OBJECT (qtdemux, "parsing theora header");
8012 buffer = gst_buffer_new_and_alloc (size);
8013 gst_buffer_fill (buffer, 0, buf, size);
8014 stream->buffers = g_slist_append (stream->buffers, buffer);
8015 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
8018 buffer = gst_buffer_new_and_alloc (size);
8019 gst_buffer_fill (buffer, 0, buf, size);
8020 stream->buffers = g_slist_append (stream->buffers, buffer);
8021 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
8024 GST_WARNING_OBJECT (qtdemux,
8025 "unknown theora cookie %" GST_FOURCC_FORMAT,
8026 GST_FOURCC_ARGS (type));
8035 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8039 guint32 node_length = 0;
8040 const QtNodeType *type;
8043 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8045 if (G_UNLIKELY (length < 8))
8046 goto not_enough_data;
8048 node_length = QT_UINT32 (buffer);
8049 fourcc = QT_FOURCC (buffer + 4);
8051 /* ignore empty nodes */
8052 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8055 type = qtdemux_type_get (fourcc);
8057 end = buffer + length;
8059 GST_LOG_OBJECT (qtdemux,
8060 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8061 GST_FOURCC_ARGS (fourcc), node_length, type->name);
8063 if (node_length > length)
8064 goto broken_atom_size;
8066 if (type->flags & QT_FLAG_CONTAINER) {
8067 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8072 if (node_length < 20) {
8073 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8076 GST_DEBUG_OBJECT (qtdemux,
8077 "parsing stsd (sample table, sample description) atom");
8078 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8079 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8091 /* also read alac (or whatever) in stead of mp4a in the following,
8092 * since a similar layout is used in other cases as well */
8093 if (fourcc == FOURCC_mp4a)
8095 else if (fourcc == FOURCC_fLaC)
8100 /* There are two things we might encounter here: a true mp4a atom, and
8101 an mp4a entry in an stsd atom. The latter is what we're interested
8102 in, and it looks like an atom, but isn't really one. The true mp4a
8103 atom is short, so we detect it based on length here. */
8104 if (length < min_size) {
8105 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8106 GST_FOURCC_ARGS (fourcc));
8110 /* 'version' here is the sound sample description version. Types 0 and
8111 1 are documented in the QTFF reference, but type 2 is not: it's
8112 described in Apple header files instead (struct SoundDescriptionV2
8114 version = QT_UINT16 (buffer + 16);
8116 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8117 GST_FOURCC_ARGS (fourcc), version);
8119 /* parse any esds descriptors */
8131 GST_WARNING_OBJECT (qtdemux,
8132 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8133 GST_FOURCC_ARGS (fourcc), version);
8138 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8166 /* codec_data is contained inside these atoms, which all have
8167 * the same format. */
8168 /* video sample description size is 86 bytes without extension.
8169 * node_length have to be bigger than 86 bytes because video sample
8170 * description can include extensions such as esds, fiel, glbl, etc. */
8171 if (node_length < 86) {
8172 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8173 " sample description length too short (%u < 86)",
8174 GST_FOURCC_ARGS (fourcc), node_length);
8178 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8179 GST_FOURCC_ARGS (fourcc));
8181 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8183 * revision level (2 bytes) : must be set to 0. */
8184 version = QT_UINT32 (buffer + 16);
8185 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8187 /* compressor name : PASCAL string and informative purposes
8188 * first byte : the number of bytes to be displayed.
8189 * it has to be less than 32 because it is reserved
8190 * space of 32 bytes total including itself. */
8191 str_len = QT_UINT8 (buffer + 50);
8193 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8194 (char *) buffer + 51);
8196 GST_WARNING_OBJECT (qtdemux,
8197 "compressorname length too big (%u > 31)", str_len);
8199 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8201 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8206 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8208 /* You are reading this correctly. QTFF specifies that the
8209 * metadata atom is a short atom, whereas ISO BMFF specifies
8210 * it's a full atom. But since so many people are doing things
8211 * differently, we actually peek into the atom to see which
8214 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8215 GST_FOURCC_ARGS (fourcc));
8218 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8219 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8220 * starts with a 'hdlr' atom */
8221 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8222 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8223 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8224 * with version/flags both set to zero */
8225 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8227 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8232 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8233 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8234 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8243 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8244 GST_FOURCC_ARGS (fourcc));
8248 version = QT_UINT32 (buffer + 12);
8249 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8256 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8261 if (length < offset) {
8262 GST_WARNING_OBJECT (qtdemux,
8263 "skipping too small %" GST_FOURCC_FORMAT " box",
8264 GST_FOURCC_ARGS (fourcc));
8267 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8273 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8278 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8283 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8287 if (!strcmp (type->name, "unknown"))
8288 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8292 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8293 GST_FOURCC_ARGS (fourcc));
8299 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8300 (_("This file is corrupt and cannot be played.")),
8301 ("Not enough data for an atom header, got only %u bytes", length));
8306 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8307 (_("This file is corrupt and cannot be played.")),
8308 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8309 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8316 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8318 /* FIXME: This can only reliably work if demuxers have a
8319 * separate streaming thread per srcpad. This should be
8320 * done in a demuxer base class, which integrates parts
8323 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8328 query = gst_query_new_allocation (stream->caps, FALSE);
8330 if (!gst_pad_peer_query (stream->pad, query)) {
8331 /* not a problem, just debug a little */
8332 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8335 if (stream->allocator)
8336 gst_object_unref (stream->allocator);
8338 if (gst_query_get_n_allocation_params (query) > 0) {
8339 /* try the allocator */
8340 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8342 stream->use_allocator = TRUE;
8344 stream->allocator = NULL;
8345 gst_allocation_params_init (&stream->params);
8346 stream->use_allocator = FALSE;
8348 gst_query_unref (query);
8353 pad_query (const GValue * item, GValue * value, gpointer user_data)
8355 GstPad *pad = g_value_get_object (item);
8356 GstQuery *query = user_data;
8359 res = gst_pad_peer_query (pad, query);
8362 g_value_set_boolean (value, TRUE);
8366 GST_INFO_OBJECT (pad, "pad peer query failed");
8371 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8372 GstPadDirection direction)
8375 GstIteratorFoldFunction func = pad_query;
8376 GValue res = { 0, };
8378 g_value_init (&res, G_TYPE_BOOLEAN);
8379 g_value_set_boolean (&res, FALSE);
8382 if (direction == GST_PAD_SRC)
8383 it = gst_element_iterate_src_pads (element);
8385 it = gst_element_iterate_sink_pads (element);
8387 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8388 gst_iterator_resync (it);
8390 gst_iterator_free (it);
8392 return g_value_get_boolean (&res);
8396 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8397 QtDemuxStream * stream)
8401 GstElement *element = GST_ELEMENT (qtdemux);
8403 gchar **filtered_sys_ids;
8404 GValue event_list = G_VALUE_INIT;
8407 /* 1. Check if we already have the context. */
8408 if (qtdemux->preferred_protection_system_id != NULL) {
8409 GST_LOG_OBJECT (element,
8410 "already have the protection context, no need to request it again");
8414 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8415 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8416 (const gchar **) qtdemux->protection_system_ids->pdata);
8418 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8419 qtdemux->protection_system_ids->len - 1);
8420 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8421 "decryptors for %u of them, running context request",
8422 qtdemux->protection_system_ids->len,
8423 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8426 if (stream->protection_scheme_event_queue.length) {
8427 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8428 stream->protection_scheme_event_queue.length);
8429 walk = stream->protection_scheme_event_queue.tail;
8431 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8432 qtdemux->protection_event_queue.length);
8433 walk = qtdemux->protection_event_queue.tail;
8436 g_value_init (&event_list, GST_TYPE_LIST);
8437 for (; walk; walk = g_list_previous (walk)) {
8438 GValue *event_value = g_new0 (GValue, 1);
8439 g_value_init (event_value, GST_TYPE_EVENT);
8440 g_value_set_boxed (event_value, walk->data);
8441 gst_value_list_append_and_take_value (&event_list, event_value);
8444 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8445 * check if downstream already has a context of the specific type
8446 * 2b) Query upstream as above.
8448 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8449 st = gst_query_writable_structure (query);
8450 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8451 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8453 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8454 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8455 gst_query_parse_context (query, &ctxt);
8456 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8457 gst_element_set_context (element, ctxt);
8458 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8459 gst_query_parse_context (query, &ctxt);
8460 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8461 gst_element_set_context (element, ctxt);
8463 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8464 * the required context type and afterwards check if a
8465 * usable context was set now as in 1). The message could
8466 * be handled by the parent bins of the element and the
8471 GST_INFO_OBJECT (element, "posting need context message");
8472 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8473 "drm-preferred-decryption-system-id");
8474 st = (GstStructure *) gst_message_get_structure (msg);
8475 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8476 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8479 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8480 gst_element_post_message (element, msg);
8483 g_strfreev (filtered_sys_ids);
8484 g_value_unset (&event_list);
8485 gst_query_unref (query);
8489 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8490 QtDemuxStream * stream)
8493 const gchar *selected_system = NULL;
8495 g_return_val_if_fail (qtdemux != NULL, FALSE);
8496 g_return_val_if_fail (stream != NULL, FALSE);
8497 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8500 if (stream->protection_scheme_type == FOURCC_aavd) {
8501 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8502 if (!gst_structure_has_name (s, "application/x-aavd")) {
8503 gst_structure_set (s,
8504 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8506 gst_structure_set_name (s, "application/x-aavd");
8511 if (stream->protection_scheme_type != FOURCC_cenc
8512 && stream->protection_scheme_type != FOURCC_cbcs) {
8513 GST_ERROR_OBJECT (qtdemux,
8514 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8515 GST_FOURCC_ARGS (stream->protection_scheme_type));
8519 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8520 if (!gst_structure_has_name (s, "application/x-cenc")) {
8521 gst_structure_set (s,
8522 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8523 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8524 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8526 gst_structure_set_name (s, "application/x-cenc");
8529 if (qtdemux->protection_system_ids == NULL) {
8530 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8531 "cenc protection system information has been found, not setting a "
8532 "protection system UUID");
8536 gst_qtdemux_request_protection_context (qtdemux, stream);
8537 if (qtdemux->preferred_protection_system_id != NULL) {
8538 const gchar *preferred_system_array[] =
8539 { qtdemux->preferred_protection_system_id, NULL };
8541 selected_system = gst_protection_select_system (preferred_system_array);
8543 if (selected_system) {
8544 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8545 qtdemux->preferred_protection_system_id);
8547 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8548 "because there is no available decryptor",
8549 qtdemux->preferred_protection_system_id);
8553 if (!selected_system) {
8554 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8555 selected_system = gst_protection_select_system ((const gchar **)
8556 qtdemux->protection_system_ids->pdata);
8557 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8558 qtdemux->protection_system_ids->len - 1);
8561 if (!selected_system) {
8562 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8563 "suitable decryptor element has been found");
8567 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8570 gst_structure_set (s,
8571 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8578 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8580 /* fps is calculated base on the duration of the average framerate since
8581 * qt does not have a fixed framerate. */
8582 gboolean fps_available = TRUE;
8583 guint32 first_duration = 0;
8585 if (stream->n_samples > 0)
8586 first_duration = stream->samples[0].duration;
8588 if ((stream->n_samples == 1 && first_duration == 0)
8589 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8591 CUR_STREAM (stream)->fps_n = 0;
8592 CUR_STREAM (stream)->fps_d = 1;
8594 if (stream->duration == 0 || stream->n_samples < 2) {
8595 CUR_STREAM (stream)->fps_n = stream->timescale;
8596 CUR_STREAM (stream)->fps_d = 1;
8597 fps_available = FALSE;
8599 GstClockTime avg_duration;
8603 /* duration and n_samples can be updated for fragmented format
8604 * so, framerate of fragmented format is calculated using data in a moof */
8605 if (qtdemux->fragmented && stream->n_samples_moof > 0
8606 && stream->duration_moof > 0) {
8607 n_samples = stream->n_samples_moof;
8608 duration = stream->duration_moof;
8610 n_samples = stream->n_samples;
8611 duration = stream->duration;
8614 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8615 /* stream->duration is guint64, timescale, n_samples are guint32 */
8617 gst_util_uint64_scale_round (duration -
8618 first_duration, GST_SECOND,
8619 (guint64) (stream->timescale) * (n_samples - 1));
8621 GST_LOG_OBJECT (qtdemux,
8622 "Calculating avg sample duration based on stream (or moof) duration %"
8624 " minus first sample %u, leaving %d samples gives %"
8625 GST_TIME_FORMAT, duration, first_duration,
8626 n_samples - 1, GST_TIME_ARGS (avg_duration));
8629 gst_video_guess_framerate (avg_duration,
8630 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8632 GST_DEBUG_OBJECT (qtdemux,
8633 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8634 stream->timescale, CUR_STREAM (stream)->fps_n,
8635 CUR_STREAM (stream)->fps_d);
8639 return fps_available;
8643 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8645 if (stream->subtype == FOURCC_vide) {
8646 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8648 if (CUR_STREAM (stream)->caps) {
8649 CUR_STREAM (stream)->caps =
8650 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8652 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8653 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8654 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8655 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8657 /* set framerate if calculated framerate is reliable */
8658 if (fps_available) {
8659 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8660 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8661 CUR_STREAM (stream)->fps_d, NULL);
8664 /* calculate pixel-aspect-ratio using display width and height */
8665 GST_DEBUG_OBJECT (qtdemux,
8666 "video size %dx%d, target display size %dx%d",
8667 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8668 stream->display_width, stream->display_height);
8669 /* qt file might have pasp atom */
8670 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8671 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8672 CUR_STREAM (stream)->par_h);
8673 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8674 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8675 CUR_STREAM (stream)->par_h, NULL);
8676 } else if (stream->display_width > 0 && stream->display_height > 0
8677 && CUR_STREAM (stream)->width > 0
8678 && CUR_STREAM (stream)->height > 0) {
8681 /* calculate the pixel aspect ratio using the display and pixel w/h */
8682 n = stream->display_width * CUR_STREAM (stream)->height;
8683 d = stream->display_height * CUR_STREAM (stream)->width;
8686 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8687 CUR_STREAM (stream)->par_w = n;
8688 CUR_STREAM (stream)->par_h = d;
8689 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8690 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8691 CUR_STREAM (stream)->par_h, NULL);
8694 if (CUR_STREAM (stream)->interlace_mode > 0) {
8695 if (CUR_STREAM (stream)->interlace_mode == 1) {
8696 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8697 G_TYPE_STRING, "progressive", NULL);
8698 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8699 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8700 G_TYPE_STRING, "interleaved", NULL);
8701 if (CUR_STREAM (stream)->field_order == 9) {
8702 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8703 G_TYPE_STRING, "top-field-first", NULL);
8704 } else if (CUR_STREAM (stream)->field_order == 14) {
8705 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8706 G_TYPE_STRING, "bottom-field-first", NULL);
8711 /* Create incomplete colorimetry here if needed */
8712 if (CUR_STREAM (stream)->colorimetry.range ||
8713 CUR_STREAM (stream)->colorimetry.matrix ||
8714 CUR_STREAM (stream)->colorimetry.transfer
8715 || CUR_STREAM (stream)->colorimetry.primaries) {
8716 gchar *colorimetry =
8717 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8718 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8719 G_TYPE_STRING, colorimetry, NULL);
8720 g_free (colorimetry);
8723 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8724 guint par_w = 1, par_h = 1;
8726 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8727 par_w = CUR_STREAM (stream)->par_w;
8728 par_h = CUR_STREAM (stream)->par_h;
8731 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8732 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8734 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8737 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8738 "multiview-mode", G_TYPE_STRING,
8739 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8740 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8741 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8746 else if (stream->subtype == FOURCC_soun) {
8747 if (CUR_STREAM (stream)->caps) {
8748 CUR_STREAM (stream)->caps =
8749 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8750 if (CUR_STREAM (stream)->rate > 0)
8751 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8752 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8753 if (CUR_STREAM (stream)->n_channels > 0)
8754 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8755 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8756 if (CUR_STREAM (stream)->n_channels > 2) {
8757 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8758 * correctly; this is just the minimum we can do - assume
8759 * we don't actually have any channel positions. */
8760 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8761 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8766 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8767 const GstStructure *s;
8768 QtDemuxStream *fps_stream = NULL;
8769 gboolean fps_available = FALSE;
8771 /* CEA608 closed caption tracks are a bit special in that each sample
8772 * can contain CCs for multiple frames, and CCs can be omitted and have to
8773 * be inferred from the duration of the sample then.
8775 * As such we take the framerate from the (first) video track here for
8776 * CEA608 as there must be one CC byte pair for every video frame
8777 * according to the spec.
8779 * For CEA708 all is fine and there is one sample per frame.
8782 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8783 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8786 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8787 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8789 if (tmp->subtype == FOURCC_vide) {
8796 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8797 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8798 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8801 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8802 fps_stream = stream;
8805 CUR_STREAM (stream)->caps =
8806 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8808 /* set framerate if calculated framerate is reliable */
8809 if (fps_available) {
8810 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8811 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8812 CUR_STREAM (stream)->fps_d, NULL);
8817 gboolean forward_collection = FALSE;
8818 GstCaps *prev_caps = NULL;
8820 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8821 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8822 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8823 gst_pad_set_active (stream->pad, TRUE);
8825 gst_pad_use_fixed_caps (stream->pad);
8827 if (stream->protected) {
8828 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8829 GST_ERROR_OBJECT (qtdemux,
8830 "Failed to configure protected stream caps.");
8835 if (stream->new_stream) {
8837 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8840 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8843 gst_event_parse_stream_flags (event, &stream_flags);
8844 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8845 qtdemux->have_group_id = TRUE;
8847 qtdemux->have_group_id = FALSE;
8848 gst_event_unref (event);
8849 } else if (!qtdemux->have_group_id) {
8850 qtdemux->have_group_id = TRUE;
8851 qtdemux->group_id = gst_util_group_id_next ();
8854 stream->new_stream = FALSE;
8855 event = gst_event_new_stream_start (stream->stream_id);
8856 if (qtdemux->have_group_id)
8857 gst_event_set_group_id (event, qtdemux->group_id);
8858 if (stream->disabled)
8859 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8860 if (CUR_STREAM (stream)->sparse) {
8861 stream_flags |= GST_STREAM_FLAG_SPARSE;
8863 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8865 gst_event_set_stream_flags (event, stream_flags);
8866 gst_pad_push_event (stream->pad, event);
8868 forward_collection = TRUE;
8871 prev_caps = gst_pad_get_current_caps (stream->pad);
8873 if (CUR_STREAM (stream)->caps) {
8875 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8876 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8877 CUR_STREAM (stream)->caps);
8878 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8880 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8883 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8887 gst_caps_unref (prev_caps);
8888 stream->new_caps = FALSE;
8890 if (forward_collection) {
8891 /* Forward upstream collection and selection if any */
8892 GstEvent *upstream_event = gst_pad_get_sticky_event (qtdemux->sinkpad,
8893 GST_EVENT_STREAM_COLLECTION, 0);
8895 gst_pad_push_event (stream->pad, upstream_event);
8902 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8903 QtDemuxStream * stream)
8905 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8908 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8909 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8910 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8911 stream->stsd_entries_length)) {
8912 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8913 (_("This file is invalid and cannot be played.")),
8914 ("New sample description id is out of bounds (%d >= %d)",
8915 stream->stsd_sample_description_id, stream->stsd_entries_length));
8917 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8918 stream->new_caps = TRUE;
8923 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8924 QtDemuxStream * stream, GstTagList * list)
8926 gboolean ret = TRUE;
8928 if (stream->subtype == FOURCC_vide) {
8929 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8932 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8935 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8936 gst_object_unref (stream->pad);
8942 qtdemux->n_video_streams++;
8943 } else if (stream->subtype == FOURCC_soun) {
8944 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8947 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8949 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8950 gst_object_unref (stream->pad);
8955 qtdemux->n_audio_streams++;
8956 } else if (stream->subtype == FOURCC_strm) {
8957 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8958 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8959 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8960 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
8961 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8964 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8966 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8967 gst_object_unref (stream->pad);
8972 qtdemux->n_sub_streams++;
8973 } else if (CUR_STREAM (stream)->caps) {
8974 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8977 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8979 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8980 gst_object_unref (stream->pad);
8985 qtdemux->n_video_streams++;
8987 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8994 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8995 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8996 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8997 GST_OBJECT_LOCK (qtdemux);
8998 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8999 GST_OBJECT_UNLOCK (qtdemux);
9001 if (stream->stream_tags)
9002 gst_tag_list_unref (stream->stream_tags);
9003 stream->stream_tags = list;
9005 /* global tags go on each pad anyway */
9006 stream->send_global_tags = TRUE;
9007 /* send upstream GST_EVENT_PROTECTION events that were received before
9008 this source pad was created */
9009 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9010 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9014 gst_tag_list_unref (list);
9018 /* find next atom with @fourcc starting at @offset */
9019 static GstFlowReturn
9020 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9021 guint64 * length, guint32 fourcc)
9027 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9028 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9034 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9035 if (G_UNLIKELY (ret != GST_FLOW_OK))
9037 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9040 gst_buffer_unref (buf);
9043 gst_buffer_map (buf, &map, GST_MAP_READ);
9044 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9045 gst_buffer_unmap (buf, &map);
9046 gst_buffer_unref (buf);
9048 if (G_UNLIKELY (*length == 0)) {
9049 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9050 ret = GST_FLOW_ERROR;
9054 if (lfourcc == fourcc) {
9055 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9056 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9059 GST_LOG_OBJECT (qtdemux,
9060 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9061 GST_FOURCC_ARGS (lfourcc), *offset);
9062 if (*offset == G_MAXUINT64)
9072 /* might simply have had last one */
9073 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9078 /* should only do something in pull mode */
9079 /* call with OBJECT lock */
9080 static GstFlowReturn
9081 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9083 guint64 length, offset;
9084 GstBuffer *buf = NULL;
9085 GstFlowReturn ret = GST_FLOW_OK;
9086 GstFlowReturn res = GST_FLOW_OK;
9089 offset = qtdemux->moof_offset;
9090 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9093 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9094 return GST_FLOW_EOS;
9097 /* best not do pull etc with lock held */
9098 GST_OBJECT_UNLOCK (qtdemux);
9100 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9101 if (ret != GST_FLOW_OK)
9104 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9105 if (G_UNLIKELY (ret != GST_FLOW_OK))
9107 gst_buffer_map (buf, &map, GST_MAP_READ);
9108 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9109 gst_buffer_unmap (buf, &map);
9110 gst_buffer_unref (buf);
9115 gst_buffer_unmap (buf, &map);
9116 gst_buffer_unref (buf);
9120 /* look for next moof */
9121 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9122 if (G_UNLIKELY (ret != GST_FLOW_OK))
9126 GST_OBJECT_LOCK (qtdemux);
9128 qtdemux->moof_offset = offset;
9134 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9136 res = GST_FLOW_ERROR;
9141 /* maybe upstream temporarily flushing */
9142 if (ret != GST_FLOW_FLUSHING) {
9143 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9146 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9147 /* resume at current position next time */
9155 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9159 gint32 stts_duration;
9160 GstByteWriter stsc, stts, stsz;
9162 /* Each sample has a different size, which we don't support for merging */
9163 if (stream->sample_size == 0) {
9164 GST_DEBUG_OBJECT (qtdemux,
9165 "Not all samples have the same size, not merging");
9169 /* The stream has a ctts table, we don't support that */
9170 if (stream->ctts_present) {
9171 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9175 /* If there's a sync sample table also ignore this stream */
9176 if (stream->stps_present || stream->stss_present) {
9177 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9181 /* If chunks are considered samples already ignore this stream */
9182 if (stream->chunks_are_samples) {
9183 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9187 /* Require that all samples have the same duration */
9188 if (stream->n_sample_times > 1) {
9189 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9193 /* Parse the stts to get the sample duration and number of samples */
9194 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9195 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9197 /* Parse the number of chunks from the stco manually because the
9198 * reader is already behind that */
9199 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9201 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9204 /* Now parse stsc, convert chunks into single samples and generate a
9205 * new stsc, stts and stsz from this information */
9206 gst_byte_writer_init (&stsc);
9207 gst_byte_writer_init (&stts);
9208 gst_byte_writer_init (&stsz);
9210 /* Note: we skip fourccs, size, version, flags and other fields of the new
9211 * atoms as the byte readers with them are already behind that position
9212 * anyway and only update the values of those inside the stream directly.
9214 stream->n_sample_times = 0;
9215 stream->n_samples = 0;
9216 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9218 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9220 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9221 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9222 sample_description_id =
9223 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9225 if (i == stream->n_samples_per_chunk - 1) {
9226 /* +1 because first_chunk is 1-based */
9227 last_chunk = num_chunks + 1;
9229 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9232 GST_DEBUG_OBJECT (qtdemux,
9233 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9234 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9236 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9237 /* One sample in this chunk */
9238 gst_byte_writer_put_uint32_be (&stsc, 1);
9239 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9241 /* For each chunk write a stts and stsz entry now */
9242 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9243 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9244 for (j = first_chunk; j < last_chunk; j++) {
9245 gst_byte_writer_put_uint32_be (&stsz,
9246 stream->sample_size * samples_per_chunk);
9249 stream->n_sample_times += 1;
9250 stream->n_samples += last_chunk - first_chunk;
9253 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9255 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9256 stream->n_samples, stream->n_sample_times);
9258 /* We don't have a fixed sample size anymore */
9259 stream->sample_size = 0;
9261 /* Free old data for the atoms */
9262 g_free ((gpointer) stream->stsz.data);
9263 stream->stsz.data = NULL;
9264 g_free ((gpointer) stream->stsc.data);
9265 stream->stsc.data = NULL;
9266 g_free ((gpointer) stream->stts.data);
9267 stream->stts.data = NULL;
9269 /* Store new data and replace byte readers */
9270 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9271 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9272 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9273 stream->stts.size = gst_byte_writer_get_size (&stts);
9274 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9275 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9276 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9277 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9278 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9281 /* initialise bytereaders for stbl sub-atoms */
9283 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9285 stream->stbl_index = -1; /* no samples have yet been parsed */
9286 stream->sample_index = -1;
9288 /* time-to-sample atom */
9289 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9292 /* copy atom data into a new buffer for later use */
9293 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9295 /* skip version + flags */
9296 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9297 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9299 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9301 /* make sure there's enough data */
9302 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9303 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9304 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9305 stream->n_sample_times);
9306 if (!stream->n_sample_times)
9310 /* sync sample atom */
9311 stream->stps_present = FALSE;
9312 if ((stream->stss_present =
9313 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9314 &stream->stss) ? TRUE : FALSE) == TRUE) {
9315 /* copy atom data into a new buffer for later use */
9316 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9318 /* skip version + flags */
9319 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9320 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9323 if (stream->n_sample_syncs) {
9324 /* make sure there's enough data */
9325 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9329 /* partial sync sample atom */
9330 if ((stream->stps_present =
9331 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9332 &stream->stps) ? TRUE : FALSE) == TRUE) {
9333 /* copy atom data into a new buffer for later use */
9334 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9336 /* skip version + flags */
9337 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9338 !gst_byte_reader_get_uint32_be (&stream->stps,
9339 &stream->n_sample_partial_syncs))
9342 /* if there are no entries, the stss table contains the real
9344 if (stream->n_sample_partial_syncs) {
9345 /* make sure there's enough data */
9346 if (!qt_atom_parser_has_chunks (&stream->stps,
9347 stream->n_sample_partial_syncs, 4))
9354 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9357 /* copy atom data into a new buffer for later use */
9358 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9360 /* skip version + flags */
9361 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9362 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9365 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9368 if (!stream->n_samples)
9371 /* sample-to-chunk atom */
9372 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9375 /* copy atom data into a new buffer for later use */
9376 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9378 /* skip version + flags */
9379 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9380 !gst_byte_reader_get_uint32_be (&stream->stsc,
9381 &stream->n_samples_per_chunk))
9384 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9385 stream->n_samples_per_chunk);
9387 /* make sure there's enough data */
9388 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9394 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9395 stream->co_size = sizeof (guint32);
9396 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9398 stream->co_size = sizeof (guint64);
9402 /* copy atom data into a new buffer for later use */
9403 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9405 /* skip version + flags */
9406 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9409 /* chunks_are_samples == TRUE means treat chunks as samples */
9410 stream->chunks_are_samples = stream->sample_size
9411 && !CUR_STREAM (stream)->sampled;
9412 if (stream->chunks_are_samples) {
9413 /* treat chunks as samples */
9414 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9417 /* skip number of entries */
9418 if (!gst_byte_reader_skip (&stream->stco, 4))
9421 /* make sure there are enough data in the stsz atom */
9422 if (!stream->sample_size) {
9423 /* different sizes for each sample */
9424 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9429 /* composition time-to-sample */
9430 if ((stream->ctts_present =
9431 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9432 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9433 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9434 guint8 ctts_version;
9435 gboolean checked_ctts = FALSE;
9437 /* copy atom data into a new buffer for later use */
9438 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9440 /* version 1 has signed offsets */
9441 if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9445 if (!gst_byte_reader_skip (&stream->ctts, 3)
9446 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9447 &stream->n_composition_times))
9450 /* make sure there's enough data */
9451 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9455 /* This is optional, if missing we iterate the ctts */
9456 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9457 guint8 cslg_version;
9459 /* cslg version 1 has 64 bit fields */
9460 if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9464 if (!gst_byte_reader_skip (&cslg, 3))
9467 if (cslg_version == 0) {
9468 gint32 composition_to_dts_shift;
9470 if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9473 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9475 gint64 composition_to_dts_shift;
9477 if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9480 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9483 gint32 cslg_least = 0;
9484 guint num_entries, pos;
9487 pos = gst_byte_reader_get_pos (&stream->ctts);
9488 num_entries = stream->n_composition_times;
9490 checked_ctts = TRUE;
9492 stream->cslg_shift = 0;
9494 for (i = 0; i < num_entries; i++) {
9497 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9498 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9499 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9500 * slightly inaccurate PTS could be more usable than corrupted one */
9501 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9502 && ABS (offset) / 2 > stream->duration)) {
9503 GST_WARNING_OBJECT (qtdemux,
9504 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9505 " larger than duration %" G_GUINT64_FORMAT, offset,
9508 stream->cslg_shift = 0;
9509 stream->ctts_present = FALSE;
9513 /* Don't consider "no decode samples" with offset G_MININT32
9514 * for the DTS/PTS shift */
9515 if (offset != G_MININT32 && offset < cslg_least)
9516 cslg_least = offset;
9520 stream->cslg_shift = -cslg_least;
9522 stream->cslg_shift = 0;
9524 /* reset the reader so we can generate sample table */
9525 gst_byte_reader_set_pos (&stream->ctts, pos);
9528 /* Check if ctts values are looking reasonable if that didn't happen above */
9529 if (!checked_ctts) {
9530 guint num_entries, pos;
9533 pos = gst_byte_reader_get_pos (&stream->ctts);
9534 num_entries = stream->n_composition_times;
9536 for (i = 0; i < num_entries; i++) {
9539 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9540 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9541 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9542 * slightly inaccurate PTS could be more usable than corrupted one */
9543 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9544 && ABS (offset) / 2 > stream->duration)) {
9545 GST_WARNING_OBJECT (qtdemux,
9546 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9547 " larger than duration %" G_GUINT64_FORMAT, offset,
9550 stream->cslg_shift = 0;
9551 stream->ctts_present = FALSE;
9556 /* reset the reader so we can generate sample table */
9557 gst_byte_reader_set_pos (&stream->ctts, pos);
9560 /* Ensure the cslg_shift value is consistent so we can use it
9561 * unconditionally to produce TS and Segment */
9562 stream->cslg_shift = 0;
9565 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
9566 stream->cslg_shift);
9568 /* For raw audio streams especially we might want to merge the samples
9569 * to not output one audio sample per buffer. We're doing this here
9570 * before allocating the sample tables so that from this point onwards
9571 * the number of container samples are static */
9572 if (stream->min_buffer_size > 0) {
9573 qtdemux_merge_sample_table (qtdemux, stream);
9577 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9578 stream->n_samples, (guint) sizeof (QtDemuxSample),
9579 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9581 if (stream->n_samples >=
9582 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9583 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9584 "be larger than %uMB (broken file?)", stream->n_samples,
9585 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9589 g_assert (stream->samples == NULL);
9590 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9591 if (!stream->samples) {
9592 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9601 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9602 (_("This file is corrupt and cannot be played.")), (NULL));
9607 gst_qtdemux_stbl_free (stream);
9608 if (!qtdemux->fragmented) {
9609 /* not quite good */
9610 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9613 /* may pick up samples elsewhere */
9619 /* collect samples from the next sample to be parsed up to sample @n for @stream
9620 * by reading the info from @stbl
9622 * This code can be executed from both the streaming thread and the seeking
9623 * thread so it takes the object lock to protect itself
9626 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9629 QtDemuxSample *samples, *first, *cur, *last;
9630 guint32 n_samples_per_chunk;
9633 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9634 GST_FOURCC_FORMAT ", pad %s",
9635 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9636 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9638 n_samples = stream->n_samples;
9641 goto out_of_samples;
9643 GST_OBJECT_LOCK (qtdemux);
9644 if (n <= stream->stbl_index)
9645 goto already_parsed;
9647 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9649 if (!stream->stsz.data) {
9650 /* so we already parsed and passed all the moov samples;
9651 * onto fragmented ones */
9652 g_assert (qtdemux->fragmented);
9656 /* pointer to the sample table */
9657 samples = stream->samples;
9659 /* starts from -1, moves to the next sample index to parse */
9660 stream->stbl_index++;
9662 /* keep track of the first and last sample to fill */
9663 first = &samples[stream->stbl_index];
9666 if (!stream->chunks_are_samples) {
9667 /* set the sample sizes */
9668 if (stream->sample_size == 0) {
9669 /* different sizes for each sample */
9670 for (cur = first; cur <= last; cur++) {
9671 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9672 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9673 (guint) (cur - samples), cur->size);
9676 /* samples have the same size */
9677 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9678 for (cur = first; cur <= last; cur++)
9679 cur->size = stream->sample_size;
9683 n_samples_per_chunk = stream->n_samples_per_chunk;
9686 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9689 if (stream->stsc_chunk_index >= stream->last_chunk
9690 || stream->stsc_chunk_index < stream->first_chunk) {
9691 stream->first_chunk =
9692 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9693 stream->samples_per_chunk =
9694 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9696 stream->stsd_sample_description_id =
9697 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9699 /* chunk numbers are counted from 1 it seems */
9700 if (G_UNLIKELY (stream->first_chunk == 0))
9703 --stream->first_chunk;
9705 /* the last chunk of each entry is calculated by taking the first chunk
9706 * of the next entry; except if there is no next, where we fake it with
9708 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9709 stream->last_chunk = G_MAXUINT32;
9711 stream->last_chunk =
9712 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9713 if (G_UNLIKELY (stream->last_chunk == 0))
9716 --stream->last_chunk;
9719 GST_LOG_OBJECT (qtdemux,
9720 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9721 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9722 stream->samples_per_chunk, stream->stsd_sample_description_id);
9724 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9727 if (stream->last_chunk != G_MAXUINT32) {
9728 if (!qt_atom_parser_peek_sub (&stream->stco,
9729 stream->first_chunk * stream->co_size,
9730 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9735 stream->co_chunk = stream->stco;
9736 if (!gst_byte_reader_skip (&stream->co_chunk,
9737 stream->first_chunk * stream->co_size))
9741 stream->stsc_chunk_index = stream->first_chunk;
9744 last_chunk = stream->last_chunk;
9746 if (stream->chunks_are_samples) {
9747 cur = &samples[stream->stsc_chunk_index];
9749 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9752 stream->stsc_chunk_index = j;
9757 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9760 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9761 "%" G_GUINT64_FORMAT, j, cur->offset);
9763 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9764 CUR_STREAM (stream)->bytes_per_frame > 0) {
9766 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9767 CUR_STREAM (stream)->samples_per_frame *
9768 CUR_STREAM (stream)->bytes_per_frame;
9770 cur->size = stream->samples_per_chunk;
9773 GST_DEBUG_OBJECT (qtdemux,
9774 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9775 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9776 stream->stco_sample_index)), cur->size);
9778 cur->timestamp = stream->stco_sample_index;
9779 cur->duration = stream->samples_per_chunk;
9780 cur->keyframe = TRUE;
9783 stream->stco_sample_index += stream->samples_per_chunk;
9785 stream->stsc_chunk_index = j;
9787 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9788 guint32 samples_per_chunk;
9789 guint64 chunk_offset;
9791 if (!stream->stsc_sample_index
9792 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9793 &stream->chunk_offset))
9796 samples_per_chunk = stream->samples_per_chunk;
9797 chunk_offset = stream->chunk_offset;
9799 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9800 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9801 G_GUINT64_FORMAT " and size %d",
9802 (guint) (cur - samples), chunk_offset, cur->size);
9804 cur->offset = chunk_offset;
9805 chunk_offset += cur->size;
9808 if (G_UNLIKELY (cur > last)) {
9810 stream->stsc_sample_index = k + 1;
9811 stream->chunk_offset = chunk_offset;
9812 stream->stsc_chunk_index = j;
9816 stream->stsc_sample_index = 0;
9818 stream->stsc_chunk_index = j;
9820 stream->stsc_index++;
9823 if (stream->chunks_are_samples)
9827 guint32 n_sample_times;
9829 n_sample_times = stream->n_sample_times;
9832 for (i = stream->stts_index; i < n_sample_times; i++) {
9833 guint32 stts_samples;
9834 gint32 stts_duration;
9837 if (stream->stts_sample_index >= stream->stts_samples
9838 || !stream->stts_sample_index) {
9840 stream->stts_samples =
9841 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9842 stream->stts_duration =
9843 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9845 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9846 i, stream->stts_samples, stream->stts_duration);
9848 stream->stts_sample_index = 0;
9851 stts_samples = stream->stts_samples;
9852 stts_duration = stream->stts_duration;
9853 stts_time = stream->stts_time;
9855 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9856 GST_DEBUG_OBJECT (qtdemux,
9857 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9858 (guint) (cur - samples), j,
9859 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9861 cur->timestamp = stts_time;
9862 cur->duration = stts_duration;
9864 /* avoid 32-bit wrap-around,
9865 * but still mind possible 'negative' duration */
9866 stts_time += (gint64) stts_duration;
9869 if (G_UNLIKELY (cur > last)) {
9871 stream->stts_time = stts_time;
9872 stream->stts_sample_index = j + 1;
9873 if (stream->stts_sample_index >= stream->stts_samples)
9874 stream->stts_index++;
9878 stream->stts_sample_index = 0;
9879 stream->stts_time = stts_time;
9880 stream->stts_index++;
9882 /* fill up empty timestamps with the last timestamp, this can happen when
9883 * the last samples do not decode and so we don't have timestamps for them.
9884 * We however look at the last timestamp to estimate the track length so we
9885 * need something in here. */
9886 for (; cur < last; cur++) {
9887 GST_DEBUG_OBJECT (qtdemux,
9888 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9889 (guint) (cur - samples),
9890 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9891 cur->timestamp = stream->stts_time;
9897 /* sample sync, can be NULL */
9898 if (stream->stss_present == TRUE) {
9899 guint32 n_sample_syncs;
9901 n_sample_syncs = stream->n_sample_syncs;
9903 if (!n_sample_syncs) {
9904 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9905 stream->all_keyframe = TRUE;
9907 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9908 /* note that the first sample is index 1, not 0 */
9911 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9913 if (G_LIKELY (index > 0 && index <= n_samples)) {
9915 samples[index].keyframe = TRUE;
9916 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9917 /* and exit if we have enough samples */
9918 if (G_UNLIKELY (index >= n)) {
9925 stream->stss_index = i;
9928 /* stps marks partial sync frames like open GOP I-Frames */
9929 if (stream->stps_present == TRUE) {
9930 guint32 n_sample_partial_syncs;
9932 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9934 /* if there are no entries, the stss table contains the real
9936 if (n_sample_partial_syncs) {
9937 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9938 /* note that the first sample is index 1, not 0 */
9941 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9943 if (G_LIKELY (index > 0 && index <= n_samples)) {
9945 samples[index].keyframe = TRUE;
9946 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9947 /* and exit if we have enough samples */
9948 if (G_UNLIKELY (index >= n)) {
9955 stream->stps_index = i;
9959 /* no stss, all samples are keyframes */
9960 stream->all_keyframe = TRUE;
9961 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9966 /* composition time to sample */
9967 if (stream->ctts_present == TRUE) {
9968 guint32 n_composition_times;
9970 gint32 ctts_soffset;
9972 /* Fill in the pts_offsets */
9974 n_composition_times = stream->n_composition_times;
9976 for (i = stream->ctts_index; i < n_composition_times; i++) {
9977 if (stream->ctts_sample_index >= stream->ctts_count
9978 || !stream->ctts_sample_index) {
9979 stream->ctts_count =
9980 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9981 stream->ctts_soffset =
9982 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9983 stream->ctts_sample_index = 0;
9986 ctts_count = stream->ctts_count;
9987 ctts_soffset = stream->ctts_soffset;
9989 /* FIXME: Set offset to 0 for "no decode samples". This needs
9990 * to be handled in a codec specific manner ideally. */
9991 if (ctts_soffset == G_MININT32)
9994 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9995 cur->pts_offset = ctts_soffset;
9998 if (G_UNLIKELY (cur > last)) {
10000 stream->ctts_sample_index = j + 1;
10004 stream->ctts_sample_index = 0;
10005 stream->ctts_index++;
10009 stream->stbl_index = n;
10010 /* if index has been completely parsed, free data that is no-longer needed */
10011 if (n + 1 == stream->n_samples) {
10012 gst_qtdemux_stbl_free (stream);
10013 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10014 if (qtdemux->pullbased) {
10015 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10016 while (n + 1 == stream->n_samples)
10017 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10021 GST_OBJECT_UNLOCK (qtdemux);
10028 GST_LOG_OBJECT (qtdemux,
10029 "Tried to parse up to sample %u but this sample has already been parsed",
10031 /* if fragmented, there may be more */
10032 if (qtdemux->fragmented && n == stream->stbl_index)
10034 GST_OBJECT_UNLOCK (qtdemux);
10040 GST_LOG_OBJECT (qtdemux,
10041 "Tried to parse up to sample %u but there are only %u samples", n + 1,
10042 stream->n_samples);
10043 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10044 (_("This file is corrupt and cannot be played.")), (NULL));
10049 GST_OBJECT_UNLOCK (qtdemux);
10050 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10051 (_("This file is corrupt and cannot be played.")), (NULL));
10056 /* collect all segment info for @stream.
10059 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10063 /* accept edts if they contain gaps at start and there is only
10064 * one media segment */
10065 gboolean allow_pushbased_edts = TRUE;
10066 gint media_segments_count = 0;
10068 /* parse and prepare segment info from the edit list */
10069 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10070 stream->n_segments = 0;
10071 stream->segments = NULL;
10072 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10075 gint segment_number, entry_size;
10077 GstClockTime stime;
10078 const guint8 *buffer;
10082 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10083 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10086 buffer = elst->data;
10088 size = QT_UINT32 (buffer);
10089 /* version, flags, n_segments */
10091 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10094 version = QT_UINT8 (buffer + 8);
10095 entry_size = (version == 1) ? 20 : 12;
10097 n_segments = QT_UINT32 (buffer + 12);
10099 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10100 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10104 /* we might allocate a bit too much, at least allocate 1 segment */
10105 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10107 /* segments always start from 0 */
10111 for (segment_number = 0; segment_number < n_segments; segment_number++) {
10113 guint64 media_time;
10114 gboolean empty_edit = FALSE;
10115 QtDemuxSegment *segment;
10117 GstClockTime media_start = GST_CLOCK_TIME_NONE;
10119 if (version == 1) {
10120 media_time = QT_UINT64 (buffer + 8);
10121 duration = QT_UINT64 (buffer);
10122 if (media_time == G_MAXUINT64)
10125 media_time = QT_UINT32 (buffer + 4);
10126 duration = QT_UINT32 (buffer);
10127 if (media_time == G_MAXUINT32)
10132 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10134 segment = &stream->segments[segment_number];
10136 /* time and duration expressed in global timescale */
10137 segment->time = stime;
10138 if (duration != 0 || empty_edit) {
10139 /* edge case: empty edits with duration=zero are treated here.
10140 * (files should not have these anyway). */
10142 /* add non scaled values so we don't cause roundoff errors */
10144 stime = QTTIME_TO_GSTTIME (qtdemux, time);
10145 segment->duration = stime - segment->time;
10147 /* zero duration does not imply media_start == media_stop
10148 * but, only specify media_start. The edit ends with the track. */
10149 stime = segment->duration = GST_CLOCK_TIME_NONE;
10150 /* Don't allow more edits after this one. */
10151 n_segments = segment_number + 1;
10153 segment->stop_time = stime;
10155 segment->trak_media_start = media_time;
10156 /* media_time expressed in stream timescale */
10158 segment->media_start = media_start;
10159 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10160 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10161 media_segments_count++;
10163 segment->media_start = GST_CLOCK_TIME_NONE;
10164 segment->media_stop = GST_CLOCK_TIME_NONE;
10166 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10168 if (rate_int <= 1) {
10169 /* 0 is not allowed, some programs write 1 instead of the floating point
10171 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10175 segment->rate = rate_int / 65536.0;
10178 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10179 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10180 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10181 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10182 segment_number, GST_TIME_ARGS (segment->time),
10183 GST_TIME_ARGS (segment->duration),
10184 GST_TIME_ARGS (segment->media_start), media_time,
10185 GST_TIME_ARGS (segment->media_stop),
10186 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10187 stream->timescale);
10188 if (segment->stop_time > qtdemux->segment.stop &&
10189 !qtdemux->upstream_format_is_time) {
10190 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10191 " extends to %" GST_TIME_FORMAT
10192 " past the end of the declared movie duration %" GST_TIME_FORMAT
10193 " movie segment will be extended", segment_number,
10194 GST_TIME_ARGS (segment->stop_time),
10195 GST_TIME_ARGS (qtdemux->segment.stop));
10196 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10199 buffer += entry_size;
10201 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10202 stream->n_segments = n_segments;
10203 if (media_segments_count != 1)
10204 allow_pushbased_edts = FALSE;
10208 /* push based does not handle segments, so act accordingly here,
10209 * and warn if applicable */
10210 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10211 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10212 /* remove and use default one below, we stream like it anyway */
10213 g_free (stream->segments);
10214 stream->segments = NULL;
10215 stream->n_segments = 0;
10218 /* no segments, create one to play the complete trak */
10219 if (stream->n_segments == 0) {
10220 GstClockTime stream_duration =
10221 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10223 if (stream->segments == NULL)
10224 stream->segments = g_new (QtDemuxSegment, 1);
10226 /* represent unknown our way */
10227 if (stream_duration == 0)
10228 stream_duration = GST_CLOCK_TIME_NONE;
10230 stream->segments[0].time = 0;
10231 stream->segments[0].stop_time = stream_duration;
10232 stream->segments[0].duration = stream_duration;
10233 stream->segments[0].media_start = 0;
10234 stream->segments[0].media_stop = stream_duration;
10235 stream->segments[0].rate = 1.0;
10236 stream->segments[0].trak_media_start = 0;
10238 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10239 GST_TIME_ARGS (stream_duration));
10240 stream->n_segments = 1;
10241 stream->dummy_segment = TRUE;
10243 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10249 * Parses the stsd atom of a svq3 trak looking for
10250 * the SMI and gama atoms.
10253 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10254 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10256 const guint8 *_gamma = NULL;
10257 GstBuffer *_seqh = NULL;
10258 const guint8 *stsd_data = stsd_entry_data;
10259 guint32 length = QT_UINT32 (stsd_data);
10263 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10269 version = QT_UINT16 (stsd_data);
10270 if (version == 3) {
10271 if (length >= 70) {
10274 while (length > 8) {
10275 guint32 fourcc, size;
10276 const guint8 *data;
10277 size = QT_UINT32 (stsd_data);
10278 fourcc = QT_FOURCC (stsd_data + 4);
10279 data = stsd_data + 8;
10282 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10283 "svq3 atom parsing");
10292 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10293 " for gama atom, expected 12", size);
10298 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10300 if (_seqh != NULL) {
10301 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10302 " found, ignoring");
10304 seqh_size = QT_UINT32 (data + 4);
10305 if (seqh_size > 0) {
10306 _seqh = gst_buffer_new_and_alloc (seqh_size);
10307 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10314 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10315 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10319 if (size <= length) {
10325 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10328 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10329 G_GUINT16_FORMAT, version);
10339 } else if (_seqh) {
10340 gst_buffer_unref (_seqh);
10345 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10348 GstByteReader dref;
10352 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10353 * atom that might contain a 'data' atom with the rtsp uri.
10354 * This case was reported in bug #597497, some info about
10355 * the hndl atom can be found in TN1195
10357 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10358 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10361 guint32 dref_num_entries = 0;
10362 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10363 gst_byte_reader_skip (&dref, 4) &&
10364 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10367 /* search dref entries for hndl atom */
10368 for (i = 0; i < dref_num_entries; i++) {
10369 guint32 size = 0, type;
10370 guint8 string_len = 0;
10371 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10372 qt_atom_parser_get_fourcc (&dref, &type)) {
10373 if (type == FOURCC_hndl) {
10374 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10376 /* skip data reference handle bytes and the
10377 * following pascal string and some extra 4
10378 * bytes I have no idea what are */
10379 if (!gst_byte_reader_skip (&dref, 4) ||
10380 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10381 !gst_byte_reader_skip (&dref, string_len + 4)) {
10382 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10386 /* iterate over the atoms to find the data atom */
10387 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10391 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10392 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10393 if (atom_type == FOURCC_data) {
10394 const guint8 *uri_aux = NULL;
10396 /* found the data atom that might contain the rtsp uri */
10397 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10398 "hndl atom, interpreting it as an URI");
10399 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10401 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10402 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10404 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10405 "didn't contain a rtsp address");
10407 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10412 /* skipping to the next entry */
10413 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10416 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10423 /* skip to the next entry */
10424 if (!gst_byte_reader_skip (&dref, size - 8))
10427 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10430 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10436 #define AMR_NB_ALL_MODES 0x81ff
10437 #define AMR_WB_ALL_MODES 0x83ff
10439 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10441 /* The 'damr' atom is of the form:
10443 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10444 * 32 b 8 b 16 b 8 b 8 b
10446 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10447 * represents the highest mode used in the stream (and thus the maximum
10448 * bitrate), with a couple of special cases as seen below.
10451 /* Map of frame type ID -> bitrate */
10452 static const guint nb_bitrates[] = {
10453 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10455 static const guint wb_bitrates[] = {
10456 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10462 gst_buffer_map (buf, &map, GST_MAP_READ);
10464 if (map.size != 0x11) {
10465 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10469 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10470 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10471 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10475 mode_set = QT_UINT16 (map.data + 13);
10477 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10478 max_mode = 7 + (wb ? 1 : 0);
10480 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10481 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10483 if (max_mode == -1) {
10484 GST_DEBUG ("No mode indication was found (mode set) = %x",
10489 gst_buffer_unmap (buf, &map);
10490 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10493 gst_buffer_unmap (buf, &map);
10498 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10499 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10502 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10508 if (gst_byte_reader_get_remaining (reader) < 36)
10511 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10512 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10513 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10514 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10515 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10516 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10517 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10518 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10519 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10521 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10522 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10523 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10525 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10526 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10528 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10529 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10536 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10537 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10544 * This macro will only compare value abdegh, it expects cfi to have already
10547 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10548 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10550 /* only handle the cases where the last column has standard values */
10551 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10552 const gchar *rotation_tag = NULL;
10554 /* no rotation needed */
10555 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10557 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10558 rotation_tag = "rotate-90";
10559 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10560 rotation_tag = "rotate-180";
10561 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10562 rotation_tag = "rotate-270";
10564 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10567 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10568 GST_STR_NULL (rotation_tag));
10569 if (rotation_tag != NULL) {
10570 if (*taglist == NULL)
10571 *taglist = gst_tag_list_new_empty ();
10572 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10573 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10576 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10581 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10582 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10586 GstBuffer *adrm_buf = NULL;
10587 QtDemuxAavdEncryptionInfo *info;
10589 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10590 if (G_UNLIKELY (!adrm)) {
10591 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10594 adrm_size = QT_UINT32 (adrm->data);
10595 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10597 stream->protection_scheme_type = FOURCC_aavd;
10599 if (!stream->protection_scheme_info)
10600 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10602 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10604 if (info->default_properties)
10605 gst_structure_free (info->default_properties);
10606 info->default_properties = gst_structure_new ("application/x-aavd",
10607 "encrypted", G_TYPE_BOOLEAN, TRUE,
10608 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10609 gst_buffer_unref (adrm_buf);
10611 *original_fmt = FOURCC_mp4a;
10615 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10616 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10617 * Common Encryption (cenc), the function will also parse the tenc box (defined
10618 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10619 * (typically an enc[v|a|t|s] sample entry); the function will set
10620 * @original_fmt to the fourcc of the original unencrypted stream format.
10621 * Returns TRUE if successful; FALSE otherwise. */
10623 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10624 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10630 QtDemuxCencSampleSetInfo *info;
10632 const guint8 *tenc_data;
10634 g_return_val_if_fail (qtdemux != NULL, FALSE);
10635 g_return_val_if_fail (stream != NULL, FALSE);
10636 g_return_val_if_fail (container != NULL, FALSE);
10637 g_return_val_if_fail (original_fmt != NULL, FALSE);
10639 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10640 if (G_UNLIKELY (!sinf)) {
10641 if (stream->protection_scheme_type == FOURCC_cenc
10642 || stream->protection_scheme_type == FOURCC_cbcs) {
10643 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10644 "mandatory for Common Encryption");
10650 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10651 if (G_UNLIKELY (!frma)) {
10652 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10656 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10657 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10658 GST_FOURCC_ARGS (*original_fmt));
10660 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10662 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10665 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10666 stream->protection_scheme_version =
10667 QT_UINT32 ((const guint8 *) schm->data + 16);
10669 GST_DEBUG_OBJECT (qtdemux,
10670 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10671 "protection_scheme_version: %#010x",
10672 GST_FOURCC_ARGS (stream->protection_scheme_type),
10673 stream->protection_scheme_version);
10675 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10677 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10680 if (stream->protection_scheme_type != FOURCC_cenc &&
10681 stream->protection_scheme_type != FOURCC_piff &&
10682 stream->protection_scheme_type != FOURCC_cbcs) {
10683 GST_ERROR_OBJECT (qtdemux,
10684 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10685 GST_FOURCC_ARGS (stream->protection_scheme_type));
10689 if (G_UNLIKELY (!stream->protection_scheme_info))
10690 stream->protection_scheme_info =
10691 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10693 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10695 if (stream->protection_scheme_type == FOURCC_cenc
10696 || stream->protection_scheme_type == FOURCC_cbcs) {
10697 guint8 is_encrypted;
10699 guint8 constant_iv_size = 0;
10700 const guint8 *default_kid;
10701 guint8 crypt_byte_block = 0;
10702 guint8 skip_byte_block = 0;
10703 const guint8 *constant_iv = NULL;
10705 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10707 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10708 "which is mandatory for Common Encryption");
10711 tenc_data = (const guint8 *) tenc->data + 12;
10712 is_encrypted = QT_UINT8 (tenc_data + 2);
10713 iv_size = QT_UINT8 (tenc_data + 3);
10714 default_kid = (tenc_data + 4);
10715 if (stream->protection_scheme_type == FOURCC_cbcs) {
10716 guint8 possible_pattern_info;
10717 if (iv_size == 0) {
10718 constant_iv_size = QT_UINT8 (tenc_data + 20);
10719 if (constant_iv_size != 8 && constant_iv_size != 16) {
10720 GST_ERROR_OBJECT (qtdemux,
10721 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10724 constant_iv = (tenc_data + 21);
10726 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10727 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10728 skip_byte_block = possible_pattern_info & 0x0f;
10730 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10731 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10732 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10733 } else if (stream->protection_scheme_type == FOURCC_piff) {
10735 static const guint8 piff_track_encryption_uuid[] = {
10736 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10737 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10740 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10742 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10743 "which is mandatory for Common Encryption");
10747 tenc_data = (const guint8 *) tenc->data + 8;
10748 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10749 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10750 GST_ERROR_OBJECT (qtdemux,
10751 "Unsupported track encryption box with uuid: %s", box_uuid);
10755 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10756 gst_byte_reader_init (&br, tenc_data, 20);
10757 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10758 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10761 stream->protection_scheme_type = FOURCC_cenc;
10768 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10769 QtDemuxStream ** stream2)
10771 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10775 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10780 /*parse svmi header if existing */
10781 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10783 guint len = QT_UINT32 ((guint8 *) svmi->data);
10784 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10786 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10787 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10788 guint8 frame_type, frame_layout;
10789 guint32 stereo_mono_change_count;
10794 /* MPEG-A stereo video */
10795 if (qtdemux->major_brand == FOURCC_ss02)
10796 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10798 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10799 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10800 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10802 switch (frame_type) {
10804 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10807 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10810 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10813 /* mode 3 is primary/secondary view sequence, ie
10814 * left/right views in separate tracks. See section 7.2
10815 * of ISO/IEC 23000-11:2009 */
10816 /* In the future this might be supported using related
10817 * streams, like an enhancement track - if files like this
10819 GST_FIXME_OBJECT (qtdemux,
10820 "Implement stereo video in separate streams");
10823 if ((frame_layout & 0x1) == 0)
10824 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10826 GST_LOG_OBJECT (qtdemux,
10827 "StereoVideo: composition type: %u, is_left_first: %u",
10828 frame_type, frame_layout);
10830 if (stereo_mono_change_count > 1) {
10831 GST_FIXME_OBJECT (qtdemux,
10832 "Mixed-mono flags are not yet supported in qtdemux.");
10835 stream->multiview_mode = mode;
10836 stream->multiview_flags = flags;
10843 /* parse the traks.
10844 * With each track we associate a new QtDemuxStream that contains all the info
10846 * traks that do not decode to something (like strm traks) will not have a pad.
10849 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10851 GstByteReader tkhd;
10865 QtDemuxStream *stream = NULL;
10866 const guint8 *stsd_data;
10867 const guint8 *stsd_entry_data;
10868 guint remaining_stsd_len;
10869 guint stsd_entry_count;
10871 guint16 lang_code; /* quicktime lang code or packed iso code */
10873 guint32 tkhd_flags = 0;
10874 guint8 tkhd_version = 0;
10875 guint32 w = 0, h = 0;
10876 guint value_size, stsd_len, len;
10880 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10882 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10883 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10884 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10887 /* pick between 64 or 32 bits */
10888 value_size = tkhd_version == 1 ? 8 : 4;
10889 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10890 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10893 /* Check if current moov has duplicated track_id */
10894 if (qtdemux_find_stream (qtdemux, track_id))
10895 goto existing_stream;
10897 stream = _create_stream (qtdemux, track_id);
10898 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10900 /* need defaults for fragments */
10901 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10903 if ((tkhd_flags & 1) == 0)
10904 stream->disabled = TRUE;
10906 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10907 tkhd_version, tkhd_flags, stream->track_id);
10909 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10912 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10913 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10914 if (qtdemux->major_brand != FOURCC_mjp2 ||
10915 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10919 len = QT_UINT32 ((guint8 *) mdhd->data);
10920 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10921 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10922 if (version == 0x01000000) {
10925 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10926 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10927 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
10931 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10932 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10933 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10936 if (lang_code < 0x400) {
10937 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10938 } else if (lang_code == 0x7fff) {
10939 stream->lang_id[0] = 0; /* unspecified */
10941 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10942 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10943 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10944 stream->lang_id[3] = 0;
10947 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10948 stream->timescale);
10949 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10951 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10952 lang_code, stream->lang_id);
10954 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10957 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10958 /* chapters track reference */
10959 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10961 gsize length = GST_READ_UINT32_BE (chap->data);
10962 if (qtdemux->chapters_track_id)
10963 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10965 if (length >= 12) {
10966 qtdemux->chapters_track_id =
10967 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10972 /* fragmented files may have bogus duration in moov */
10973 if (!qtdemux->fragmented &&
10974 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10975 guint64 tdur1, tdur2;
10977 /* don't overflow */
10978 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10979 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10982 * some of those trailers, nowadays, have prologue images that are
10983 * themselves video tracks as well. I haven't really found a way to
10984 * identify those yet, except for just looking at their duration. */
10985 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10986 GST_WARNING_OBJECT (qtdemux,
10987 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10988 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10989 "found, assuming preview image or something; skipping track",
10990 stream->duration, stream->timescale, qtdemux->duration,
10991 qtdemux->timescale);
10992 gst_qtdemux_stream_unref (stream);
10997 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11000 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11001 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11003 len = QT_UINT32 ((guint8 *) hdlr->data);
11005 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11006 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11007 GST_FOURCC_ARGS (stream->subtype));
11009 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11012 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11015 /* Parse out svmi (and later st3d/sv3d) atoms */
11016 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
11019 /* parse rest of tkhd */
11020 if (stream->subtype == FOURCC_vide) {
11023 /* version 1 uses some 64-bit ints */
11024 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11027 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11030 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11031 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11034 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11035 &stream->stream_tags);
11039 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11041 stsd_data = (const guint8 *) stsd->data;
11043 /* stsd should at least have one entry */
11044 stsd_len = QT_UINT32 (stsd_data);
11045 if (stsd_len < 24) {
11046 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11047 if (stream->subtype == FOURCC_vivo) {
11048 gst_qtdemux_stream_unref (stream);
11055 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11056 /* each stsd entry must contain at least 8 bytes */
11057 if (stream->stsd_entries_length == 0
11058 || stream->stsd_entries_length > stsd_len / 8) {
11059 stream->stsd_entries_length = 0;
11062 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11063 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
11064 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
11066 stsd_entry_data = stsd_data + 16;
11067 remaining_stsd_len = stsd_len - 16;
11068 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11070 gchar *codec = NULL;
11071 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11073 /* and that entry should fit within stsd */
11074 len = QT_UINT32 (stsd_entry_data);
11075 if (len > remaining_stsd_len)
11078 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11079 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
11080 GST_FOURCC_ARGS (entry->fourcc));
11081 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
11083 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11084 goto error_encrypted;
11086 if (fourcc == FOURCC_aavd) {
11087 if (stream->subtype != FOURCC_soun) {
11088 GST_ERROR_OBJECT (qtdemux,
11089 "Unexpeced stsd type 'aavd' outside 'soun' track");
11091 /* encrypted audio with sound sample description v0 */
11092 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11093 stream->protected = TRUE;
11094 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11095 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11099 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11100 /* FIXME this looks wrong, there might be multiple children
11101 * with the same type */
11102 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11103 stream->protected = TRUE;
11104 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11105 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11108 if (stream->subtype == FOURCC_vide) {
11113 gint depth, palette_size, palette_count;
11114 guint32 *palette_data = NULL;
11116 entry->sampled = TRUE;
11118 stream->display_width = w >> 16;
11119 stream->display_height = h >> 16;
11122 if (len < 86) /* TODO verify */
11125 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11126 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11127 entry->fps_n = 0; /* this is filled in later */
11128 entry->fps_d = 0; /* this is filled in later */
11129 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11130 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11132 /* if color_table_id is 0, ctab atom must follow; however some files
11133 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11134 * if color table is not present we'll correct the value */
11135 if (entry->color_table_id == 0 &&
11137 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11138 entry->color_table_id = -1;
11141 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11142 entry->width, entry->height, entry->bits_per_sample,
11143 entry->color_table_id);
11145 depth = entry->bits_per_sample;
11147 /* more than 32 bits means grayscale */
11148 gray = (depth > 32);
11149 /* low 32 bits specify the depth */
11152 /* different number of palette entries is determined by depth. */
11154 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11155 palette_count = (1 << depth);
11156 palette_size = palette_count * 4;
11158 if (entry->color_table_id) {
11159 switch (palette_count) {
11163 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11166 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11171 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11173 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11178 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11181 g_memdup2 (ff_qt_default_palette_256, palette_size);
11184 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11185 (_("The video in this file might not play correctly.")),
11186 ("unsupported palette depth %d", depth));
11190 gint i, j, start, end;
11196 start = QT_UINT32 (stsd_entry_data + offset + 70);
11197 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11198 end = QT_UINT16 (stsd_entry_data + offset + 76);
11200 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11201 start, end, palette_count);
11208 if (len < 94 + (end - start) * 8)
11211 /* palette is always the same size */
11212 palette_data = g_malloc0 (256 * 4);
11213 palette_size = 256 * 4;
11215 for (j = 0, i = start; i <= end; j++, i++) {
11216 guint32 a, r, g, b;
11218 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11219 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11220 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11221 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11223 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11224 (g & 0xff00) | (b >> 8);
11229 gst_caps_unref (entry->caps);
11232 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11234 if (G_UNLIKELY (!entry->caps)) {
11235 g_free (palette_data);
11236 goto unknown_stream;
11240 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11241 GST_TAG_VIDEO_CODEC, codec, NULL);
11246 if (palette_data) {
11249 if (entry->rgb8_palette)
11250 gst_memory_unref (entry->rgb8_palette);
11251 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11252 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11254 s = gst_caps_get_structure (entry->caps, 0);
11256 /* non-raw video has a palette_data property. raw video has the palette as
11257 * an extra plane that we append to the output buffers before we push
11259 if (!gst_structure_has_name (s, "video/x-raw")) {
11260 GstBuffer *palette;
11262 palette = gst_buffer_new ();
11263 gst_buffer_append_memory (palette, entry->rgb8_palette);
11264 entry->rgb8_palette = NULL;
11266 gst_caps_set_simple (entry->caps, "palette_data",
11267 GST_TYPE_BUFFER, palette, NULL);
11268 gst_buffer_unref (palette);
11270 } else if (palette_count != 0) {
11271 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11272 (NULL), ("Unsupported palette depth %d", depth));
11275 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11276 QT_UINT16 (stsd_entry_data + offset + 32));
11282 /* pick 'the' stsd child */
11283 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11284 // We should skip parsing the stsd for non-protected streams if
11285 // the entry doesn't match the fourcc, since they don't change
11286 // format. However, for protected streams we can have partial
11287 // encryption, where parts of the stream are encrypted and parts
11288 // not. For both parts of such streams, we should ensure the
11289 // esds overrides are parsed for both from the stsd.
11290 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11291 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11293 else if (!stream->protected)
11298 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11299 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11300 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11301 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11305 const guint8 *pasp_data = (const guint8 *) pasp->data;
11306 gint len = QT_UINT32 (pasp_data);
11309 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11310 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11312 CUR_STREAM (stream)->par_w = 0;
11313 CUR_STREAM (stream)->par_h = 0;
11316 CUR_STREAM (stream)->par_w = 0;
11317 CUR_STREAM (stream)->par_h = 0;
11321 const guint8 *fiel_data = (const guint8 *) fiel->data;
11322 gint len = QT_UINT32 (fiel_data);
11325 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11326 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11331 const guint8 *colr_data = (const guint8 *) colr->data;
11332 gint len = QT_UINT32 (colr_data);
11334 if (len == 19 || len == 18) {
11335 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11337 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11338 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11339 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11340 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11341 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11343 CUR_STREAM (stream)->colorimetry.primaries =
11344 gst_video_color_primaries_from_iso (primaries);
11345 CUR_STREAM (stream)->colorimetry.transfer =
11346 gst_video_transfer_function_from_iso (transfer_function);
11347 CUR_STREAM (stream)->colorimetry.matrix =
11348 gst_video_color_matrix_from_iso (matrix);
11349 CUR_STREAM (stream)->colorimetry.range =
11350 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11351 GST_VIDEO_COLOR_RANGE_16_235;
11353 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11356 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11361 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11362 stream->stream_tags);
11369 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11370 const guint8 *avc_data = stsd_entry_data + 0x56;
11373 while (len >= 0x8) {
11376 if (QT_UINT32 (avc_data) <= len)
11377 size = QT_UINT32 (avc_data) - 0x8;
11382 /* No real data, so break out */
11385 switch (QT_FOURCC (avc_data + 0x4)) {
11388 /* parse, if found */
11391 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11393 /* First 4 bytes are the length of the atom, the next 4 bytes
11394 * are the fourcc, the next 1 byte is the version, and the
11395 * subsequent bytes are profile_tier_level structure like data. */
11396 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11397 avc_data + 8 + 1, size - 1);
11398 buf = gst_buffer_new_and_alloc (size);
11399 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11400 gst_caps_set_simple (entry->caps,
11401 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11402 gst_buffer_unref (buf);
11410 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11412 /* First 4 bytes are the length of the atom, the next 4 bytes
11413 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11414 * next 1 byte is the version, and the
11415 * subsequent bytes are sequence parameter set like data. */
11417 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11419 gst_codec_utils_h264_caps_set_level_and_profile
11420 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11422 buf = gst_buffer_new_and_alloc (size);
11423 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11424 gst_caps_set_simple (entry->caps,
11425 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11426 gst_buffer_unref (buf);
11432 guint avg_bitrate, max_bitrate;
11434 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11438 max_bitrate = QT_UINT32 (avc_data + 0xc);
11439 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11441 if (!max_bitrate && !avg_bitrate)
11444 /* Some muxers seem to swap the average and maximum bitrates
11445 * (I'm looking at you, YouTube), so we swap for sanity. */
11446 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11447 guint temp = avg_bitrate;
11449 avg_bitrate = max_bitrate;
11450 max_bitrate = temp;
11453 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11454 gst_tag_list_add (stream->stream_tags,
11455 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11456 max_bitrate, NULL);
11458 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11459 gst_tag_list_add (stream->stream_tags,
11460 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11472 avc_data += size + 8;
11483 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11484 const guint8 *hevc_data = stsd_entry_data + 0x56;
11487 while (len >= 0x8) {
11490 if (QT_UINT32 (hevc_data) <= len)
11491 size = QT_UINT32 (hevc_data) - 0x8;
11496 /* No real data, so break out */
11499 switch (QT_FOURCC (hevc_data + 0x4)) {
11502 /* parse, if found */
11505 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11507 /* First 4 bytes are the length of the atom, the next 4 bytes
11508 * are the fourcc, the next 1 byte is the version, and the
11509 * subsequent bytes are sequence parameter set like data. */
11510 gst_codec_utils_h265_caps_set_level_tier_and_profile
11511 (entry->caps, hevc_data + 8 + 1, size - 1);
11513 buf = gst_buffer_new_and_alloc (size);
11514 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11515 gst_caps_set_simple (entry->caps,
11516 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11517 gst_buffer_unref (buf);
11524 hevc_data += size + 8;
11537 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11538 GST_FOURCC_ARGS (fourcc));
11540 /* codec data might be in glbl extension atom */
11542 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11548 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11550 len = QT_UINT32 (data);
11553 buf = gst_buffer_new_and_alloc (len);
11554 gst_buffer_fill (buf, 0, data + 8, len);
11555 gst_caps_set_simple (entry->caps,
11556 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11557 gst_buffer_unref (buf);
11564 /* see annex I of the jpeg2000 spec */
11565 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11566 const guint8 *data;
11567 const gchar *colorspace = NULL;
11569 guint32 ncomp_map = 0;
11570 gint32 *comp_map = NULL;
11571 guint32 nchan_def = 0;
11572 gint32 *chan_def = NULL;
11574 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11575 /* some required atoms */
11576 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11579 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11583 /* number of components; redundant with info in codestream, but useful
11585 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11586 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11588 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11590 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11593 GST_DEBUG_OBJECT (qtdemux, "found colr");
11594 /* extract colour space info */
11595 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11596 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11598 colorspace = "sRGB";
11601 colorspace = "GRAY";
11604 colorspace = "sYUV";
11612 /* colr is required, and only values 16, 17, and 18 are specified,
11613 so error if we have no colorspace */
11616 /* extract component mapping */
11617 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11619 guint32 cmap_len = 0;
11621 cmap_len = QT_UINT32 (cmap->data);
11622 if (cmap_len >= 8) {
11623 /* normal box, subtract off header */
11625 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11626 if (cmap_len % 4 == 0) {
11627 ncomp_map = (cmap_len / 4);
11628 comp_map = g_new0 (gint32, ncomp_map);
11629 for (i = 0; i < ncomp_map; i++) {
11632 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11633 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11634 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11635 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11640 /* extract channel definitions */
11641 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11643 guint32 cdef_len = 0;
11645 cdef_len = QT_UINT32 (cdef->data);
11646 if (cdef_len >= 10) {
11647 /* normal box, subtract off header and len */
11649 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11650 if (cdef_len % 6 == 0) {
11651 nchan_def = (cdef_len / 6);
11652 chan_def = g_new0 (gint32, nchan_def);
11653 for (i = 0; i < nchan_def; i++)
11655 for (i = 0; i < nchan_def; i++) {
11656 guint16 cn, typ, asoc;
11657 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11658 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11659 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11660 if (cn < nchan_def) {
11663 chan_def[cn] = asoc;
11666 chan_def[cn] = 0; /* alpha */
11669 chan_def[cn] = -typ;
11677 gst_caps_set_simple (entry->caps,
11678 "num-components", G_TYPE_INT, ncomp, NULL);
11679 gst_caps_set_simple (entry->caps,
11680 "colorspace", G_TYPE_STRING, colorspace, NULL);
11683 GValue arr = { 0, };
11684 GValue elt = { 0, };
11686 g_value_init (&arr, GST_TYPE_ARRAY);
11687 g_value_init (&elt, G_TYPE_INT);
11688 for (i = 0; i < ncomp_map; i++) {
11689 g_value_set_int (&elt, comp_map[i]);
11690 gst_value_array_append_value (&arr, &elt);
11692 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11693 "component-map", &arr);
11694 g_value_unset (&elt);
11695 g_value_unset (&arr);
11700 GValue arr = { 0, };
11701 GValue elt = { 0, };
11703 g_value_init (&arr, GST_TYPE_ARRAY);
11704 g_value_init (&elt, G_TYPE_INT);
11705 for (i = 0; i < nchan_def; i++) {
11706 g_value_set_int (&elt, chan_def[i]);
11707 gst_value_array_append_value (&arr, &elt);
11709 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11710 "channel-definitions", &arr);
11711 g_value_unset (&elt);
11712 g_value_unset (&arr);
11716 /* some optional atoms */
11717 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11718 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11720 /* indicate possible fields in caps */
11722 data = (guint8 *) field->data + 8;
11724 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11725 (gint) * data, NULL);
11727 /* add codec_data if provided */
11732 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11733 data = prefix->data;
11734 len = QT_UINT32 (data);
11737 buf = gst_buffer_new_and_alloc (len);
11738 gst_buffer_fill (buf, 0, data + 8, len);
11739 gst_caps_set_simple (entry->caps,
11740 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11741 gst_buffer_unref (buf);
11750 GstBuffer *seqh = NULL;
11751 const guint8 *gamma_data = NULL;
11752 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11754 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11757 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11758 QT_FP32 (gamma_data), NULL);
11761 /* sorry for the bad name, but we don't know what this is, other
11762 * than its own fourcc */
11763 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11765 gst_buffer_unref (seqh);
11768 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11769 buf = gst_buffer_new_and_alloc (len);
11770 gst_buffer_fill (buf, 0, stsd_data, len);
11771 gst_caps_set_simple (entry->caps,
11772 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11773 gst_buffer_unref (buf);
11778 /* https://developer.apple.com/standards/qtff-2001.pdf,
11779 * page 92, "Video Sample Description", under table 3.1 */
11782 const gint compressor_offset =
11783 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11784 const gint min_size = compressor_offset + 32 + 2 + 2;
11787 guint16 color_table_id = 0;
11790 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11792 /* recover information on interlaced/progressive */
11793 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11797 len = QT_UINT32 (jpeg->data);
11798 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11800 if (len >= min_size) {
11801 gst_byte_reader_init (&br, jpeg->data, len);
11803 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11804 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11805 if (color_table_id != 0) {
11806 /* the spec says there can be concatenated chunks in the data, and we want
11807 * to find one called field. Walk through them. */
11808 gint offset = min_size;
11809 while (offset + 8 < len) {
11810 guint32 size = 0, tag;
11811 ok = gst_byte_reader_get_uint32_le (&br, &size);
11812 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11813 if (!ok || size < 8) {
11814 GST_WARNING_OBJECT (qtdemux,
11815 "Failed to walk optional chunk list");
11818 GST_DEBUG_OBJECT (qtdemux,
11819 "Found optional %4.4s chunk, size %u",
11820 (const char *) &tag, size);
11821 if (tag == FOURCC_fiel) {
11822 guint8 n_fields = 0, ordering = 0;
11823 gst_byte_reader_get_uint8 (&br, &n_fields);
11824 gst_byte_reader_get_uint8 (&br, &ordering);
11825 if (n_fields == 1 || n_fields == 2) {
11826 GST_DEBUG_OBJECT (qtdemux,
11827 "Found fiel tag with %u fields, ordering %u",
11828 n_fields, ordering);
11830 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11831 "interlace-mode", G_TYPE_STRING, "interleaved",
11834 GST_WARNING_OBJECT (qtdemux,
11835 "Found fiel tag with invalid fields (%u)", n_fields);
11841 GST_DEBUG_OBJECT (qtdemux,
11842 "Color table ID is 0, not trying to get interlacedness");
11845 GST_WARNING_OBJECT (qtdemux,
11846 "Length of jpeg chunk is too small, not trying to get interlacedness");
11854 gst_caps_set_simple (entry->caps,
11855 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11861 GNode *xith, *xdxt;
11863 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11864 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11868 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11872 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11873 /* collect the headers and store them in a stream list so that we can
11874 * send them out first */
11875 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11885 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11886 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11889 ovc1_data = ovc1->data;
11890 ovc1_len = QT_UINT32 (ovc1_data);
11891 if (ovc1_len <= 198) {
11892 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11895 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11896 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11897 gst_caps_set_simple (entry->caps,
11898 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11899 gst_buffer_unref (buf);
11904 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11905 const guint8 *vc1_data = stsd_entry_data + 0x56;
11911 if (QT_UINT32 (vc1_data) <= len)
11912 size = QT_UINT32 (vc1_data) - 8;
11917 /* No real data, so break out */
11920 switch (QT_FOURCC (vc1_data + 0x4)) {
11921 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11925 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11926 buf = gst_buffer_new_and_alloc (size);
11927 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11928 gst_caps_set_simple (entry->caps,
11929 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11930 gst_buffer_unref (buf);
11937 vc1_data += size + 8;
11943 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11944 const guint8 *av1_data = stsd_entry_data + 0x56;
11947 while (len >= 0x8) {
11950 if (QT_UINT32 (av1_data) <= len)
11951 size = QT_UINT32 (av1_data) - 0x8;
11956 /* No real data, so break out */
11959 switch (QT_FOURCC (av1_data + 0x4)) {
11962 /* parse, if found */
11964 guint8 pres_delay_field;
11966 GST_DEBUG_OBJECT (qtdemux,
11967 "found av1C codec_data in stsd of size %d", size);
11969 /* not enough data, just ignore and hope for the best */
11974 * 4 bytes: atom length
11979 * 1 bits: initial_presentation_delay_present
11980 * 4 bits: initial_presentation_delay (if present else reserved
11984 if (av1_data[9] != 0) {
11985 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11989 /* We skip initial_presentation_delay* for now */
11990 pres_delay_field = *(av1_data + 12);
11991 if (pres_delay_field & (1 << 5)) {
11992 gst_caps_set_simple (entry->caps,
11993 "presentation-delay", G_TYPE_INT,
11994 (gint) (pres_delay_field & 0x0F) + 1, NULL);
11997 buf = gst_buffer_new_and_alloc (size - 5);
11998 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11999 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12000 gst_caps_set_simple (entry->caps,
12001 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12002 gst_buffer_unref (buf);
12011 av1_data += size + 8;
12017 /* TODO: Need to parse vpcC for VP8 codec too.
12018 * Note that VPCodecConfigurationBox (vpcC) is defined for
12019 * vp08, vp09, and vp10 fourcc. */
12022 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12023 const guint8 *vpcc_data = stsd_entry_data + 0x56;
12026 while (len >= 0x8) {
12029 if (QT_UINT32 (vpcc_data) <= len)
12030 size = QT_UINT32 (vpcc_data) - 0x8;
12035 /* No real data, so break out */
12038 switch (QT_FOURCC (vpcc_data + 0x4)) {
12041 const gchar *profile_str = NULL;
12042 const gchar *chroma_format_str = NULL;
12045 guint8 chroma_format;
12046 GstVideoColorimetry cinfo;
12048 /* parse, if found */
12049 GST_DEBUG_OBJECT (qtdemux,
12050 "found vp codec_data in stsd of size %d", size);
12052 /* the meaning of "size" is length of the atom body, excluding
12053 * atom length and fourcc fields */
12058 * 4 bytes: atom length
12065 * 3 bits: chromaSubsampling
12066 * 1 bit: videoFullRangeFlag
12067 * 1 byte: colourPrimaries
12068 * 1 byte: transferCharacteristics
12069 * 1 byte: matrixCoefficients
12070 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
12071 * rest: codecIntializationData (not used for vp8 and vp9)
12074 if (vpcc_data[8] != 1) {
12075 GST_WARNING_OBJECT (qtdemux,
12076 "unknown vpcC version %d", vpcc_data[8]);
12080 profile = vpcc_data[12];
12099 gst_caps_set_simple (entry->caps,
12100 "profile", G_TYPE_STRING, profile_str, NULL);
12103 /* skip level, the VP9 spec v0.6 defines only one level atm,
12104 * but webm spec define various ones. Add level to caps
12105 * if we really need it then */
12107 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12108 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12109 gst_caps_set_simple (entry->caps,
12110 "bit-depth-luma", G_TYPE_UINT, bitdepth,
12111 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12114 chroma_format = (vpcc_data[14] & 0xe) >> 1;
12115 switch (chroma_format) {
12118 chroma_format_str = "4:2:0";
12121 chroma_format_str = "4:2:2";
12124 chroma_format_str = "4:4:4";
12130 if (chroma_format_str) {
12131 gst_caps_set_simple (entry->caps,
12132 "chroma-format", G_TYPE_STRING, chroma_format_str,
12136 if ((vpcc_data[14] & 0x1) != 0)
12137 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12139 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12141 gst_video_color_primaries_from_iso (vpcc_data[15]);
12143 gst_video_transfer_function_from_iso (vpcc_data[16]);
12145 gst_video_color_matrix_from_iso (vpcc_data[17]);
12147 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12148 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12149 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12150 /* set this only if all values are known, otherwise this
12151 * might overwrite valid ones parsed from other color box */
12152 CUR_STREAM (stream)->colorimetry = cinfo;
12161 vpcc_data += size + 8;
12171 GST_INFO_OBJECT (qtdemux,
12172 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12173 GST_FOURCC_ARGS (fourcc), entry->caps);
12175 } else if (stream->subtype == FOURCC_soun) {
12177 int version, samplesize;
12178 guint16 compression_id;
12179 gboolean amrwb = FALSE;
12182 /* sample description entry (16) + sound sample description v0 (20) */
12186 version = QT_UINT32 (stsd_entry_data + offset);
12187 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12188 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12189 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12190 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12192 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12193 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12194 QT_UINT32 (stsd_entry_data + offset + 4));
12195 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12196 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12197 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12198 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12199 QT_UINT16 (stsd_entry_data + offset + 14));
12200 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12202 if (compression_id == 0xfffe)
12203 entry->sampled = TRUE;
12205 /* first assume uncompressed audio */
12206 entry->bytes_per_sample = samplesize / 8;
12207 entry->samples_per_frame = entry->n_channels;
12208 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12209 entry->samples_per_packet = entry->samples_per_frame;
12210 entry->bytes_per_packet = entry->bytes_per_sample;
12214 if (version == 0x00010000) {
12215 /* sample description entry (16) + sound sample description v1 (20+16) */
12219 /* take information from here over the normal sample description */
12220 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12221 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12222 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12223 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12225 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12226 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12227 entry->samples_per_packet);
12228 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12229 entry->bytes_per_packet);
12230 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12231 entry->bytes_per_frame);
12232 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12233 entry->bytes_per_sample);
12235 if (!entry->sampled && entry->bytes_per_packet) {
12236 entry->samples_per_frame = (entry->bytes_per_frame /
12237 entry->bytes_per_packet) * entry->samples_per_packet;
12238 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12239 entry->samples_per_frame);
12241 } else if (version == 0x00020000) {
12242 /* sample description entry (16) + sound sample description v2 (56) */
12246 /* take information from here over the normal sample description */
12247 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12248 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12249 entry->samples_per_frame = entry->n_channels;
12250 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12251 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12252 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12253 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12255 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12256 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12257 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12258 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12259 entry->bytes_per_sample * 8);
12260 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12261 QT_UINT32 (stsd_entry_data + offset + 24));
12262 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12263 entry->bytes_per_packet);
12264 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12265 entry->samples_per_packet);
12266 } else if (version != 0x00000) {
12267 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12272 /* Yes, these have to be hard-coded */
12275 entry->samples_per_packet = 6;
12276 entry->bytes_per_packet = 1;
12277 entry->bytes_per_frame = 1 * entry->n_channels;
12278 entry->bytes_per_sample = 1;
12279 entry->samples_per_frame = 6 * entry->n_channels;
12284 entry->samples_per_packet = 3;
12285 entry->bytes_per_packet = 1;
12286 entry->bytes_per_frame = 1 * entry->n_channels;
12287 entry->bytes_per_sample = 1;
12288 entry->samples_per_frame = 3 * entry->n_channels;
12293 entry->samples_per_packet = 64;
12294 entry->bytes_per_packet = 34;
12295 entry->bytes_per_frame = 34 * entry->n_channels;
12296 entry->bytes_per_sample = 2;
12297 entry->samples_per_frame = 64 * entry->n_channels;
12303 entry->samples_per_packet = 1;
12304 entry->bytes_per_packet = 1;
12305 entry->bytes_per_frame = 1 * entry->n_channels;
12306 entry->bytes_per_sample = 1;
12307 entry->samples_per_frame = 1 * entry->n_channels;
12312 entry->samples_per_packet = 160;
12313 entry->bytes_per_packet = 33;
12314 entry->bytes_per_frame = 33 * entry->n_channels;
12315 entry->bytes_per_sample = 2;
12316 entry->samples_per_frame = 160 * entry->n_channels;
12319 /* fix up any invalid header information from above */
12324 /* Sometimes these are set to 0 in the sound sample descriptions so
12325 * let's try to infer useful values from the other information we
12326 * have available */
12327 if (entry->bytes_per_sample == 0)
12328 entry->bytes_per_sample =
12329 entry->bytes_per_frame / entry->n_channels;
12330 if (entry->bytes_per_sample == 0)
12331 entry->bytes_per_sample = samplesize / 8;
12333 if (entry->bytes_per_frame == 0)
12334 entry->bytes_per_frame =
12335 entry->bytes_per_sample * entry->n_channels;
12337 if (entry->bytes_per_packet == 0)
12338 entry->bytes_per_packet = entry->bytes_per_sample;
12340 if (entry->samples_per_frame == 0)
12341 entry->samples_per_frame = entry->n_channels;
12343 if (entry->samples_per_packet == 0)
12344 entry->samples_per_packet = entry->samples_per_frame;
12354 entry->bytes_per_sample = 3;
12358 entry->bytes_per_sample = 4;
12361 entry->bytes_per_sample = 8;
12364 entry->bytes_per_sample = 2;
12367 g_assert_not_reached ();
12370 entry->samples_per_frame = entry->n_channels;
12371 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12372 entry->samples_per_packet = entry->samples_per_frame;
12373 entry->bytes_per_packet = entry->bytes_per_sample;
12381 gst_caps_unref (entry->caps);
12383 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12384 stsd_entry_data + 32, len - 16, &codec);
12395 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12397 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12399 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12401 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12404 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12405 const gchar *format_str;
12409 format_str = (enda_value) ? "S24LE" : "S24BE";
12412 format_str = (enda_value) ? "S32LE" : "S32BE";
12415 format_str = (enda_value) ? "F32LE" : "F32BE";
12418 format_str = (enda_value) ? "F64LE" : "F64BE";
12421 g_assert_not_reached ();
12424 gst_caps_set_simple (entry->caps,
12425 "format", G_TYPE_STRING, format_str, NULL);
12431 const guint8 *owma_data;
12432 const gchar *codec_name = NULL;
12436 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12437 /* FIXME this should also be gst_riff_strf_auds,
12438 * but the latter one is actually missing bits-per-sample :( */
12443 gint32 nSamplesPerSec;
12444 gint32 nAvgBytesPerSec;
12445 gint16 nBlockAlign;
12446 gint16 wBitsPerSample;
12449 WAVEFORMATEX *wfex;
12451 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12452 owma_data = stsd_entry_data;
12453 owma_len = QT_UINT32 (owma_data);
12454 if (owma_len <= 54) {
12455 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12458 wfex = (WAVEFORMATEX *) (owma_data + 36);
12459 buf = gst_buffer_new_and_alloc (owma_len - 54);
12460 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12461 if (wfex->wFormatTag == 0x0161) {
12462 codec_name = "Windows Media Audio";
12464 } else if (wfex->wFormatTag == 0x0162) {
12465 codec_name = "Windows Media Audio 9 Pro";
12467 } else if (wfex->wFormatTag == 0x0163) {
12468 codec_name = "Windows Media Audio 9 Lossless";
12469 /* is that correct? gstffmpegcodecmap.c is missing it, but
12470 * fluendo codec seems to support it */
12474 gst_caps_set_simple (entry->caps,
12475 "codec_data", GST_TYPE_BUFFER, buf,
12476 "wmaversion", G_TYPE_INT, version,
12477 "block_align", G_TYPE_INT,
12478 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12479 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12480 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12481 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12482 gst_buffer_unref (buf);
12486 codec = g_strdup (codec_name);
12492 gint len = QT_UINT32 (stsd_entry_data) - offset;
12493 const guint8 *wfex_data = stsd_entry_data + offset;
12494 const gchar *codec_name = NULL;
12496 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12497 /* FIXME this should also be gst_riff_strf_auds,
12498 * but the latter one is actually missing bits-per-sample :( */
12503 gint32 nSamplesPerSec;
12504 gint32 nAvgBytesPerSec;
12505 gint16 nBlockAlign;
12506 gint16 wBitsPerSample;
12511 /* FIXME: unify with similar wavformatex parsing code above */
12512 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12518 if (QT_UINT32 (wfex_data) <= len)
12519 size = QT_UINT32 (wfex_data) - 8;
12524 /* No real data, so break out */
12527 switch (QT_FOURCC (wfex_data + 4)) {
12528 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12530 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12535 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12536 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12537 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12538 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12539 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12540 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12541 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12543 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12544 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12545 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12546 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12547 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12548 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12550 if (wfex.wFormatTag == 0x0161) {
12551 codec_name = "Windows Media Audio";
12553 } else if (wfex.wFormatTag == 0x0162) {
12554 codec_name = "Windows Media Audio 9 Pro";
12556 } else if (wfex.wFormatTag == 0x0163) {
12557 codec_name = "Windows Media Audio 9 Lossless";
12558 /* is that correct? gstffmpegcodecmap.c is missing it, but
12559 * fluendo codec seems to support it */
12563 gst_caps_set_simple (entry->caps,
12564 "wmaversion", G_TYPE_INT, version,
12565 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12566 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12567 "width", G_TYPE_INT, wfex.wBitsPerSample,
12568 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12570 if (size > wfex.cbSize) {
12573 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12574 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12575 size - wfex.cbSize);
12576 gst_caps_set_simple (entry->caps,
12577 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12578 gst_buffer_unref (buf);
12580 GST_WARNING_OBJECT (qtdemux, "no codec data");
12585 codec = g_strdup (codec_name);
12593 wfex_data += size + 8;
12599 const guint8 *dops_data;
12600 guint8 *channel_mapping = NULL;
12603 guint8 channel_mapping_family;
12604 guint8 stream_count;
12605 guint8 coupled_count;
12608 version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12610 dops_data = stsd_entry_data + 51;
12612 dops_data = stsd_entry_data + 35;
12614 channels = GST_READ_UINT8 (dops_data + 10);
12615 rate = GST_READ_UINT32_LE (dops_data + 13);
12616 channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12617 stream_count = GST_READ_UINT8 (dops_data + 20);
12618 coupled_count = GST_READ_UINT8 (dops_data + 21);
12620 if (channels > 0) {
12621 channel_mapping = g_malloc (channels * sizeof (guint8));
12622 for (i = 0; i < channels; i++)
12623 channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12626 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12627 channel_mapping_family, stream_count, coupled_count,
12629 g_free (channel_mapping);
12640 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12641 GST_TAG_AUDIO_CODEC, codec, NULL);
12645 /* some bitrate info may have ended up in caps */
12646 s = gst_caps_get_structure (entry->caps, 0);
12647 gst_structure_get_int (s, "bitrate", &bitrate);
12649 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12650 GST_TAG_BITRATE, bitrate, NULL);
12654 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12655 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12656 if (stream->protected) {
12657 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12658 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12660 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12670 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12672 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12674 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12678 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12679 16 bits is a byte-swapped wave-style codec identifier,
12680 and we can find a WAVE header internally to a 'wave' atom here.
12681 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12682 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12685 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12686 if (len < offset + 20) {
12687 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12689 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12690 const guint8 *data = stsd_entry_data + offset + 16;
12692 GNode *waveheadernode;
12694 wavenode = g_node_new ((guint8 *) data);
12695 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12696 const guint8 *waveheader;
12699 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12700 if (waveheadernode) {
12701 waveheader = (const guint8 *) waveheadernode->data;
12702 headerlen = QT_UINT32 (waveheader);
12704 if (headerlen > 8) {
12705 gst_riff_strf_auds *header = NULL;
12706 GstBuffer *headerbuf;
12712 headerbuf = gst_buffer_new_and_alloc (headerlen);
12713 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12715 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12716 headerbuf, &header, &extra)) {
12717 gst_caps_unref (entry->caps);
12718 /* FIXME: Need to do something with the channel reorder map */
12720 gst_riff_create_audio_caps (header->format, NULL, header,
12721 extra, NULL, NULL, NULL);
12724 gst_buffer_unref (extra);
12729 GST_DEBUG ("Didn't find waveheadernode for this codec");
12731 g_node_destroy (wavenode);
12734 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12735 stream->stream_tags);
12739 /* FIXME: what is in the chunk? */
12742 gint len = QT_UINT32 (stsd_data);
12744 /* seems to be always = 116 = 0x74 */
12750 gint len = QT_UINT32 (stsd_entry_data);
12753 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12755 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12756 gst_caps_set_simple (entry->caps,
12757 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12758 gst_buffer_unref (buf);
12760 gst_caps_set_simple (entry->caps,
12761 "samplesize", G_TYPE_INT, samplesize, NULL);
12766 GNode *alac, *wave = NULL;
12768 /* apparently, m4a has this atom appended directly in the stsd entry,
12769 * while mov has it in a wave atom */
12770 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12772 /* alac now refers to stsd entry atom */
12773 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12775 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12777 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12780 const guint8 *alac_data = alac->data;
12781 gint len = QT_UINT32 (alac->data);
12785 GST_DEBUG_OBJECT (qtdemux,
12786 "discarding alac atom with unexpected len %d", len);
12788 /* codec-data contains alac atom size and prefix,
12789 * ffmpeg likes it that way, not quite gst-ish though ...*/
12790 buf = gst_buffer_new_and_alloc (len);
12791 gst_buffer_fill (buf, 0, alac->data, len);
12792 gst_caps_set_simple (entry->caps,
12793 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12794 gst_buffer_unref (buf);
12796 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12797 entry->n_channels = QT_UINT8 (alac_data + 21);
12798 entry->rate = QT_UINT32 (alac_data + 32);
12799 samplesize = QT_UINT8 (alac_data + 16 + 1);
12802 gst_caps_set_simple (entry->caps,
12803 "samplesize", G_TYPE_INT, samplesize, NULL);
12808 /* The codingname of the sample entry is 'fLaC' */
12809 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12812 /* The 'dfLa' box is added to the sample entry to convey
12813 initializing information for the decoder. */
12814 const GNode *dfla =
12815 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12818 const guint32 len = QT_UINT32 (dfla->data);
12820 /* Must contain at least dfLa box header (12),
12821 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12823 GST_DEBUG_OBJECT (qtdemux,
12824 "discarding dfla atom with unexpected len %d", len);
12826 /* skip dfLa header to get the METADATA_BLOCKs */
12827 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12828 const guint32 metadata_blocks_len = len - 12;
12830 gchar *stream_marker = g_strdup ("fLaC");
12831 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12832 strlen (stream_marker));
12835 guint32 remainder = 0;
12836 guint32 block_size = 0;
12837 gboolean is_last = FALSE;
12839 GValue array = G_VALUE_INIT;
12840 GValue value = G_VALUE_INIT;
12842 g_value_init (&array, GST_TYPE_ARRAY);
12843 g_value_init (&value, GST_TYPE_BUFFER);
12845 gst_value_set_buffer (&value, block);
12846 gst_value_array_append_value (&array, &value);
12847 g_value_reset (&value);
12849 gst_buffer_unref (block);
12851 /* check there's at least one METADATA_BLOCK_HEADER's worth
12852 * of data, and we haven't already finished parsing */
12853 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12854 remainder = metadata_blocks_len - index;
12856 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12858 (metadata_blocks[index + 1] << 16) +
12859 (metadata_blocks[index + 2] << 8) +
12860 metadata_blocks[index + 3];
12862 /* be careful not to read off end of box */
12863 if (block_size > remainder) {
12867 is_last = metadata_blocks[index] >> 7;
12869 block = gst_buffer_new_and_alloc (block_size);
12871 gst_buffer_fill (block, 0, &metadata_blocks[index],
12874 gst_value_set_buffer (&value, block);
12875 gst_value_array_append_value (&array, &value);
12876 g_value_reset (&value);
12878 gst_buffer_unref (block);
12880 index += block_size;
12883 /* only append the metadata if we successfully read all of it */
12885 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12886 (stream)->caps, 0), "streamheader", &array);
12888 GST_WARNING_OBJECT (qtdemux,
12889 "discarding all METADATA_BLOCKs due to invalid "
12890 "block_size %d at idx %d, rem %d", block_size, index,
12894 g_value_unset (&value);
12895 g_value_unset (&array);
12897 /* The sample rate obtained from the stsd may not be accurate
12898 * since it cannot represent rates greater than 65535Hz, so
12899 * override that value with the sample rate from the
12900 * METADATA_BLOCK_STREAMINFO block */
12901 CUR_STREAM (stream)->rate =
12902 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12913 gint len = QT_UINT32 (stsd_entry_data);
12916 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12919 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12921 /* If we have enough data, let's try to get the 'damr' atom. See
12922 * the 3GPP container spec (26.244) for more details. */
12923 if ((len - 0x34) > 8 &&
12924 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12925 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12926 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12929 gst_caps_set_simple (entry->caps,
12930 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12931 gst_buffer_unref (buf);
12937 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12938 gint len = QT_UINT32 (stsd_entry_data);
12939 guint16 sound_version = 0;
12940 /* FIXME: Can this be determined somehow? There doesn't seem to be
12941 * anything in mp4a atom that specifis compression */
12943 guint16 channels = entry->n_channels;
12944 guint32 time_scale = (guint32) entry->rate;
12945 gint sample_rate_index = -1;
12948 sound_version = QT_UINT16 (stsd_entry_data + 16);
12950 if (sound_version == 1) {
12951 channels = QT_UINT16 (stsd_entry_data + 24);
12952 time_scale = QT_UINT32 (stsd_entry_data + 30);
12954 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
12958 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
12962 sample_rate_index =
12963 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12964 if (sample_rate_index >= 0 && channels > 0) {
12965 guint8 codec_data[2];
12968 /* build AAC codec data */
12969 codec_data[0] = profile << 3;
12970 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12971 codec_data[1] = (sample_rate_index & 0x01) << 7;
12972 codec_data[1] |= (channels & 0xF) << 3;
12974 buf = gst_buffer_new_and_alloc (2);
12975 gst_buffer_fill (buf, 0, codec_data, 2);
12976 gst_caps_set_simple (entry->caps,
12977 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12978 gst_buffer_unref (buf);
12988 /* Fully handled elsewhere */
12991 GST_INFO_OBJECT (qtdemux,
12992 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12996 GST_INFO_OBJECT (qtdemux,
12997 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12998 GST_FOURCC_ARGS (fourcc), entry->caps);
13000 } else if (stream->subtype == FOURCC_strm) {
13001 if (fourcc == FOURCC_rtsp) {
13002 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
13004 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
13005 GST_FOURCC_ARGS (fourcc));
13006 goto unknown_stream;
13008 entry->sampled = TRUE;
13009 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
13010 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
13011 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
13013 entry->sampled = TRUE;
13014 entry->sparse = TRUE;
13017 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13020 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13021 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13026 /* hunt for sort-of codec data */
13030 GNode *mp4s = NULL;
13031 GNode *esds = NULL;
13033 /* look for palette in a stsd->mp4s->esds sub-atom */
13034 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
13036 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
13037 if (esds == NULL) {
13039 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13043 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13044 stream->stream_tags);
13048 GST_INFO_OBJECT (qtdemux,
13049 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13052 GST_INFO_OBJECT (qtdemux,
13053 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13054 GST_FOURCC_ARGS (fourcc), entry->caps);
13056 /* everything in 1 sample */
13057 entry->sampled = TRUE;
13060 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13063 if (entry->caps == NULL)
13064 goto unknown_stream;
13067 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13068 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13074 /* promote to sampled format */
13075 if (entry->fourcc == FOURCC_samr) {
13076 /* force mono 8000 Hz for AMR */
13077 entry->sampled = TRUE;
13078 entry->n_channels = 1;
13079 entry->rate = 8000;
13080 } else if (entry->fourcc == FOURCC_sawb) {
13081 /* force mono 16000 Hz for AMR-WB */
13082 entry->sampled = TRUE;
13083 entry->n_channels = 1;
13084 entry->rate = 16000;
13085 } else if (entry->fourcc == FOURCC_mp4a) {
13086 entry->sampled = TRUE;
13090 stsd_entry_data += len;
13091 remaining_stsd_len -= len;
13095 /* collect sample information */
13096 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13097 goto samples_failed;
13099 if (qtdemux->fragmented) {
13102 /* need all moov samples as basis; probably not many if any at all */
13103 /* prevent moof parsing taking of at this time */
13104 offset = qtdemux->moof_offset;
13105 qtdemux->moof_offset = 0;
13106 if (stream->n_samples &&
13107 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13108 qtdemux->moof_offset = offset;
13109 goto samples_failed;
13111 qtdemux->moof_offset = offset;
13112 /* movie duration more reliable in this case (e.g. mehd) */
13113 if (qtdemux->segment.duration &&
13114 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13116 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13119 /* configure segments */
13120 if (!qtdemux_parse_segments (qtdemux, stream, trak))
13121 goto segments_failed;
13123 /* add some language tag, if useful */
13124 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13125 strcmp (stream->lang_id, "und")) {
13126 const gchar *lang_code;
13128 /* convert ISO 639-2 code to ISO 639-1 */
13129 lang_code = gst_tag_get_language_code (stream->lang_id);
13130 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13131 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13134 /* Check for UDTA tags */
13135 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13136 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13139 /* Insert and sort new stream in track-id order.
13140 * This will help in comparing old/new streams during stream update check */
13141 g_ptr_array_add (qtdemux->active_streams, stream);
13142 g_ptr_array_sort (qtdemux->active_streams,
13143 (GCompareFunc) qtdemux_track_id_compare_func);
13144 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13145 QTDEMUX_N_STREAMS (qtdemux));
13152 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13153 (_("This file is corrupt and cannot be played.")), (NULL));
13155 gst_qtdemux_stream_unref (stream);
13160 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13161 gst_qtdemux_stream_unref (stream);
13167 /* we posted an error already */
13168 /* free stbl sub-atoms */
13169 gst_qtdemux_stbl_free (stream);
13170 gst_qtdemux_stream_unref (stream);
13175 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13181 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13182 GST_FOURCC_ARGS (stream->subtype));
13183 gst_qtdemux_stream_unref (stream);
13188 /* If we can estimate the overall bitrate, and don't have information about the
13189 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13190 * the overall bitrate minus the sum of the bitrates of all other streams. This
13191 * should be useful for the common case where we have one audio and one video
13192 * stream and can estimate the bitrate of one, but not the other. */
13194 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13196 QtDemuxStream *stream = NULL;
13197 gint64 size, sys_bitrate, sum_bitrate = 0;
13198 GstClockTime duration;
13202 if (qtdemux->fragmented)
13205 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13207 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13209 GST_DEBUG_OBJECT (qtdemux,
13210 "Size in bytes of the stream not known - bailing");
13214 /* Subtract the header size */
13215 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13216 size, qtdemux->header_size);
13218 if (size < qtdemux->header_size)
13221 size = size - qtdemux->header_size;
13223 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13224 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13228 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13229 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13230 switch (str->subtype) {
13233 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13234 CUR_STREAM (str)->caps);
13235 /* retrieve bitrate, prefer avg then max */
13237 if (str->stream_tags) {
13238 if (gst_tag_list_get_uint (str->stream_tags,
13239 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13240 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13241 if (gst_tag_list_get_uint (str->stream_tags,
13242 GST_TAG_NOMINAL_BITRATE, &bitrate))
13243 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13244 if (gst_tag_list_get_uint (str->stream_tags,
13245 GST_TAG_BITRATE, &bitrate))
13246 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13249 sum_bitrate += bitrate;
13252 GST_DEBUG_OBJECT (qtdemux,
13253 ">1 stream with unknown bitrate - bailing");
13260 /* For other subtypes, we assume no significant impact on bitrate */
13266 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13270 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13272 if (sys_bitrate < sum_bitrate) {
13273 /* This can happen, since sum_bitrate might be derived from maximum
13274 * bitrates and not average bitrates */
13275 GST_DEBUG_OBJECT (qtdemux,
13276 "System bitrate less than sum bitrate - bailing");
13280 bitrate = sys_bitrate - sum_bitrate;
13281 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13282 ", Stream bitrate = %u", sys_bitrate, bitrate);
13284 if (!stream->stream_tags)
13285 stream->stream_tags = gst_tag_list_new_empty ();
13287 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13289 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13290 GST_TAG_BITRATE, bitrate, NULL);
13293 static GstFlowReturn
13294 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13296 GstFlowReturn ret = GST_FLOW_OK;
13299 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13301 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13302 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13303 guint32 sample_num = 0;
13305 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13306 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13308 if (qtdemux->fragmented && qtdemux->pullbased) {
13309 /* need all moov samples first */
13310 GST_OBJECT_LOCK (qtdemux);
13311 while (stream->n_samples == 0)
13312 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13314 GST_OBJECT_UNLOCK (qtdemux);
13316 /* discard any stray moof */
13317 qtdemux->moof_offset = 0;
13320 /* prepare braking */
13321 if (ret != GST_FLOW_ERROR)
13324 /* in pull mode, we should have parsed some sample info by now;
13325 * and quite some code will not handle no samples.
13326 * in push mode, we'll just have to deal with it */
13327 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13328 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13329 g_ptr_array_remove_index (qtdemux->active_streams, i);
13332 } else if (stream->track_id == qtdemux->chapters_track_id &&
13333 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13334 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13335 so that it doesn't look like a subtitle track */
13336 g_ptr_array_remove_index (qtdemux->active_streams, i);
13341 /* parse the initial sample for use in setting the frame rate cap */
13342 while (sample_num == 0 && sample_num < stream->n_samples) {
13343 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13353 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13355 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13359 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13363 /* Different length, updated */
13364 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13367 /* streams in list are sorted in track-id order */
13368 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13369 /* Different stream-id, updated */
13370 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13371 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13379 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13380 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13382 /* Connect old stream's srcpad to new stream */
13383 newstream->pad = oldstream->pad;
13384 oldstream->pad = NULL;
13386 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13387 * case we need to force one through */
13388 newstream->new_stream = GST_PAD_IS_EOS (newstream->pad);
13390 return gst_qtdemux_configure_stream (qtdemux, newstream);
13394 qtdemux_update_streams (GstQTDemux * qtdemux)
13397 g_assert (qtdemux->streams_aware);
13399 /* At below, figure out which stream in active_streams has identical stream-id
13400 * with that of in old_streams. If there is matching stream-id,
13401 * corresponding newstream will not be exposed again,
13402 * but demux will reuse srcpad of matched old stream
13404 * active_streams : newly created streams from the latest moov
13405 * old_streams : existing streams (belong to previous moov)
13408 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13409 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13410 QtDemuxStream *oldstream = NULL;
13413 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13414 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13416 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13417 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13418 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13420 /* null pad stream cannot be reused */
13421 if (oldstream->pad == NULL)
13426 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13428 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13431 /* we don't need to preserve order of old streams */
13432 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13436 /* now we have all info and can expose */
13437 list = stream->stream_tags;
13438 stream->stream_tags = NULL;
13439 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13447 /* Must be called with expose lock */
13448 static GstFlowReturn
13449 qtdemux_expose_streams (GstQTDemux * qtdemux)
13453 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13455 if (!qtdemux_is_streams_update (qtdemux)) {
13456 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13457 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13458 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13459 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13460 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13461 return GST_FLOW_ERROR;
13464 g_ptr_array_set_size (qtdemux->old_streams, 0);
13465 qtdemux->need_segment = TRUE;
13467 return GST_FLOW_OK;
13470 if (qtdemux->streams_aware) {
13471 if (!qtdemux_update_streams (qtdemux))
13472 return GST_FLOW_ERROR;
13474 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13475 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13478 /* now we have all info and can expose */
13479 list = stream->stream_tags;
13480 stream->stream_tags = NULL;
13481 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13482 return GST_FLOW_ERROR;
13487 gst_qtdemux_guess_bitrate (qtdemux);
13489 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13491 /* If we have still old_streams, it's no more used stream */
13492 for (i = 0; i < qtdemux->old_streams->len; i++) {
13493 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13498 event = gst_event_new_eos ();
13499 if (qtdemux->segment_seqnum)
13500 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13502 gst_pad_push_event (stream->pad, event);
13506 g_ptr_array_set_size (qtdemux->old_streams, 0);
13508 /* check if we should post a redirect in case there is a single trak
13509 * and it is a redirecting trak */
13510 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13511 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13514 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13515 "an external content");
13516 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13517 gst_structure_new ("redirect",
13518 "new-location", G_TYPE_STRING,
13519 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13520 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13521 g_free (qtdemux->redirect_location);
13522 qtdemux->redirect_location =
13523 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13526 g_ptr_array_foreach (qtdemux->active_streams,
13527 (GFunc) qtdemux_do_allocation, qtdemux);
13529 qtdemux->need_segment = TRUE;
13531 qtdemux->exposed = TRUE;
13532 return GST_FLOW_OK;
13537 GstStructure *structure; /* helper for sort function */
13539 guint min_req_bitrate;
13540 guint min_req_qt_version;
13544 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13546 GstQtReference *ref_a = (GstQtReference *) a;
13547 GstQtReference *ref_b = (GstQtReference *) b;
13549 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13550 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13552 /* known bitrates go before unknown; higher bitrates go first */
13553 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13556 /* sort the redirects and post a message for the application.
13559 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13561 GstQtReference *best;
13564 GValue list_val = { 0, };
13567 g_assert (references != NULL);
13569 references = g_list_sort (references, qtdemux_redirects_sort_func);
13571 best = (GstQtReference *) references->data;
13573 g_value_init (&list_val, GST_TYPE_LIST);
13575 for (l = references; l != NULL; l = l->next) {
13576 GstQtReference *ref = (GstQtReference *) l->data;
13577 GValue struct_val = { 0, };
13579 ref->structure = gst_structure_new ("redirect",
13580 "new-location", G_TYPE_STRING, ref->location, NULL);
13582 if (ref->min_req_bitrate > 0) {
13583 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13584 ref->min_req_bitrate, NULL);
13587 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13588 g_value_set_boxed (&struct_val, ref->structure);
13589 gst_value_list_append_value (&list_val, &struct_val);
13590 g_value_unset (&struct_val);
13591 /* don't free anything here yet, since we need best->structure below */
13594 g_assert (best != NULL);
13595 s = gst_structure_copy (best->structure);
13597 if (g_list_length (references) > 1) {
13598 gst_structure_set_value (s, "locations", &list_val);
13601 g_value_unset (&list_val);
13603 for (l = references; l != NULL; l = l->next) {
13604 GstQtReference *ref = (GstQtReference *) l->data;
13606 gst_structure_free (ref->structure);
13607 g_free (ref->location);
13610 g_list_free (references);
13612 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13613 g_free (qtdemux->redirect_location);
13614 qtdemux->redirect_location =
13615 g_strdup (gst_structure_get_string (s, "new-location"));
13616 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13617 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13620 /* look for redirect nodes, collect all redirect information and
13624 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13626 GNode *rmra, *rmda, *rdrf;
13628 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13630 GList *redirects = NULL;
13632 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13634 GstQtReference ref = { NULL, NULL, 0, 0 };
13635 GNode *rmdr, *rmvc;
13637 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13638 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13639 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13640 ref.min_req_bitrate);
13643 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13644 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13645 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13647 #ifndef GST_DISABLE_GST_DEBUG
13648 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13650 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13652 GST_LOG_OBJECT (qtdemux,
13653 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13654 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13655 bitmask, check_type);
13656 if (package == FOURCC_qtim && check_type == 0) {
13657 ref.min_req_qt_version = version;
13661 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13667 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13668 if (ref_len > 20) {
13669 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13670 ref_data = (guint8 *) rdrf->data + 20;
13671 if (ref_type == FOURCC_alis) {
13672 guint record_len, record_version, fn_len;
13674 if (ref_len > 70) {
13675 /* MacOSX alias record, google for alias-layout.txt */
13676 record_len = QT_UINT16 (ref_data + 4);
13677 record_version = QT_UINT16 (ref_data + 4 + 2);
13678 fn_len = QT_UINT8 (ref_data + 50);
13679 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13680 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13683 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13686 } else if (ref_type == FOURCC_url_) {
13687 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13689 GST_DEBUG_OBJECT (qtdemux,
13690 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13691 GST_FOURCC_ARGS (ref_type));
13693 if (ref.location != NULL) {
13694 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13696 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13698 GST_WARNING_OBJECT (qtdemux,
13699 "Failed to extract redirect location from rdrf atom");
13702 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13706 /* look for others */
13707 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13710 if (redirects != NULL) {
13711 qtdemux_process_redirects (qtdemux, redirects);
13717 static GstTagList *
13718 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13722 if (tags == NULL) {
13723 tags = gst_tag_list_new_empty ();
13724 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13727 if (qtdemux->major_brand == FOURCC_mjp2)
13728 fmt = "Motion JPEG 2000";
13729 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13731 else if (qtdemux->major_brand == FOURCC_qt__)
13733 else if (qtdemux->fragmented)
13736 fmt = "ISO MP4/M4A";
13738 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13739 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13741 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13747 /* we have read the complete moov node now.
13748 * This function parses all of the relevant info, creates the traks and
13749 * prepares all data structures for playback
13752 qtdemux_parse_tree (GstQTDemux * qtdemux)
13759 guint64 creation_time;
13760 GstDateTime *datetime = NULL;
13763 /* make sure we have a usable taglist */
13764 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13766 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13767 if (mvhd == NULL) {
13768 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13769 return qtdemux_parse_redirects (qtdemux);
13772 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13773 if (version == 1) {
13774 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13775 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13776 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13777 } else if (version == 0) {
13778 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13779 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13780 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13782 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13786 /* Moving qt creation time (secs since 1904) to unix time */
13787 if (creation_time != 0) {
13788 /* Try to use epoch first as it should be faster and more commonly found */
13789 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13792 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13793 /* some data cleansing sanity */
13794 now_s = g_get_real_time () / G_USEC_PER_SEC;
13795 if (now_s + 24 * 3600 < creation_time) {
13796 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13798 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13801 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13802 GDateTime *dt, *dt_local;
13804 dt = g_date_time_add_seconds (base_dt, creation_time);
13805 dt_local = g_date_time_to_local (dt);
13806 datetime = gst_date_time_new_from_g_date_time (dt_local);
13808 g_date_time_unref (base_dt);
13809 g_date_time_unref (dt);
13813 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13814 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13816 gst_date_time_unref (datetime);
13819 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13820 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13822 /* check for fragmented file and get some (default) data */
13823 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13826 GstByteReader mehd_data;
13828 /* let track parsing or anyone know weird stuff might happen ... */
13829 qtdemux->fragmented = TRUE;
13831 /* compensate for total duration */
13832 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13834 qtdemux_parse_mehd (qtdemux, &mehd_data);
13837 /* Update the movie segment duration, unless it was directly given to us
13838 * by upstream. Otherwise let it as is, as we don't want to mangle the
13839 * duration provided by upstream that may come e.g. from a MPD file. */
13840 if (!qtdemux->upstream_format_is_time) {
13841 GstClockTime duration;
13842 /* set duration in the segment info */
13843 gst_qtdemux_get_duration (qtdemux, &duration);
13844 qtdemux->segment.duration = duration;
13845 /* also do not exceed duration; stop is set that way post seek anyway,
13846 * and segment activation falls back to duration,
13847 * whereas loop only checks stop, so let's align this here as well */
13848 qtdemux->segment.stop = duration;
13851 /* parse all traks */
13852 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13854 qtdemux_parse_trak (qtdemux, trak);
13855 /* iterate all siblings */
13856 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13859 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13862 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13864 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13866 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13869 /* maybe also some tags in meta box */
13870 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13872 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13873 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13875 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13878 /* parse any protection system info */
13879 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13881 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13882 qtdemux_parse_pssh (qtdemux, pssh);
13883 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13886 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13891 /* taken from ffmpeg */
13893 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13905 len = (len << 7) | (c & 0x7f);
13914 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13915 gsize codec_data_size)
13917 GList *list = NULL;
13918 guint8 *p = codec_data;
13919 gint i, offset, num_packets;
13920 guint *length, last;
13922 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13924 if (codec_data == NULL || codec_data_size == 0)
13927 /* start of the stream and vorbis audio or theora video, need to
13928 * send the codec_priv data as first three packets */
13929 num_packets = p[0] + 1;
13930 GST_DEBUG_OBJECT (qtdemux,
13931 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13932 (guint) num_packets, codec_data_size);
13934 /* Let's put some limits, Don't think there even is a xiph codec
13935 * with more than 3-4 headers */
13936 if (G_UNLIKELY (num_packets > 16)) {
13937 GST_WARNING_OBJECT (qtdemux,
13938 "Unlikely number of xiph headers, most likely not valid");
13942 length = g_alloca (num_packets * sizeof (guint));
13946 /* first packets, read length values */
13947 for (i = 0; i < num_packets - 1; i++) {
13949 while (offset < codec_data_size) {
13950 length[i] += p[offset];
13951 if (p[offset++] != 0xff)
13956 if (offset + last > codec_data_size)
13959 /* last packet is the remaining size */
13960 length[i] = codec_data_size - offset - last;
13962 for (i = 0; i < num_packets; i++) {
13965 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
13967 if (offset + length[i] > codec_data_size)
13970 hdr = gst_buffer_new_memdup (p + offset, length[i]);
13971 list = g_list_append (list, hdr);
13973 offset += length[i];
13982 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
13988 /* this can change the codec originally present in @list */
13990 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13991 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13993 int len = QT_UINT32 (esds->data);
13994 guint8 *ptr = esds->data;
13995 guint8 *end = ptr + len;
13997 guint8 *data_ptr = NULL;
13999 guint8 object_type_id = 0;
14000 guint8 stream_type = 0;
14001 const char *codec_name = NULL;
14002 GstCaps *caps = NULL;
14004 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14006 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14008 while (ptr + 1 < end) {
14009 tag = QT_UINT8 (ptr);
14010 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14012 len = read_descr_size (ptr, end, &ptr);
14013 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14015 /* Check the stated amount of data is available for reading */
14016 if (len < 0 || ptr + len > end)
14020 case ES_DESCRIPTOR_TAG:
14021 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14022 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14025 case DECODER_CONFIG_DESC_TAG:{
14026 guint max_bitrate, avg_bitrate;
14028 object_type_id = QT_UINT8 (ptr);
14029 stream_type = QT_UINT8 (ptr + 1) >> 2;
14030 max_bitrate = QT_UINT32 (ptr + 5);
14031 avg_bitrate = QT_UINT32 (ptr + 9);
14032 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14033 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14034 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14035 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14036 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14037 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14038 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14039 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14041 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14042 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14043 avg_bitrate, NULL);
14048 case DECODER_SPECIFIC_INFO_TAG:
14049 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14050 if (object_type_id == 0xe0 && len == 0x40) {
14056 GST_DEBUG_OBJECT (qtdemux,
14057 "Have VOBSUB palette. Creating palette event");
14058 /* move to decConfigDescr data and read palette */
14060 for (i = 0; i < 16; i++) {
14061 clut[i] = QT_UINT32 (data);
14065 s = gst_structure_new ("application/x-gst-dvd", "event",
14066 G_TYPE_STRING, "dvd-spu-clut-change",
14067 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14068 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14069 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14070 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14071 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14072 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14073 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14074 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14077 /* store event and trigger custom processing */
14078 stream->pending_event =
14079 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14081 /* Generic codec_data handler puts it on the caps */
14088 case SL_CONFIG_DESC_TAG:
14089 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14093 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14095 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14101 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14102 * in use, and should also be used to override some other parameters for some
14104 switch (object_type_id) {
14105 case 0x20: /* MPEG-4 */
14106 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14107 * profile_and_level_indication */
14108 if (data_ptr != NULL && data_len >= 5 &&
14109 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14110 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14111 data_ptr + 4, data_len - 4);
14113 break; /* Nothing special needed here */
14114 case 0x21: /* H.264 */
14115 codec_name = "H.264 / AVC";
14116 caps = gst_caps_new_simple ("video/x-h264",
14117 "stream-format", G_TYPE_STRING, "avc",
14118 "alignment", G_TYPE_STRING, "au", NULL);
14120 case 0x40: /* AAC (any) */
14121 case 0x66: /* AAC Main */
14122 case 0x67: /* AAC LC */
14123 case 0x68: /* AAC SSR */
14124 /* Override channels and rate based on the codec_data, as it's often
14126 /* Only do so for basic setup without HE-AAC extension */
14127 if (data_ptr && data_len == 2) {
14128 guint channels, rate;
14130 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14132 entry->n_channels = channels;
14134 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14136 entry->rate = rate;
14139 /* Set level and profile if possible */
14140 if (data_ptr != NULL && data_len >= 2) {
14141 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14142 data_ptr, data_len);
14144 const gchar *profile_str = NULL;
14147 guint8 *codec_data;
14148 gint rate_idx, profile;
14150 /* No codec_data, let's invent something.
14151 * FIXME: This is wrong for SBR! */
14153 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14155 buffer = gst_buffer_new_and_alloc (2);
14156 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14157 codec_data = map.data;
14160 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14163 switch (object_type_id) {
14165 profile_str = "main";
14169 profile_str = "lc";
14173 profile_str = "ssr";
14181 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14183 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14185 gst_buffer_unmap (buffer, &map);
14186 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14187 GST_TYPE_BUFFER, buffer, NULL);
14188 gst_buffer_unref (buffer);
14191 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14192 G_TYPE_STRING, profile_str, NULL);
14196 case 0x60: /* MPEG-2, various profiles */
14202 codec_name = "MPEG-2 video";
14203 caps = gst_caps_new_simple ("video/mpeg",
14204 "mpegversion", G_TYPE_INT, 2,
14205 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14207 case 0x69: /* MPEG-2 BC audio */
14208 case 0x6B: /* MPEG-1 audio */
14209 caps = gst_caps_new_simple ("audio/mpeg",
14210 "mpegversion", G_TYPE_INT, 1, NULL);
14211 codec_name = "MPEG-1 audio";
14213 case 0x6A: /* MPEG-1 */
14214 codec_name = "MPEG-1 video";
14215 caps = gst_caps_new_simple ("video/mpeg",
14216 "mpegversion", G_TYPE_INT, 1,
14217 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14219 case 0x6C: /* MJPEG */
14221 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14223 codec_name = "Motion-JPEG";
14225 case 0x6D: /* PNG */
14227 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14229 codec_name = "PNG still images";
14231 case 0x6E: /* JPEG2000 */
14232 codec_name = "JPEG-2000";
14233 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14235 case 0xA4: /* Dirac */
14236 codec_name = "Dirac";
14237 caps = gst_caps_new_empty_simple ("video/x-dirac");
14239 case 0xA5: /* AC3 */
14240 codec_name = "AC-3 audio";
14241 caps = gst_caps_new_simple ("audio/x-ac3",
14242 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14244 case 0xA9: /* AC3 */
14245 codec_name = "DTS audio";
14246 caps = gst_caps_new_simple ("audio/x-dts",
14247 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14250 if (stream_type == 0x05 && data_ptr) {
14252 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14255 GValue arr_val = G_VALUE_INIT;
14256 GValue buf_val = G_VALUE_INIT;
14259 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14260 codec_name = "Vorbis";
14261 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14262 g_value_init (&arr_val, GST_TYPE_ARRAY);
14263 g_value_init (&buf_val, GST_TYPE_BUFFER);
14264 for (tmp = headers; tmp; tmp = tmp->next) {
14265 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14266 gst_value_array_append_value (&arr_val, &buf_val);
14268 s = gst_caps_get_structure (caps, 0);
14269 gst_structure_take_value (s, "streamheader", &arr_val);
14270 g_value_unset (&buf_val);
14271 g_list_free (headers);
14278 case 0xE1: /* QCELP */
14279 /* QCELP, the codec_data is a riff tag (little endian) with
14280 * 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). */
14281 caps = gst_caps_new_empty_simple ("audio/qcelp");
14282 codec_name = "QCELP";
14288 /* If we have a replacement caps, then change our caps for this stream */
14290 gst_caps_unref (entry->caps);
14291 entry->caps = caps;
14294 if (codec_name && list)
14295 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14296 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14298 /* Add the codec_data attribute to caps, if we have it */
14302 buffer = gst_buffer_new_and_alloc (data_len);
14303 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14305 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14306 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14308 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14310 gst_buffer_unref (buffer);
14315 static inline GstCaps *
14316 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14320 char *s, fourstr[5];
14322 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14323 for (i = 0; i < 4; i++) {
14324 if (!g_ascii_isalnum (fourstr[i]))
14327 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14328 caps = gst_caps_new_empty_simple (s);
14333 #define _codec(name) \
14335 if (codec_name) { \
14336 *codec_name = g_strdup (name); \
14341 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14342 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14343 const guint8 * stsd_entry_data, gchar ** codec_name)
14345 GstCaps *caps = NULL;
14346 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14350 _codec ("PNG still images");
14351 caps = gst_caps_new_empty_simple ("image/png");
14354 _codec ("JPEG still images");
14356 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14359 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14360 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14361 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14362 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14363 _codec ("Motion-JPEG");
14365 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14368 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14369 _codec ("Motion-JPEG format B");
14370 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14373 _codec ("JPEG-2000");
14374 /* override to what it should be according to spec, avoid palette_data */
14375 entry->bits_per_sample = 24;
14376 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14379 _codec ("Sorensen video v.3");
14380 caps = gst_caps_new_simple ("video/x-svq",
14381 "svqversion", G_TYPE_INT, 3, NULL);
14383 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14384 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14385 _codec ("Sorensen video v.1");
14386 caps = gst_caps_new_simple ("video/x-svq",
14387 "svqversion", G_TYPE_INT, 1, NULL);
14389 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14390 caps = gst_caps_new_empty_simple ("video/x-raw");
14391 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14392 _codec ("Windows Raw RGB");
14393 stream->alignment = 32;
14399 bps = QT_UINT16 (stsd_entry_data + 82);
14402 format = GST_VIDEO_FORMAT_RGB15;
14405 format = GST_VIDEO_FORMAT_RGB16;
14408 format = GST_VIDEO_FORMAT_RGB;
14411 format = GST_VIDEO_FORMAT_ARGB;
14419 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14420 format = GST_VIDEO_FORMAT_I420;
14422 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14423 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14424 format = GST_VIDEO_FORMAT_I420;
14427 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14428 format = GST_VIDEO_FORMAT_UYVY;
14430 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14431 format = GST_VIDEO_FORMAT_v308;
14433 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14434 format = GST_VIDEO_FORMAT_v216;
14437 format = GST_VIDEO_FORMAT_v210;
14439 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14440 format = GST_VIDEO_FORMAT_r210;
14442 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14443 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14444 format = GST_VIDEO_FORMAT_v410;
14447 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14448 * but different order than AYUV
14449 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14450 format = GST_VIDEO_FORMAT_v408;
14453 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14454 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14455 _codec ("MPEG-1 video");
14456 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14457 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14459 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14460 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14461 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14462 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14463 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14464 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14465 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14466 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14467 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14468 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14469 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14470 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14471 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14472 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14473 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14474 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14475 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14476 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14477 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14478 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14479 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14480 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14481 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14482 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14483 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14484 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14485 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14486 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14487 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14488 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14489 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14490 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14491 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14492 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14493 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14494 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14495 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14496 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14497 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14498 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14499 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14500 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14501 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14502 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14503 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14504 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14505 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14506 _codec ("MPEG-2 video");
14507 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14508 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14510 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14511 _codec ("GIF still images");
14512 caps = gst_caps_new_empty_simple ("image/gif");
14515 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14517 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14519 /* ffmpeg uses the height/width props, don't know why */
14520 caps = gst_caps_new_simple ("video/x-h263",
14521 "variant", G_TYPE_STRING, "itu", NULL);
14525 _codec ("MPEG-4 video");
14526 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14527 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14529 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14530 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14531 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14532 caps = gst_caps_new_simple ("video/x-msmpeg",
14533 "msmpegversion", G_TYPE_INT, 43, NULL);
14535 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14537 caps = gst_caps_new_simple ("video/x-divx",
14538 "divxversion", G_TYPE_INT, 3, NULL);
14540 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14541 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14543 caps = gst_caps_new_simple ("video/x-divx",
14544 "divxversion", G_TYPE_INT, 4, NULL);
14546 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14548 caps = gst_caps_new_simple ("video/x-divx",
14549 "divxversion", G_TYPE_INT, 5, NULL);
14552 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14554 caps = gst_caps_new_simple ("video/x-ffv",
14555 "ffvversion", G_TYPE_INT, 1, NULL);
14558 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14559 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14564 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14565 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14566 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14570 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14571 _codec ("Cinepak");
14572 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14574 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14575 _codec ("Apple QuickDraw");
14576 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14578 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14579 _codec ("Apple video");
14580 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14585 _codec ("H.264 / AVC");
14586 caps = gst_caps_new_simple ("video/x-h264",
14587 "stream-format", G_TYPE_STRING, "avc",
14588 "alignment", G_TYPE_STRING, "au", NULL);
14592 _codec ("H.264 / AVC");
14593 caps = gst_caps_new_simple ("video/x-h264",
14594 "stream-format", G_TYPE_STRING, "avc3",
14595 "alignment", G_TYPE_STRING, "au", NULL);
14600 _codec ("H.265 / HEVC");
14601 caps = gst_caps_new_simple ("video/x-h265",
14602 "stream-format", G_TYPE_STRING, "hvc1",
14603 "alignment", G_TYPE_STRING, "au", NULL);
14607 _codec ("H.265 / HEVC");
14608 caps = gst_caps_new_simple ("video/x-h265",
14609 "stream-format", G_TYPE_STRING, "hev1",
14610 "alignment", G_TYPE_STRING, "au", NULL);
14613 _codec ("Run-length encoding");
14614 caps = gst_caps_new_simple ("video/x-rle",
14615 "layout", G_TYPE_STRING, "quicktime", NULL);
14618 _codec ("Run-length encoding");
14619 caps = gst_caps_new_simple ("video/x-rle",
14620 "layout", G_TYPE_STRING, "microsoft", NULL);
14622 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14623 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14624 _codec ("Indeo Video 3");
14625 caps = gst_caps_new_simple ("video/x-indeo",
14626 "indeoversion", G_TYPE_INT, 3, NULL);
14628 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14629 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14630 _codec ("Intel Video 4");
14631 caps = gst_caps_new_simple ("video/x-indeo",
14632 "indeoversion", G_TYPE_INT, 4, NULL);
14636 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14637 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14638 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14639 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14640 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14641 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14642 _codec ("DV Video");
14643 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14644 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14646 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14647 case FOURCC_dv5p: /* DVCPRO50 PAL */
14648 _codec ("DVCPro50 Video");
14649 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14650 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14652 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14653 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14654 _codec ("DVCProHD Video");
14655 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14656 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14658 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14659 _codec ("Apple Graphics (SMC)");
14660 caps = gst_caps_new_empty_simple ("video/x-smc");
14662 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14664 caps = gst_caps_new_empty_simple ("video/x-vp3");
14666 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14667 _codec ("VP6 Flash");
14668 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14672 caps = gst_caps_new_empty_simple ("video/x-theora");
14673 /* theora uses one byte of padding in the data stream because it does not
14674 * allow 0 sized packets while theora does */
14675 entry->padding = 1;
14679 caps = gst_caps_new_empty_simple ("video/x-dirac");
14681 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14682 _codec ("TIFF still images");
14683 caps = gst_caps_new_empty_simple ("image/tiff");
14685 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14686 _codec ("Apple Intermediate Codec");
14687 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14689 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14690 _codec ("AVID DNxHD");
14691 caps = gst_caps_from_string ("video/x-dnxhd");
14695 _codec ("On2 VP8");
14696 caps = gst_caps_from_string ("video/x-vp8");
14699 _codec ("Google VP9");
14700 caps = gst_caps_from_string ("video/x-vp9");
14703 _codec ("Apple ProRes LT");
14705 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14709 _codec ("Apple ProRes HQ");
14711 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14715 _codec ("Apple ProRes");
14717 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14721 _codec ("Apple ProRes Proxy");
14723 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14727 _codec ("Apple ProRes 4444");
14729 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14732 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14733 if (entry->bits_per_sample > 0) {
14734 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14739 _codec ("Apple ProRes 4444 XQ");
14741 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14744 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14745 if (entry->bits_per_sample > 0) {
14746 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14751 _codec ("GoPro CineForm");
14752 caps = gst_caps_from_string ("video/x-cineform");
14757 caps = gst_caps_new_simple ("video/x-wmv",
14758 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14762 caps = gst_caps_new_simple ("video/x-av1",
14763 "alignment", G_TYPE_STRING, "tu", NULL);
14765 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14768 caps = _get_unknown_codec_name ("video", fourcc);
14773 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14776 gst_video_info_init (&info);
14777 gst_video_info_set_format (&info, format, entry->width, entry->height);
14779 caps = gst_video_info_to_caps (&info);
14780 *codec_name = gst_pb_utils_get_codec_description (caps);
14782 /* enable clipping for raw video streams */
14783 stream->need_clip = TRUE;
14784 stream->alignment = 32;
14791 round_up_pow2 (guint n)
14803 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14804 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14805 int len, gchar ** codec_name)
14808 const GstStructure *s;
14811 GstAudioFormat format = 0;
14814 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14816 depth = entry->bytes_per_packet * 8;
14819 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14821 /* 8-bit audio is unsigned */
14823 format = GST_AUDIO_FORMAT_U8;
14824 /* otherwise it's signed and big-endian just like 'twos' */
14826 endian = G_BIG_ENDIAN;
14833 endian = G_LITTLE_ENDIAN;
14836 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14838 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14842 caps = gst_caps_new_simple ("audio/x-raw",
14843 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14844 "layout", G_TYPE_STRING, "interleaved", NULL);
14845 stream->alignment = GST_ROUND_UP_8 (depth);
14846 stream->alignment = round_up_pow2 (stream->alignment);
14850 _codec ("Raw 64-bit floating-point audio");
14851 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14853 caps = gst_caps_new_simple ("audio/x-raw",
14854 "format", G_TYPE_STRING, "F64BE",
14855 "layout", G_TYPE_STRING, "interleaved", NULL);
14856 stream->alignment = 8;
14859 _codec ("Raw 32-bit floating-point audio");
14860 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14862 caps = gst_caps_new_simple ("audio/x-raw",
14863 "format", G_TYPE_STRING, "F32BE",
14864 "layout", G_TYPE_STRING, "interleaved", NULL);
14865 stream->alignment = 4;
14868 _codec ("Raw 24-bit PCM audio");
14869 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14871 caps = gst_caps_new_simple ("audio/x-raw",
14872 "format", G_TYPE_STRING, "S24BE",
14873 "layout", G_TYPE_STRING, "interleaved", NULL);
14874 stream->alignment = 4;
14877 _codec ("Raw 32-bit PCM audio");
14878 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14880 caps = gst_caps_new_simple ("audio/x-raw",
14881 "format", G_TYPE_STRING, "S32BE",
14882 "layout", G_TYPE_STRING, "interleaved", NULL);
14883 stream->alignment = 4;
14886 _codec ("Raw 16-bit PCM audio");
14887 caps = gst_caps_new_simple ("audio/x-raw",
14888 "format", G_TYPE_STRING, "S16LE",
14889 "layout", G_TYPE_STRING, "interleaved", NULL);
14890 stream->alignment = 2;
14893 _codec ("Mu-law audio");
14894 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14897 _codec ("A-law audio");
14898 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14902 _codec ("Microsoft ADPCM");
14903 /* Microsoft ADPCM-ACM code 2 */
14904 caps = gst_caps_new_simple ("audio/x-adpcm",
14905 "layout", G_TYPE_STRING, "microsoft", NULL);
14909 _codec ("DVI/IMA ADPCM");
14910 caps = gst_caps_new_simple ("audio/x-adpcm",
14911 "layout", G_TYPE_STRING, "dvi", NULL);
14915 _codec ("DVI/Intel IMA ADPCM");
14916 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14917 caps = gst_caps_new_simple ("audio/x-adpcm",
14918 "layout", G_TYPE_STRING, "quicktime", NULL);
14922 /* MPEG layer 3, CBR only (pre QT4.1) */
14925 _codec ("MPEG-1 layer 3");
14926 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14927 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14928 "mpegversion", G_TYPE_INT, 1, NULL);
14930 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14931 _codec ("MPEG-1 layer 2");
14933 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14934 "mpegversion", G_TYPE_INT, 1, NULL);
14937 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14938 _codec ("EAC-3 audio");
14939 caps = gst_caps_new_simple ("audio/x-eac3",
14940 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14941 entry->sampled = TRUE;
14943 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14945 _codec ("AC-3 audio");
14946 caps = gst_caps_new_simple ("audio/x-ac3",
14947 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14948 entry->sampled = TRUE;
14950 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14951 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14952 _codec ("DTS audio");
14953 caps = gst_caps_new_simple ("audio/x-dts",
14954 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14955 entry->sampled = TRUE;
14957 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14958 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14959 _codec ("DTS-HD audio");
14960 caps = gst_caps_new_simple ("audio/x-dts",
14961 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14962 entry->sampled = TRUE;
14966 caps = gst_caps_new_simple ("audio/x-mace",
14967 "maceversion", G_TYPE_INT, 3, NULL);
14971 caps = gst_caps_new_simple ("audio/x-mace",
14972 "maceversion", G_TYPE_INT, 6, NULL);
14974 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14976 caps = gst_caps_new_empty_simple ("application/ogg");
14978 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14979 _codec ("DV audio");
14980 caps = gst_caps_new_empty_simple ("audio/x-dv");
14983 _codec ("MPEG-4 AAC audio");
14984 caps = gst_caps_new_simple ("audio/mpeg",
14985 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14986 "stream-format", G_TYPE_STRING, "raw", NULL);
14988 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14989 _codec ("QDesign Music");
14990 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14993 _codec ("QDesign Music v.2");
14994 /* FIXME: QDesign music version 2 (no constant) */
14995 if (FALSE && data) {
14996 caps = gst_caps_new_simple ("audio/x-qdm2",
14997 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14998 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14999 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15001 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15005 _codec ("GSM audio");
15006 caps = gst_caps_new_empty_simple ("audio/x-gsm");
15009 _codec ("AMR audio");
15010 caps = gst_caps_new_empty_simple ("audio/AMR");
15013 _codec ("AMR-WB audio");
15014 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15017 _codec ("Quicktime IMA ADPCM");
15018 caps = gst_caps_new_simple ("audio/x-adpcm",
15019 "layout", G_TYPE_STRING, "quicktime", NULL);
15022 _codec ("Apple lossless audio");
15023 caps = gst_caps_new_empty_simple ("audio/x-alac");
15026 _codec ("Free Lossless Audio Codec");
15027 caps = gst_caps_new_simple ("audio/x-flac",
15028 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15030 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15031 _codec ("QualComm PureVoice");
15032 caps = gst_caps_from_string ("audio/qcelp");
15037 caps = gst_caps_new_empty_simple ("audio/x-wma");
15041 caps = gst_caps_new_empty_simple ("audio/x-opus");
15048 GstAudioFormat format;
15051 FLAG_IS_FLOAT = 0x1,
15052 FLAG_IS_BIG_ENDIAN = 0x2,
15053 FLAG_IS_SIGNED = 0x4,
15054 FLAG_IS_PACKED = 0x8,
15055 FLAG_IS_ALIGNED_HIGH = 0x10,
15056 FLAG_IS_NON_INTERLEAVED = 0x20
15058 _codec ("Raw LPCM audio");
15060 if (data && len >= 36) {
15061 depth = QT_UINT32 (data + 24);
15062 flags = QT_UINT32 (data + 28);
15063 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15065 if ((flags & FLAG_IS_FLOAT) == 0) {
15070 if ((flags & FLAG_IS_ALIGNED_HIGH))
15073 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15074 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15075 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15076 caps = gst_caps_new_simple ("audio/x-raw",
15077 "format", G_TYPE_STRING,
15079 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15080 "UNKNOWN", "layout", G_TYPE_STRING,
15081 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15082 "interleaved", NULL);
15083 stream->alignment = GST_ROUND_UP_8 (depth);
15084 stream->alignment = round_up_pow2 (stream->alignment);
15089 if (flags & FLAG_IS_BIG_ENDIAN)
15090 format = GST_AUDIO_FORMAT_F64BE;
15092 format = GST_AUDIO_FORMAT_F64LE;
15094 if (flags & FLAG_IS_BIG_ENDIAN)
15095 format = GST_AUDIO_FORMAT_F32BE;
15097 format = GST_AUDIO_FORMAT_F32LE;
15099 caps = gst_caps_new_simple ("audio/x-raw",
15100 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15101 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15102 "non-interleaved" : "interleaved", NULL);
15103 stream->alignment = width / 8;
15107 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15110 caps = gst_caps_new_empty_simple ("audio/x-ac4");
15113 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15117 caps = _get_unknown_codec_name ("audio", fourcc);
15123 GstCaps *templ_caps =
15124 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15125 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15126 gst_caps_unref (caps);
15127 gst_caps_unref (templ_caps);
15128 caps = intersection;
15131 /* enable clipping for raw audio streams */
15132 s = gst_caps_get_structure (caps, 0);
15133 name = gst_structure_get_name (s);
15134 if (g_str_has_prefix (name, "audio/x-raw")) {
15135 stream->need_clip = TRUE;
15136 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15137 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15138 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15139 stream->max_buffer_size);
15145 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15146 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15147 const guint8 * stsd_entry_data, gchar ** codec_name)
15151 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15155 _codec ("DVD subtitle");
15156 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15157 stream->process_func = gst_qtdemux_process_buffer_dvd;
15160 _codec ("Quicktime timed text");
15163 _codec ("3GPP timed text");
15165 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15167 /* actual text piece needs to be extracted */
15168 stream->process_func = gst_qtdemux_process_buffer_text;
15171 _codec ("XML subtitles");
15172 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15177 const gchar *buf = "WEBVTT\n\n";
15179 _codec ("WebVTT subtitles");
15180 caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15181 stream->process_func = gst_qtdemux_process_buffer_wvtt;
15183 /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15184 buffer = gst_buffer_new_and_alloc (8);
15185 gst_buffer_fill (buffer, 0, buf, 8);
15186 stream->buffers = g_slist_append (stream->buffers, buffer);
15191 _codec ("CEA 608 Closed Caption");
15193 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15194 G_TYPE_STRING, "s334-1a", NULL);
15195 stream->process_func = gst_qtdemux_process_buffer_clcp;
15196 stream->need_split = TRUE;
15199 _codec ("CEA 708 Closed Caption");
15201 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15202 G_TYPE_STRING, "cdp", NULL);
15203 stream->process_func = gst_qtdemux_process_buffer_clcp;
15208 caps = _get_unknown_codec_name ("text", fourcc);
15216 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15217 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15218 const guint8 * stsd_entry_data, gchar ** codec_name)
15224 _codec ("MPEG 1 video");
15225 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15226 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15236 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15237 const gchar * system_id)
15241 if (!qtdemux->protection_system_ids)
15242 qtdemux->protection_system_ids =
15243 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15244 /* Check whether we already have an entry for this system ID. */
15245 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15246 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15247 if (g_ascii_strcasecmp (system_id, id) == 0) {
15251 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15252 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,