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 static GstStaticPadTemplate gst_qtdemux_metasrc_template =
293 GST_STATIC_PAD_TEMPLATE ("meta_%u",
296 GST_STATIC_CAPS_ANY);
298 #define gst_qtdemux_parent_class parent_class
299 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
300 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
301 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
303 static void gst_qtdemux_dispose (GObject * object);
304 static void gst_qtdemux_finalize (GObject * object);
307 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
308 GstClockTime media_time);
310 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
311 QtDemuxStream * str, gint64 media_offset);
314 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
315 static GstIndex *gst_qtdemux_get_index (GstElement * element);
317 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
318 GstStateChange transition);
319 static void gst_qtdemux_set_context (GstElement * element,
320 GstContext * context);
321 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
322 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
323 GstObject * parent, GstPadMode mode, gboolean active);
325 static void gst_qtdemux_loop (GstPad * pad);
326 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
328 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
330 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
332 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
333 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
334 QtDemuxStream * stream);
335 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
336 QtDemuxStream * stream);
337 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
340 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
342 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
343 const guint8 * buffer, guint length);
344 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
345 const guint8 * buffer, guint length);
346 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
348 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
349 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
351 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
352 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
353 const guint8 * stsd_entry_data, gchar ** codec_name);
354 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
355 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
356 const guint8 * data, int len, gchar ** codec_name);
357 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
358 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
359 gchar ** codec_name);
360 static GstCaps *qtdemux_meta_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
361 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
362 gchar ** codec_name);
363 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
364 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
365 const guint8 * stsd_entry_data, gchar ** codec_name);
367 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
368 QtDemuxStream * stream, guint32 n);
369 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
370 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
371 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
372 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
373 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
374 static void qtdemux_do_allocation (QtDemuxStream * stream,
375 GstQTDemux * qtdemux);
376 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
377 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
378 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
379 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
380 GstClockTime * _start, GstClockTime * _stop);
381 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
382 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
384 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
385 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
387 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
389 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
390 QtDemuxStream * stream, guint sample_index);
391 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
393 static void qtdemux_gst_structure_free (GstStructure * gststructure);
394 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
395 static void qtdemux_clear_protection_events_on_all_streams (GstQTDemux *
399 gst_qtdemux_class_init (GstQTDemuxClass * klass)
401 GObjectClass *gobject_class;
402 GstElementClass *gstelement_class;
404 gobject_class = (GObjectClass *) klass;
405 gstelement_class = (GstElementClass *) klass;
407 parent_class = g_type_class_peek_parent (klass);
409 gobject_class->dispose = gst_qtdemux_dispose;
410 gobject_class->finalize = gst_qtdemux_finalize;
412 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
414 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
415 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
417 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
419 gst_tag_register_musicbrainz_tags ();
421 gst_element_class_add_static_pad_template (gstelement_class,
422 &gst_qtdemux_sink_template);
423 gst_element_class_add_static_pad_template (gstelement_class,
424 &gst_qtdemux_videosrc_template);
425 gst_element_class_add_static_pad_template (gstelement_class,
426 &gst_qtdemux_audiosrc_template);
427 gst_element_class_add_static_pad_template (gstelement_class,
428 &gst_qtdemux_subsrc_template);
429 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
431 "Demultiplex a QuickTime file into audio and video streams",
432 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
434 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
439 gst_qtdemux_init (GstQTDemux * qtdemux)
442 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
443 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
444 gst_pad_set_activatemode_function (qtdemux->sinkpad,
445 qtdemux_sink_activate_mode);
446 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
447 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
448 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
449 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
451 qtdemux->adapter = gst_adapter_new ();
452 g_queue_init (&qtdemux->protection_event_queue);
453 qtdemux->flowcombiner = gst_flow_combiner_new ();
454 g_mutex_init (&qtdemux->expose_lock);
456 qtdemux->active_streams = g_ptr_array_new_with_free_func
457 ((GDestroyNotify) gst_qtdemux_stream_unref);
458 qtdemux->old_streams = g_ptr_array_new_with_free_func
459 ((GDestroyNotify) gst_qtdemux_stream_unref);
461 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
463 gst_qtdemux_reset (qtdemux, TRUE);
467 gst_qtdemux_finalize (GObject * object)
469 GstQTDemux *qtdemux = GST_QTDEMUX (object);
471 g_free (qtdemux->redirect_location);
473 G_OBJECT_CLASS (parent_class)->finalize (object);
477 gst_qtdemux_dispose (GObject * object)
479 GstQTDemux *qtdemux = GST_QTDEMUX (object);
481 if (qtdemux->adapter) {
482 g_object_unref (G_OBJECT (qtdemux->adapter));
483 qtdemux->adapter = NULL;
485 gst_tag_list_unref (qtdemux->tag_list);
486 gst_flow_combiner_free (qtdemux->flowcombiner);
487 g_queue_clear_full (&qtdemux->protection_event_queue,
488 (GDestroyNotify) gst_event_unref);
490 g_free (qtdemux->cenc_aux_info_sizes);
491 qtdemux->cenc_aux_info_sizes = NULL;
492 g_mutex_clear (&qtdemux->expose_lock);
494 g_ptr_array_free (qtdemux->active_streams, TRUE);
495 g_ptr_array_free (qtdemux->old_streams, TRUE);
497 G_OBJECT_CLASS (parent_class)->dispose (object);
501 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
503 if (qtdemux->redirect_location) {
504 GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
505 (_("This file contains no playable streams.")),
506 ("no known streams found, a redirect message has been posted"),
507 ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
509 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
510 (_("This file contains no playable streams.")),
511 ("no known streams found"));
516 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
518 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
519 mem, size, 0, size, mem, free_func);
523 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
530 if (G_UNLIKELY (size == 0)) {
532 GstBuffer *tmp = NULL;
534 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
535 if (ret != GST_FLOW_OK)
538 gst_buffer_map (tmp, &map, GST_MAP_READ);
539 size = QT_UINT32 (map.data);
540 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
542 gst_buffer_unmap (tmp, &map);
543 gst_buffer_unref (tmp);
546 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
547 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
548 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
549 /* we're pulling header but already got most interesting bits,
550 * so never mind the rest (e.g. tags) (that much) */
551 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
555 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
556 (_("This file is invalid and cannot be played.")),
557 ("atom has bogus size %" G_GUINT64_FORMAT, size));
558 return GST_FLOW_ERROR;
562 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
564 if (G_UNLIKELY (flow != GST_FLOW_OK))
567 bsize = gst_buffer_get_size (*buf);
568 /* Catch short reads - we don't want any partial atoms */
569 if (G_UNLIKELY (bsize < size)) {
570 GST_WARNING_OBJECT (qtdemux,
571 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
572 gst_buffer_unref (*buf);
582 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
583 GstFormat src_format, gint64 src_value, GstFormat dest_format,
587 QtDemuxStream *stream = gst_pad_get_element_private (pad);
590 if (stream->subtype != FOURCC_vide) {
595 switch (src_format) {
596 case GST_FORMAT_TIME:
597 switch (dest_format) {
598 case GST_FORMAT_BYTES:{
599 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
605 *dest_value = stream->samples[index].offset;
607 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
608 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
609 GST_TIME_ARGS (src_value), *dest_value);
617 case GST_FORMAT_BYTES:
618 switch (dest_format) {
619 case GST_FORMAT_TIME:{
621 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
630 QTSTREAMTIME_TO_GSTTIME (stream,
631 stream->samples[index].timestamp);
632 GST_DEBUG_OBJECT (qtdemux,
633 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
634 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
653 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
655 gboolean res = FALSE;
657 *duration = GST_CLOCK_TIME_NONE;
659 if (qtdemux->duration != 0 &&
660 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
661 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
664 *duration = GST_CLOCK_TIME_NONE;
671 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
674 gboolean res = FALSE;
675 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
677 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
679 switch (GST_QUERY_TYPE (query)) {
680 case GST_QUERY_POSITION:{
683 gst_query_parse_position (query, &fmt, NULL);
684 if (fmt == GST_FORMAT_TIME
685 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
686 gst_query_set_position (query, GST_FORMAT_TIME,
687 qtdemux->segment.position);
692 case GST_QUERY_DURATION:{
695 gst_query_parse_duration (query, &fmt, NULL);
696 if (fmt == GST_FORMAT_TIME) {
697 /* First try to query upstream */
698 res = gst_pad_query_default (pad, parent, query);
700 GstClockTime duration;
701 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
702 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
709 case GST_QUERY_CONVERT:{
710 GstFormat src_fmt, dest_fmt;
711 gint64 src_value, dest_value = 0;
713 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
715 res = gst_qtdemux_src_convert (qtdemux, pad,
716 src_fmt, src_value, dest_fmt, &dest_value);
718 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
722 case GST_QUERY_FORMATS:
723 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
726 case GST_QUERY_SEEKING:{
730 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
732 if (fmt == GST_FORMAT_BYTES) {
733 /* We always refuse BYTES seeks from downstream */
737 /* try upstream first */
738 res = gst_pad_query_default (pad, parent, query);
741 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
742 if (fmt == GST_FORMAT_TIME) {
743 GstClockTime duration;
745 gst_qtdemux_get_duration (qtdemux, &duration);
747 if (!qtdemux->pullbased) {
750 /* we might be able with help from upstream */
752 q = gst_query_new_seeking (GST_FORMAT_BYTES);
753 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
754 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
755 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
759 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
765 case GST_QUERY_SEGMENT:
770 format = qtdemux->segment.format;
773 gst_segment_to_stream_time (&qtdemux->segment, format,
774 qtdemux->segment.start);
775 if ((stop = qtdemux->segment.stop) == -1)
776 stop = qtdemux->segment.duration;
778 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
780 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
785 res = gst_pad_query_default (pad, parent, query);
793 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
795 if (G_LIKELY (stream->pad)) {
796 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
797 GST_DEBUG_PAD_NAME (stream->pad));
799 if (!gst_tag_list_is_empty (stream->stream_tags)) {
800 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
801 stream->stream_tags);
802 gst_pad_push_event (stream->pad,
803 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
806 if (G_UNLIKELY (stream->send_global_tags)) {
807 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
809 gst_pad_push_event (stream->pad,
810 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
811 stream->send_global_tags = FALSE;
816 /* push event on all source pads; takes ownership of the event */
818 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
820 gboolean has_valid_stream = FALSE;
821 GstEventType etype = GST_EVENT_TYPE (event);
824 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
825 GST_EVENT_TYPE_NAME (event));
827 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
829 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
830 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
832 if ((pad = stream->pad)) {
833 has_valid_stream = TRUE;
835 if (etype == GST_EVENT_EOS) {
836 /* let's not send twice */
837 if (stream->sent_eos)
839 stream->sent_eos = TRUE;
842 gst_pad_push_event (pad, gst_event_ref (event));
846 gst_event_unref (event);
848 /* if it is EOS and there are no pads, post an error */
849 if (!has_valid_stream && etype == GST_EVENT_EOS) {
850 gst_qtdemux_post_no_playable_stream_error (qtdemux);
860 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
862 if ((gint64) s1->timestamp > *media_time)
864 if ((gint64) s1->timestamp == *media_time)
870 /* find the index of the sample that includes the data for @media_time using a
871 * binary search. Only to be called in optimized cases of linear search below.
873 * Returns the index of the sample with the corresponding *DTS*.
876 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
879 QtDemuxSample *result;
882 /* convert media_time to mov format */
884 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
886 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
887 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
888 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
890 if (G_LIKELY (result))
891 index = result - str->samples;
900 /* find the index of the sample that includes the data for @media_offset using a
903 * Returns the index of the sample.
906 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
907 QtDemuxStream * str, gint64 media_offset)
909 QtDemuxSample *result = str->samples;
912 if (result == NULL || str->n_samples == 0)
915 if (media_offset == result->offset)
919 while (index < str->n_samples - 1) {
920 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
923 if (media_offset < result->offset)
934 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
939 /* find the index of the sample that includes the data for @media_time using a
940 * linear search, and keeping in mind that not all samples may have been parsed
941 * yet. If possible, it will delegate to binary search.
943 * Returns the index of the sample.
946 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
947 GstClockTime media_time)
951 QtDemuxSample *sample;
953 /* convert media_time to mov format */
955 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
957 sample = str->samples;
958 if (mov_time == sample->timestamp + sample->pts_offset)
961 /* use faster search if requested time in already parsed range */
962 sample = str->samples + str->stbl_index;
963 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
964 index = gst_qtdemux_find_index (qtdemux, str, media_time);
965 sample = str->samples + index;
967 while (index < str->n_samples - 1) {
968 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
971 sample = str->samples + index + 1;
972 if (mov_time < sample->timestamp) {
973 sample = str->samples + index;
981 /* sample->timestamp is now <= media_time, need to find the corresponding
982 * PTS now by looking backwards */
983 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
985 sample = str->samples + index;
993 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
998 /* find the index of the keyframe needed to decode the sample at @index
999 * of stream @str, or of a subsequent keyframe (depending on @next)
1001 * Returns the index of the keyframe.
1004 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1005 guint32 index, gboolean next)
1007 guint32 new_index = index;
1009 if (index >= str->n_samples) {
1010 new_index = str->n_samples;
1014 /* all keyframes, return index */
1015 if (str->all_keyframe) {
1020 /* else search until we have a keyframe */
1021 while (new_index < str->n_samples) {
1022 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1025 if (str->samples[new_index].keyframe)
1037 if (new_index == str->n_samples) {
1038 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1043 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1044 "gave %u", next ? "after" : "before", index, new_index);
1051 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1056 /* find the segment for @time_position for @stream
1058 * Returns the index of the segment containing @time_position.
1059 * Returns the last segment and sets the @eos variable to TRUE
1060 * if the time is beyond the end. @eos may be NULL
1063 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1064 GstClockTime time_position)
1069 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1070 GST_TIME_ARGS (time_position));
1073 for (i = 0; i < stream->n_segments; i++) {
1074 QtDemuxSegment *segment = &stream->segments[i];
1076 GST_LOG_OBJECT (stream->pad,
1077 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1078 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1080 /* For the last segment we include stop_time in the last segment */
1081 if (i < stream->n_segments - 1) {
1082 if (segment->time <= time_position && time_position < segment->stop_time) {
1083 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1088 /* Last segment always matches */
1096 /* move the stream @str to the sample position @index.
1098 * Updates @str->sample_index and marks discontinuity if needed.
1101 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1104 /* no change needed */
1105 if (index == str->sample_index)
1108 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1111 /* position changed, we have a discont */
1112 str->sample_index = index;
1113 str->offset_in_sample = 0;
1114 /* Each time we move in the stream we store the position where we are
1116 str->from_sample = index;
1117 str->discont = TRUE;
1121 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1122 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1125 gint64 min_byte_offset = -1;
1128 min_offset = desired_time;
1130 /* for each stream, find the index of the sample in the segment
1131 * and move back to the previous keyframe. */
1132 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1134 guint32 index, kindex;
1136 GstClockTime media_start;
1137 GstClockTime media_time;
1138 GstClockTime seg_time;
1139 QtDemuxSegment *seg;
1140 gboolean empty_segment = FALSE;
1142 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1144 if (CUR_STREAM (str)->sparse && !use_sparse)
1147 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1148 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1150 /* get segment and time in the segment */
1151 seg = &str->segments[seg_idx];
1152 seg_time = (desired_time - seg->time) * seg->rate;
1154 while (QTSEGMENT_IS_EMPTY (seg)) {
1156 empty_segment = TRUE;
1157 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1160 if (seg_idx == str->n_segments)
1162 seg = &str->segments[seg_idx];
1165 if (seg_idx == str->n_segments) {
1166 /* FIXME track shouldn't have the last segment as empty, but if it
1167 * happens we better handle it */
1171 /* get the media time in the segment */
1172 media_start = seg->media_start + seg_time;
1174 /* get the index of the sample with media time */
1175 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1176 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1177 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1178 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1181 /* shift to next frame if we are looking for next keyframe */
1182 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1183 && index < str->stbl_index)
1186 if (!empty_segment) {
1187 /* find previous keyframe */
1188 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1190 /* we will settle for one before if none found after */
1191 if (next && kindex == -1)
1192 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1194 /* Update the requested time whenever a keyframe was found, to make it
1195 * accurate and avoid having the first buffer fall outside of the segment
1200 /* get timestamp of keyframe */
1201 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1202 GST_DEBUG_OBJECT (qtdemux,
1203 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1204 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1205 str->samples[kindex].offset);
1207 /* keyframes in the segment get a chance to change the
1208 * desired_offset. keyframes out of the segment are
1210 if (media_time >= seg->media_start) {
1211 GstClockTime seg_time;
1213 /* this keyframe is inside the segment, convert back to
1215 seg_time = (media_time - seg->media_start) + seg->time;
1216 if ((!next && (seg_time < min_offset)) ||
1217 (next && (seg_time > min_offset)))
1218 min_offset = seg_time;
1223 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1224 min_byte_offset = str->samples[index].offset;
1228 *key_time = min_offset;
1230 *key_offset = min_byte_offset;
1234 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1235 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1239 g_return_val_if_fail (format != NULL, FALSE);
1240 g_return_val_if_fail (cur != NULL, FALSE);
1241 g_return_val_if_fail (stop != NULL, FALSE);
1243 if (*format == GST_FORMAT_TIME)
1247 if (cur_type != GST_SEEK_TYPE_NONE)
1248 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1249 if (res && stop_type != GST_SEEK_TYPE_NONE)
1250 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1253 *format = GST_FORMAT_TIME;
1258 /* perform seek in push based mode:
1259 find BYTE position to move to based on time and delegate to upstream
1262 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1267 GstSeekType cur_type, stop_type;
1268 gint64 cur, stop, key_cur;
1271 gint64 original_stop;
1274 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1276 gst_event_parse_seek (event, &rate, &format, &flags,
1277 &cur_type, &cur, &stop_type, &stop);
1278 seqnum = gst_event_get_seqnum (event);
1280 /* Directly send the instant-rate-change event here before taking the
1281 * stream-lock so that it can be applied as soon as possible */
1282 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1285 /* instant rate change only supported if direction does not change. All
1286 * other requirements are already checked before creating the seek event
1287 * but let's double-check here to be sure */
1288 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1289 (qtdemux->segment.rate < 0 && rate > 0) ||
1290 cur_type != GST_SEEK_TYPE_NONE ||
1291 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1292 GST_ERROR_OBJECT (qtdemux,
1293 "Instant rate change seeks only supported in the "
1294 "same direction, without flushing and position change");
1298 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1299 (GstSegmentFlags) flags);
1300 gst_event_set_seqnum (ev, seqnum);
1301 gst_qtdemux_push_event (qtdemux, ev);
1305 /* only forward streaming and seeking is possible */
1307 goto unsupported_seek;
1309 /* convert to TIME if needed and possible */
1310 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1314 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1315 * the original stop position to use when upstream pushes the new segment
1317 original_stop = stop;
1320 /* find reasonable corresponding BYTE position,
1321 * also try to mind about keyframes, since we can not go back a bit for them
1323 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1324 * mostly just work, but let's not yet boldly go there ... */
1325 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1330 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1331 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1334 GST_OBJECT_LOCK (qtdemux);
1335 qtdemux->seek_offset = byte_cur;
1336 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1337 qtdemux->push_seek_start = cur;
1339 qtdemux->push_seek_start = key_cur;
1342 if (stop_type == GST_SEEK_TYPE_NONE) {
1343 qtdemux->push_seek_stop = qtdemux->segment.stop;
1345 qtdemux->push_seek_stop = original_stop;
1347 GST_OBJECT_UNLOCK (qtdemux);
1349 qtdemux->segment_seqnum = seqnum;
1350 /* BYTE seek event */
1351 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1353 gst_event_set_seqnum (event, seqnum);
1354 res = gst_pad_push_event (qtdemux->sinkpad, event);
1361 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1367 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1372 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1377 /* perform the seek.
1379 * We set all segment_indexes in the streams to unknown and
1380 * adjust the time_position to the desired position. this is enough
1381 * to trigger a segment switch in the streaming thread to start
1382 * streaming from the desired position.
1384 * Keyframe seeking is a little more complicated when dealing with
1385 * segments. Ideally we want to move to the previous keyframe in
1386 * the segment but there might not be a keyframe in the segment. In
1387 * fact, none of the segments could contain a keyframe. We take a
1388 * practical approach: seek to the previous keyframe in the segment,
1389 * if there is none, seek to the beginning of the segment.
1391 * Called with STREAM_LOCK
1394 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1395 guint32 seqnum, GstSeekFlags flags)
1397 gint64 desired_offset;
1400 desired_offset = segment->position;
1402 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1403 GST_TIME_ARGS (desired_offset));
1405 /* may not have enough fragmented info to do this adjustment,
1406 * and we can't scan (and probably should not) at this time with
1407 * possibly flushing upstream */
1408 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1410 gboolean next, before, after;
1412 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1413 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1414 next = after && !before;
1415 if (segment->rate < 0)
1418 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1420 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1421 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1422 desired_offset = min_offset;
1425 /* and set all streams to the final position */
1426 GST_OBJECT_LOCK (qtdemux);
1427 gst_flow_combiner_reset (qtdemux->flowcombiner);
1428 GST_OBJECT_UNLOCK (qtdemux);
1429 qtdemux->segment_seqnum = seqnum;
1430 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1431 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1433 stream->time_position = desired_offset;
1434 stream->accumulated_base = 0;
1435 stream->sample_index = -1;
1436 stream->offset_in_sample = 0;
1437 stream->segment_index = -1;
1438 stream->sent_eos = FALSE;
1439 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1441 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1442 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1444 segment->position = desired_offset;
1445 if (segment->rate >= 0) {
1446 segment->start = desired_offset;
1447 /* We need to update time as we update start in that direction */
1448 segment->time = desired_offset;
1450 /* we stop at the end */
1451 if (segment->stop == -1)
1452 segment->stop = segment->duration;
1454 segment->stop = desired_offset;
1457 if (qtdemux->fragmented)
1458 qtdemux->fragmented_seek_pending = TRUE;
1463 /* do a seek in pull based mode */
1465 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1470 GstSeekType cur_type, stop_type;
1472 gboolean flush, instant_rate_change;
1474 GstSegment seeksegment;
1475 guint32 seqnum = GST_SEQNUM_INVALID;
1476 GstEvent *flush_event;
1479 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1481 gst_event_parse_seek (event, &rate, &format, &flags,
1482 &cur_type, &cur, &stop_type, &stop);
1483 seqnum = gst_event_get_seqnum (event);
1485 /* we have to have a format as the segment format. Try to convert
1487 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1491 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1493 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1494 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1496 /* Directly send the instant-rate-change event here before taking the
1497 * stream-lock so that it can be applied as soon as possible */
1498 if (instant_rate_change) {
1501 /* instant rate change only supported if direction does not change. All
1502 * other requirements are already checked before creating the seek event
1503 * but let's double-check here to be sure */
1504 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1505 (qtdemux->segment.rate < 0 && rate > 0) ||
1506 cur_type != GST_SEEK_TYPE_NONE ||
1507 stop_type != GST_SEEK_TYPE_NONE || flush) {
1508 GST_ERROR_OBJECT (qtdemux,
1509 "Instant rate change seeks only supported in the "
1510 "same direction, without flushing and position change");
1514 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1515 (GstSegmentFlags) flags);
1516 gst_event_set_seqnum (ev, seqnum);
1517 gst_qtdemux_push_event (qtdemux, ev);
1521 /* stop streaming, either by flushing or by pausing the task */
1523 flush_event = gst_event_new_flush_start ();
1524 if (seqnum != GST_SEQNUM_INVALID)
1525 gst_event_set_seqnum (flush_event, seqnum);
1526 /* unlock upstream pull_range */
1527 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1528 /* make sure out loop function exits */
1529 gst_qtdemux_push_event (qtdemux, flush_event);
1531 /* non flushing seek, pause the task */
1532 gst_pad_pause_task (qtdemux->sinkpad);
1535 /* wait for streaming to finish */
1536 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1538 /* copy segment, we need this because we still need the old
1539 * segment when we close the current segment. */
1540 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1542 /* configure the segment with the seek variables */
1543 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1544 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1545 cur_type, cur, stop_type, stop, &update)) {
1547 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1549 /* now do the seek */
1550 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1553 /* prepare for streaming again */
1555 flush_event = gst_event_new_flush_stop (TRUE);
1556 if (seqnum != GST_SEQNUM_INVALID)
1557 gst_event_set_seqnum (flush_event, seqnum);
1559 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1560 gst_qtdemux_push_event (qtdemux, flush_event);
1563 /* commit the new segment */
1564 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1566 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1567 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1568 qtdemux->segment.format, qtdemux->segment.position);
1569 if (seqnum != GST_SEQNUM_INVALID)
1570 gst_message_set_seqnum (msg, seqnum);
1571 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1574 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1575 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1576 qtdemux->sinkpad, NULL);
1578 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1585 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1591 qtdemux_ensure_index (GstQTDemux * qtdemux)
1595 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1597 /* Build complete index */
1598 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1599 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1601 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1602 GST_LOG_OBJECT (qtdemux,
1603 "Building complete index of track-id %u for seeking failed!",
1613 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1616 gboolean res = TRUE;
1617 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1619 switch (GST_EVENT_TYPE (event)) {
1620 case GST_EVENT_RECONFIGURE:
1621 GST_OBJECT_LOCK (qtdemux);
1622 gst_flow_combiner_reset (qtdemux->flowcombiner);
1623 GST_OBJECT_UNLOCK (qtdemux);
1624 res = gst_pad_event_default (pad, parent, event);
1626 case GST_EVENT_SEEK:
1628 GstSeekFlags flags = 0;
1629 GstFormat seek_format;
1630 gboolean instant_rate_change;
1632 #ifndef GST_DISABLE_GST_DEBUG
1633 GstClockTime ts = gst_util_get_timestamp ();
1635 guint32 seqnum = gst_event_get_seqnum (event);
1637 qtdemux->received_seek = TRUE;
1639 gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1641 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1643 if (seqnum == qtdemux->segment_seqnum) {
1644 GST_LOG_OBJECT (pad,
1645 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1646 gst_event_unref (event);
1650 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1651 /* seek should be handled by upstream, we might need to re-download fragments */
1652 GST_DEBUG_OBJECT (qtdemux,
1653 "let upstream handle seek for fragmented playback");
1657 if (seek_format == GST_FORMAT_BYTES) {
1658 GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1659 gst_event_unref (event);
1663 gst_event_parse_seek_trickmode_interval (event,
1664 &qtdemux->trickmode_interval);
1666 /* Build complete index for seeking;
1667 * if not a fragmented file at least and we're really doing a seek,
1668 * not just an instant-rate-change */
1669 if (!qtdemux->fragmented && !instant_rate_change) {
1670 if (!qtdemux_ensure_index (qtdemux))
1673 #ifndef GST_DISABLE_GST_DEBUG
1674 ts = gst_util_get_timestamp () - ts;
1675 GST_INFO_OBJECT (qtdemux,
1676 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1678 if (qtdemux->pullbased) {
1679 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1680 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1681 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1683 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1684 && QTDEMUX_N_STREAMS (qtdemux)
1685 && !qtdemux->fragmented) {
1686 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1688 GST_DEBUG_OBJECT (qtdemux,
1689 "ignoring seek in push mode in current state");
1692 gst_event_unref (event);
1697 res = gst_pad_event_default (pad, parent, event);
1707 GST_ERROR_OBJECT (qtdemux, "Index failed");
1708 gst_event_unref (event);
1714 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1716 * If @fw is false, the coding order is explored backwards.
1718 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1719 * sample is found for that track.
1721 * The stream and sample index of the sample with the minimum offset in the direction explored
1722 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1724 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1725 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1726 * @_stream and @_index. */
1728 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1729 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1732 gint64 time, min_time;
1733 QtDemuxStream *stream;
1740 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1743 gboolean set_sample;
1745 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1752 i = str->n_samples - 1;
1756 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1757 if (str->samples[i].size == 0)
1760 if (fw && (str->samples[i].offset < byte_pos))
1763 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1766 /* move stream to first available sample */
1768 gst_qtdemux_move_stream (qtdemux, str, i);
1772 /* avoid index from sparse streams since they might be far away */
1773 if (!CUR_STREAM (str)->sparse) {
1774 /* determine min/max time */
1775 time = QTSAMPLE_PTS (str, &str->samples[i]);
1776 if (min_time == -1 || (!fw && time > min_time) ||
1777 (fw && time < min_time)) {
1781 /* determine stream with leading sample, to get its position */
1783 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1784 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1792 /* no sample for this stream, mark eos */
1794 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1805 /* Copied from mpegtsbase code */
1806 /* FIXME: replace this function when we add new util function for stream-id creation */
1808 _get_upstream_id (GstQTDemux * demux)
1810 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1813 /* Try to create one from the upstream URI, else use a randome number */
1817 /* Try to generate one from the URI query and
1818 * if it fails take a random number instead */
1819 query = gst_query_new_uri ();
1820 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1821 gst_query_parse_uri (query, &uri);
1827 /* And then generate an SHA256 sum of the URI */
1828 cs = g_checksum_new (G_CHECKSUM_SHA256);
1829 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1831 upstream_id = g_strdup (g_checksum_get_string (cs));
1832 g_checksum_free (cs);
1834 /* Just get some random number if the URI query fails */
1835 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1836 "implementing a deterministic way of creating a stream-id");
1838 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1839 g_random_int (), g_random_int ());
1842 gst_query_unref (query);
1847 static QtDemuxStream *
1848 _create_stream (GstQTDemux * demux, guint32 track_id)
1850 QtDemuxStream *stream;
1853 stream = g_new0 (QtDemuxStream, 1);
1854 stream->demux = demux;
1855 stream->track_id = track_id;
1856 upstream_id = _get_upstream_id (demux);
1857 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1858 g_free (upstream_id);
1859 /* new streams always need a discont */
1860 stream->discont = TRUE;
1861 /* we enable clipping for raw audio/video streams */
1862 stream->need_clip = FALSE;
1863 stream->process_func = NULL;
1864 stream->segment_index = -1;
1865 stream->time_position = 0;
1866 stream->sample_index = -1;
1867 stream->offset_in_sample = 0;
1868 stream->new_stream = TRUE;
1869 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1870 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1871 stream->protected = FALSE;
1872 stream->protection_scheme_type = 0;
1873 stream->protection_scheme_version = 0;
1874 stream->protection_scheme_info = NULL;
1875 stream->n_samples_moof = 0;
1876 stream->duration_moof = 0;
1877 stream->duration_last_moof = 0;
1878 stream->alignment = 1;
1879 stream->stream_tags = gst_tag_list_new_empty ();
1880 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1881 g_queue_init (&stream->protection_scheme_event_queue);
1882 stream->ref_count = 1;
1883 /* consistent default for push based mode */
1884 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1889 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1891 GstStructure *structure;
1892 const gchar *variant;
1893 const GstCaps *mediacaps = NULL;
1895 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1897 structure = gst_caps_get_structure (caps, 0);
1898 variant = gst_structure_get_string (structure, "variant");
1900 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1901 QtDemuxStream *stream;
1902 const GValue *value;
1904 demux->fragmented = TRUE;
1905 demux->mss_mode = TRUE;
1907 if (QTDEMUX_N_STREAMS (demux) > 1) {
1908 /* can't do this, we can only renegotiate for another mss format */
1912 value = gst_structure_get_value (structure, "media-caps");
1915 const GValue *timescale_v;
1917 /* TODO update when stream changes during playback */
1919 if (QTDEMUX_N_STREAMS (demux) == 0) {
1920 stream = _create_stream (demux, 1);
1921 g_ptr_array_add (demux->active_streams, stream);
1922 /* mss has no stsd/stsd entry, use id 0 as default */
1923 stream->stsd_entries_length = 1;
1924 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1925 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1927 stream = QTDEMUX_NTH_STREAM (demux, 0);
1930 timescale_v = gst_structure_get_value (structure, "timescale");
1932 stream->timescale = g_value_get_uint64 (timescale_v);
1934 /* default mss timescale */
1935 stream->timescale = 10000000;
1937 demux->timescale = stream->timescale;
1939 mediacaps = gst_value_get_caps (value);
1940 if (!CUR_STREAM (stream)->caps
1941 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1942 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1944 stream->new_caps = TRUE;
1946 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1947 structure = gst_caps_get_structure (mediacaps, 0);
1948 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1949 stream->subtype = FOURCC_vide;
1951 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1952 gst_structure_get_int (structure, "height",
1953 &CUR_STREAM (stream)->height);
1954 gst_structure_get_fraction (structure, "framerate",
1955 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1956 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1958 stream->subtype = FOURCC_soun;
1959 gst_structure_get_int (structure, "channels",
1960 &CUR_STREAM (stream)->n_channels);
1961 gst_structure_get_int (structure, "rate", &rate);
1962 CUR_STREAM (stream)->rate = rate;
1963 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1964 if (gst_structure_has_field (structure, "original-media-type")) {
1965 const gchar *media_type =
1966 gst_structure_get_string (structure, "original-media-type");
1967 if (g_str_has_prefix (media_type, "video")) {
1968 stream->subtype = FOURCC_vide;
1969 } else if (g_str_has_prefix (media_type, "audio")) {
1970 stream->subtype = FOURCC_soun;
1975 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1977 demux->mss_mode = FALSE;
1984 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1988 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1990 if (hard || qtdemux->upstream_format_is_time) {
1991 qtdemux->state = QTDEMUX_STATE_INITIAL;
1992 qtdemux->neededbytes = 16;
1993 qtdemux->todrop = 0;
1994 qtdemux->pullbased = FALSE;
1995 g_clear_pointer (&qtdemux->redirect_location, g_free);
1996 qtdemux->first_mdat = -1;
1997 qtdemux->header_size = 0;
1998 qtdemux->mdatoffset = -1;
1999 qtdemux->restoredata_offset = -1;
2000 if (qtdemux->mdatbuffer)
2001 gst_buffer_unref (qtdemux->mdatbuffer);
2002 if (qtdemux->restoredata_buffer)
2003 gst_buffer_unref (qtdemux->restoredata_buffer);
2004 qtdemux->mdatbuffer = NULL;
2005 qtdemux->restoredata_buffer = NULL;
2006 qtdemux->mdatleft = 0;
2007 qtdemux->mdatsize = 0;
2008 if (qtdemux->comp_brands)
2009 gst_buffer_unref (qtdemux->comp_brands);
2010 qtdemux->comp_brands = NULL;
2011 qtdemux->last_moov_offset = -1;
2012 if (qtdemux->moov_node_compressed) {
2013 g_node_destroy (qtdemux->moov_node_compressed);
2014 if (qtdemux->moov_node)
2015 g_free (qtdemux->moov_node->data);
2017 qtdemux->moov_node_compressed = NULL;
2018 if (qtdemux->moov_node)
2019 g_node_destroy (qtdemux->moov_node);
2020 qtdemux->moov_node = NULL;
2021 if (qtdemux->tag_list)
2022 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2023 qtdemux->tag_list = gst_tag_list_new_empty ();
2024 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2026 if (qtdemux->element_index)
2027 gst_object_unref (qtdemux->element_index);
2028 qtdemux->element_index = NULL;
2030 qtdemux->major_brand = 0;
2031 qtdemux->upstream_format_is_time = FALSE;
2032 qtdemux->upstream_seekable = FALSE;
2033 qtdemux->upstream_size = 0;
2035 qtdemux->fragment_start = -1;
2036 qtdemux->fragment_start_offset = -1;
2037 qtdemux->duration = 0;
2038 qtdemux->moof_offset = 0;
2039 qtdemux->chapters_track_id = 0;
2040 qtdemux->have_group_id = FALSE;
2041 qtdemux->group_id = G_MAXUINT;
2043 g_queue_clear_full (&qtdemux->protection_event_queue,
2044 (GDestroyNotify) gst_event_unref);
2046 qtdemux->received_seek = FALSE;
2047 qtdemux->first_moof_already_parsed = FALSE;
2049 qtdemux->offset = 0;
2050 gst_adapter_clear (qtdemux->adapter);
2051 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2052 qtdemux->need_segment = TRUE;
2055 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2056 qtdemux->trickmode_interval = 0;
2057 g_ptr_array_set_size (qtdemux->active_streams, 0);
2058 g_ptr_array_set_size (qtdemux->old_streams, 0);
2059 qtdemux->n_video_streams = 0;
2060 qtdemux->n_audio_streams = 0;
2061 qtdemux->n_sub_streams = 0;
2062 qtdemux->n_meta_streams = 0;
2063 qtdemux->exposed = FALSE;
2064 qtdemux->fragmented = FALSE;
2065 qtdemux->mss_mode = FALSE;
2066 gst_caps_replace (&qtdemux->media_caps, NULL);
2067 qtdemux->timescale = 0;
2068 qtdemux->got_moov = FALSE;
2069 qtdemux->start_utc_time = GST_CLOCK_TIME_NONE;
2070 qtdemux->cenc_aux_info_offset = 0;
2071 g_free (qtdemux->cenc_aux_info_sizes);
2072 qtdemux->cenc_aux_info_sizes = NULL;
2073 qtdemux->cenc_aux_sample_count = 0;
2074 if (qtdemux->protection_system_ids) {
2075 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2076 qtdemux->protection_system_ids = NULL;
2078 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2079 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2080 GST_BIN_FLAG_STREAMS_AWARE);
2082 if (qtdemux->preferred_protection_system_id) {
2083 g_free (qtdemux->preferred_protection_system_id);
2084 qtdemux->preferred_protection_system_id = NULL;
2086 } else if (qtdemux->mss_mode) {
2087 gst_flow_combiner_reset (qtdemux->flowcombiner);
2088 g_ptr_array_foreach (qtdemux->active_streams,
2089 (GFunc) gst_qtdemux_stream_clear, NULL);
2091 gst_flow_combiner_reset (qtdemux->flowcombiner);
2092 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2093 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2094 stream->sent_eos = FALSE;
2095 stream->time_position = 0;
2096 stream->accumulated_base = 0;
2097 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2103 qtdemux_clear_protection_events_on_all_streams (GstQTDemux * qtdemux)
2105 for (unsigned i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2106 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2107 g_queue_clear_full (&stream->protection_scheme_event_queue,
2108 (GDestroyNotify) gst_event_unref);
2112 /* Maps the @segment to the qt edts internal segments and pushes
2113 * the corresponding segment event.
2115 * If it ends up being at a empty segment, a gap will be pushed and the next
2116 * edts segment will be activated in sequence.
2118 * To be used in push-mode only */
2120 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2124 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2125 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2127 stream->time_position = segment->start;
2129 /* in push mode we should be guaranteed that we will have empty segments
2130 * at the beginning and then one segment after, other scenarios are not
2131 * supported and are discarded when parsing the edts */
2132 for (i = 0; i < stream->n_segments; i++) {
2133 if (stream->segments[i].stop_time > segment->start) {
2134 /* push the empty segment and move to the next one */
2135 gst_qtdemux_activate_segment (qtdemux, stream, i,
2136 stream->time_position);
2137 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2138 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2139 stream->time_position);
2141 /* accumulate previous segments */
2142 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2143 stream->accumulated_base +=
2144 (stream->segment.stop -
2145 stream->segment.start) / ABS (stream->segment.rate);
2149 g_assert (i == stream->n_segments - 1);
2156 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2167 for (i = 0; i < len; i++) {
2168 QtDemuxStream *stream = g_ptr_array_index (src, i);
2170 #ifndef GST_DISABLE_GST_DEBUG
2171 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2172 stream, GST_STR_NULL (stream->stream_id), dest);
2174 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2177 g_ptr_array_set_size (src, 0);
2181 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2184 GstQTDemux *demux = GST_QTDEMUX (parent);
2185 gboolean res = TRUE;
2187 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2189 switch (GST_EVENT_TYPE (event)) {
2190 case GST_EVENT_SEGMENT:
2193 QtDemuxStream *stream;
2197 /* some debug output */
2198 gst_event_copy_segment (event, &segment);
2199 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2202 if (segment.format == GST_FORMAT_TIME) {
2203 demux->upstream_format_is_time = TRUE;
2204 demux->segment_seqnum = gst_event_get_seqnum (event);
2206 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2207 "not in time format");
2209 /* chain will send initial newsegment after pads have been added */
2210 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2211 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2216 /* check if this matches a time seek we received previously
2217 * FIXME for backwards compatibility reasons we use the
2218 * seek_offset here to compare. In the future we might want to
2219 * change this to use the seqnum as it uniquely should identify
2220 * the segment that corresponds to the seek. */
2221 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2222 ", received segment offset %" G_GINT64_FORMAT,
2223 demux->seek_offset, segment.start);
2224 if (segment.format == GST_FORMAT_BYTES
2225 && demux->seek_offset == segment.start) {
2226 GST_OBJECT_LOCK (demux);
2227 offset = segment.start;
2229 segment.format = GST_FORMAT_TIME;
2230 segment.start = demux->push_seek_start;
2231 segment.stop = demux->push_seek_stop;
2232 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2233 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2234 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2235 GST_OBJECT_UNLOCK (demux);
2238 /* we only expect a BYTE segment, e.g. following a seek */
2239 if (segment.format == GST_FORMAT_BYTES) {
2240 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2241 offset = segment.start;
2243 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2244 NULL, (gint64 *) & segment.start);
2245 if ((gint64) segment.start < 0)
2248 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2249 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2250 NULL, (gint64 *) & segment.stop);
2251 /* keyframe seeking should already arrange for start >= stop,
2252 * but make sure in other rare cases */
2253 segment.stop = MAX (segment.stop, segment.start);
2255 } else if (segment.format == GST_FORMAT_TIME) {
2256 /* push all data on the adapter before starting this
2258 gst_qtdemux_process_adapter (demux, TRUE);
2260 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2264 /* We shouldn't modify upstream driven TIME FORMAT segment */
2265 if (!demux->upstream_format_is_time) {
2266 /* accept upstream's notion of segment and distribute along */
2267 segment.format = GST_FORMAT_TIME;
2268 segment.position = segment.time = segment.start;
2269 segment.duration = demux->segment.duration;
2270 segment.base = gst_segment_to_running_time (&demux->segment,
2271 GST_FORMAT_TIME, demux->segment.position);
2274 gst_segment_copy_into (&segment, &demux->segment);
2275 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2277 /* map segment to internal qt segments and push on each stream */
2278 if (QTDEMUX_N_STREAMS (demux)) {
2279 demux->need_segment = TRUE;
2280 gst_qtdemux_check_send_pending_segment (demux);
2283 /* clear leftover in current segment, if any */
2284 gst_adapter_clear (demux->adapter);
2286 /* set up streaming thread */
2287 demux->offset = offset;
2288 if (demux->upstream_format_is_time) {
2289 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2290 "set values to restart reading from a new atom");
2291 demux->neededbytes = 16;
2294 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2297 demux->todrop = stream->samples[idx].offset - offset;
2298 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2300 /* set up for EOS */
2301 demux->neededbytes = -1;
2306 gst_event_unref (event);
2310 case GST_EVENT_FLUSH_START:
2312 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2313 gst_event_unref (event);
2316 QTDEMUX_EXPOSE_LOCK (demux);
2317 res = gst_pad_event_default (demux->sinkpad, parent, event);
2318 QTDEMUX_EXPOSE_UNLOCK (demux);
2321 case GST_EVENT_FLUSH_STOP:
2325 dur = demux->segment.duration;
2326 gst_qtdemux_reset (demux, FALSE);
2327 demux->segment.duration = dur;
2329 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2330 gst_event_unref (event);
2336 /* If we are in push mode, and get an EOS before we've seen any streams,
2337 * then error out - we have nowhere to send the EOS */
2338 if (!demux->pullbased) {
2340 gboolean has_valid_stream = FALSE;
2341 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2342 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2343 has_valid_stream = TRUE;
2347 if (!has_valid_stream)
2348 gst_qtdemux_post_no_playable_stream_error (demux);
2350 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2351 (guint) gst_adapter_available (demux->adapter));
2352 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2358 case GST_EVENT_CAPS:{
2359 GstCaps *caps = NULL;
2361 gst_event_parse_caps (event, &caps);
2362 gst_qtdemux_setcaps (demux, caps);
2364 gst_event_unref (event);
2367 case GST_EVENT_PROTECTION:
2369 const gchar *system_id = NULL;
2371 gst_event_parse_protection (event, &system_id, NULL, NULL);
2372 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2374 gst_qtdemux_append_protection_system_id (demux, system_id);
2375 /* save the event for later, for source pads that have not been created */
2376 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2377 /* send it to all pads that already exist */
2378 gst_qtdemux_push_event (demux, event);
2382 case GST_EVENT_STREAM_START:
2385 gst_event_unref (event);
2387 /* Drain all the buffers */
2388 gst_qtdemux_process_adapter (demux, TRUE);
2389 gst_qtdemux_reset (demux, FALSE);
2390 /* We expect new moov box after new stream-start event */
2391 if (demux->exposed) {
2392 gst_qtdemux_stream_concat (demux,
2393 demux->old_streams, demux->active_streams);
2402 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2409 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2412 GstQTDemux *demux = GST_QTDEMUX (parent);
2413 gboolean res = FALSE;
2415 switch (GST_QUERY_TYPE (query)) {
2416 case GST_QUERY_BITRATE:
2418 GstClockTime duration;
2420 /* populate demux->upstream_size if not done yet */
2421 gst_qtdemux_check_seekability (demux);
2423 if (demux->upstream_size != -1
2424 && gst_qtdemux_get_duration (demux, &duration)) {
2426 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2429 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2430 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2431 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2433 /* TODO: better results based on ranges/index tables */
2434 gst_query_set_bitrate (query, bitrate);
2440 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2450 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2452 GstQTDemux *demux = GST_QTDEMUX (element);
2454 GST_OBJECT_LOCK (demux);
2455 if (demux->element_index)
2456 gst_object_unref (demux->element_index);
2458 demux->element_index = gst_object_ref (index);
2460 demux->element_index = NULL;
2462 GST_OBJECT_UNLOCK (demux);
2463 /* object lock might be taken again */
2465 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2466 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2467 demux->element_index, demux->index_id);
2471 gst_qtdemux_get_index (GstElement * element)
2473 GstIndex *result = NULL;
2474 GstQTDemux *demux = GST_QTDEMUX (element);
2476 GST_OBJECT_LOCK (demux);
2477 if (demux->element_index)
2478 result = gst_object_ref (demux->element_index);
2479 GST_OBJECT_UNLOCK (demux);
2481 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2488 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2490 g_free ((gpointer) stream->stco.data);
2491 stream->stco.data = NULL;
2492 g_free ((gpointer) stream->stsz.data);
2493 stream->stsz.data = NULL;
2494 g_free ((gpointer) stream->stsc.data);
2495 stream->stsc.data = NULL;
2496 g_free ((gpointer) stream->stts.data);
2497 stream->stts.data = NULL;
2498 g_free ((gpointer) stream->stss.data);
2499 stream->stss.data = NULL;
2500 g_free ((gpointer) stream->stps.data);
2501 stream->stps.data = NULL;
2502 g_free ((gpointer) stream->ctts.data);
2503 stream->ctts.data = NULL;
2507 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2509 g_free (stream->segments);
2510 stream->segments = NULL;
2511 stream->segment_index = -1;
2512 stream->accumulated_base = 0;
2516 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2518 g_free (stream->samples);
2519 stream->samples = NULL;
2520 gst_qtdemux_stbl_free (stream);
2523 g_free (stream->ra_entries);
2524 stream->ra_entries = NULL;
2525 stream->n_ra_entries = 0;
2527 stream->sample_index = -1;
2528 stream->stbl_index = -1;
2529 stream->n_samples = 0;
2530 stream->time_position = 0;
2532 stream->n_samples_moof = 0;
2533 stream->duration_moof = 0;
2534 stream->duration_last_moof = 0;
2538 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2541 if (stream->allocator)
2542 gst_object_unref (stream->allocator);
2543 while (stream->buffers) {
2544 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2545 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2547 for (i = 0; i < stream->stsd_entries_length; i++) {
2548 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2549 if (entry->rgb8_palette) {
2550 gst_memory_unref (entry->rgb8_palette);
2551 entry->rgb8_palette = NULL;
2553 entry->sparse = FALSE;
2556 if (stream->stream_tags)
2557 gst_tag_list_unref (stream->stream_tags);
2559 stream->stream_tags = gst_tag_list_new_empty ();
2560 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2561 g_free (stream->redirect_uri);
2562 stream->redirect_uri = NULL;
2563 stream->sent_eos = FALSE;
2564 stream->protected = FALSE;
2565 if (stream->protection_scheme_info) {
2566 if (stream->protection_scheme_type == FOURCC_cenc
2567 || stream->protection_scheme_type == FOURCC_cbcs) {
2568 QtDemuxCencSampleSetInfo *info =
2569 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2570 if (info->default_properties)
2571 gst_structure_free (info->default_properties);
2572 if (info->crypto_info)
2573 g_ptr_array_free (info->crypto_info, TRUE);
2575 if (stream->protection_scheme_type == FOURCC_aavd) {
2576 QtDemuxAavdEncryptionInfo *info =
2577 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2578 if (info->default_properties)
2579 gst_structure_free (info->default_properties);
2581 g_free (stream->protection_scheme_info);
2582 stream->protection_scheme_info = NULL;
2584 stream->protection_scheme_type = 0;
2585 stream->protection_scheme_version = 0;
2586 g_queue_clear_full (&stream->protection_scheme_event_queue,
2587 (GDestroyNotify) gst_event_unref);
2588 gst_qtdemux_stream_flush_segments_data (stream);
2589 gst_qtdemux_stream_flush_samples_data (stream);
2593 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2596 gst_qtdemux_stream_clear (stream);
2597 for (i = 0; i < stream->stsd_entries_length; i++) {
2598 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2600 gst_caps_unref (entry->caps);
2604 g_free (stream->stsd_entries);
2605 stream->stsd_entries = NULL;
2606 stream->stsd_entries_length = 0;
2609 static QtDemuxStream *
2610 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2612 g_atomic_int_add (&stream->ref_count, 1);
2618 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2620 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2621 gst_qtdemux_stream_reset (stream);
2622 gst_tag_list_unref (stream->stream_tags);
2624 GstQTDemux *demux = stream->demux;
2625 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2626 GST_OBJECT_LOCK (demux);
2627 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2628 GST_OBJECT_UNLOCK (demux);
2630 g_free (stream->stream_id);
2635 static GstStateChangeReturn
2636 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2638 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2639 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2641 switch (transition) {
2642 case GST_STATE_CHANGE_READY_TO_PAUSED:
2643 gst_qtdemux_reset (qtdemux, TRUE);
2649 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2651 switch (transition) {
2652 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2653 gst_qtdemux_reset (qtdemux, TRUE);
2664 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2666 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2668 g_return_if_fail (GST_IS_CONTEXT (context));
2670 if (gst_context_has_context_type (context,
2671 "drm-preferred-decryption-system-id")) {
2672 const GstStructure *s;
2674 s = gst_context_get_structure (context);
2675 g_free (qtdemux->preferred_protection_system_id);
2676 qtdemux->preferred_protection_system_id =
2677 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2678 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2679 qtdemux->preferred_protection_system_id);
2682 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2686 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2688 /* counts as header data */
2689 qtdemux->header_size += length;
2691 /* only consider at least a sufficiently complete ftyp atom */
2694 guint32 minor_version;
2697 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2698 GST_DEBUG_OBJECT (qtdemux, "ftyp major brand: %" GST_FOURCC_FORMAT,
2699 GST_FOURCC_ARGS (qtdemux->major_brand));
2700 minor_version = QT_UINT32 (buffer + 12);
2701 GST_DEBUG_OBJECT (qtdemux, "ftyp minor version: %u", minor_version);
2702 if (qtdemux->comp_brands)
2703 gst_buffer_unref (qtdemux->comp_brands);
2704 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2705 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2708 length = length - 16;
2709 while (length > 0) {
2710 GST_DEBUG_OBJECT (qtdemux, "ftyp compatible brand: %" GST_FOURCC_FORMAT,
2711 GST_FOURCC_ARGS (QT_FOURCC (p)));
2719 qtdemux_parse_styp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2721 /* only consider at least a sufficiently complete styp atom */
2724 guint32 major_brand;
2725 guint32 minor_version;
2728 major_brand = QT_FOURCC (buffer + 8);
2729 GST_DEBUG_OBJECT (qtdemux, "styp major brand: %" GST_FOURCC_FORMAT,
2730 GST_FOURCC_ARGS (major_brand));
2731 minor_version = QT_UINT32 (buffer + 12);
2732 GST_DEBUG_OBJECT (qtdemux, "styp minor version: %u", minor_version);
2733 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2734 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2737 length = length - 16;
2738 while (length > 0) {
2739 GST_DEBUG_OBJECT (qtdemux, "styp compatible brand: %" GST_FOURCC_FORMAT,
2740 GST_FOURCC_ARGS (QT_FOURCC (p)));
2748 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2749 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2750 guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2751 guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2752 const guint8 * constant_iv)
2754 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2755 gst_buffer_fill (kid_buf, 0, kid, 16);
2756 if (info->default_properties)
2757 gst_structure_free (info->default_properties);
2758 info->default_properties =
2759 gst_structure_new ("application/x-cenc",
2760 "iv_size", G_TYPE_UINT, iv_size,
2761 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2762 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2763 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2764 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2765 gst_buffer_unref (kid_buf);
2766 if (protection_scheme_type == FOURCC_cbcs) {
2767 if (crypt_byte_block != 0 || skip_byte_block != 0) {
2768 gst_structure_set (info->default_properties, "crypt_byte_block",
2769 G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2770 skip_byte_block, NULL);
2772 if (constant_iv != NULL) {
2773 GstBuffer *constant_iv_buf =
2774 gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2775 gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2776 gst_structure_set (info->default_properties, "constant_iv_size",
2777 G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2779 gst_buffer_unref (constant_iv_buf);
2781 gst_structure_set (info->default_properties, "cipher-mode",
2782 G_TYPE_STRING, "cbcs", NULL);
2784 gst_structure_set (info->default_properties, "cipher-mode",
2785 G_TYPE_STRING, "cenc", NULL);
2790 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2791 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2793 guint32 algorithm_id = 0;
2795 gboolean is_encrypted = TRUE;
2798 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2799 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2804 if (algorithm_id == 0) {
2805 is_encrypted = FALSE;
2806 } else if (algorithm_id == 1) {
2807 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2808 } else if (algorithm_id == 2) {
2809 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2812 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2815 if (!gst_byte_reader_get_data (br, 16, &kid))
2818 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2819 is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2820 gst_structure_set (info->default_properties, "piff_algorithm_id",
2821 G_TYPE_UINT, algorithm_id, NULL);
2827 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2835 QtDemuxStream *stream;
2836 GstStructure *structure;
2837 QtDemuxCencSampleSetInfo *ss_info = NULL;
2838 const gchar *system_id;
2839 gboolean uses_sub_sample_encryption = FALSE;
2840 guint32 sample_count;
2842 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2845 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2847 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2848 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2849 GST_WARNING_OBJECT (qtdemux,
2850 "Attempting PIFF box parsing on an unencrypted stream.");
2854 if (!gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2855 G_TYPE_STRING, &system_id, NULL)) {
2856 GST_WARNING_OBJECT (qtdemux, "%s field not present in caps",
2857 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD);
2861 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2863 stream->protected = TRUE;
2864 stream->protection_scheme_type = FOURCC_cenc;
2866 if (!stream->protection_scheme_info)
2867 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2869 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2870 if (!ss_info->default_properties) {
2871 ss_info->default_properties =
2872 gst_structure_new ("application/x-cenc",
2873 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2878 if (ss_info->crypto_info) {
2879 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2880 g_ptr_array_free (ss_info->crypto_info, TRUE);
2881 ss_info->crypto_info = NULL;
2885 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2887 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2888 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2892 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2893 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2897 if ((flags & 0x000001)) {
2898 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2901 } else if ((flags & 0x000002)) {
2902 uses_sub_sample_encryption = TRUE;
2905 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2907 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2911 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2912 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2916 ss_info->crypto_info =
2917 g_ptr_array_new_full (sample_count,
2918 (GDestroyNotify) qtdemux_gst_structure_free);
2920 for (i = 0; i < sample_count; ++i) {
2921 GstStructure *properties;
2925 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2926 if (properties == NULL) {
2927 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2928 qtdemux->cenc_aux_sample_count = i;
2932 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2933 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2934 gst_structure_free (properties);
2935 qtdemux->cenc_aux_sample_count = i;
2938 buf = gst_buffer_new_wrapped (data, iv_size);
2939 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2940 gst_buffer_unref (buf);
2942 if (uses_sub_sample_encryption) {
2943 guint16 n_subsamples;
2944 const GValue *kid_buf_value;
2946 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2947 || n_subsamples == 0) {
2948 GST_ERROR_OBJECT (qtdemux,
2949 "failed to get subsample count for sample %u", i);
2950 gst_structure_free (properties);
2951 qtdemux->cenc_aux_sample_count = i;
2954 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2955 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2956 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2958 gst_structure_free (properties);
2959 qtdemux->cenc_aux_sample_count = i;
2962 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2965 gst_structure_get_value (ss_info->default_properties, "kid");
2967 gst_structure_set (properties,
2968 "subsample_count", G_TYPE_UINT, n_subsamples,
2969 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2970 gst_structure_set_value (properties, "kid", kid_buf_value);
2971 gst_buffer_unref (buf);
2973 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2976 g_ptr_array_add (ss_info->crypto_info, properties);
2979 qtdemux->cenc_aux_sample_count = sample_count;
2983 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2985 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2986 0x97, 0xA9, 0x42, 0xE8,
2987 0x9C, 0x71, 0x99, 0x94,
2988 0x91, 0xE3, 0xAF, 0xAC
2990 static const guint8 playready_uuid[] = {
2991 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2992 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2995 static const guint8 piff_sample_encryption_uuid[] = {
2996 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2997 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
3002 /* counts as header data */
3003 qtdemux->header_size += length;
3005 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3007 if (length <= offset + 16) {
3008 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
3012 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
3014 GstTagList *taglist;
3016 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3017 length - offset - 16, NULL);
3018 taglist = gst_tag_list_from_xmp_buffer (buf);
3019 gst_buffer_unref (buf);
3021 /* make sure we have a usable taglist */
3022 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3024 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3026 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3028 const gunichar2 *s_utf16;
3031 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3032 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3033 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3034 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3038 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3039 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3041 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3042 qtdemux_parse_piff (qtdemux, buffer, length, offset);
3044 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3045 GST_READ_UINT32_LE (buffer + offset),
3046 GST_READ_UINT32_LE (buffer + offset + 4),
3047 GST_READ_UINT32_LE (buffer + offset + 8),
3048 GST_READ_UINT32_LE (buffer + offset + 12));
3053 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3055 GstSidxParser sidx_parser;
3056 GstIsoffParserResult res;
3059 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3062 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3064 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3065 if (res == GST_ISOFF_QT_PARSER_DONE) {
3066 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3068 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3072 qtdemux_parse_cstb (GstQTDemux * qtdemux, GstByteReader * data)
3075 guint32 entry_count;
3077 GST_DEBUG_OBJECT (qtdemux, "Parsing CorrectStartTime box");
3079 qtdemux->start_utc_time = GST_CLOCK_TIME_NONE;
3081 if (gst_byte_reader_get_remaining (data) < 4) {
3082 GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box");
3086 entry_count = gst_byte_reader_get_uint32_be_unchecked (data);
3087 if (entry_count == 0)
3090 /* XXX: We assume that all start times are the same as different start times
3091 * would violate the MP4 synchronization model, so we just take the first
3092 * one here and apply it to all tracks.
3095 if (gst_byte_reader_get_remaining (data) < entry_count * 12) {
3096 GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box");
3101 gst_byte_reader_skip_unchecked (data, 4);
3103 /* In 100ns intervals */
3104 start_time = gst_byte_reader_get_uint64_be_unchecked (data);
3106 /* Convert from Jan 1 1601 to Jan 1 1970 */
3107 if (start_time < 11644473600 * G_GUINT64_CONSTANT (10000000)) {
3108 GST_WARNING_OBJECT (qtdemux, "Start UTC time before UNIX epoch");
3111 start_time -= 11644473600 * G_GUINT64_CONSTANT (10000000);
3113 /* Convert to GstClockTime */
3116 GST_DEBUG_OBJECT (qtdemux, "Start UTC time: %" GST_TIME_FORMAT,
3117 GST_TIME_ARGS (start_time));
3119 qtdemux->start_utc_time = start_time;
3122 /* caller verifies at least 8 bytes in buf */
3124 extract_initial_length_and_fourcc (const guint8 * data, gsize size,
3125 guint64 * plength, guint32 * pfourcc)
3130 length = QT_UINT32 (data);
3131 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3132 fourcc = QT_FOURCC (data + 4);
3133 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3136 length = G_MAXUINT64;
3137 } else if (length == 1 && size >= 16) {
3138 /* this means we have an extended size, which is the 64 bit value of
3139 * the next 8 bytes */
3140 length = QT_UINT64 (data + 8);
3141 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3151 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3153 guint32 version = 0;
3154 GstClockTime duration = 0;
3156 if (!gst_byte_reader_get_uint32_be (br, &version))
3161 if (!gst_byte_reader_get_uint64_be (br, &duration))
3166 if (!gst_byte_reader_get_uint32_be (br, &dur))
3171 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3172 qtdemux->duration = duration;
3178 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3184 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3185 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3187 if (!stream->parsed_trex && qtdemux->moov_node) {
3189 GstByteReader trex_data;
3191 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3193 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3196 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3198 /* skip version/flags */
3199 if (!gst_byte_reader_skip (&trex_data, 4))
3201 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3203 if (id != stream->track_id)
3205 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3207 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3209 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3211 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3214 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3215 "duration %d, size %d, flags 0x%x", stream->track_id,
3218 stream->parsed_trex = TRUE;
3219 stream->def_sample_description_index = sdi;
3220 stream->def_sample_duration = dur;
3221 stream->def_sample_size = size;
3222 stream->def_sample_flags = flags;
3225 /* iterate all siblings */
3226 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3232 *ds_duration = stream->def_sample_duration;
3233 *ds_size = stream->def_sample_size;
3234 *ds_flags = stream->def_sample_flags;
3236 /* even then, above values are better than random ... */
3237 if (G_UNLIKELY (!stream->parsed_trex)) {
3238 GST_WARNING_OBJECT (qtdemux,
3239 "failed to find fragment defaults for stream %d", stream->track_id);
3246 /* This method should be called whenever a more accurate duration might
3247 * have been found. It will update all relevant variables if/where needed
3250 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3254 GstClockTime prevdur;
3256 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3258 if (movdur > qtdemux->duration) {
3259 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3260 GST_DEBUG_OBJECT (qtdemux,
3261 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3262 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3263 qtdemux->duration = movdur;
3264 GST_DEBUG_OBJECT (qtdemux,
3265 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3266 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3267 GST_TIME_ARGS (qtdemux->segment.stop));
3268 if (qtdemux->segment.duration == prevdur) {
3269 /* If the current segment has duration/stop identical to previous duration
3270 * update them also (because they were set at that point in time with
3271 * the wrong duration */
3272 /* We convert the value *from* the timescale version to avoid rounding errors */
3273 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3274 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3275 qtdemux->segment.duration = fixeddur;
3276 qtdemux->segment.stop = fixeddur;
3280 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3281 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3283 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3284 if (movdur > stream->duration) {
3285 GST_DEBUG_OBJECT (qtdemux,
3286 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3287 GST_TIME_ARGS (duration));
3288 stream->duration = movdur;
3289 /* internal duration tracking state has been updated above, so */
3290 /* preserve an open-ended dummy segment rather than repeatedly updating
3291 * it and spamming downstream accordingly with segment events */
3292 /* also mangle the edit list end time when fragmented with a single edit
3293 * list that may only cover any non-fragmented data */
3294 if ((stream->dummy_segment ||
3295 (qtdemux->fragmented && stream->n_segments == 1)) &&
3296 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3297 /* Update all dummy values to new duration */
3298 stream->segments[0].stop_time = duration;
3299 stream->segments[0].duration = duration;
3300 stream->segments[0].media_stop = duration;
3302 /* let downstream know we possibly have a new stop time */
3303 if (stream->segment_index != -1) {
3306 if (qtdemux->segment.rate >= 0) {
3307 pos = stream->segment.start;
3309 pos = stream->segment.stop;
3312 gst_qtdemux_stream_update_segment (qtdemux, stream,
3313 stream->segment_index, pos, NULL, NULL);
3321 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3322 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3323 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3324 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3327 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3329 gint32 data_offset = 0;
3331 guint32 flags = 0, first_flags = 0, samples_count = 0;
3334 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3335 QtDemuxSample *sample;
3336 gboolean ismv = FALSE;
3337 gint64 initial_offset;
3340 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3341 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3342 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3343 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3345 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3346 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3350 /* presence of stss or not can't really tell us much,
3351 * and flags and so on tend to be marginally reliable in these files */
3352 if (stream->subtype == FOURCC_soun) {
3353 GST_DEBUG_OBJECT (qtdemux,
3354 "sound track in fragmented file; marking all keyframes");
3355 stream->all_keyframe = TRUE;
3358 if (!gst_byte_reader_get_uint8 (trun, &version) ||
3359 !gst_byte_reader_get_uint24_be (trun, &flags))
3362 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3365 if (flags & TR_DATA_OFFSET) {
3366 /* note this is really signed */
3367 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3369 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3370 /* default base offset = first byte of moof */
3371 if (*base_offset == -1) {
3372 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3373 *base_offset = moof_offset;
3375 *running_offset = *base_offset + data_offset;
3377 /* if no offset at all, that would mean data starts at moof start,
3378 * which is a bit wrong and is ismv crappy way, so compensate
3379 * assuming data is in mdat following moof */
3380 if (*base_offset == -1) {
3381 *base_offset = moof_offset + moof_length + 8;
3382 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3385 if (*running_offset == -1)
3386 *running_offset = *base_offset;
3389 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3391 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3392 data_offset, flags, samples_count);
3394 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3395 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3396 GST_DEBUG_OBJECT (qtdemux,
3397 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3398 flags ^= TR_FIRST_SAMPLE_FLAGS;
3400 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3402 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3406 /* FIXME ? spec says other bits should also be checked to determine
3407 * entry size (and prefix size for that matter) */
3409 dur_offset = size_offset = 0;
3410 if (flags & TR_SAMPLE_DURATION) {
3411 GST_LOG_OBJECT (qtdemux, "entry duration present");
3412 dur_offset = entry_size;
3415 if (flags & TR_SAMPLE_SIZE) {
3416 GST_LOG_OBJECT (qtdemux, "entry size present");
3417 size_offset = entry_size;
3420 if (flags & TR_SAMPLE_FLAGS) {
3421 GST_LOG_OBJECT (qtdemux, "entry flags present");
3422 flags_offset = entry_size;
3425 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3426 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3427 ct_offset = entry_size;
3431 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3433 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3435 if (stream->n_samples + samples_count >=
3436 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3439 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3440 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3441 (stream->n_samples + samples_count) *
3442 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3444 /* create a new array of samples if it's the first sample parsed */
3445 if (stream->n_samples == 0) {
3446 g_assert (stream->samples == NULL);
3447 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3448 /* or try to reallocate it with space enough to insert the new samples */
3450 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3451 stream->n_samples + samples_count);
3452 if (stream->samples == NULL)
3455 if (qtdemux->fragment_start != -1) {
3456 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3457 qtdemux->fragment_start = -1;
3459 if (stream->n_samples == 0) {
3460 if (decode_ts > 0) {
3461 timestamp = decode_ts;
3462 } else if (stream->pending_seek != NULL) {
3463 /* if we don't have a timestamp from a tfdt box, we'll use the one
3464 * from the mfra seek table */
3465 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3466 GST_TIME_ARGS (stream->pending_seek->ts));
3468 /* FIXME: this is not fully correct, the timestamp refers to the random
3469 * access sample refered to in the tfra entry, which may not necessarily
3470 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3471 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3476 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3477 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3478 GST_TIME_ARGS (gst_ts));
3480 /* If this is a GST_FORMAT_BYTES stream and we have a tfdt then use it
3481 * instead of the sum of sample durations */
3482 if (has_tfdt && !qtdemux->upstream_format_is_time) {
3483 timestamp = decode_ts;
3484 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3485 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3486 " (using tfdt)", GST_TIME_ARGS (gst_ts));
3488 /* subsequent fragments extend stream */
3490 stream->samples[stream->n_samples - 1].timestamp +
3491 stream->samples[stream->n_samples - 1].duration;
3492 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3493 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3494 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3499 initial_offset = *running_offset;
3501 sample = stream->samples + stream->n_samples;
3502 for (i = 0; i < samples_count; i++) {
3503 guint32 dur, size, sflags;
3506 /* first read sample data */
3507 if (flags & TR_SAMPLE_DURATION) {
3508 dur = QT_UINT32 (data + dur_offset);
3510 dur = d_sample_duration;
3512 if (flags & TR_SAMPLE_SIZE) {
3513 size = QT_UINT32 (data + size_offset);
3515 size = d_sample_size;
3517 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3519 sflags = first_flags;
3521 sflags = d_sample_flags;
3523 } else if (flags & TR_SAMPLE_FLAGS) {
3524 sflags = QT_UINT32 (data + flags_offset);
3526 sflags = d_sample_flags;
3529 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3530 /* Read offsets as signed numbers regardless of trun version as very
3531 * high offsets are unlikely and there are files out there that use
3532 * version=0 truns with negative offsets */
3533 ct = QT_UINT32 (data + ct_offset);
3535 /* FIXME: Set offset to 0 for "no decode samples". This needs
3536 * to be handled in a codec specific manner ideally. */
3537 if (ct == G_MININT32)
3544 /* fill the sample information */
3545 sample->offset = *running_offset;
3546 sample->pts_offset = ct;
3547 sample->size = size;
3548 sample->timestamp = timestamp;
3549 sample->duration = dur;
3550 /* sample-is-difference-sample */
3551 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3552 * now idea how it relates to bitfield other than massive LE/BE confusion */
3553 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3554 *running_offset += size;
3556 stream->duration_moof += dur;
3563 /* Shift PTS/DTS to allow for negative composition offsets while keeping
3564 * A/V sync in place. This is similar to the code handling ctts/cslg in the
3565 * non-fragmented case.
3568 stream->cslg_shift = -min_ct;
3570 stream->cslg_shift = 0;
3572 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
3573 stream->cslg_shift);
3575 /* Update total duration if needed */
3576 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3578 /* Pre-emptively figure out size of mdat based on trun information.
3579 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3580 * size, else we will still be able to use this when dealing with gap'ed
3582 qtdemux->mdatleft = *running_offset - initial_offset;
3583 qtdemux->mdatoffset = initial_offset;
3584 qtdemux->mdatsize = qtdemux->mdatleft;
3586 stream->n_samples += samples_count;
3587 stream->n_samples_moof += samples_count;
3589 if (stream->pending_seek != NULL)
3590 stream->pending_seek = NULL;
3596 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3601 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3607 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3608 "be larger than %uMB (broken file?)", stream->n_samples,
3609 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3614 /* find stream with @id */
3615 static inline QtDemuxStream *
3616 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3618 QtDemuxStream *stream;
3622 if (G_UNLIKELY (!id)) {
3623 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3627 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3628 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3629 if (stream->track_id == id)
3632 if (qtdemux->mss_mode) {
3633 /* mss should have only 1 stream anyway */
3634 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3641 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3642 guint32 * fragment_number)
3644 if (!gst_byte_reader_skip (mfhd, 4))
3646 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3651 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3657 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3658 QtDemuxStream ** stream, guint32 * default_sample_duration,
3659 guint32 * default_sample_size, guint32 * default_sample_flags,
3660 gint64 * base_offset)
3663 guint32 track_id = 0;
3665 if (!gst_byte_reader_skip (tfhd, 1) ||
3666 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3669 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3672 *stream = qtdemux_find_stream (qtdemux, track_id);
3673 if (G_UNLIKELY (!*stream))
3674 goto unknown_stream;
3676 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3677 *base_offset = qtdemux->moof_offset;
3679 if (flags & TF_BASE_DATA_OFFSET)
3680 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3683 /* obtain stream defaults */
3684 if (qtdemux_parse_trex (qtdemux, *stream,
3685 default_sample_duration, default_sample_size, default_sample_flags)) {
3687 /* Default sample description index is only valid if trex parsing succeeded */
3688 (*stream)->stsd_sample_description_id =
3689 (*stream)->def_sample_description_index - 1;
3692 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3693 guint32 sample_description_index;
3694 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3696 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3699 if (qtdemux->mss_mode) {
3700 /* mss has no stsd entry */
3701 (*stream)->stsd_sample_description_id = 0;
3704 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3705 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3708 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3709 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3712 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3713 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3720 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3725 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3731 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3732 guint64 * decode_time)
3734 guint32 version = 0;
3736 if (!gst_byte_reader_get_uint32_be (br, &version))
3741 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3744 guint32 dec_time = 0;
3745 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3747 *decode_time = dec_time;
3750 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3757 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3762 /* Returns a pointer to a GstStructure containing the properties of
3763 * the stream sample identified by @sample_index. The caller must unref
3764 * the returned object after use. Returns NULL if unsuccessful. */
3765 static GstStructure *
3766 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3767 QtDemuxStream * stream, guint sample_index)
3769 QtDemuxCencSampleSetInfo *info = NULL;
3771 g_return_val_if_fail (stream != NULL, NULL);
3772 g_return_val_if_fail (stream->protected, NULL);
3773 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3775 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3777 /* Currently, cenc properties for groups of samples are not supported, so
3778 * simply return a copy of the default sample properties */
3779 return gst_structure_copy (info->default_properties);
3782 /* Parses the sizes of sample auxiliary information contained within a stream,
3783 * as given in a saiz box. Returns array of sample_count guint8 size values,
3784 * or NULL on failure */
3786 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3787 GstByteReader * br, guint32 * sample_count)
3791 guint8 default_info_size;
3793 g_return_val_if_fail (qtdemux != NULL, NULL);
3794 g_return_val_if_fail (stream != NULL, NULL);
3795 g_return_val_if_fail (br != NULL, NULL);
3796 g_return_val_if_fail (sample_count != NULL, NULL);
3798 if (!gst_byte_reader_get_uint32_be (br, &flags))
3802 /* aux_info_type and aux_info_type_parameter are ignored */
3803 if (!gst_byte_reader_skip (br, 8))
3807 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3809 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3811 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3813 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3816 if (default_info_size == 0) {
3817 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3821 info_sizes = g_new (guint8, *sample_count);
3822 memset (info_sizes, default_info_size, *sample_count);
3828 /* Parses the offset of sample auxiliary information contained within a stream,
3829 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3831 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3832 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3837 guint32 aux_info_type = 0;
3838 guint32 aux_info_type_parameter = 0;
3839 guint32 entry_count;
3842 const guint8 *aux_info_type_data = NULL;
3844 g_return_val_if_fail (qtdemux != NULL, FALSE);
3845 g_return_val_if_fail (stream != NULL, FALSE);
3846 g_return_val_if_fail (br != NULL, FALSE);
3847 g_return_val_if_fail (offset != NULL, FALSE);
3849 if (!gst_byte_reader_get_uint8 (br, &version))
3852 if (!gst_byte_reader_get_uint24_be (br, &flags))
3857 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3859 aux_info_type = QT_FOURCC (aux_info_type_data);
3861 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3863 } else if (stream->protected) {
3864 aux_info_type = stream->protection_scheme_type;
3866 aux_info_type = CUR_STREAM (stream)->fourcc;
3870 *info_type = aux_info_type;
3871 if (info_type_parameter)
3872 *info_type_parameter = aux_info_type_parameter;
3874 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3875 "aux_info_type_parameter: %#06x",
3876 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3878 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3881 if (entry_count != 1) {
3882 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3887 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3889 *offset = (guint64) off_32;
3891 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3896 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3901 qtdemux_gst_structure_free (GstStructure * gststructure)
3904 gst_structure_free (gststructure);
3908 /* Parses auxiliary information relating to samples protected using
3909 * Common Encryption (cenc); the format of this information
3910 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3913 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3914 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3916 QtDemuxCencSampleSetInfo *ss_info = NULL;
3919 GPtrArray *old_crypto_info = NULL;
3920 guint old_entries = 0;
3922 g_return_val_if_fail (qtdemux != NULL, FALSE);
3923 g_return_val_if_fail (stream != NULL, FALSE);
3924 g_return_val_if_fail (br != NULL, FALSE);
3925 g_return_val_if_fail (stream->protected, FALSE);
3926 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3928 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3930 if (ss_info->crypto_info) {
3931 old_crypto_info = ss_info->crypto_info;
3932 /* Count number of non-null entries remaining at the tail end */
3933 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3934 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3940 ss_info->crypto_info =
3941 g_ptr_array_new_full (sample_count + old_entries,
3942 (GDestroyNotify) qtdemux_gst_structure_free);
3944 /* We preserve old entries because we parse the next moof in advance
3945 * of consuming all samples from the previous moof, and otherwise
3946 * we'd discard the corresponding crypto info for the samples
3947 * from the previous fragment. */
3949 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3951 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3952 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3954 g_ptr_array_index (old_crypto_info, i) = NULL;
3958 if (old_crypto_info) {
3959 /* Everything now belongs to the new array */
3960 g_ptr_array_free (old_crypto_info, TRUE);
3963 for (i = 0; i < sample_count; ++i) {
3964 GstStructure *properties;
3965 guint16 n_subsamples = 0;
3969 gboolean could_read_iv;
3971 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3972 if (properties == NULL) {
3973 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3976 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3977 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3978 gst_structure_free (properties);
3982 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3983 if (could_read_iv) {
3984 buf = gst_buffer_new_wrapped (data, iv_size);
3985 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3986 gst_buffer_unref (buf);
3987 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3988 const GValue *constant_iv_size_value =
3989 gst_structure_get_value (properties, "constant_iv_size");
3990 const GValue *constant_iv_value =
3991 gst_structure_get_value (properties, "iv");
3992 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3993 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3994 gst_structure_free (properties);
3997 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3998 gst_structure_remove_field (properties, "constant_iv_size");
3999 } else if (stream->protection_scheme_type == FOURCC_cenc) {
4000 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
4001 gst_structure_free (properties);
4004 size = info_sizes[i];
4005 if (size > iv_size) {
4006 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
4007 || !(n_subsamples > 0)) {
4008 gst_structure_free (properties);
4009 GST_ERROR_OBJECT (qtdemux,
4010 "failed to get subsample count for sample %u", i);
4013 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
4014 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
4015 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
4017 gst_structure_free (properties);
4020 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
4022 gst_structure_free (properties);
4025 gst_structure_set (properties,
4026 "subsample_count", G_TYPE_UINT, n_subsamples,
4027 "subsamples", GST_TYPE_BUFFER, buf, NULL);
4028 gst_buffer_unref (buf);
4030 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
4032 g_ptr_array_add (ss_info->crypto_info, properties);
4037 /* Converts a UUID in raw byte form to a string representation, as defined in
4038 * RFC 4122. The caller takes ownership of the returned string and is
4039 * responsible for freeing it after use. */
4041 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
4043 const guint8 *uuid = (const guint8 *) uuid_bytes;
4045 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
4046 "%02x%02x-%02x%02x%02x%02x%02x%02x",
4047 uuid[0], uuid[1], uuid[2], uuid[3],
4048 uuid[4], uuid[5], uuid[6], uuid[7],
4049 uuid[8], uuid[9], uuid[10], uuid[11],
4050 uuid[12], uuid[13], uuid[14], uuid[15]);
4053 /* Parses a Protection System Specific Header box (pssh), as defined in the
4054 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
4055 * information needed by a specific content protection system in order to
4056 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
4059 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4061 gchar *sysid_string;
4062 guint32 pssh_size = QT_UINT32 (node->data);
4063 GstBuffer *pssh = NULL;
4064 GstEvent *event = NULL;
4065 guint32 parent_box_type;
4068 if (G_UNLIKELY (pssh_size < 32U)) {
4069 GST_ERROR_OBJECT (qtdemux, "invalid box size");
4074 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4076 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4078 pssh = gst_buffer_new_memdup (node->data, pssh_size);
4079 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4080 gst_buffer_get_size (pssh));
4082 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4084 /* Push an event containing the pssh box onto the queues of all streams. */
4085 event = gst_event_new_protection (sysid_string, pssh,
4086 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4087 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4088 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4089 GST_TRACE_OBJECT (qtdemux,
4090 "adding protection event for stream %s and system %s",
4091 stream->stream_id, sysid_string);
4092 g_queue_push_tail (&stream->protection_scheme_event_queue,
4093 gst_event_ref (event));
4095 g_free (sysid_string);
4096 gst_event_unref (event);
4097 gst_buffer_unref (pssh);
4102 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4103 guint64 moof_offset, QtDemuxStream * stream)
4105 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4107 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4108 GNode *saiz_node, *saio_node, *pssh_node;
4109 GstByteReader saiz_data, saio_data;
4110 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4111 gint64 base_offset, running_offset;
4113 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4115 /* NOTE @stream ignored */
4117 moof_node = g_node_new ((guint8 *) buffer);
4118 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4119 qtdemux_node_dump (qtdemux, moof_node);
4121 /* Get fragment number from mfhd and check it's valid */
4123 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4124 if (mfhd_node == NULL)
4126 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4128 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4130 /* unknown base_offset to start with */
4131 base_offset = running_offset = -1;
4132 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4134 guint64 decode_time = 0;
4136 /* Fragment Header node */
4138 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4142 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4143 &ds_size, &ds_flags, &base_offset))
4146 /* The following code assumes at most a single set of sample auxiliary
4147 * data in the fragment (consisting of a saiz box and a corresponding saio
4148 * box); in theory, however, there could be multiple sets of sample
4149 * auxiliary data in a fragment. */
4151 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4154 guint32 info_type = 0;
4156 guint32 info_type_parameter = 0;
4158 g_free (qtdemux->cenc_aux_info_sizes);
4160 qtdemux->cenc_aux_info_sizes =
4161 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4162 &qtdemux->cenc_aux_sample_count);
4163 if (qtdemux->cenc_aux_info_sizes == NULL) {
4164 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4168 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4171 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4172 g_free (qtdemux->cenc_aux_info_sizes);
4173 qtdemux->cenc_aux_info_sizes = NULL;
4177 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4178 &info_type, &info_type_parameter, &offset))) {
4179 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4180 g_free (qtdemux->cenc_aux_info_sizes);
4181 qtdemux->cenc_aux_info_sizes = NULL;
4184 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4185 offset += (guint64) (base_offset - qtdemux->moof_offset);
4186 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4187 && info_type_parameter == 0U) {
4189 if (offset > length) {
4190 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4191 qtdemux->cenc_aux_info_offset = offset;
4193 gst_byte_reader_init (&br, buffer + offset, length - offset);
4194 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4195 qtdemux->cenc_aux_info_sizes,
4196 qtdemux->cenc_aux_sample_count)) {
4197 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4198 g_free (qtdemux->cenc_aux_info_sizes);
4199 qtdemux->cenc_aux_info_sizes = NULL;
4207 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4210 /* We'll use decode_time to interpolate timestamps
4211 * in case the input timestamps are missing */
4212 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4214 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4215 " (%" GST_TIME_FORMAT ")", decode_time,
4216 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4217 decode_time) : GST_CLOCK_TIME_NONE));
4219 /* Discard the fragment buffer timestamp info to avoid using it.
4220 * Rely on tfdt instead as it is more accurate than the timestamp
4221 * that is fetched from a manifest/playlist and is usually
4223 qtdemux->fragment_start = -1;
4226 if (G_UNLIKELY (!stream)) {
4227 /* we lost track of offset, we'll need to regain it,
4228 * but can delay complaining until later or avoid doing so altogether */
4232 if (G_UNLIKELY (base_offset < -1))
4235 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4237 if (!qtdemux->pullbased) {
4238 /* Sample tables can grow enough to be problematic if the system memory
4239 * is very low (e.g. embedded devices) and the videos very long
4240 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4241 * Fortunately, we can easily discard them for each new fragment when
4242 * we know qtdemux will not receive seeks outside of the current fragment.
4243 * adaptivedemux honors this assumption.
4244 * This optimization is also useful for applications that use qtdemux as
4245 * a push-based simple demuxer, like Media Source Extensions. */
4246 gst_qtdemux_stream_flush_samples_data (stream);
4249 /* initialise moof sample data */
4250 stream->n_samples_moof = 0;
4251 stream->duration_last_moof = stream->duration_moof;
4252 stream->duration_moof = 0;
4254 /* Track Run node */
4256 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4259 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4260 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4261 &running_offset, decode_time, (tfdt_node != NULL));
4262 /* iterate all siblings */
4263 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4265 /* don't use tfdt for subsequent trun as it only refers to the first */
4269 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4271 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4272 guint32 box_length = QT_UINT32 (uuid_buffer);
4274 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4277 /* if no new base_offset provided for next traf,
4278 * base is end of current traf */
4279 base_offset = running_offset;
4280 running_offset = -1;
4282 if (stream->n_samples_moof && stream->duration_moof)
4283 stream->new_caps = TRUE;
4286 /* iterate all siblings */
4287 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4290 /* parse any protection system info */
4291 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4293 /* Unref old protection events if we are going to receive new ones. */
4294 qtdemux_clear_protection_events_on_all_streams (qtdemux);
4297 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4298 qtdemux_parse_pssh (qtdemux, pssh_node);
4299 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4302 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4303 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4305 /* Unless the user has explicitly requested another seek, perform an
4306 * internal seek to the time specified in the tfdt.
4308 * This way if the user opens a file where the first tfdt is 1 hour
4309 * into the presentation, they will not have to wait 1 hour for run
4310 * time to catch up and actual playback to start. */
4313 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4314 "performing an internal seek to %" GST_TIME_FORMAT,
4315 GST_TIME_ARGS (min_dts));
4317 qtdemux->segment.start = min_dts;
4318 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4320 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4321 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4322 stream->time_position = min_dts;
4325 /* Before this code was run a segment was already sent when the moov was
4326 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4327 * be emitted after a moov, and we can emit a second segment anyway for
4328 * special cases like this. */
4329 qtdemux->need_segment = TRUE;
4332 qtdemux->first_moof_already_parsed = TRUE;
4334 g_node_destroy (moof_node);
4339 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4344 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4349 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4354 g_node_destroy (moof_node);
4355 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4356 (_("This file is corrupt and cannot be played.")), (NULL));
4362 /* might be used if some day we actually use mfra & co
4363 * for random access to fragments,
4364 * but that will require quite some modifications and much less relying
4365 * on a sample array */
4369 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4371 QtDemuxStream *stream;
4372 guint32 ver_flags, track_id, len, num_entries, i;
4373 guint value_size, traf_size, trun_size, sample_size;
4374 guint64 time = 0, moof_offset = 0;
4376 GstBuffer *buf = NULL;
4381 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4383 if (!gst_byte_reader_skip (&tfra, 8))
4386 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4389 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4390 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4391 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4394 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4396 stream = qtdemux_find_stream (qtdemux, track_id);
4398 goto unknown_trackid;
4400 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4401 sample_size = (len & 3) + 1;
4402 trun_size = ((len & 12) >> 2) + 1;
4403 traf_size = ((len & 48) >> 4) + 1;
4405 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4406 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4408 if (num_entries == 0)
4411 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4412 value_size + value_size + traf_size + trun_size + sample_size))
4415 g_free (stream->ra_entries);
4416 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4417 stream->n_ra_entries = num_entries;
4419 for (i = 0; i < num_entries; i++) {
4420 qt_atom_parser_get_offset (&tfra, value_size, &time);
4421 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4422 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4423 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4424 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4426 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4428 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4429 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4431 stream->ra_entries[i].ts = time;
4432 stream->ra_entries[i].moof_offset = moof_offset;
4434 /* don't want to go through the entire file and read all moofs at startup */
4436 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4437 if (ret != GST_FLOW_OK)
4439 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4440 moof_offset, stream);
4441 gst_buffer_unref (buf);
4445 check_update_duration (qtdemux, time);
4452 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4457 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4462 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4468 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4470 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4471 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4472 GstBuffer *mfro = NULL, *mfra = NULL;
4474 gboolean ret = FALSE;
4475 GNode *mfra_node, *tfra_node;
4476 guint64 mfra_offset = 0;
4477 guint32 fourcc, mfra_size;
4480 /* query upstream size in bytes */
4481 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4482 goto size_query_failed;
4484 /* mfro box should be at the very end of the file */
4485 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4486 if (flow != GST_FLOW_OK)
4489 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4491 fourcc = QT_FOURCC (mfro_map.data + 4);
4492 if (fourcc != FOURCC_mfro)
4495 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4496 if (mfro_map.size < 16)
4497 goto invalid_mfro_size;
4499 mfra_size = QT_UINT32 (mfro_map.data + 12);
4500 if (mfra_size >= len)
4501 goto invalid_mfra_size;
4503 mfra_offset = len - mfra_size;
4505 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4506 mfra_offset, mfra_size);
4508 /* now get and parse mfra box */
4509 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4510 if (flow != GST_FLOW_OK)
4513 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4515 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4516 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4518 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4521 qtdemux_parse_tfra (qtdemux, tfra_node);
4522 /* iterate all siblings */
4523 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4525 g_node_destroy (mfra_node);
4527 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4533 if (mfro_map.memory != NULL)
4534 gst_buffer_unmap (mfro, &mfro_map);
4535 gst_buffer_unref (mfro);
4538 if (mfra_map.memory != NULL)
4539 gst_buffer_unmap (mfra, &mfra_map);
4540 gst_buffer_unref (mfra);
4547 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4552 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4557 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4562 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4568 add_offset (guint64 offset, guint64 advance)
4570 /* Avoid 64-bit overflow by clamping */
4571 if (offset > G_MAXUINT64 - advance)
4573 return offset + advance;
4576 static GstFlowReturn
4577 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4581 GstBuffer *buf = NULL;
4582 GstFlowReturn ret = GST_FLOW_OK;
4583 guint64 cur_offset = qtdemux->offset;
4586 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4587 if (G_UNLIKELY (ret != GST_FLOW_OK))
4589 gst_buffer_map (buf, &map, GST_MAP_READ);
4590 if (G_LIKELY (map.size >= 8))
4591 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4592 gst_buffer_unmap (buf, &map);
4593 gst_buffer_unref (buf);
4595 /* maybe we already got most we needed, so only consider this eof */
4596 if (G_UNLIKELY (length == 0)) {
4597 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4598 (_("Invalid atom size.")),
4599 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4600 GST_FOURCC_ARGS (fourcc)));
4607 /* record for later parsing when needed */
4608 if (!qtdemux->moof_offset) {
4609 qtdemux->moof_offset = qtdemux->offset;
4611 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4614 qtdemux->offset += length; /* skip moof and keep going */
4616 if (qtdemux->got_moov) {
4617 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4629 GST_LOG_OBJECT (qtdemux,
4630 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4631 GST_FOURCC_ARGS (fourcc), cur_offset);
4632 qtdemux->offset = add_offset (qtdemux->offset, length);
4637 GstBuffer *moov = NULL;
4639 if (qtdemux->got_moov) {
4640 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4641 qtdemux->offset = add_offset (qtdemux->offset, length);
4645 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4646 if (ret != GST_FLOW_OK)
4648 gst_buffer_map (moov, &map, GST_MAP_READ);
4650 if (length != map.size) {
4651 /* Some files have a 'moov' atom at the end of the file which contains
4652 * a terminal 'free' atom where the body of the atom is missing.
4653 * Check for, and permit, this special case.
4655 if (map.size >= 8) {
4656 guint8 *final_data = map.data + (map.size - 8);
4657 guint32 final_length = QT_UINT32 (final_data);
4658 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4660 if (final_fourcc == FOURCC_free
4661 && map.size + final_length - 8 == length) {
4662 /* Ok, we've found that special case. Allocate a new buffer with
4663 * that free atom actually present. */
4664 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4665 gst_buffer_fill (newmoov, 0, map.data, map.size);
4666 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4667 gst_buffer_unmap (moov, &map);
4668 gst_buffer_unref (moov);
4670 gst_buffer_map (moov, &map, GST_MAP_READ);
4675 if (length != map.size) {
4676 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4677 (_("This file is incomplete and cannot be played.")),
4678 ("We got less than expected (received %" G_GSIZE_FORMAT
4679 ", wanted %" G_GUINT64_FORMAT ", offset %" G_GUINT64_FORMAT ")",
4680 map.size, length, cur_offset));
4681 gst_buffer_unmap (moov, &map);
4682 gst_buffer_unref (moov);
4683 ret = GST_FLOW_ERROR;
4686 qtdemux->offset += length;
4688 qtdemux_parse_moov (qtdemux, map.data, length);
4689 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4691 qtdemux_parse_tree (qtdemux);
4692 if (qtdemux->moov_node_compressed) {
4693 g_node_destroy (qtdemux->moov_node_compressed);
4694 g_free (qtdemux->moov_node->data);
4696 qtdemux->moov_node_compressed = NULL;
4697 g_node_destroy (qtdemux->moov_node);
4698 qtdemux->moov_node = NULL;
4699 gst_buffer_unmap (moov, &map);
4700 gst_buffer_unref (moov);
4701 qtdemux->got_moov = TRUE;
4707 GstBuffer *ftyp = NULL;
4709 /* extract major brand; might come in handy for ISO vs QT issues */
4710 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4711 if (ret != GST_FLOW_OK)
4713 qtdemux->offset += length;
4714 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4715 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4716 gst_buffer_unmap (ftyp, &map);
4717 gst_buffer_unref (ftyp);
4722 GstBuffer *styp = NULL;
4724 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &styp);
4725 if (ret != GST_FLOW_OK)
4727 qtdemux->offset += length;
4728 gst_buffer_map (styp, &map, GST_MAP_READ);
4729 qtdemux_parse_styp (qtdemux, map.data, map.size);
4730 gst_buffer_unmap (styp, &map);
4731 gst_buffer_unref (styp);
4736 GstBuffer *uuid = NULL;
4738 /* uuid are extension atoms */
4739 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4740 if (ret != GST_FLOW_OK)
4742 qtdemux->offset += length;
4743 gst_buffer_map (uuid, &map, GST_MAP_READ);
4744 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4745 gst_buffer_unmap (uuid, &map);
4746 gst_buffer_unref (uuid);
4751 GstBuffer *sidx = NULL;
4752 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4753 if (ret != GST_FLOW_OK)
4755 qtdemux->offset += length;
4756 gst_buffer_map (sidx, &map, GST_MAP_READ);
4757 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4758 gst_buffer_unmap (sidx, &map);
4759 gst_buffer_unref (sidx);
4764 GstBuffer *meta = NULL;
4765 GNode *node, *child;
4766 GstByteReader child_data;
4767 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &meta);
4768 if (ret != GST_FLOW_OK)
4770 qtdemux->offset += length;
4771 gst_buffer_map (meta, &map, GST_MAP_READ);
4773 node = g_node_new (map.data);
4775 qtdemux_parse_node (qtdemux, node, map.data, map.size);
4777 /* Parse ONVIF Export File Format CorrectStartTime box if available */
4779 qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb,
4781 qtdemux_parse_cstb (qtdemux, &child_data);
4784 g_node_destroy (node);
4786 gst_buffer_unmap (meta, &map);
4787 gst_buffer_unref (meta);
4792 GstBuffer *unknown = NULL;
4794 GST_LOG_OBJECT (qtdemux,
4795 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4796 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4798 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4799 if (ret != GST_FLOW_OK)
4801 gst_buffer_map (unknown, &map, GST_MAP_READ);
4802 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4803 gst_buffer_unmap (unknown, &map);
4804 gst_buffer_unref (unknown);
4805 qtdemux->offset += length;
4811 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4812 /* digested all data, show what we have */
4813 qtdemux_prepare_streams (qtdemux);
4814 QTDEMUX_EXPOSE_LOCK (qtdemux);
4815 ret = qtdemux_expose_streams (qtdemux);
4816 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4818 qtdemux->state = QTDEMUX_STATE_MOVIE;
4819 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4826 /* Seeks to the previous keyframe of the indexed stream and
4827 * aligns other streams with respect to the keyframe timestamp
4828 * of indexed stream. Only called in case of Reverse Playback
4830 static GstFlowReturn
4831 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4833 guint32 seg_idx = 0, k_index = 0;
4834 guint32 ref_seg_idx, ref_k_index;
4835 GstClockTime k_pos = 0, last_stop = 0;
4836 QtDemuxSegment *seg = NULL;
4837 QtDemuxStream *ref_str = NULL;
4838 guint64 seg_media_start_mov; /* segment media start time in mov format */
4842 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4843 * and finally align all the other streams on that timestamp with their
4844 * respective keyframes */
4845 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4846 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4848 /* No candidate yet, take the first stream */
4854 /* So that stream has a segment, we prefer video streams */
4855 if (str->subtype == FOURCC_vide) {
4861 if (G_UNLIKELY (!ref_str)) {
4862 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4866 if (G_UNLIKELY (!ref_str->from_sample)) {
4867 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4871 /* So that stream has been playing from from_sample to to_sample. We will
4872 * get the timestamp of the previous sample and search for a keyframe before
4873 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4874 if (ref_str->subtype == FOURCC_vide) {
4875 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4876 ref_str->from_sample - 1, FALSE);
4878 if (ref_str->from_sample >= 10)
4879 k_index = ref_str->from_sample - 10;
4885 ref_str->samples[k_index].timestamp +
4886 ref_str->samples[k_index].pts_offset;
4888 /* get current segment for that stream */
4889 seg = &ref_str->segments[ref_str->segment_index];
4890 /* Use segment start in original timescale for comparisons */
4891 seg_media_start_mov = seg->trak_media_start;
4893 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4894 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4895 k_index, target_ts, seg_media_start_mov,
4896 GST_TIME_ARGS (seg->media_start));
4898 /* Crawl back through segments to find the one containing this I frame */
4899 while (target_ts < seg_media_start_mov) {
4900 GST_DEBUG_OBJECT (qtdemux,
4901 "keyframe position (sample %u) is out of segment %u " " target %"
4902 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4903 ref_str->segment_index, target_ts, seg_media_start_mov);
4905 if (G_UNLIKELY (!ref_str->segment_index)) {
4906 /* Reached first segment, let's consider it's EOS */
4909 ref_str->segment_index--;
4910 seg = &ref_str->segments[ref_str->segment_index];
4911 /* Use segment start in original timescale for comparisons */
4912 seg_media_start_mov = seg->trak_media_start;
4914 /* Calculate time position of the keyframe and where we should stop */
4916 QTSTREAMTIME_TO_GSTTIME (ref_str,
4917 target_ts - seg->trak_media_start) + seg->time;
4919 QTSTREAMTIME_TO_GSTTIME (ref_str,
4920 ref_str->samples[ref_str->from_sample].timestamp -
4921 seg->trak_media_start) + seg->time;
4923 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4924 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4925 k_index, GST_TIME_ARGS (k_pos));
4927 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4928 qtdemux->segment.position = last_stop;
4929 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4930 GST_TIME_ARGS (last_stop));
4932 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4933 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4937 ref_seg_idx = ref_str->segment_index;
4938 ref_k_index = k_index;
4940 /* Align them all on this */
4941 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4943 GstClockTime seg_time = 0;
4944 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4946 /* aligning reference stream again might lead to backing up to yet another
4947 * keyframe (due to timestamp rounding issues),
4948 * potentially putting more load on downstream; so let's try to avoid */
4949 if (str == ref_str) {
4950 seg_idx = ref_seg_idx;
4951 seg = &str->segments[seg_idx];
4952 k_index = ref_k_index;
4953 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4954 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4956 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4957 GST_DEBUG_OBJECT (qtdemux,
4958 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4959 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4961 /* get segment and time in the segment */
4962 seg = &str->segments[seg_idx];
4963 seg_time = k_pos - seg->time;
4965 /* get the media time in the segment.
4966 * No adjustment for empty "filler" segments */
4967 if (seg->media_start != GST_CLOCK_TIME_NONE)
4968 seg_time += seg->media_start;
4970 /* get the index of the sample with media time */
4971 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4972 GST_DEBUG_OBJECT (qtdemux,
4973 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4974 GST_TIME_ARGS (seg_time), index);
4976 /* find previous keyframe */
4977 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4980 /* Remember until where we want to go */
4981 str->to_sample = str->from_sample - 1;
4982 /* Define our time position */
4984 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4985 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4986 if (seg->media_start != GST_CLOCK_TIME_NONE)
4987 str->time_position -= seg->media_start;
4989 /* Now seek back in time */
4990 gst_qtdemux_move_stream (qtdemux, str, k_index);
4991 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4992 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4993 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4999 return GST_FLOW_EOS;
5003 * Gets the current qt segment start, stop and position for the
5004 * given time offset. This is used in update_segment()
5007 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
5008 QtDemuxStream * stream, GstClockTime offset,
5009 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
5011 GstClockTime seg_time;
5012 GstClockTime start, stop, time;
5013 QtDemuxSegment *segment;
5015 segment = &stream->segments[stream->segment_index];
5017 /* get time in this segment */
5018 seg_time = (offset - segment->time) * segment->rate;
5020 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
5021 GST_TIME_ARGS (seg_time));
5023 if (G_UNLIKELY (seg_time > segment->duration)) {
5024 GST_LOG_OBJECT (stream->pad,
5025 "seg_time > segment->duration %" GST_TIME_FORMAT,
5026 GST_TIME_ARGS (segment->duration));
5027 seg_time = segment->duration;
5030 /* qtdemux->segment.stop is in outside-time-realm, whereas
5031 * segment->media_stop is in track-time-realm.
5033 * In order to compare the two, we need to bring segment.stop
5034 * into the track-time-realm
5036 * FIXME - does this comment still hold? Don't see any conversion here */
5038 stop = qtdemux->segment.stop;
5039 if (stop == GST_CLOCK_TIME_NONE)
5040 stop = qtdemux->segment.duration;
5041 if (stop == GST_CLOCK_TIME_NONE)
5042 stop = segment->media_stop;
5045 MIN (segment->media_stop, stop - segment->time + segment->media_start);
5047 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5048 start = segment->time + seg_time;
5050 stop = start - seg_time + segment->duration;
5051 } else if (qtdemux->segment.rate >= 0) {
5052 start = MIN (segment->media_start + seg_time, stop);
5055 if (segment->media_start >= qtdemux->segment.start) {
5056 time = segment->time;
5058 time = segment->time + (qtdemux->segment.start - segment->media_start);
5061 start = MAX (segment->media_start, qtdemux->segment.start);
5062 stop = MIN (segment->media_start + seg_time, stop);
5071 * Updates the qt segment used for the stream and pushes a new segment event
5072 * downstream on this stream's pad.
5075 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5076 gint seg_idx, GstClockTime offset, GstClockTime * _start,
5077 GstClockTime * _stop)
5079 QtDemuxSegment *segment;
5080 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
5084 /* update the current segment */
5085 stream->segment_index = seg_idx;
5087 /* get the segment */
5088 segment = &stream->segments[seg_idx];
5090 if (G_UNLIKELY (offset < segment->time)) {
5091 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
5092 GST_TIME_ARGS (segment->time));
5096 /* segment lies beyond total indicated duration */
5097 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5098 segment->time > qtdemux->segment.duration)) {
5099 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5100 " < segment->time %" GST_TIME_FORMAT,
5101 GST_TIME_ARGS (qtdemux->segment.duration),
5102 GST_TIME_ARGS (segment->time));
5106 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5107 &start, &stop, &time);
5109 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5110 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5111 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5113 /* combine global rate with that of the segment */
5114 rate = segment->rate * qtdemux->segment.rate;
5116 /* Copy flags from main segment */
5117 stream->segment.flags = qtdemux->segment.flags;
5119 /* update the segment values used for clipping */
5120 stream->segment.offset = qtdemux->segment.offset;
5121 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5122 stream->segment.applied_rate = qtdemux->segment.applied_rate;
5123 stream->segment.rate = rate;
5124 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5125 stream->cslg_shift);
5127 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5128 stream->cslg_shift);
5130 stream->segment.stop = stop;
5131 stream->segment.time = time;
5132 stream->segment.position = stream->segment.start;
5134 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5137 /* now prepare and send the segment */
5139 event = gst_event_new_segment (&stream->segment);
5140 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5141 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5143 gst_pad_push_event (stream->pad, event);
5144 /* assume we can send more data now */
5145 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5146 /* clear to send tags on this pad now */
5147 gst_qtdemux_push_tags (qtdemux, stream);
5158 /* activate the given segment number @seg_idx of @stream at time @offset.
5159 * @offset is an absolute global position over all the segments.
5161 * This will push out a NEWSEGMENT event with the right values and
5162 * position the stream index to the first decodable sample before
5166 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5167 guint32 seg_idx, GstClockTime offset)
5169 QtDemuxSegment *segment;
5170 guint32 index, kf_index;
5171 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5173 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5174 seg_idx, GST_TIME_ARGS (offset));
5176 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5180 segment = &stream->segments[stream->segment_index];
5182 /* in the fragmented case, we pick a fragment that starts before our
5183 * desired position and rely on downstream to wait for a keyframe
5184 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5185 * tfra entries tells us which trun/sample the key unit is in, but we don't
5186 * make use of this additional information at the moment) */
5187 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5188 stream->to_sample = G_MAXUINT32;
5191 /* well, it will be taken care of below */
5192 qtdemux->fragmented_seek_pending = FALSE;
5193 /* FIXME ideally the do_fragmented_seek can be done right here,
5194 * rather than at loop level
5195 * (which might even allow handling edit lists in a fragmented file) */
5198 /* We don't need to look for a sample in push-based */
5199 if (!qtdemux->pullbased)
5202 /* and move to the keyframe before the indicated media time of the
5204 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5205 if (qtdemux->segment.rate >= 0) {
5206 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5207 stream->to_sample = G_MAXUINT32;
5208 GST_DEBUG_OBJECT (stream->pad,
5209 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5210 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5211 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5213 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5214 stream->to_sample = index;
5215 GST_DEBUG_OBJECT (stream->pad,
5216 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5217 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5218 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5221 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5222 "this is an empty segment");
5226 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5227 * encountered an error and printed a message so we return appropriately */
5231 /* we're at the right spot */
5232 if (index == stream->sample_index) {
5233 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5237 /* find keyframe of the target index */
5238 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5240 /* go back two frames to provide lead-in for non-raw audio decoders */
5241 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5242 guint32 lead_in = 2;
5243 guint32 old_index = kf_index;
5244 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5246 if (gst_structure_has_name (s, "audio/mpeg")) {
5248 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5249 && mpegversion == 1) {
5250 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5255 kf_index = MAX (kf_index, lead_in) - lead_in;
5256 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5257 GST_DEBUG_OBJECT (stream->pad,
5258 "Moving backwards %u frames to ensure sufficient sound lead-in",
5259 old_index - kf_index);
5261 kf_index = old_index;
5265 /* if we move forwards, we don't have to go back to the previous
5266 * keyframe since we already sent that. We can also just jump to
5267 * the keyframe right before the target index if there is one. */
5268 if (index > stream->sample_index) {
5269 /* moving forwards check if we move past a keyframe */
5270 if (kf_index > stream->sample_index) {
5271 GST_DEBUG_OBJECT (stream->pad,
5272 "moving forwards to keyframe at %u "
5273 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5275 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5276 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5277 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5279 GST_DEBUG_OBJECT (stream->pad,
5280 "moving forwards, keyframe at %u "
5281 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5283 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5284 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5287 GST_DEBUG_OBJECT (stream->pad,
5288 "moving backwards to %sframe at %u "
5289 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5290 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5291 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5292 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5293 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5299 /* prepare to get the current sample of @stream, getting essential values.
5301 * This function will also prepare and send the segment when needed.
5303 * Return FALSE if the stream is EOS.
5308 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5309 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5310 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5311 gboolean * keyframe)
5313 QtDemuxSample *sample;
5314 GstClockTime time_position;
5317 g_return_val_if_fail (stream != NULL, FALSE);
5319 time_position = stream->time_position;
5320 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5323 seg_idx = stream->segment_index;
5324 if (G_UNLIKELY (seg_idx == -1)) {
5325 /* find segment corresponding to time_position if we are looking
5327 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5330 /* different segment, activate it, sample_index will be set. */
5331 if (G_UNLIKELY (stream->segment_index != seg_idx))
5332 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5334 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5335 segments[stream->segment_index]))) {
5336 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5338 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5339 " prepare empty sample");
5342 *pts = *dts = time_position;
5343 *duration = seg->duration - (time_position - seg->time);
5350 if (stream->sample_index == -1)
5351 stream->sample_index = 0;
5353 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5354 stream->sample_index, stream->n_samples);
5356 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5357 if (!qtdemux->fragmented)
5360 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5364 GST_OBJECT_LOCK (qtdemux);
5365 flow = qtdemux_add_fragmented_samples (qtdemux);
5366 GST_OBJECT_UNLOCK (qtdemux);
5368 if (flow != GST_FLOW_OK)
5371 while (stream->sample_index >= stream->n_samples);
5374 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5375 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5376 stream->sample_index);
5380 /* now get the info for the sample we're at */
5381 sample = &stream->samples[stream->sample_index];
5383 *dts = QTSAMPLE_DTS (stream, sample);
5384 *pts = QTSAMPLE_PTS (stream, sample);
5385 *offset = sample->offset;
5386 *size = sample->size;
5387 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5388 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5395 stream->time_position = GST_CLOCK_TIME_NONE;
5400 /* move to the next sample in @stream.
5402 * Moves to the next segment when needed.
5405 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5407 QtDemuxSample *sample;
5408 QtDemuxSegment *segment;
5410 /* get current segment */
5411 segment = &stream->segments[stream->segment_index];
5413 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5414 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5418 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5419 /* Mark the stream as EOS */
5420 GST_DEBUG_OBJECT (qtdemux,
5421 "reached max allowed sample %u, mark EOS", stream->to_sample);
5422 stream->time_position = GST_CLOCK_TIME_NONE;
5426 /* move to next sample */
5427 stream->sample_index++;
5428 stream->offset_in_sample = 0;
5430 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5433 /* reached the last sample, we need the next segment */
5434 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5437 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5438 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5439 stream->sample_index);
5443 /* get next sample */
5444 sample = &stream->samples[stream->sample_index];
5446 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5447 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5448 GST_TIME_ARGS (segment->media_stop));
5450 /* see if we are past the segment */
5451 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5454 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5455 /* inside the segment, update time_position, looks very familiar to
5456 * GStreamer segments, doesn't it? */
5457 stream->time_position =
5458 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5460 /* not yet in segment, time does not yet increment. This means
5461 * that we are still prerolling keyframes to the decoder so it can
5462 * decode the first sample of the segment. */
5463 stream->time_position = segment->time;
5467 /* move to the next segment */
5470 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5472 if (stream->segment_index == stream->n_segments - 1) {
5473 /* are we at the end of the last segment, we're EOS */
5474 stream->time_position = GST_CLOCK_TIME_NONE;
5476 /* else we're only at the end of the current segment */
5477 stream->time_position = segment->stop_time;
5479 /* make sure we select a new segment */
5481 /* accumulate previous segments */
5482 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5483 stream->accumulated_base +=
5484 (stream->segment.stop -
5485 stream->segment.start) / ABS (stream->segment.rate);
5487 stream->segment_index = -1;
5492 gst_qtdemux_sync_streams (GstQTDemux * demux)
5496 if (QTDEMUX_N_STREAMS (demux) <= 1)
5499 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5500 QtDemuxStream *stream;
5501 GstClockTime end_time;
5503 stream = QTDEMUX_NTH_STREAM (demux, i);
5508 /* TODO advance time on subtitle streams here, if any some day */
5510 /* some clips/trailers may have unbalanced streams at the end,
5511 * so send EOS on shorter stream to prevent stalling others */
5513 /* do not mess with EOS if SEGMENT seeking */
5514 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5517 if (demux->pullbased) {
5518 /* loop mode is sample time based */
5519 if (!STREAM_IS_EOS (stream))
5522 /* push mode is byte position based */
5523 if (stream->n_samples &&
5524 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5528 if (stream->sent_eos)
5531 /* only act if some gap */
5532 end_time = stream->segments[stream->n_segments - 1].stop_time;
5533 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5534 ", stream end: %" GST_TIME_FORMAT,
5535 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5536 if (GST_CLOCK_TIME_IS_VALID (end_time)
5537 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5540 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5541 GST_PAD_NAME (stream->pad));
5542 stream->sent_eos = TRUE;
5543 event = gst_event_new_eos ();
5544 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5545 gst_event_set_seqnum (event, demux->segment_seqnum);
5546 gst_pad_push_event (stream->pad, event);
5551 /* EOS and NOT_LINKED need to be combined. This means that we return:
5553 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5554 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5556 static GstFlowReturn
5557 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5560 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5563 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5566 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5568 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5572 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5573 * completely clipped
5575 * Should be used only with raw buffers */
5577 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5580 guint64 start, stop, cstart, cstop, diff;
5581 GstClockTime pts, duration;
5583 gint num_rate, denom_rate;
5588 osize = size = gst_buffer_get_size (buf);
5591 /* depending on the type, setup the clip parameters */
5592 if (stream->subtype == FOURCC_soun) {
5593 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5594 num_rate = GST_SECOND;
5595 denom_rate = (gint) CUR_STREAM (stream)->rate;
5597 } else if (stream->subtype == FOURCC_vide) {
5599 num_rate = CUR_STREAM (stream)->fps_n;
5600 denom_rate = CUR_STREAM (stream)->fps_d;
5605 if (frame_size <= 0)
5606 goto bad_frame_size;
5608 /* we can only clip if we have a valid pts */
5609 pts = GST_BUFFER_PTS (buf);
5610 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5613 duration = GST_BUFFER_DURATION (buf);
5615 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5617 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5621 stop = start + duration;
5623 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5624 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5627 /* see if some clipping happened */
5628 diff = cstart - start;
5634 /* bring clipped time to samples and to bytes */
5635 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5638 GST_DEBUG_OBJECT (qtdemux,
5639 "clipping start to %" GST_TIME_FORMAT " %"
5640 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5646 diff = stop - cstop;
5651 /* bring clipped time to samples and then to bytes */
5652 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5654 GST_DEBUG_OBJECT (qtdemux,
5655 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5656 " bytes", GST_TIME_ARGS (cstop), diff);
5661 if (offset != 0 || size != osize)
5662 gst_buffer_resize (buf, offset, size);
5664 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5665 GST_BUFFER_PTS (buf) = pts;
5666 GST_BUFFER_DURATION (buf) = duration;
5670 /* dropped buffer */
5673 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5678 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5683 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5688 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5689 gst_buffer_unref (buf);
5695 gst_qtdemux_align_buffer (GstQTDemux * demux,
5696 GstBuffer * buffer, gsize alignment)
5700 gst_buffer_map (buffer, &map, GST_MAP_READ);
5702 if (map.size < sizeof (guintptr)) {
5703 gst_buffer_unmap (buffer, &map);
5707 if (((guintptr) map.data) & (alignment - 1)) {
5708 GstBuffer *new_buffer;
5709 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5711 new_buffer = gst_buffer_new_allocate (NULL,
5712 gst_buffer_get_size (buffer), ¶ms);
5714 /* Copy data "by hand", so ensure alignment is kept: */
5715 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5717 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5718 GST_DEBUG_OBJECT (demux,
5719 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5722 gst_buffer_unmap (buffer, &map);
5723 gst_buffer_unref (buffer);
5728 gst_buffer_unmap (buffer, &map);
5733 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5739 /* We are converting from pairs to triplets */
5740 *res = ccpair_size / 2 * 3;
5741 storage = g_malloc (*res);
5742 for (i = 0; i * 2 < ccpair_size; i += 1) {
5743 /* FIXME: Use line offset 0 as we simply can't know here */
5745 storage[i * 3] = 0x80 | 0x00;
5747 storage[i * 3] = 0x00 | 0x00;
5748 storage[i * 3 + 1] = ccpair[i * 2];
5749 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5756 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5760 guint32 atom_length, fourcc;
5761 QtDemuxStreamStsdEntry *stsd_entry;
5763 GST_MEMDUMP ("caption atom", data, size);
5765 /* There might be multiple atoms */
5770 atom_length = QT_UINT32 (data);
5771 fourcc = QT_FOURCC (data + 4);
5772 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5775 GST_DEBUG_OBJECT (stream->pad, "here");
5777 /* Check if we have something compatible */
5778 stsd_entry = CUR_STREAM (stream);
5779 switch (stsd_entry->fourcc) {
5781 guint8 *cdat = NULL, *cdt2 = NULL;
5782 gsize cdat_size = 0, cdt2_size = 0;
5783 /* Should be cdat or cdt2 */
5784 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5785 GST_WARNING_OBJECT (stream->pad,
5786 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5787 GST_FOURCC_ARGS (fourcc));
5791 /* Convert to S334-1 Annex A byte triplet */
5792 if (fourcc == FOURCC_cdat)
5793 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5795 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5796 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5799 /* Check for another atom ? */
5800 if (size > atom_length + 8) {
5801 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5802 if (size >= atom_length + new_atom_length) {
5803 fourcc = QT_FOURCC (data + atom_length + 4);
5804 if (fourcc == FOURCC_cdat) {
5807 convert_to_s334_1a (data + atom_length + 8,
5808 new_atom_length - 8, 1, &cdat_size);
5810 GST_WARNING_OBJECT (stream->pad,
5811 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5815 convert_to_s334_1a (data + atom_length + 8,
5816 new_atom_length - 8, 2, &cdt2_size);
5818 GST_WARNING_OBJECT (stream->pad,
5819 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5824 *cclen = cdat_size + cdt2_size;
5825 res = g_malloc (*cclen);
5827 memcpy (res, cdat, cdat_size);
5829 memcpy (res + cdat_size, cdt2, cdt2_size);
5835 if (fourcc != FOURCC_ccdp) {
5836 GST_WARNING_OBJECT (stream->pad,
5837 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5838 GST_FOURCC_ARGS (fourcc));
5841 *cclen = atom_length - 8;
5842 res = g_memdup2 (data + 8, *cclen);
5845 /* Keep this here in case other closed caption formats are added */
5846 g_assert_not_reached ();
5850 GST_MEMDUMP ("Output", res, *cclen);
5855 GST_WARNING ("[cdat] atom is too small or invalid");
5859 /* Handle Closed Caption sample buffers.
5860 * The input buffer metadata must be writable,
5861 * but time/duration etc not yet set and need not be preserved */
5863 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5866 GstBuffer *outbuf = NULL;
5871 gst_buffer_map (buf, &map, GST_MAP_READ);
5873 /* empty buffer is sent to terminate previous subtitle */
5874 if (map.size <= 2) {
5875 gst_buffer_unmap (buf, &map);
5876 gst_buffer_unref (buf);
5880 /* For closed caption, we need to extract the information from the
5881 * [cdat],[cdt2] or [ccdp] atom */
5882 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5883 gst_buffer_unmap (buf, &map);
5885 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5886 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5888 /* Conversion failed or there's nothing */
5890 gst_buffer_unref (buf);
5895 /* DVD subpicture specific sample handling.
5896 * the input buffer metadata must be writable,
5897 * but time/duration etc not yet set and need not be preserved */
5899 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5902 /* send a one time dvd clut event */
5903 if (stream->pending_event && stream->pad)
5904 gst_pad_push_event (stream->pad, stream->pending_event);
5905 stream->pending_event = NULL;
5907 /* empty buffer is sent to terminate previous subtitle */
5908 if (gst_buffer_get_size (buf) <= 2) {
5909 gst_buffer_unref (buf);
5913 /* That's all the processing needed for subpictures */
5917 /* Timed text formats
5918 * the input buffer metadata must be writable,
5919 * but time/duration etc not yet set and need not be preserved */
5921 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5924 GstBuffer *outbuf = NULL;
5929 /* not many cases for now */
5930 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5931 stream->subtype != FOURCC_sbtl)) {
5935 gst_buffer_map (buf, &map, GST_MAP_READ);
5937 /* empty buffer is sent to terminate previous subtitle */
5938 if (map.size <= 2) {
5939 gst_buffer_unmap (buf, &map);
5940 gst_buffer_unref (buf);
5944 nsize = GST_READ_UINT16_BE (map.data);
5945 nsize = MIN (nsize, map.size - 2);
5947 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5950 /* takes care of UTF-8 validation or UTF-16 recognition,
5951 * no other encoding expected */
5952 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5953 gst_buffer_unmap (buf, &map);
5956 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5957 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5959 /* this should not really happen unless the subtitle is corrupted */
5961 gst_buffer_unref (buf);
5963 /* FIXME ? convert optional subsequent style info to markup */
5968 /* WebVTT sample handling according to 14496-30 */
5970 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5973 GstBuffer *outbuf = NULL;
5976 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5977 g_assert_not_reached (); /* The buffer must be mappable */
5980 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5981 GstEvent *gap = NULL;
5982 /* Push a gap event */
5983 stream->segment.position = GST_BUFFER_PTS (buf);
5985 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5986 gst_pad_push_event (stream->pad, gap);
5988 if (GST_BUFFER_DURATION_IS_VALID (buf))
5989 stream->segment.position += GST_BUFFER_DURATION (buf);
5992 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5993 GST_BUFFER_DURATION (buf), map.data, map.size);
5994 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5997 gst_buffer_unmap (buf, &map);
5998 gst_buffer_unref (buf);
6003 static GstFlowReturn
6004 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6007 GstFlowReturn ret = GST_FLOW_OK;
6008 GstClockTime pts, duration;
6010 if (stream->need_clip)
6011 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
6013 if (G_UNLIKELY (buf == NULL))
6016 if (G_UNLIKELY (stream->discont)) {
6017 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6018 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
6019 stream->discont = FALSE;
6021 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6024 GST_LOG_OBJECT (qtdemux,
6025 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
6026 ", duration %" GST_TIME_FORMAT " on pad %s",
6027 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
6028 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
6029 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
6031 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
6032 GstStructure *crypto_info;
6033 QtDemuxAavdEncryptionInfo *info =
6034 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
6036 crypto_info = gst_structure_copy (info->default_properties);
6037 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6038 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
6041 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
6042 || stream->protection_scheme_type == FOURCC_cbcs)) {
6043 GstStructure *crypto_info;
6044 QtDemuxCencSampleSetInfo *info =
6045 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6049 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
6050 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
6051 GST_PTR_FORMAT, event);
6052 gst_pad_push_event (stream->pad, event);
6055 if (info->crypto_info == NULL) {
6056 if (stream->protection_scheme_type == FOURCC_cbcs) {
6057 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
6058 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
6059 GST_ERROR_OBJECT (qtdemux,
6060 "failed to attach cbcs metadata to buffer");
6061 qtdemux_gst_structure_free (crypto_info);
6063 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
6066 GST_DEBUG_OBJECT (qtdemux,
6067 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
6070 /* The end of the crypto_info array matches our n_samples position,
6071 * so count backward from there */
6072 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
6073 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
6074 /* steal structure from array */
6075 crypto_info = g_ptr_array_index (info->crypto_info, index);
6076 g_ptr_array_index (info->crypto_info, index) = NULL;
6077 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
6078 info->crypto_info->len);
6079 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6080 GST_ERROR_OBJECT (qtdemux,
6081 "failed to attach cenc metadata to buffer");
6083 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
6084 index, stream->sample_index);
6089 if (stream->alignment > 1)
6090 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6092 pts = GST_BUFFER_PTS (buf);
6093 duration = GST_BUFFER_DURATION (buf);
6095 ret = gst_pad_push (stream->pad, buf);
6097 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6098 /* mark position in stream, we'll need this to know when to send GAP event */
6099 stream->segment.position = pts + duration;
6107 static GstFlowReturn
6108 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6111 GstFlowReturn ret = GST_FLOW_OK;
6113 if (stream->subtype == FOURCC_clcp
6114 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6116 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6117 guint n_triplets, i;
6118 guint field1_off = 0, field2_off = 0;
6120 /* We have to split CEA608 buffers so that each outgoing buffer contains
6121 * one byte pair per field according to the framerate of the video track.
6123 * If there is only a single byte pair per field we don't have to do
6127 gst_buffer_map (buf, &map, GST_MAP_READ);
6129 n_triplets = map.size / 3;
6130 for (i = 0; i < n_triplets; i++) {
6131 if (map.data[3 * i] & 0x80)
6137 g_assert (n_field1 || n_field2);
6139 /* If there's more than 1 frame we have to split, otherwise we can just
6141 if (n_field1 > 1 || n_field2 > 1) {
6143 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6144 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6146 for (i = 0; i < n_output_buffers; i++) {
6148 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6152 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6153 outptr = outmap.data;
6156 gboolean found = FALSE;
6158 while (map.data + field1_off < map.data + map.size) {
6159 if (map.data[field1_off] & 0x80) {
6160 memcpy (outptr, &map.data[field1_off], 3);
6169 const guint8 empty[] = { 0x80, 0x80, 0x80 };
6171 memcpy (outptr, empty, 3);
6178 gboolean found = FALSE;
6180 while (map.data + field2_off < map.data + map.size) {
6181 if ((map.data[field2_off] & 0x80) == 0) {
6182 memcpy (outptr, &map.data[field2_off], 3);
6191 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6193 memcpy (outptr, empty, 3);
6199 gst_buffer_unmap (outbuf, &outmap);
6201 GST_BUFFER_PTS (outbuf) =
6202 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6203 GST_SECOND * CUR_STREAM (stream)->fps_d,
6204 CUR_STREAM (stream)->fps_n);
6205 GST_BUFFER_DURATION (outbuf) =
6206 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6207 CUR_STREAM (stream)->fps_n);
6208 GST_BUFFER_OFFSET (outbuf) = -1;
6209 GST_BUFFER_OFFSET_END (outbuf) = -1;
6211 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6213 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6216 gst_buffer_unmap (buf, &map);
6217 gst_buffer_unref (buf);
6219 gst_buffer_unmap (buf, &map);
6220 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6223 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6229 /* Sets a buffer's attributes properly and pushes it downstream.
6230 * Also checks for additional actions and custom processing that may
6231 * need to be done first.
6233 static GstFlowReturn
6234 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6235 QtDemuxStream * stream, GstBuffer * buf,
6236 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6237 gboolean keyframe, GstClockTime position, guint64 byte_position)
6239 GstFlowReturn ret = GST_FLOW_OK;
6241 /* offset the timestamps according to the edit list */
6243 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6247 gst_buffer_map (buf, &map, GST_MAP_READ);
6248 url = g_strndup ((gchar *) map.data, map.size);
6249 gst_buffer_unmap (buf, &map);
6250 if (url != NULL && strlen (url) != 0) {
6251 /* we have RTSP redirect now */
6252 g_free (qtdemux->redirect_location);
6253 qtdemux->redirect_location = g_strdup (url);
6254 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6255 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6256 gst_structure_new ("redirect",
6257 "new-location", G_TYPE_STRING, url, NULL)));
6259 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6265 /* position reporting */
6266 if (qtdemux->segment.rate >= 0) {
6267 qtdemux->segment.position = position;
6268 gst_qtdemux_sync_streams (qtdemux);
6271 if (G_UNLIKELY (!stream->pad)) {
6272 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6273 gst_buffer_unref (buf);
6277 /* send out pending buffers */
6278 while (stream->buffers) {
6279 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6281 if (G_UNLIKELY (stream->discont)) {
6282 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6283 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6284 stream->discont = FALSE;
6286 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6289 if (stream->alignment > 1)
6290 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6291 gst_pad_push (stream->pad, buffer);
6293 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6296 /* we're going to modify the metadata */
6297 buf = gst_buffer_make_writable (buf);
6299 if (qtdemux->start_utc_time != GST_CLOCK_TIME_NONE) {
6300 static GstStaticCaps unix_caps = GST_STATIC_CAPS ("timestamp/x-unix");
6301 GstCaps *caps = gst_static_caps_get (&unix_caps);
6302 gst_buffer_add_reference_timestamp_meta (buf, caps,
6303 pts + qtdemux->start_utc_time - stream->cslg_shift,
6304 GST_CLOCK_TIME_NONE);
6305 gst_caps_unref (caps);
6308 GST_BUFFER_DTS (buf) = dts;
6309 GST_BUFFER_PTS (buf) = pts;
6310 GST_BUFFER_DURATION (buf) = duration;
6311 GST_BUFFER_OFFSET (buf) = -1;
6312 GST_BUFFER_OFFSET_END (buf) = -1;
6314 if (G_UNLIKELY (stream->process_func))
6315 buf = stream->process_func (qtdemux, stream, buf);
6322 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6323 stream->on_keyframe = FALSE;
6325 stream->on_keyframe = TRUE;
6328 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6329 gst_buffer_append_memory (buf,
6330 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6332 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6333 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6336 if (G_UNLIKELY (qtdemux->element_index)) {
6337 GstClockTime stream_time;
6340 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6342 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6343 GST_LOG_OBJECT (qtdemux,
6344 "adding association %" GST_TIME_FORMAT "-> %"
6345 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6346 gst_index_add_association (qtdemux->element_index,
6348 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6349 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6350 GST_FORMAT_BYTES, byte_position, NULL);
6355 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6361 static const QtDemuxRandomAccessEntry *
6362 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6363 GstClockTime pos, gboolean after)
6365 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6366 guint n_entries = stream->n_ra_entries;
6369 /* we assume the table is sorted */
6370 for (i = 0; i < n_entries; ++i) {
6371 if (entries[i].ts > pos)
6375 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6376 * probably okay to assume that the index lists the very first fragment */
6383 return &entries[i - 1];
6387 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6389 const QtDemuxRandomAccessEntry *best_entry = NULL;
6392 GST_OBJECT_LOCK (qtdemux);
6394 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6396 /* first see if we can determine where to go to using mfra,
6397 * before we start clearing things */
6398 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6399 const QtDemuxRandomAccessEntry *entry;
6400 QtDemuxStream *stream;
6401 gboolean is_audio_or_video;
6403 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6405 if (stream->ra_entries == NULL)
6408 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6409 is_audio_or_video = TRUE;
6411 is_audio_or_video = FALSE;
6414 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6415 stream->time_position, !is_audio_or_video);
6417 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6418 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6420 stream->pending_seek = entry;
6422 /* decide position to jump to just based on audio/video tracks, not subs */
6423 if (!is_audio_or_video)
6426 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6430 /* no luck, will handle seek otherwise */
6431 if (best_entry == NULL) {
6432 GST_OBJECT_UNLOCK (qtdemux);
6436 /* ok, now we can prepare for processing as of located moof */
6437 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6438 QtDemuxStream *stream;
6440 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6442 g_free (stream->samples);
6443 stream->samples = NULL;
6444 stream->n_samples = 0;
6445 stream->stbl_index = -1; /* no samples have yet been parsed */
6446 stream->sample_index = -1;
6448 if (stream->protection_scheme_info) {
6449 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6450 if (stream->protection_scheme_type == FOURCC_cenc
6451 || stream->protection_scheme_type == FOURCC_cbcs) {
6452 QtDemuxCencSampleSetInfo *info =
6453 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6454 if (info->crypto_info) {
6455 g_ptr_array_free (info->crypto_info, TRUE);
6456 info->crypto_info = NULL;
6462 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6463 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6464 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6465 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6467 qtdemux->moof_offset = best_entry->moof_offset;
6469 qtdemux_add_fragmented_samples (qtdemux);
6471 GST_OBJECT_UNLOCK (qtdemux);
6475 static GstFlowReturn
6476 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6478 GstFlowReturn ret = GST_FLOW_OK;
6479 GstBuffer *buf = NULL;
6480 QtDemuxStream *stream, *target_stream = NULL;
6481 GstClockTime min_time;
6483 GstClockTime dts = GST_CLOCK_TIME_NONE;
6484 GstClockTime pts = GST_CLOCK_TIME_NONE;
6485 GstClockTime duration = 0;
6486 gboolean keyframe = FALSE;
6487 guint sample_size = 0;
6488 guint num_samples = 1;
6493 if (qtdemux->fragmented_seek_pending) {
6494 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6495 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6496 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6497 qtdemux->fragmented_seek_pending = FALSE;
6499 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6503 /* Figure out the next stream sample to output, min_time is expressed in
6504 * global time and runs over the edit list segments. */
6505 min_time = G_MAXUINT64;
6506 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6507 GstClockTime position;
6509 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6510 position = stream->time_position;
6512 if (!GST_CLOCK_TIME_IS_VALID (position))
6515 if (stream->segment_index != -1) {
6516 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6517 position += segment->media_start;
6520 /* position of -1 is EOS */
6521 if (position < min_time) {
6522 min_time = position;
6523 target_stream = stream;
6527 if (G_UNLIKELY (target_stream == NULL)) {
6528 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6532 /* check for segment end */
6533 if (G_UNLIKELY (qtdemux->segment.stop != -1
6534 && qtdemux->segment.rate >= 0
6535 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6536 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6537 target_stream->time_position = GST_CLOCK_TIME_NONE;
6541 /* fetch info for the current sample of this stream */
6542 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, target_stream,
6543 &empty, &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6546 /* Send catche-up GAP event for each other stream if required.
6547 * This logic will be applied only for positive rate */
6548 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux) &&
6549 qtdemux->segment.rate >= 0; i++) {
6550 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6552 if (stream == target_stream ||
6553 !GST_CLOCK_TIME_IS_VALID (stream->segment.stop) ||
6554 !GST_CLOCK_TIME_IS_VALID (stream->segment.position))
6558 GstClockTime gap_threshold;
6559 /* kind of running time with offset segment.base and segment.start */
6560 GstClockTime pseudo_target_time = target_stream->segment.base;
6561 GstClockTime pseudo_cur_time = stream->segment.base;
6563 /* make sure positive offset, segment.position can be smallr than
6564 * segment.start for some reasons */
6565 if (target_stream->segment.position >= target_stream->segment.start) {
6566 pseudo_target_time +=
6567 (target_stream->segment.position - target_stream->segment.start);
6570 if (stream->segment.position >= stream->segment.start)
6571 pseudo_cur_time += (stream->segment.position - stream->segment.start);
6573 /* Only send gap events on non-subtitle streams if lagging way behind. */
6574 if (stream->subtype == FOURCC_subp
6575 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6576 stream->subtype == FOURCC_wvtt)
6577 gap_threshold = 1 * GST_SECOND;
6579 gap_threshold = 3 * GST_SECOND;
6581 /* send gap events until the stream catches up */
6582 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6583 while (GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6584 pseudo_cur_time < (G_MAXUINT64 - gap_threshold) &&
6585 pseudo_cur_time + gap_threshold < pseudo_target_time) {
6587 gst_event_new_gap (stream->segment.position, gap_threshold);
6588 GST_LOG_OBJECT (stream->pad, "Sending %" GST_PTR_FORMAT, gap);
6590 gst_pad_push_event (stream->pad, gap);
6591 stream->segment.position += gap_threshold;
6592 pseudo_cur_time += gap_threshold;
6597 stream = target_stream;
6599 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6600 if (stream->new_caps) {
6601 gst_qtdemux_configure_stream (qtdemux, stream);
6602 qtdemux_do_allocation (stream, qtdemux);
6605 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6606 if (G_UNLIKELY (qtdemux->segment.
6607 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6608 if (stream->subtype == FOURCC_vide) {
6610 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6613 } else if (qtdemux->trickmode_interval > 0) {
6614 GstClockTimeDiff interval;
6616 if (qtdemux->segment.rate > 0)
6617 interval = stream->time_position - stream->last_keyframe_dts;
6619 interval = stream->last_keyframe_dts - stream->time_position;
6621 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6622 && interval < qtdemux->trickmode_interval) {
6623 GST_LOG_OBJECT (qtdemux,
6624 "Skipping keyframe within interval on track-id %u",
6628 stream->last_keyframe_dts = stream->time_position;
6634 GST_DEBUG_OBJECT (qtdemux,
6635 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6636 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6637 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6638 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6639 GST_TIME_ARGS (duration));
6641 if (G_UNLIKELY (empty)) {
6642 /* empty segment, push a gap if there's a second or more
6643 * difference and move to the next one */
6644 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6645 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6646 stream->segment.position = pts + duration;
6650 /* hmm, empty sample, skip and move to next sample */
6651 if (G_UNLIKELY (sample_size <= 0))
6654 /* last pushed sample was out of boundary, goto next sample */
6655 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6658 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6659 GST_DEBUG_OBJECT (qtdemux,
6660 "size %d larger than stream max_buffer_size %d, trimming",
6661 sample_size, stream->max_buffer_size);
6663 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6664 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6665 && sample_size < stream->min_buffer_size) {
6666 guint start_sample_index = stream->sample_index;
6667 guint accumulated_size = sample_size;
6668 guint64 expected_next_offset = offset + sample_size;
6670 GST_DEBUG_OBJECT (qtdemux,
6671 "size %d smaller than stream min_buffer_size %d, combining with the next",
6672 sample_size, stream->min_buffer_size);
6674 while (stream->sample_index < stream->to_sample
6675 && stream->sample_index + 1 < stream->n_samples) {
6676 const QtDemuxSample *next_sample;
6678 /* Increment temporarily */
6679 stream->sample_index++;
6681 /* Failed to parse sample so let's go back to the previous one that was
6682 * still successful */
6683 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6684 stream->sample_index--;
6688 next_sample = &stream->samples[stream->sample_index];
6690 /* Not contiguous with the previous sample so let's go back to the
6691 * previous one that was still successful */
6692 if (next_sample->offset != expected_next_offset) {
6693 stream->sample_index--;
6697 accumulated_size += next_sample->size;
6698 expected_next_offset += next_sample->size;
6699 if (accumulated_size >= stream->min_buffer_size)
6703 num_samples = stream->sample_index + 1 - start_sample_index;
6704 stream->sample_index = start_sample_index;
6705 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6706 num_samples, accumulated_size);
6707 size = accumulated_size;
6712 if (qtdemux->cenc_aux_info_offset > 0) {
6715 GstBuffer *aux_info = NULL;
6717 /* pull the data stored before the sample */
6719 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6720 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6721 if (G_UNLIKELY (ret != GST_FLOW_OK))
6723 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6724 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6725 gst_byte_reader_init (&br, map.data + 8, map.size);
6726 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6727 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6728 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6729 gst_buffer_unmap (aux_info, &map);
6730 gst_buffer_unref (aux_info);
6731 ret = GST_FLOW_ERROR;
6734 gst_buffer_unmap (aux_info, &map);
6735 gst_buffer_unref (aux_info);
6738 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6741 if (stream->use_allocator) {
6742 /* if we have a per-stream allocator, use it */
6743 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6746 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6748 if (G_UNLIKELY (ret != GST_FLOW_OK))
6751 /* Update for both splitting and combining of samples */
6752 if (size != sample_size) {
6753 pts += gst_util_uint64_scale_int (GST_SECOND,
6754 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6757 gst_util_uint64_scale_int (GST_SECOND,
6758 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6761 gst_util_uint64_scale_int (GST_SECOND,
6762 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6765 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6766 dts, pts, duration, keyframe, min_time, offset);
6768 if (size < sample_size) {
6769 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6770 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6772 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6774 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6775 if (time_position >= segment->media_start) {
6776 /* inside the segment, update time_position, looks very familiar to
6777 * GStreamer segments, doesn't it? */
6778 stream->time_position = (time_position - segment->media_start) +
6781 /* not yet in segment, time does not yet increment. This means
6782 * that we are still prerolling keyframes to the decoder so it can
6783 * decode the first sample of the segment. */
6784 stream->time_position = segment->time;
6786 } else if (size > sample_size) {
6787 /* Increase to the last sample we already pulled so that advancing
6788 * below brings us to the next sample we need to pull */
6789 stream->sample_index += num_samples - 1;
6793 GST_OBJECT_LOCK (qtdemux);
6794 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6795 GST_OBJECT_UNLOCK (qtdemux);
6796 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6797 * we have no more data for the pad to push */
6798 if (ret == GST_FLOW_EOS)
6801 stream->offset_in_sample += size;
6802 if (stream->offset_in_sample >= sample_size) {
6803 gst_qtdemux_advance_sample (qtdemux, stream);
6808 gst_qtdemux_advance_sample (qtdemux, stream);
6816 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6822 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6823 /* EOS will be raised if all are EOS */
6830 gst_qtdemux_loop (GstPad * pad)
6832 GstQTDemux *qtdemux;
6836 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6838 cur_offset = qtdemux->offset;
6839 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6840 cur_offset, qt_demux_state_string (qtdemux->state));
6842 switch (qtdemux->state) {
6843 case QTDEMUX_STATE_INITIAL:
6844 case QTDEMUX_STATE_HEADER:
6845 ret = gst_qtdemux_loop_state_header (qtdemux);
6847 case QTDEMUX_STATE_MOVIE:
6848 ret = gst_qtdemux_loop_state_movie (qtdemux);
6849 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6850 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6858 /* if something went wrong, pause */
6859 if (ret != GST_FLOW_OK)
6863 gst_object_unref (qtdemux);
6869 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6870 (NULL), ("streaming stopped, invalid state"));
6871 gst_pad_pause_task (pad);
6872 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6877 const gchar *reason = gst_flow_get_name (ret);
6879 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6881 gst_pad_pause_task (pad);
6883 /* fatal errors need special actions */
6885 if (ret == GST_FLOW_EOS) {
6886 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6887 /* we have no streams, post an error */
6888 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6890 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6893 if ((stop = qtdemux->segment.stop) == -1)
6894 stop = qtdemux->segment.duration;
6896 if (qtdemux->segment.rate >= 0) {
6897 GstMessage *message;
6900 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6901 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6902 GST_FORMAT_TIME, stop);
6903 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6904 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6905 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6906 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6908 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6909 gst_qtdemux_push_event (qtdemux, event);
6911 GstMessage *message;
6914 /* For Reverse Playback */
6915 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6916 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6917 GST_FORMAT_TIME, qtdemux->segment.start);
6918 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6919 qtdemux->segment.start);
6920 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6921 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6922 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6924 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6925 gst_qtdemux_push_event (qtdemux, event);
6930 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6931 event = gst_event_new_eos ();
6932 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6933 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6934 gst_qtdemux_push_event (qtdemux, event);
6936 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6937 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6938 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6947 * Returns if there are samples to be played.
6950 has_next_entry (GstQTDemux * demux)
6952 QtDemuxStream *stream;
6955 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6957 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6958 stream = QTDEMUX_NTH_STREAM (demux, i);
6960 if (stream->sample_index == -1) {
6961 stream->sample_index = 0;
6962 stream->offset_in_sample = 0;
6965 if (stream->sample_index >= stream->n_samples) {
6966 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6969 GST_DEBUG_OBJECT (demux, "Found a sample");
6973 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6980 * Returns the size of the first entry at the current offset.
6981 * If -1, there are none (which means EOS or empty file).
6984 next_entry_size (GstQTDemux * demux)
6986 QtDemuxStream *stream, *target_stream = NULL;
6987 guint64 smalloffs = (guint64) - 1;
6988 QtDemuxSample *sample;
6991 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6994 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6995 stream = QTDEMUX_NTH_STREAM (demux, i);
6997 if (stream->sample_index == -1) {
6998 stream->sample_index = 0;
6999 stream->offset_in_sample = 0;
7002 if (stream->sample_index >= stream->n_samples) {
7003 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
7007 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
7008 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
7009 stream->sample_index);
7013 sample = &stream->samples[stream->sample_index];
7015 GST_LOG_OBJECT (demux,
7016 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
7017 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
7018 stream->sample_index, sample->offset, sample->size);
7020 if (((smalloffs == -1)
7021 || (sample->offset < smalloffs)) && (sample->size)) {
7022 smalloffs = sample->offset;
7023 target_stream = stream;
7030 GST_LOG_OBJECT (demux,
7031 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
7032 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
7034 stream = target_stream;
7035 sample = &stream->samples[stream->sample_index];
7037 if (sample->offset >= demux->offset) {
7038 demux->todrop = sample->offset - demux->offset;
7039 return sample->size + demux->todrop;
7042 GST_DEBUG_OBJECT (demux,
7043 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
7048 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
7050 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
7052 gst_element_post_message (GST_ELEMENT_CAST (demux),
7053 gst_message_new_element (GST_OBJECT_CAST (demux),
7054 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
7058 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
7063 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
7066 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
7067 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
7068 GST_SEEK_TYPE_NONE, -1);
7070 /* store seqnum to drop flush events, they don't need to reach downstream */
7071 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
7072 res = gst_pad_push_event (demux->sinkpad, event);
7073 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
7078 /* check for seekable upstream, above and beyond a mere query */
7080 gst_qtdemux_check_seekability (GstQTDemux * demux)
7083 gboolean seekable = FALSE;
7084 gint64 start = -1, stop = -1;
7086 if (demux->upstream_size)
7089 if (demux->upstream_format_is_time)
7092 query = gst_query_new_seeking (GST_FORMAT_BYTES);
7093 if (!gst_pad_peer_query (demux->sinkpad, query)) {
7094 GST_DEBUG_OBJECT (demux, "seeking query failed");
7098 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
7100 /* try harder to query upstream size if we didn't get it the first time */
7101 if (seekable && stop == -1) {
7102 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
7103 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
7106 /* if upstream doesn't know the size, it's likely that it's not seekable in
7107 * practice even if it technically may be seekable */
7108 if (seekable && (start != 0 || stop <= start)) {
7109 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
7114 gst_query_unref (query);
7116 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
7117 G_GUINT64_FORMAT ")", seekable, start, stop);
7118 demux->upstream_seekable = seekable;
7119 demux->upstream_size = seekable ? stop : -1;
7123 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
7125 g_return_if_fail (bytes <= demux->todrop);
7127 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
7128 gst_adapter_flush (demux->adapter, bytes);
7129 demux->neededbytes -= bytes;
7130 demux->offset += bytes;
7131 demux->todrop -= bytes;
7134 /* PUSH-MODE only: Send a segment, if not done already. */
7136 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
7138 if (G_UNLIKELY (demux->need_segment)) {
7141 if (!demux->upstream_format_is_time) {
7142 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
7144 GstEvent *segment_event;
7145 segment_event = gst_event_new_segment (&demux->segment);
7146 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
7147 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
7148 gst_qtdemux_push_event (demux, segment_event);
7151 demux->need_segment = FALSE;
7153 /* clear to send tags on all streams */
7154 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7155 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7156 gst_qtdemux_push_tags (demux, stream);
7157 if (CUR_STREAM (stream)->sparse) {
7158 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
7159 gst_pad_push_event (stream->pad,
7160 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7166 /* Used for push mode only. */
7168 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7169 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7171 GstClockTime ts, dur;
7175 stream->segments[segment_index].duration - (pos -
7176 stream->segments[segment_index].time);
7177 stream->time_position += dur;
7179 /* Only gaps with a duration of at least one second are propagated.
7180 * Same workaround as in pull mode.
7181 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7182 if (dur >= GST_SECOND) {
7184 gap = gst_event_new_gap (ts, dur);
7186 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7187 "segment: %" GST_PTR_FORMAT, gap);
7188 gst_pad_push_event (stream->pad, gap);
7192 static GstFlowReturn
7193 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7197 demux = GST_QTDEMUX (parent);
7199 GST_DEBUG_OBJECT (demux,
7200 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7201 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7202 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7203 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7204 gst_buffer_get_size (inbuf), demux->offset);
7206 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7207 gboolean is_gap_input = FALSE;
7210 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7212 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7213 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7216 /* Check if we can land back on our feet in the case where upstream is
7217 * handling the seeking/pushing of samples with gaps in between (like
7218 * in the case of trick-mode DASH for example) */
7219 if (demux->upstream_format_is_time
7220 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7221 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7223 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7224 GST_LOG_OBJECT (demux,
7225 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7226 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7228 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7229 stream, GST_BUFFER_OFFSET (inbuf));
7231 QtDemuxSample *sample = &stream->samples[res];
7232 GST_LOG_OBJECT (demux,
7233 "Checking if sample %d from track-id %u is valid (offset:%"
7234 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7235 stream->track_id, sample->offset, sample->size);
7236 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7237 GST_LOG_OBJECT (demux,
7238 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7240 is_gap_input = TRUE;
7241 /* We can go back to standard playback mode */
7242 demux->state = QTDEMUX_STATE_MOVIE;
7243 /* Remember which sample this stream is at */
7244 stream->sample_index = res;
7245 /* Finally update all push-based values to the expected values */
7246 demux->neededbytes = stream->samples[res].size;
7247 demux->offset = GST_BUFFER_OFFSET (inbuf);
7249 demux->mdatsize - demux->offset + demux->mdatoffset;
7254 if (!is_gap_input) {
7255 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7256 /* Reset state if it's a real discont */
7257 demux->neededbytes = 16;
7258 demux->state = QTDEMUX_STATE_INITIAL;
7259 demux->offset = GST_BUFFER_OFFSET (inbuf);
7260 gst_adapter_clear (demux->adapter);
7263 /* Reverse fragmented playback, need to flush all we have before
7264 * consuming a new fragment.
7265 * The samples array have the timestamps calculated by accumulating the
7266 * durations but this won't work for reverse playback of fragments as
7267 * the timestamps of a subsequent fragment should be smaller than the
7268 * previously received one. */
7269 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7270 gst_qtdemux_process_adapter (demux, TRUE);
7271 g_ptr_array_foreach (demux->active_streams,
7272 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7276 gst_adapter_push (demux->adapter, inbuf);
7278 GST_DEBUG_OBJECT (demux,
7279 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7280 demux->neededbytes, gst_adapter_available (demux->adapter));
7282 return gst_qtdemux_process_adapter (demux, FALSE);
7285 static GstFlowReturn
7286 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7288 GstFlowReturn ret = GST_FLOW_OK;
7290 /* we never really mean to buffer that much */
7291 if (demux->neededbytes == -1) {
7295 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7296 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7298 #ifndef GST_DISABLE_GST_DEBUG
7300 guint64 discont_offset, distance_from_discont;
7302 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7303 distance_from_discont =
7304 gst_adapter_distance_from_discont (demux->adapter);
7306 GST_DEBUG_OBJECT (demux,
7307 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7308 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7309 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7310 demux->offset, discont_offset, distance_from_discont);
7314 switch (demux->state) {
7315 case QTDEMUX_STATE_INITIAL:{
7320 gst_qtdemux_check_seekability (demux);
7322 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7324 /* get fourcc/length, set neededbytes */
7325 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7327 gst_adapter_unmap (demux->adapter);
7329 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7330 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7332 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7333 (_("This file is invalid and cannot be played.")),
7334 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7335 GST_FOURCC_ARGS (fourcc)));
7336 ret = GST_FLOW_ERROR;
7339 if (fourcc == FOURCC_mdat) {
7340 gint next_entry = next_entry_size (demux);
7341 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7342 || !demux->fragmented)) {
7343 /* we have the headers, start playback */
7344 demux->state = QTDEMUX_STATE_MOVIE;
7345 demux->neededbytes = next_entry;
7346 demux->mdatleft = size;
7347 demux->mdatsize = demux->mdatleft;
7349 /* no headers yet, try to get them */
7352 guint64 old, target;
7355 old = demux->offset;
7356 target = old + size;
7358 /* try to jump over the atom with a seek */
7359 /* only bother if it seems worth doing so,
7360 * and avoids possible upstream/server problems */
7361 if (demux->upstream_seekable &&
7362 demux->upstream_size > 4 * (1 << 20)) {
7363 res = qtdemux_seek_offset (demux, target);
7365 GST_DEBUG_OBJECT (demux, "skipping seek");
7370 GST_DEBUG_OBJECT (demux, "seek success");
7371 /* remember the offset fo the first mdat so we can seek back to it
7372 * after we have the headers */
7373 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7374 demux->first_mdat = old;
7375 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7378 /* seek worked, continue reading */
7379 demux->offset = target;
7380 demux->neededbytes = 16;
7381 demux->state = QTDEMUX_STATE_INITIAL;
7383 /* seek failed, need to buffer */
7384 demux->offset = old;
7385 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7386 /* there may be multiple mdat (or alike) buffers */
7388 if (demux->mdatbuffer)
7389 bs = gst_buffer_get_size (demux->mdatbuffer);
7392 if (size + bs > 10 * (1 << 20))
7394 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7395 demux->neededbytes = size;
7396 if (!demux->mdatbuffer)
7397 demux->mdatoffset = demux->offset;
7400 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7401 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7402 (_("This file is invalid and cannot be played.")),
7403 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7404 GST_FOURCC_ARGS (fourcc), size));
7405 ret = GST_FLOW_ERROR;
7408 /* this means we already started buffering and still no moov header,
7409 * let's continue buffering everything till we get moov */
7410 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7411 || fourcc == FOURCC_moof))
7413 demux->neededbytes = size;
7414 demux->state = QTDEMUX_STATE_HEADER;
7418 case QTDEMUX_STATE_HEADER:{
7422 GST_DEBUG_OBJECT (demux, "In header");
7424 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7426 /* parse the header */
7427 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7429 if (fourcc == FOURCC_moov) {
7430 /* in usual fragmented setup we could try to scan for more
7431 * and end up at the the moov (after mdat) again */
7432 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7434 || demux->last_moov_offset == demux->offset)) {
7435 GST_DEBUG_OBJECT (demux,
7436 "Skipping moov atom as we have (this) one already");
7438 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7440 if (demux->got_moov && demux->fragmented) {
7441 GST_DEBUG_OBJECT (demux,
7442 "Got a second moov, clean up data from old one");
7443 if (demux->moov_node_compressed) {
7444 g_node_destroy (demux->moov_node_compressed);
7445 if (demux->moov_node)
7446 g_free (demux->moov_node->data);
7448 demux->moov_node_compressed = NULL;
7449 if (demux->moov_node)
7450 g_node_destroy (demux->moov_node);
7451 demux->moov_node = NULL;
7452 demux->start_utc_time = GST_CLOCK_TIME_NONE;
7455 demux->last_moov_offset = demux->offset;
7457 /* Update streams with new moov */
7458 gst_qtdemux_stream_concat (demux,
7459 demux->old_streams, demux->active_streams);
7461 qtdemux_parse_moov (demux, data, demux->neededbytes);
7462 qtdemux_node_dump (demux, demux->moov_node);
7463 qtdemux_parse_tree (demux);
7464 qtdemux_prepare_streams (demux);
7465 QTDEMUX_EXPOSE_LOCK (demux);
7466 qtdemux_expose_streams (demux);
7467 QTDEMUX_EXPOSE_UNLOCK (demux);
7469 demux->got_moov = TRUE;
7471 gst_qtdemux_check_send_pending_segment (demux);
7473 if (demux->moov_node_compressed) {
7474 g_node_destroy (demux->moov_node_compressed);
7475 g_free (demux->moov_node->data);
7477 demux->moov_node_compressed = NULL;
7478 g_node_destroy (demux->moov_node);
7479 demux->moov_node = NULL;
7480 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7482 } else if (fourcc == FOURCC_moof) {
7483 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7485 GstClockTime prev_pts;
7486 guint64 prev_offset;
7487 guint64 adapter_discont_offset, adapter_discont_dist;
7489 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7492 * The timestamp of the moof buffer is relevant as some scenarios
7493 * won't have the initial timestamp in the atoms. Whenever a new
7494 * buffer has started, we get that buffer's PTS and use it as a base
7495 * timestamp for the trun entries.
7497 * To keep track of the current buffer timestamp and starting point
7498 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7499 * from the beginning of the buffer, with the distance and demux->offset
7500 * we know if it is still the same buffer or not.
7502 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7503 prev_offset = demux->offset - dist;
7504 if (demux->fragment_start_offset == -1
7505 || prev_offset > demux->fragment_start_offset) {
7506 demux->fragment_start_offset = prev_offset;
7507 demux->fragment_start = prev_pts;
7508 GST_DEBUG_OBJECT (demux,
7509 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7510 GST_TIME_FORMAT, demux->fragment_start_offset,
7511 GST_TIME_ARGS (demux->fragment_start));
7514 /* We can't use prev_offset() here because this would require
7515 * upstream to set consistent and correct offsets on all buffers
7516 * since the discont. Nothing ever did that in the past and we
7517 * would break backwards compatibility here then.
7518 * Instead take the offset we had at the last discont and count
7519 * the bytes from there. This works with old code as there would
7520 * be no discont between moov and moof, and also works with
7521 * adaptivedemux which correctly sets offset and will set the
7522 * DISCONT flag accordingly when needed.
7524 * We also only do this for upstream TIME segments as otherwise
7525 * there are potential backwards compatibility problems with
7526 * seeking in PUSH mode and upstream providing inconsistent
7528 adapter_discont_offset =
7529 gst_adapter_offset_at_discont (demux->adapter);
7530 adapter_discont_dist =
7531 gst_adapter_distance_from_discont (demux->adapter);
7533 GST_DEBUG_OBJECT (demux,
7534 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7535 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7536 demux->offset, adapter_discont_offset, adapter_discont_dist);
7538 if (demux->upstream_format_is_time) {
7539 demux->moof_offset = adapter_discont_offset;
7540 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7541 demux->moof_offset += adapter_discont_dist;
7542 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7543 demux->moof_offset = demux->offset;
7545 demux->moof_offset = demux->offset;
7548 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7549 demux->moof_offset, NULL)) {
7550 gst_adapter_unmap (demux->adapter);
7551 ret = GST_FLOW_ERROR;
7555 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7556 if (demux->mss_mode && !demux->exposed) {
7557 QTDEMUX_EXPOSE_LOCK (demux);
7558 qtdemux_expose_streams (demux);
7559 QTDEMUX_EXPOSE_UNLOCK (demux);
7562 gst_qtdemux_check_send_pending_segment (demux);
7564 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7566 } else if (fourcc == FOURCC_ftyp) {
7567 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7568 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7569 } else if (fourcc == FOURCC_uuid) {
7570 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7571 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7572 } else if (fourcc == FOURCC_sidx) {
7573 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7574 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7575 } else if (fourcc == FOURCC_meta) {
7576 GNode *node, *child;
7577 GstByteReader child_data;
7579 node = g_node_new ((gpointer) data);
7580 qtdemux_parse_node (demux, node, data, demux->neededbytes);
7582 /* Parse ONVIF Export File Format CorrectStartTime box if available */
7584 qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb,
7586 qtdemux_parse_cstb (demux, &child_data);
7589 g_node_destroy (node);
7593 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7597 /* [free] and [skip] are padding atoms */
7598 GST_DEBUG_OBJECT (demux,
7599 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7600 GST_FOURCC_ARGS (fourcc));
7603 GST_WARNING_OBJECT (demux,
7604 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7605 GST_FOURCC_ARGS (fourcc));
7606 /* Let's jump that one and go back to initial state */
7610 gst_adapter_unmap (demux->adapter);
7613 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7614 gsize remaining_data_size = 0;
7616 /* the mdat was before the header */
7617 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7618 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7619 /* restore our adapter/offset view of things with upstream;
7620 * put preceding buffered data ahead of current moov data.
7621 * This should also handle evil mdat, moov, mdat cases and alike */
7622 gst_adapter_flush (demux->adapter, demux->neededbytes);
7624 /* Store any remaining data after the mdat for later usage */
7625 remaining_data_size = gst_adapter_available (demux->adapter);
7626 if (remaining_data_size > 0) {
7627 g_assert (demux->restoredata_buffer == NULL);
7628 demux->restoredata_buffer =
7629 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7630 demux->restoredata_offset = demux->offset + demux->neededbytes;
7631 GST_DEBUG_OBJECT (demux,
7632 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7633 G_GUINT64_FORMAT, remaining_data_size,
7634 demux->restoredata_offset);
7637 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7638 demux->mdatbuffer = NULL;
7639 demux->offset = demux->mdatoffset;
7640 demux->neededbytes = next_entry_size (demux);
7641 demux->state = QTDEMUX_STATE_MOVIE;
7642 demux->mdatleft = gst_adapter_available (demux->adapter);
7643 demux->mdatsize = demux->mdatleft;
7645 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7646 gst_adapter_flush (demux->adapter, demux->neededbytes);
7648 /* only go back to the mdat if there are samples to play */
7649 if (demux->got_moov && demux->first_mdat != -1
7650 && has_next_entry (demux)) {
7653 /* we need to seek back */
7654 res = qtdemux_seek_offset (demux, demux->first_mdat);
7656 demux->offset = demux->first_mdat;
7658 GST_DEBUG_OBJECT (demux, "Seek back failed");
7661 demux->offset += demux->neededbytes;
7663 demux->neededbytes = 16;
7664 demux->state = QTDEMUX_STATE_INITIAL;
7669 case QTDEMUX_STATE_BUFFER_MDAT:{
7673 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7675 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7676 gst_buffer_extract (buf, 0, fourcc, 4);
7677 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7678 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7679 if (demux->mdatbuffer)
7680 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7682 demux->mdatbuffer = buf;
7683 demux->offset += demux->neededbytes;
7684 demux->neededbytes = 16;
7685 demux->state = QTDEMUX_STATE_INITIAL;
7686 gst_qtdemux_post_progress (demux, 1, 1);
7690 case QTDEMUX_STATE_MOVIE:{
7691 QtDemuxStream *stream = NULL;
7692 QtDemuxSample *sample;
7693 GstClockTime dts, pts, duration;
7697 GST_DEBUG_OBJECT (demux,
7698 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7700 if (demux->fragmented) {
7701 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7703 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7704 /* if needed data starts within this atom,
7705 * then it should not exceed this atom */
7706 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7707 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7708 (_("This file is invalid and cannot be played.")),
7709 ("sample data crosses atom boundary"));
7710 ret = GST_FLOW_ERROR;
7713 demux->mdatleft -= demux->neededbytes;
7715 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7716 /* so we are dropping more than left in this atom */
7717 gst_qtdemux_drop_data (demux, demux->mdatleft);
7718 demux->mdatleft = 0;
7720 /* need to resume atom parsing so we do not miss any other pieces */
7721 demux->state = QTDEMUX_STATE_INITIAL;
7722 demux->neededbytes = 16;
7724 /* check if there was any stored post mdat data from previous buffers */
7725 if (demux->restoredata_buffer) {
7726 g_assert (gst_adapter_available (demux->adapter) == 0);
7728 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7729 demux->restoredata_buffer = NULL;
7730 demux->offset = demux->restoredata_offset;
7737 if (demux->todrop) {
7738 if (demux->cenc_aux_info_offset > 0) {
7742 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7743 data = gst_adapter_map (demux->adapter, demux->todrop);
7744 gst_byte_reader_init (&br, data + 8, demux->todrop);
7745 if (!qtdemux_parse_cenc_aux_info (demux,
7746 QTDEMUX_NTH_STREAM (demux, 0), &br,
7747 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7748 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7749 ret = GST_FLOW_ERROR;
7750 gst_adapter_unmap (demux->adapter);
7751 g_free (demux->cenc_aux_info_sizes);
7752 demux->cenc_aux_info_sizes = NULL;
7755 demux->cenc_aux_info_offset = 0;
7756 g_free (demux->cenc_aux_info_sizes);
7757 demux->cenc_aux_info_sizes = NULL;
7758 gst_adapter_unmap (demux->adapter);
7760 gst_qtdemux_drop_data (demux, demux->todrop);
7764 /* initial newsegment sent here after having added pads,
7765 * possible others in sink_event */
7766 gst_qtdemux_check_send_pending_segment (demux);
7768 /* Figure out which stream this packet belongs to */
7769 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7770 stream = QTDEMUX_NTH_STREAM (demux, i);
7771 if (stream->sample_index >= stream->n_samples) {
7772 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7776 GST_LOG_OBJECT (demux,
7777 "Checking track-id %u (sample_index:%d / offset:%"
7778 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7779 stream->sample_index,
7780 stream->samples[stream->sample_index].offset,
7781 stream->samples[stream->sample_index].size);
7783 if (stream->samples[stream->sample_index].offset == demux->offset)
7787 if (G_UNLIKELY (stream == NULL))
7788 goto unknown_stream;
7790 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7792 if (stream->new_caps) {
7793 gst_qtdemux_configure_stream (demux, stream);
7796 /* Put data in a buffer, set timestamps, caps, ... */
7797 sample = &stream->samples[stream->sample_index];
7799 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7800 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7801 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7803 dts = QTSAMPLE_DTS (stream, sample);
7804 pts = QTSAMPLE_PTS (stream, sample);
7805 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7806 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7808 /* check for segment end */
7809 if (G_UNLIKELY (demux->segment.stop != -1
7810 && demux->segment.stop <= pts && stream->on_keyframe)
7811 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7812 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7813 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7815 /* skip this data, stream is EOS */
7816 gst_adapter_flush (demux->adapter, demux->neededbytes);
7817 demux->offset += demux->neededbytes;
7819 /* check if all streams are eos */
7821 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7822 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7831 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7833 /* FIXME: should either be an assert or a plain check */
7834 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7836 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7837 dts, pts, duration, keyframe, dts, demux->offset);
7841 GST_OBJECT_LOCK (demux);
7842 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7843 GST_OBJECT_UNLOCK (demux);
7845 /* skip this data, stream is EOS */
7846 gst_adapter_flush (demux->adapter, demux->neededbytes);
7849 stream->sample_index++;
7850 stream->offset_in_sample = 0;
7852 /* update current offset and figure out size of next buffer */
7853 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7854 demux->offset, demux->neededbytes);
7855 demux->offset += demux->neededbytes;
7856 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7860 if (ret == GST_FLOW_EOS) {
7861 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7862 demux->neededbytes = -1;
7866 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7867 if (demux->fragmented) {
7868 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7869 /* there may be more to follow, only finish this atom */
7870 demux->todrop = demux->mdatleft;
7871 demux->neededbytes = demux->todrop;
7876 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7877 goto non_ok_unlinked_flow;
7886 /* when buffering movie data, at least show user something is happening */
7887 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7888 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7889 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7890 demux->neededbytes);
7897 non_ok_unlinked_flow:
7899 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7900 gst_flow_get_name (ret));
7905 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7906 ret = GST_FLOW_ERROR;
7911 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7917 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7918 (NULL), ("qtdemuxer invalid state %d", demux->state));
7919 ret = GST_FLOW_ERROR;
7924 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7925 (NULL), ("no 'moov' atom within the first 10 MB"));
7926 ret = GST_FLOW_ERROR;
7932 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7937 query = gst_query_new_scheduling ();
7939 if (!gst_pad_peer_query (sinkpad, query)) {
7940 gst_query_unref (query);
7944 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7945 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7946 gst_query_unref (query);
7951 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7952 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7956 GST_DEBUG_OBJECT (sinkpad, "activating push");
7957 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7962 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7963 GstPadMode mode, gboolean active)
7966 GstQTDemux *demux = GST_QTDEMUX (parent);
7969 case GST_PAD_MODE_PUSH:
7970 demux->pullbased = FALSE;
7973 case GST_PAD_MODE_PULL:
7975 demux->pullbased = TRUE;
7976 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7979 res = gst_pad_stop_task (sinkpad);
7991 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7997 memset (&z, 0, sizeof (z));
8002 if ((ret = inflateInit (&z)) != Z_OK) {
8003 GST_ERROR ("inflateInit() returned %d", ret);
8007 z.next_in = z_buffer;
8008 z.avail_in = z_length;
8010 buffer = (guint8 *) g_malloc (*length);
8011 z.avail_out = *length;
8012 z.next_out = (Bytef *) buffer;
8014 ret = inflate (&z, Z_NO_FLUSH);
8015 if (ret == Z_STREAM_END) {
8017 } else if (ret != Z_OK) {
8018 GST_WARNING ("inflate() returned %d", ret);
8022 if (*length > G_MAXUINT - 4096 || *length > QTDEMUX_MAX_SAMPLE_INDEX_SIZE) {
8023 GST_WARNING ("too big decompressed data");
8029 buffer = (guint8 *) g_realloc (buffer, *length);
8030 z.next_out = (Bytef *) (buffer + z.total_out);
8031 z.avail_out += *length - z.total_out;
8032 } while (z.avail_in > 0);
8034 if (ret != Z_STREAM_END) {
8039 *length = z.total_out;
8046 #endif /* HAVE_ZLIB */
8049 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
8053 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
8055 /* counts as header data */
8056 qtdemux->header_size += length;
8058 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
8059 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
8061 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
8068 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
8069 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
8070 if (dcom == NULL || cmvd == NULL)
8071 goto invalid_compression;
8073 dcom_len = QT_UINT32 (dcom->data);
8075 goto invalid_compression;
8077 method = QT_FOURCC ((guint8 *) dcom->data + 8);
8081 guint uncompressed_length;
8082 guint compressed_length;
8086 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
8088 goto invalid_compression;
8090 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
8091 compressed_length = cmvd_len - 12;
8092 GST_LOG ("length = %u", uncompressed_length);
8095 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
8096 compressed_length, &uncompressed_length);
8099 qtdemux->moov_node_compressed = qtdemux->moov_node;
8100 qtdemux->moov_node = g_node_new (buf);
8102 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
8103 uncompressed_length);
8107 #endif /* HAVE_ZLIB */
8109 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
8110 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
8117 invalid_compression:
8119 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
8125 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
8128 while (G_UNLIKELY (buf < end)) {
8132 if (G_UNLIKELY (buf + 4 > end)) {
8133 GST_LOG_OBJECT (qtdemux, "buffer overrun");
8136 len = QT_UINT32 (buf);
8137 if (G_UNLIKELY (len == 0)) {
8138 GST_LOG_OBJECT (qtdemux, "empty container");
8141 if (G_UNLIKELY (len < 8)) {
8142 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
8145 if (G_UNLIKELY (len > (end - buf))) {
8146 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
8147 (gint) (end - buf));
8151 child = g_node_new ((guint8 *) buf);
8152 g_node_append (node, child);
8153 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
8154 qtdemux_parse_node (qtdemux, child, buf, len);
8162 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
8165 int len = QT_UINT32 (xdxt->data);
8166 guint8 *buf = xdxt->data;
8167 guint8 *end = buf + len;
8170 /* skip size and type */
8178 size = QT_UINT32 (buf);
8179 type = QT_FOURCC (buf + 4);
8181 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
8183 if (buf + size > end || size <= 0)
8189 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8190 GST_FOURCC_ARGS (type));
8194 buffer = gst_buffer_new_and_alloc (size);
8195 gst_buffer_fill (buffer, 0, buf, size);
8196 stream->buffers = g_slist_append (stream->buffers, buffer);
8197 GST_LOG_OBJECT (qtdemux, "parsing theora header");
8200 buffer = gst_buffer_new_and_alloc (size);
8201 gst_buffer_fill (buffer, 0, buf, size);
8202 stream->buffers = g_slist_append (stream->buffers, buffer);
8203 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
8206 buffer = gst_buffer_new_and_alloc (size);
8207 gst_buffer_fill (buffer, 0, buf, size);
8208 stream->buffers = g_slist_append (stream->buffers, buffer);
8209 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
8212 GST_WARNING_OBJECT (qtdemux,
8213 "unknown theora cookie %" GST_FOURCC_FORMAT,
8214 GST_FOURCC_ARGS (type));
8223 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8227 guint32 node_length = 0;
8228 const QtNodeType *type;
8231 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8233 if (G_UNLIKELY (length < 8))
8234 goto not_enough_data;
8236 node_length = QT_UINT32 (buffer);
8237 fourcc = QT_FOURCC (buffer + 4);
8239 /* ignore empty nodes */
8240 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8243 type = qtdemux_type_get (fourcc);
8245 end = buffer + length;
8247 GST_LOG_OBJECT (qtdemux,
8248 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8249 GST_FOURCC_ARGS (fourcc), node_length, type->name);
8251 if (node_length > length)
8252 goto broken_atom_size;
8254 if (type->flags & QT_FLAG_CONTAINER) {
8255 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8260 if (node_length < 20) {
8261 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8264 GST_DEBUG_OBJECT (qtdemux,
8265 "parsing stsd (sample table, sample description) atom");
8266 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8267 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8279 /* also read alac (or whatever) in stead of mp4a in the following,
8280 * since a similar layout is used in other cases as well */
8281 if (fourcc == FOURCC_mp4a)
8283 else if (fourcc == FOURCC_fLaC)
8288 /* There are two things we might encounter here: a true mp4a atom, and
8289 an mp4a entry in an stsd atom. The latter is what we're interested
8290 in, and it looks like an atom, but isn't really one. The true mp4a
8291 atom is short, so we detect it based on length here. */
8292 if (length < min_size) {
8293 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8294 GST_FOURCC_ARGS (fourcc));
8298 /* 'version' here is the sound sample description version. Types 0 and
8299 1 are documented in the QTFF reference, but type 2 is not: it's
8300 described in Apple header files instead (struct SoundDescriptionV2
8302 version = QT_UINT16 (buffer + 16);
8304 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8305 GST_FOURCC_ARGS (fourcc), version);
8307 /* parse any esds descriptors */
8319 GST_WARNING_OBJECT (qtdemux,
8320 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8321 GST_FOURCC_ARGS (fourcc), version);
8326 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8354 /* codec_data is contained inside these atoms, which all have
8355 * the same format. */
8356 /* video sample description size is 86 bytes without extension.
8357 * node_length have to be bigger than 86 bytes because video sample
8358 * description can include extensions such as esds, fiel, glbl, etc. */
8359 if (node_length < 86) {
8360 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8361 " sample description length too short (%u < 86)",
8362 GST_FOURCC_ARGS (fourcc), node_length);
8366 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8367 GST_FOURCC_ARGS (fourcc));
8369 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8371 * revision level (2 bytes) : must be set to 0. */
8372 version = QT_UINT32 (buffer + 16);
8373 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8375 /* compressor name : PASCAL string and informative purposes
8376 * first byte : the number of bytes to be displayed.
8377 * it has to be less than 32 because it is reserved
8378 * space of 32 bytes total including itself. */
8379 str_len = QT_UINT8 (buffer + 50);
8381 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8382 (char *) buffer + 51);
8384 GST_WARNING_OBJECT (qtdemux,
8385 "compressorname length too big (%u > 31)", str_len);
8387 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8389 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8394 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8396 /* You are reading this correctly. QTFF specifies that the
8397 * metadata atom is a short atom, whereas ISO BMFF specifies
8398 * it's a full atom. But since so many people are doing things
8399 * differently, we actually peek into the atom to see which
8402 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8403 GST_FOURCC_ARGS (fourcc));
8406 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8407 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8408 * starts with a 'hdlr' atom */
8409 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8410 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8411 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8412 * with version/flags both set to zero */
8413 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8415 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8420 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8421 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8422 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8431 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8432 GST_FOURCC_ARGS (fourcc));
8436 version = QT_UINT32 (buffer + 12);
8437 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8444 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8449 if (length < offset) {
8450 GST_WARNING_OBJECT (qtdemux,
8451 "skipping too small %" GST_FOURCC_FORMAT " box",
8452 GST_FOURCC_ARGS (fourcc));
8455 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8461 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8466 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8471 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8475 if (!strcmp (type->name, "unknown"))
8476 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8480 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8481 GST_FOURCC_ARGS (fourcc));
8487 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8488 (_("This file is corrupt and cannot be played.")),
8489 ("Not enough data for an atom header, got only %u bytes", length));
8494 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8495 (_("This file is corrupt and cannot be played.")),
8496 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8497 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8504 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8506 /* FIXME: This can only reliably work if demuxers have a
8507 * separate streaming thread per srcpad. This should be
8508 * done in a demuxer base class, which integrates parts
8511 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8516 query = gst_query_new_allocation (stream->caps, FALSE);
8518 if (!gst_pad_peer_query (stream->pad, query)) {
8519 /* not a problem, just debug a little */
8520 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8523 if (stream->allocator)
8524 gst_object_unref (stream->allocator);
8526 if (gst_query_get_n_allocation_params (query) > 0) {
8527 /* try the allocator */
8528 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8530 stream->use_allocator = TRUE;
8532 stream->allocator = NULL;
8533 gst_allocation_params_init (&stream->params);
8534 stream->use_allocator = FALSE;
8536 gst_query_unref (query);
8541 pad_query (const GValue * item, GValue * value, gpointer user_data)
8543 GstPad *pad = g_value_get_object (item);
8544 GstQuery *query = user_data;
8547 res = gst_pad_peer_query (pad, query);
8550 g_value_set_boolean (value, TRUE);
8554 GST_INFO_OBJECT (pad, "pad peer query failed");
8559 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8560 GstPadDirection direction)
8563 GstIteratorFoldFunction func = pad_query;
8564 GValue res = { 0, };
8566 g_value_init (&res, G_TYPE_BOOLEAN);
8567 g_value_set_boolean (&res, FALSE);
8570 if (direction == GST_PAD_SRC)
8571 it = gst_element_iterate_src_pads (element);
8573 it = gst_element_iterate_sink_pads (element);
8575 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8576 gst_iterator_resync (it);
8578 gst_iterator_free (it);
8580 return g_value_get_boolean (&res);
8584 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8585 QtDemuxStream * stream)
8589 GstElement *element = GST_ELEMENT (qtdemux);
8591 gchar **filtered_sys_ids;
8592 GValue event_list = G_VALUE_INIT;
8595 /* 1. Check if we already have the context. */
8596 if (qtdemux->preferred_protection_system_id != NULL) {
8597 GST_LOG_OBJECT (element,
8598 "already have the protection context, no need to request it again");
8602 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8603 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8604 (const gchar **) qtdemux->protection_system_ids->pdata);
8606 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8607 qtdemux->protection_system_ids->len - 1);
8608 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8609 "decryptors for %u of them, running context request",
8610 qtdemux->protection_system_ids->len,
8611 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8614 if (stream->protection_scheme_event_queue.length) {
8615 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8616 stream->protection_scheme_event_queue.length);
8617 walk = stream->protection_scheme_event_queue.tail;
8619 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8620 qtdemux->protection_event_queue.length);
8621 walk = qtdemux->protection_event_queue.tail;
8624 g_value_init (&event_list, GST_TYPE_LIST);
8625 for (; walk; walk = g_list_previous (walk)) {
8626 GValue event_value = G_VALUE_INIT;
8627 g_value_init (&event_value, GST_TYPE_EVENT);
8628 g_value_set_boxed (&event_value, walk->data);
8629 gst_value_list_append_and_take_value (&event_list, &event_value);
8632 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8633 * check if downstream already has a context of the specific type
8634 * 2b) Query upstream as above.
8636 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8637 st = gst_query_writable_structure (query);
8638 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8639 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8641 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8642 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8643 gst_query_parse_context (query, &ctxt);
8644 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8645 gst_element_set_context (element, ctxt);
8646 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8647 gst_query_parse_context (query, &ctxt);
8648 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8649 gst_element_set_context (element, ctxt);
8651 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8652 * the required context type and afterwards check if a
8653 * usable context was set now as in 1). The message could
8654 * be handled by the parent bins of the element and the
8659 GST_INFO_OBJECT (element, "posting need context message");
8660 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8661 "drm-preferred-decryption-system-id");
8662 st = (GstStructure *) gst_message_get_structure (msg);
8663 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8664 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8667 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8668 gst_element_post_message (element, msg);
8671 g_strfreev (filtered_sys_ids);
8672 g_value_unset (&event_list);
8673 gst_query_unref (query);
8677 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8678 QtDemuxStream * stream)
8681 const gchar *selected_system = NULL;
8683 g_return_val_if_fail (qtdemux != NULL, FALSE);
8684 g_return_val_if_fail (stream != NULL, FALSE);
8685 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8688 if (stream->protection_scheme_type == FOURCC_aavd) {
8689 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8690 if (!gst_structure_has_name (s, "application/x-aavd")) {
8691 gst_structure_set (s,
8692 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8694 gst_structure_set_name (s, "application/x-aavd");
8699 if (stream->protection_scheme_type != FOURCC_cenc
8700 && stream->protection_scheme_type != FOURCC_cbcs) {
8701 GST_ERROR_OBJECT (qtdemux,
8702 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8703 GST_FOURCC_ARGS (stream->protection_scheme_type));
8707 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8708 if (!gst_structure_has_name (s, "application/x-cenc")) {
8709 gst_structure_set (s,
8710 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8711 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8712 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8714 gst_structure_set_name (s, "application/x-cenc");
8717 if (qtdemux->protection_system_ids == NULL) {
8718 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8719 "cenc protection system information has been found, not setting a "
8720 "protection system UUID");
8724 gst_qtdemux_request_protection_context (qtdemux, stream);
8725 if (qtdemux->preferred_protection_system_id != NULL) {
8726 const gchar *preferred_system_array[] =
8727 { qtdemux->preferred_protection_system_id, NULL };
8729 selected_system = gst_protection_select_system (preferred_system_array);
8731 if (selected_system) {
8732 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8733 qtdemux->preferred_protection_system_id);
8735 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8736 "because there is no available decryptor",
8737 qtdemux->preferred_protection_system_id);
8741 if (!selected_system) {
8742 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8743 selected_system = gst_protection_select_system ((const gchar **)
8744 qtdemux->protection_system_ids->pdata);
8745 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8746 qtdemux->protection_system_ids->len - 1);
8749 if (!selected_system) {
8750 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8751 "suitable decryptor element has been found");
8755 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8758 gst_structure_set (s,
8759 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8766 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8768 /* fps is calculated base on the duration of the average framerate since
8769 * qt does not have a fixed framerate. */
8770 gboolean fps_available = TRUE;
8771 guint32 first_duration = 0;
8773 if (stream->n_samples > 0)
8774 first_duration = stream->samples[0].duration;
8776 if ((stream->n_samples == 1 && first_duration == 0)
8777 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8779 CUR_STREAM (stream)->fps_n = 0;
8780 CUR_STREAM (stream)->fps_d = 1;
8782 if (stream->duration == 0 || stream->n_samples < 2) {
8783 CUR_STREAM (stream)->fps_n = stream->timescale;
8784 CUR_STREAM (stream)->fps_d = 1;
8785 fps_available = FALSE;
8787 GstClockTime avg_duration;
8791 /* duration and n_samples can be updated for fragmented format
8792 * so, framerate of fragmented format is calculated using data in a moof */
8793 if (qtdemux->fragmented && stream->n_samples_moof > 0
8794 && stream->duration_moof > 0) {
8795 n_samples = stream->n_samples_moof;
8796 duration = stream->duration_moof;
8798 n_samples = stream->n_samples;
8799 duration = stream->duration;
8802 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8803 /* stream->duration is guint64, timescale, n_samples are guint32 */
8805 gst_util_uint64_scale_round (duration -
8806 first_duration, GST_SECOND,
8807 (guint64) (stream->timescale) * (n_samples - 1));
8809 GST_LOG_OBJECT (qtdemux,
8810 "Calculating avg sample duration based on stream (or moof) duration %"
8812 " minus first sample %u, leaving %d samples gives %"
8813 GST_TIME_FORMAT, duration, first_duration,
8814 n_samples - 1, GST_TIME_ARGS (avg_duration));
8817 gst_video_guess_framerate (avg_duration,
8818 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8820 GST_DEBUG_OBJECT (qtdemux,
8821 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8822 stream->timescale, CUR_STREAM (stream)->fps_n,
8823 CUR_STREAM (stream)->fps_d);
8827 return fps_available;
8831 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8833 if (stream->subtype == FOURCC_vide) {
8834 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8836 if (CUR_STREAM (stream)->caps) {
8837 CUR_STREAM (stream)->caps =
8838 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8840 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8841 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8842 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8843 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8845 /* set framerate if calculated framerate is reliable */
8846 if (fps_available) {
8847 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8848 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8849 CUR_STREAM (stream)->fps_d, NULL);
8852 /* calculate pixel-aspect-ratio using display width and height */
8853 GST_DEBUG_OBJECT (qtdemux,
8854 "video size %dx%d, target display size %dx%d",
8855 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8856 stream->display_width, stream->display_height);
8857 /* qt file might have pasp atom */
8858 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8859 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8860 CUR_STREAM (stream)->par_h);
8861 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8862 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8863 CUR_STREAM (stream)->par_h, NULL);
8864 } else if (stream->display_width > 0 && stream->display_height > 0
8865 && CUR_STREAM (stream)->width > 0
8866 && CUR_STREAM (stream)->height > 0) {
8869 /* calculate the pixel aspect ratio using the display and pixel w/h */
8870 n = stream->display_width * CUR_STREAM (stream)->height;
8871 d = stream->display_height * CUR_STREAM (stream)->width;
8874 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8875 CUR_STREAM (stream)->par_w = n;
8876 CUR_STREAM (stream)->par_h = d;
8877 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8878 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8879 CUR_STREAM (stream)->par_h, NULL);
8882 if (CUR_STREAM (stream)->interlace_mode > 0) {
8883 if (CUR_STREAM (stream)->interlace_mode == 1) {
8884 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8885 G_TYPE_STRING, "progressive", NULL);
8886 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8887 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8888 G_TYPE_STRING, "interleaved", NULL);
8889 if (CUR_STREAM (stream)->field_order == 9) {
8890 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8891 G_TYPE_STRING, "top-field-first", NULL);
8892 } else if (CUR_STREAM (stream)->field_order == 14) {
8893 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8894 G_TYPE_STRING, "bottom-field-first", NULL);
8899 /* Create incomplete colorimetry here if needed */
8900 if (CUR_STREAM (stream)->colorimetry.range ||
8901 CUR_STREAM (stream)->colorimetry.matrix ||
8902 CUR_STREAM (stream)->colorimetry.transfer
8903 || CUR_STREAM (stream)->colorimetry.primaries) {
8904 gchar *colorimetry =
8905 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8906 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8907 G_TYPE_STRING, colorimetry, NULL);
8908 g_free (colorimetry);
8911 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8912 guint par_w = 1, par_h = 1;
8914 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8915 par_w = CUR_STREAM (stream)->par_w;
8916 par_h = CUR_STREAM (stream)->par_h;
8919 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8920 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8922 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8925 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8926 "multiview-mode", G_TYPE_STRING,
8927 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8928 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8929 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8934 else if (stream->subtype == FOURCC_soun) {
8935 if (CUR_STREAM (stream)->caps) {
8936 CUR_STREAM (stream)->caps =
8937 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8938 if (CUR_STREAM (stream)->rate > 0)
8939 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8940 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8941 if (CUR_STREAM (stream)->n_channels > 0)
8942 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8943 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8944 if (CUR_STREAM (stream)->n_channels > 2) {
8945 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8946 * correctly; this is just the minimum we can do - assume
8947 * we don't actually have any channel positions. */
8948 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8949 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8954 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8955 const GstStructure *s;
8956 QtDemuxStream *fps_stream = NULL;
8957 gboolean fps_available = FALSE;
8959 /* CEA608 closed caption tracks are a bit special in that each sample
8960 * can contain CCs for multiple frames, and CCs can be omitted and have to
8961 * be inferred from the duration of the sample then.
8963 * As such we take the framerate from the (first) video track here for
8964 * CEA608 as there must be one CC byte pair for every video frame
8965 * according to the spec.
8967 * For CEA708 all is fine and there is one sample per frame.
8970 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8971 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8974 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8975 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8977 if (tmp->subtype == FOURCC_vide) {
8984 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8985 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8986 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8989 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8990 fps_stream = stream;
8993 CUR_STREAM (stream)->caps =
8994 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8996 /* set framerate if calculated framerate is reliable */
8997 if (fps_available) {
8998 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8999 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
9000 CUR_STREAM (stream)->fps_d, NULL);
9005 gboolean forward_collection = FALSE;
9006 GstCaps *prev_caps = NULL;
9008 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
9009 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
9010 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
9011 gst_pad_set_active (stream->pad, TRUE);
9013 gst_pad_use_fixed_caps (stream->pad);
9015 if (stream->protected) {
9016 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
9017 GST_ERROR_OBJECT (qtdemux,
9018 "Failed to configure protected stream caps.");
9023 if (stream->new_stream) {
9025 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
9028 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
9031 gst_event_parse_stream_flags (event, &stream_flags);
9032 if (gst_event_parse_group_id (event, &qtdemux->group_id))
9033 qtdemux->have_group_id = TRUE;
9035 qtdemux->have_group_id = FALSE;
9036 gst_event_unref (event);
9037 } else if (!qtdemux->have_group_id) {
9038 qtdemux->have_group_id = TRUE;
9039 qtdemux->group_id = gst_util_group_id_next ();
9042 stream->new_stream = FALSE;
9043 event = gst_event_new_stream_start (stream->stream_id);
9044 if (qtdemux->have_group_id)
9045 gst_event_set_group_id (event, qtdemux->group_id);
9046 if (stream->disabled)
9047 stream_flags |= GST_STREAM_FLAG_UNSELECT;
9048 if (CUR_STREAM (stream)->sparse) {
9049 stream_flags |= GST_STREAM_FLAG_SPARSE;
9051 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
9053 gst_event_set_stream_flags (event, stream_flags);
9054 gst_pad_push_event (stream->pad, event);
9056 forward_collection = TRUE;
9059 prev_caps = gst_pad_get_current_caps (stream->pad);
9061 if (CUR_STREAM (stream)->caps) {
9063 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
9064 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
9065 CUR_STREAM (stream)->caps);
9066 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
9068 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
9071 GST_WARNING_OBJECT (qtdemux, "stream without caps");
9075 gst_caps_unref (prev_caps);
9076 stream->new_caps = FALSE;
9078 if (forward_collection) {
9079 /* Forward upstream collection and selection if any */
9080 GstEvent *upstream_event = gst_pad_get_sticky_event (qtdemux->sinkpad,
9081 GST_EVENT_STREAM_COLLECTION, 0);
9083 gst_pad_push_event (stream->pad, upstream_event);
9090 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
9091 QtDemuxStream * stream)
9093 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
9096 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
9097 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
9098 if (G_UNLIKELY (stream->stsd_sample_description_id >=
9099 stream->stsd_entries_length)) {
9100 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
9101 (_("This file is invalid and cannot be played.")),
9102 ("New sample description id is out of bounds (%d >= %d)",
9103 stream->stsd_sample_description_id, stream->stsd_entries_length));
9105 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
9106 stream->new_caps = TRUE;
9111 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
9112 QtDemuxStream * stream, GstTagList * list)
9114 gboolean ret = TRUE;
9116 if (stream->subtype == FOURCC_vide) {
9117 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9120 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9123 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9124 gst_object_unref (stream->pad);
9130 qtdemux->n_video_streams++;
9131 } else if (stream->subtype == FOURCC_soun) {
9132 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
9135 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9137 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9138 gst_object_unref (stream->pad);
9143 qtdemux->n_audio_streams++;
9144 } else if (stream->subtype == FOURCC_strm) {
9145 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9146 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9147 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9148 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
9149 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9152 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9154 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9155 gst_object_unref (stream->pad);
9160 qtdemux->n_sub_streams++;
9161 } else if (stream->subtype == FOURCC_meta) {
9162 gchar *name = g_strdup_printf ("meta_%u", qtdemux->n_meta_streams);
9165 gst_pad_new_from_static_template (&gst_qtdemux_metasrc_template, name);
9167 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9168 gst_object_unref (stream->pad);
9173 qtdemux->n_meta_streams++;
9174 } else if (CUR_STREAM (stream)->caps) {
9175 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9178 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9180 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9181 gst_object_unref (stream->pad);
9186 qtdemux->n_video_streams++;
9188 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9195 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9196 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9197 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9198 GST_OBJECT_LOCK (qtdemux);
9199 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9200 GST_OBJECT_UNLOCK (qtdemux);
9202 if (stream->stream_tags)
9203 gst_tag_list_unref (stream->stream_tags);
9204 stream->stream_tags = list;
9206 /* global tags go on each pad anyway */
9207 stream->send_global_tags = TRUE;
9208 /* send upstream GST_EVENT_PROTECTION events that were received before
9209 this source pad was created */
9210 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9211 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9215 gst_tag_list_unref (list);
9219 /* find next atom with @fourcc starting at @offset */
9220 static GstFlowReturn
9221 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9222 guint64 * length, guint32 fourcc)
9228 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9229 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9235 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9236 if (G_UNLIKELY (ret != GST_FLOW_OK))
9238 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9241 gst_buffer_unref (buf);
9244 gst_buffer_map (buf, &map, GST_MAP_READ);
9245 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9246 gst_buffer_unmap (buf, &map);
9247 gst_buffer_unref (buf);
9249 if (G_UNLIKELY (*length == 0)) {
9250 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9251 ret = GST_FLOW_ERROR;
9255 if (lfourcc == fourcc) {
9256 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9257 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9260 GST_LOG_OBJECT (qtdemux,
9261 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9262 GST_FOURCC_ARGS (lfourcc), *offset);
9263 if (*offset == G_MAXUINT64)
9273 /* might simply have had last one */
9274 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9279 /* should only do something in pull mode */
9280 /* call with OBJECT lock */
9281 static GstFlowReturn
9282 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9284 guint64 length, offset;
9285 GstBuffer *buf = NULL;
9286 GstFlowReturn ret = GST_FLOW_OK;
9287 GstFlowReturn res = GST_FLOW_OK;
9290 offset = qtdemux->moof_offset;
9291 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9294 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9295 return GST_FLOW_EOS;
9298 /* best not do pull etc with lock held */
9299 GST_OBJECT_UNLOCK (qtdemux);
9301 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9302 if (ret != GST_FLOW_OK)
9305 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9306 if (G_UNLIKELY (ret != GST_FLOW_OK))
9308 gst_buffer_map (buf, &map, GST_MAP_READ);
9309 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9310 gst_buffer_unmap (buf, &map);
9311 gst_buffer_unref (buf);
9316 gst_buffer_unmap (buf, &map);
9317 gst_buffer_unref (buf);
9321 /* look for next moof */
9322 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9323 if (G_UNLIKELY (ret != GST_FLOW_OK))
9327 GST_OBJECT_LOCK (qtdemux);
9329 qtdemux->moof_offset = offset;
9335 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9337 res = GST_FLOW_ERROR;
9342 /* maybe upstream temporarily flushing */
9343 if (ret != GST_FLOW_FLUSHING) {
9344 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9347 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9348 /* resume at current position next time */
9356 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9360 gint32 stts_duration;
9361 GstByteWriter stsc, stts, stsz;
9363 /* Each sample has a different size, which we don't support for merging */
9364 if (stream->sample_size == 0) {
9365 GST_DEBUG_OBJECT (qtdemux,
9366 "Not all samples have the same size, not merging");
9370 /* The stream has a ctts table, we don't support that */
9371 if (stream->ctts_present) {
9372 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9376 /* If there's a sync sample table also ignore this stream */
9377 if (stream->stps_present || stream->stss_present) {
9378 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9382 /* If chunks are considered samples already ignore this stream */
9383 if (stream->chunks_are_samples) {
9384 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9388 /* Require that all samples have the same duration */
9389 if (stream->n_sample_times > 1) {
9390 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9394 /* Parse the stts to get the sample duration and number of samples */
9395 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9396 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9398 /* Parse the number of chunks from the stco manually because the
9399 * reader is already behind that */
9400 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9402 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9405 /* Now parse stsc, convert chunks into single samples and generate a
9406 * new stsc, stts and stsz from this information */
9407 gst_byte_writer_init (&stsc);
9408 gst_byte_writer_init (&stts);
9409 gst_byte_writer_init (&stsz);
9411 /* Note: we skip fourccs, size, version, flags and other fields of the new
9412 * atoms as the byte readers with them are already behind that position
9413 * anyway and only update the values of those inside the stream directly.
9415 stream->n_sample_times = 0;
9416 stream->n_samples = 0;
9417 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9419 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9421 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9422 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9423 sample_description_id =
9424 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9426 if (i == stream->n_samples_per_chunk - 1) {
9427 /* +1 because first_chunk is 1-based */
9428 last_chunk = num_chunks + 1;
9430 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9433 GST_DEBUG_OBJECT (qtdemux,
9434 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9435 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9437 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9438 /* One sample in this chunk */
9439 gst_byte_writer_put_uint32_be (&stsc, 1);
9440 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9442 /* For each chunk write a stts and stsz entry now */
9443 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9444 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9445 for (j = first_chunk; j < last_chunk; j++) {
9446 gst_byte_writer_put_uint32_be (&stsz,
9447 stream->sample_size * samples_per_chunk);
9450 stream->n_sample_times += 1;
9451 stream->n_samples += last_chunk - first_chunk;
9454 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9456 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9457 stream->n_samples, stream->n_sample_times);
9459 /* We don't have a fixed sample size anymore */
9460 stream->sample_size = 0;
9462 /* Free old data for the atoms */
9463 g_free ((gpointer) stream->stsz.data);
9464 stream->stsz.data = NULL;
9465 g_free ((gpointer) stream->stsc.data);
9466 stream->stsc.data = NULL;
9467 g_free ((gpointer) stream->stts.data);
9468 stream->stts.data = NULL;
9470 /* Store new data and replace byte readers */
9471 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9472 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9473 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9474 stream->stts.size = gst_byte_writer_get_size (&stts);
9475 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9476 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9477 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9478 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9479 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9482 /* initialise bytereaders for stbl sub-atoms */
9484 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9486 stream->stbl_index = -1; /* no samples have yet been parsed */
9487 stream->sample_index = -1;
9489 /* time-to-sample atom */
9490 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9493 /* copy atom data into a new buffer for later use */
9494 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9496 /* skip version + flags */
9497 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9498 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9500 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9502 /* make sure there's enough data */
9503 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9504 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9505 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9506 stream->n_sample_times);
9507 if (!stream->n_sample_times)
9511 /* sync sample atom */
9512 stream->stps_present = FALSE;
9513 if ((stream->stss_present =
9514 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9515 &stream->stss) ? TRUE : FALSE) == TRUE) {
9516 /* copy atom data into a new buffer for later use */
9517 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9519 /* skip version + flags */
9520 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9521 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9524 if (stream->n_sample_syncs) {
9525 /* make sure there's enough data */
9526 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9530 /* partial sync sample atom */
9531 if ((stream->stps_present =
9532 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9533 &stream->stps) ? TRUE : FALSE) == TRUE) {
9534 /* copy atom data into a new buffer for later use */
9535 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9537 /* skip version + flags */
9538 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9539 !gst_byte_reader_get_uint32_be (&stream->stps,
9540 &stream->n_sample_partial_syncs))
9543 /* if there are no entries, the stss table contains the real
9545 if (stream->n_sample_partial_syncs) {
9546 /* make sure there's enough data */
9547 if (!qt_atom_parser_has_chunks (&stream->stps,
9548 stream->n_sample_partial_syncs, 4))
9555 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9558 /* copy atom data into a new buffer for later use */
9559 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9561 /* skip version + flags */
9562 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9563 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9566 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9569 if (!stream->n_samples)
9572 /* sample-to-chunk atom */
9573 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9576 /* copy atom data into a new buffer for later use */
9577 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9579 /* skip version + flags */
9580 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9581 !gst_byte_reader_get_uint32_be (&stream->stsc,
9582 &stream->n_samples_per_chunk))
9585 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9586 stream->n_samples_per_chunk);
9588 /* make sure there's enough data */
9589 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9595 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9596 stream->co_size = sizeof (guint32);
9597 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9599 stream->co_size = sizeof (guint64);
9603 /* copy atom data into a new buffer for later use */
9604 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9606 /* skip version + flags */
9607 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9610 /* chunks_are_samples == TRUE means treat chunks as samples */
9611 stream->chunks_are_samples = stream->sample_size
9612 && !CUR_STREAM (stream)->sampled;
9613 if (stream->chunks_are_samples) {
9614 /* treat chunks as samples */
9615 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9618 /* skip number of entries */
9619 if (!gst_byte_reader_skip (&stream->stco, 4))
9622 /* make sure there are enough data in the stsz atom */
9623 if (!stream->sample_size) {
9624 /* different sizes for each sample */
9625 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9630 /* composition time-to-sample */
9631 if ((stream->ctts_present =
9632 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9633 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9634 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9635 guint8 ctts_version;
9636 gboolean checked_ctts = FALSE;
9638 /* copy atom data into a new buffer for later use */
9639 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9641 /* version 1 has signed offsets */
9642 if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9646 if (!gst_byte_reader_skip (&stream->ctts, 3)
9647 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9648 &stream->n_composition_times))
9651 /* make sure there's enough data */
9652 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9656 /* This is optional, if missing we iterate the ctts */
9657 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9658 guint8 cslg_version;
9660 /* cslg version 1 has 64 bit fields */
9661 if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9665 if (!gst_byte_reader_skip (&cslg, 3))
9668 if (cslg_version == 0) {
9669 gint32 composition_to_dts_shift;
9671 if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9674 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9676 gint64 composition_to_dts_shift;
9678 if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9681 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9684 gint32 cslg_least = 0;
9685 guint num_entries, pos;
9688 pos = gst_byte_reader_get_pos (&stream->ctts);
9689 num_entries = stream->n_composition_times;
9691 checked_ctts = TRUE;
9693 stream->cslg_shift = 0;
9695 for (i = 0; i < num_entries; i++) {
9698 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9699 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9700 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9701 * slightly inaccurate PTS could be more usable than corrupted one */
9702 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9703 && ABS (offset) / 2 > stream->duration)) {
9704 GST_WARNING_OBJECT (qtdemux,
9705 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9706 " larger than duration %" G_GUINT64_FORMAT, offset,
9709 stream->cslg_shift = 0;
9710 stream->ctts_present = FALSE;
9714 /* Don't consider "no decode samples" with offset G_MININT32
9715 * for the DTS/PTS shift */
9716 if (offset != G_MININT32 && offset < cslg_least)
9717 cslg_least = offset;
9721 stream->cslg_shift = -cslg_least;
9723 stream->cslg_shift = 0;
9725 /* reset the reader so we can generate sample table */
9726 gst_byte_reader_set_pos (&stream->ctts, pos);
9729 /* Check if ctts values are looking reasonable if that didn't happen above */
9730 if (!checked_ctts) {
9731 guint num_entries, pos;
9734 pos = gst_byte_reader_get_pos (&stream->ctts);
9735 num_entries = stream->n_composition_times;
9737 for (i = 0; i < num_entries; i++) {
9740 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9741 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9742 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9743 * slightly inaccurate PTS could be more usable than corrupted one */
9744 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9745 && ABS (offset) / 2 > stream->duration)) {
9746 GST_WARNING_OBJECT (qtdemux,
9747 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9748 " larger than duration %" G_GUINT64_FORMAT, offset,
9751 stream->cslg_shift = 0;
9752 stream->ctts_present = FALSE;
9757 /* reset the reader so we can generate sample table */
9758 gst_byte_reader_set_pos (&stream->ctts, pos);
9761 /* Ensure the cslg_shift value is consistent so we can use it
9762 * unconditionally to produce TS and Segment */
9763 stream->cslg_shift = 0;
9766 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
9767 stream->cslg_shift);
9769 /* For raw audio streams especially we might want to merge the samples
9770 * to not output one audio sample per buffer. We're doing this here
9771 * before allocating the sample tables so that from this point onwards
9772 * the number of container samples are static */
9773 if (stream->min_buffer_size > 0) {
9774 qtdemux_merge_sample_table (qtdemux, stream);
9778 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9779 stream->n_samples, (guint) sizeof (QtDemuxSample),
9780 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9782 if (stream->n_samples >=
9783 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9784 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9785 "be larger than %uMB (broken file?)", stream->n_samples,
9786 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9790 g_assert (stream->samples == NULL);
9791 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9792 if (!stream->samples) {
9793 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9802 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9803 (_("This file is corrupt and cannot be played.")), (NULL));
9808 gst_qtdemux_stbl_free (stream);
9809 if (!qtdemux->fragmented) {
9810 /* not quite good */
9811 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9814 /* may pick up samples elsewhere */
9820 /* collect samples from the next sample to be parsed up to sample @n for @stream
9821 * by reading the info from @stbl
9823 * This code can be executed from both the streaming thread and the seeking
9824 * thread so it takes the object lock to protect itself
9827 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9830 QtDemuxSample *samples, *first, *cur, *last;
9831 guint32 n_samples_per_chunk;
9834 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9835 GST_FOURCC_FORMAT ", pad %s",
9836 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9837 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9839 n_samples = stream->n_samples;
9842 goto out_of_samples;
9844 GST_OBJECT_LOCK (qtdemux);
9845 if (n <= stream->stbl_index)
9846 goto already_parsed;
9848 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9850 if (!stream->stsz.data) {
9851 /* so we already parsed and passed all the moov samples;
9852 * onto fragmented ones */
9853 g_assert (qtdemux->fragmented);
9857 /* pointer to the sample table */
9858 samples = stream->samples;
9860 /* starts from -1, moves to the next sample index to parse */
9861 stream->stbl_index++;
9863 /* keep track of the first and last sample to fill */
9864 first = &samples[stream->stbl_index];
9867 if (!stream->chunks_are_samples) {
9868 /* set the sample sizes */
9869 if (stream->sample_size == 0) {
9870 /* different sizes for each sample */
9871 for (cur = first; cur <= last; cur++) {
9872 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9873 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9874 (guint) (cur - samples), cur->size);
9877 /* samples have the same size */
9878 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9879 for (cur = first; cur <= last; cur++)
9880 cur->size = stream->sample_size;
9884 n_samples_per_chunk = stream->n_samples_per_chunk;
9887 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9890 if (stream->stsc_chunk_index >= stream->last_chunk
9891 || stream->stsc_chunk_index < stream->first_chunk) {
9892 stream->first_chunk =
9893 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9894 stream->samples_per_chunk =
9895 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9897 stream->stsd_sample_description_id =
9898 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9900 /* chunk numbers are counted from 1 it seems */
9901 if (G_UNLIKELY (stream->first_chunk == 0))
9904 --stream->first_chunk;
9906 /* the last chunk of each entry is calculated by taking the first chunk
9907 * of the next entry; except if there is no next, where we fake it with
9909 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9910 stream->last_chunk = G_MAXUINT32;
9912 stream->last_chunk =
9913 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9914 if (G_UNLIKELY (stream->last_chunk == 0))
9917 --stream->last_chunk;
9920 GST_LOG_OBJECT (qtdemux,
9921 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9922 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9923 stream->samples_per_chunk, stream->stsd_sample_description_id);
9925 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9928 if (stream->last_chunk != G_MAXUINT32) {
9929 if (!qt_atom_parser_peek_sub (&stream->stco,
9930 stream->first_chunk * stream->co_size,
9931 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9936 stream->co_chunk = stream->stco;
9937 if (!gst_byte_reader_skip (&stream->co_chunk,
9938 stream->first_chunk * stream->co_size))
9942 stream->stsc_chunk_index = stream->first_chunk;
9945 last_chunk = stream->last_chunk;
9947 if (stream->chunks_are_samples) {
9948 cur = &samples[stream->stsc_chunk_index];
9950 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9953 stream->stsc_chunk_index = j;
9958 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9961 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9962 "%" G_GUINT64_FORMAT, j, cur->offset);
9964 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9965 CUR_STREAM (stream)->bytes_per_frame > 0) {
9967 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9968 CUR_STREAM (stream)->samples_per_frame *
9969 CUR_STREAM (stream)->bytes_per_frame;
9971 cur->size = stream->samples_per_chunk;
9974 GST_DEBUG_OBJECT (qtdemux,
9975 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9976 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9977 stream->stco_sample_index)), cur->size);
9979 cur->timestamp = stream->stco_sample_index;
9980 cur->duration = stream->samples_per_chunk;
9981 cur->keyframe = TRUE;
9984 stream->stco_sample_index += stream->samples_per_chunk;
9986 stream->stsc_chunk_index = j;
9988 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9989 guint32 samples_per_chunk;
9990 guint64 chunk_offset;
9992 if (!stream->stsc_sample_index
9993 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9994 &stream->chunk_offset))
9997 samples_per_chunk = stream->samples_per_chunk;
9998 chunk_offset = stream->chunk_offset;
10000 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
10001 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
10002 G_GUINT64_FORMAT " and size %d",
10003 (guint) (cur - samples), chunk_offset, cur->size);
10005 cur->offset = chunk_offset;
10006 chunk_offset += cur->size;
10009 if (G_UNLIKELY (cur > last)) {
10011 stream->stsc_sample_index = k + 1;
10012 stream->chunk_offset = chunk_offset;
10013 stream->stsc_chunk_index = j;
10017 stream->stsc_sample_index = 0;
10019 stream->stsc_chunk_index = j;
10021 stream->stsc_index++;
10024 if (stream->chunks_are_samples)
10028 guint32 n_sample_times;
10030 n_sample_times = stream->n_sample_times;
10033 for (i = stream->stts_index; i < n_sample_times; i++) {
10034 guint32 stts_samples;
10035 gint32 stts_duration;
10038 if (stream->stts_sample_index >= stream->stts_samples
10039 || !stream->stts_sample_index) {
10041 stream->stts_samples =
10042 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10043 stream->stts_duration =
10044 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10046 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
10047 i, stream->stts_samples, stream->stts_duration);
10049 stream->stts_sample_index = 0;
10052 stts_samples = stream->stts_samples;
10053 stts_duration = stream->stts_duration;
10054 stts_time = stream->stts_time;
10056 for (j = stream->stts_sample_index; j < stts_samples; j++) {
10057 GST_DEBUG_OBJECT (qtdemux,
10058 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
10059 (guint) (cur - samples), j,
10060 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
10062 cur->timestamp = stts_time;
10063 cur->duration = stts_duration;
10065 /* avoid 32-bit wrap-around,
10066 * but still mind possible 'negative' duration */
10067 stts_time += (gint64) stts_duration;
10070 if (G_UNLIKELY (cur > last)) {
10072 stream->stts_time = stts_time;
10073 stream->stts_sample_index = j + 1;
10074 if (stream->stts_sample_index >= stream->stts_samples)
10075 stream->stts_index++;
10079 stream->stts_sample_index = 0;
10080 stream->stts_time = stts_time;
10081 stream->stts_index++;
10083 /* fill up empty timestamps with the last timestamp, this can happen when
10084 * the last samples do not decode and so we don't have timestamps for them.
10085 * We however look at the last timestamp to estimate the track length so we
10086 * need something in here. */
10087 for (; cur < last; cur++) {
10088 GST_DEBUG_OBJECT (qtdemux,
10089 "fill sample %d: timestamp %" GST_TIME_FORMAT,
10090 (guint) (cur - samples),
10091 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
10092 cur->timestamp = stream->stts_time;
10093 cur->duration = -1;
10098 /* sample sync, can be NULL */
10099 if (stream->stss_present == TRUE) {
10100 guint32 n_sample_syncs;
10102 n_sample_syncs = stream->n_sample_syncs;
10104 if (!n_sample_syncs) {
10105 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
10106 stream->all_keyframe = TRUE;
10108 for (i = stream->stss_index; i < n_sample_syncs; i++) {
10109 /* note that the first sample is index 1, not 0 */
10112 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
10114 if (G_LIKELY (index > 0 && index <= n_samples)) {
10116 samples[index].keyframe = TRUE;
10117 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10118 /* and exit if we have enough samples */
10119 if (G_UNLIKELY (index >= n)) {
10126 stream->stss_index = i;
10129 /* stps marks partial sync frames like open GOP I-Frames */
10130 if (stream->stps_present == TRUE) {
10131 guint32 n_sample_partial_syncs;
10133 n_sample_partial_syncs = stream->n_sample_partial_syncs;
10135 /* if there are no entries, the stss table contains the real
10137 if (n_sample_partial_syncs) {
10138 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
10139 /* note that the first sample is index 1, not 0 */
10142 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
10144 if (G_LIKELY (index > 0 && index <= n_samples)) {
10146 samples[index].keyframe = TRUE;
10147 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10148 /* and exit if we have enough samples */
10149 if (G_UNLIKELY (index >= n)) {
10156 stream->stps_index = i;
10160 /* no stss, all samples are keyframes */
10161 stream->all_keyframe = TRUE;
10162 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10167 /* composition time to sample */
10168 if (stream->ctts_present == TRUE) {
10169 guint32 n_composition_times;
10170 guint32 ctts_count;
10171 gint32 ctts_soffset;
10173 /* Fill in the pts_offsets */
10175 n_composition_times = stream->n_composition_times;
10177 for (i = stream->ctts_index; i < n_composition_times; i++) {
10178 if (stream->ctts_sample_index >= stream->ctts_count
10179 || !stream->ctts_sample_index) {
10180 stream->ctts_count =
10181 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10182 stream->ctts_soffset =
10183 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10184 stream->ctts_sample_index = 0;
10187 ctts_count = stream->ctts_count;
10188 ctts_soffset = stream->ctts_soffset;
10190 /* FIXME: Set offset to 0 for "no decode samples". This needs
10191 * to be handled in a codec specific manner ideally. */
10192 if (ctts_soffset == G_MININT32)
10195 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10196 cur->pts_offset = ctts_soffset;
10199 if (G_UNLIKELY (cur > last)) {
10201 stream->ctts_sample_index = j + 1;
10205 stream->ctts_sample_index = 0;
10206 stream->ctts_index++;
10210 stream->stbl_index = n;
10211 /* if index has been completely parsed, free data that is no-longer needed */
10212 if (n + 1 == stream->n_samples) {
10213 gst_qtdemux_stbl_free (stream);
10214 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10215 if (qtdemux->pullbased) {
10216 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10217 while (n + 1 == stream->n_samples)
10218 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10222 GST_OBJECT_UNLOCK (qtdemux);
10229 GST_LOG_OBJECT (qtdemux,
10230 "Tried to parse up to sample %u but this sample has already been parsed",
10232 /* if fragmented, there may be more */
10233 if (qtdemux->fragmented && n == stream->stbl_index)
10235 GST_OBJECT_UNLOCK (qtdemux);
10241 GST_LOG_OBJECT (qtdemux,
10242 "Tried to parse up to sample %u but there are only %u samples", n + 1,
10243 stream->n_samples);
10244 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10245 (_("This file is corrupt and cannot be played.")), (NULL));
10250 GST_OBJECT_UNLOCK (qtdemux);
10251 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10252 (_("This file is corrupt and cannot be played.")), (NULL));
10257 /* collect all segment info for @stream.
10260 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10264 /* accept edts if they contain gaps at start and there is only
10265 * one media segment */
10266 gboolean allow_pushbased_edts = TRUE;
10267 gint media_segments_count = 0;
10269 /* parse and prepare segment info from the edit list */
10270 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10271 stream->n_segments = 0;
10272 stream->segments = NULL;
10273 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10276 guint segment_number, entry_size;
10278 GstClockTime stime;
10279 const guint8 *buffer;
10283 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10284 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10287 buffer = elst->data;
10289 size = QT_UINT32 (buffer);
10290 /* version, flags, n_segments */
10292 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10295 version = QT_UINT8 (buffer + 8);
10296 entry_size = (version == 1) ? 20 : 12;
10298 n_segments = QT_UINT32 (buffer + 12);
10300 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10301 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10305 /* we might allocate a bit too much, at least allocate 1 segment */
10306 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10308 /* segments always start from 0 */
10312 for (segment_number = 0; segment_number < n_segments; segment_number++) {
10314 guint64 media_time;
10315 gboolean empty_edit = FALSE;
10316 QtDemuxSegment *segment;
10318 GstClockTime media_start = GST_CLOCK_TIME_NONE;
10320 if (version == 1) {
10321 media_time = QT_UINT64 (buffer + 8);
10322 duration = QT_UINT64 (buffer);
10323 if (media_time == G_MAXUINT64)
10326 media_time = QT_UINT32 (buffer + 4);
10327 duration = QT_UINT32 (buffer);
10328 if (media_time == G_MAXUINT32)
10333 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10335 segment = &stream->segments[segment_number];
10337 /* time and duration expressed in global timescale */
10338 segment->time = stime;
10339 if (duration != 0 || empty_edit) {
10340 /* edge case: empty edits with duration=zero are treated here.
10341 * (files should not have these anyway). */
10343 /* add non scaled values so we don't cause roundoff errors */
10345 stime = QTTIME_TO_GSTTIME (qtdemux, time);
10346 segment->duration = stime - segment->time;
10348 /* zero duration does not imply media_start == media_stop
10349 * but, only specify media_start. The edit ends with the track. */
10350 stime = segment->duration = GST_CLOCK_TIME_NONE;
10351 /* Don't allow more edits after this one. */
10352 n_segments = segment_number + 1;
10354 segment->stop_time = stime;
10356 segment->trak_media_start = media_time;
10357 /* media_time expressed in stream timescale */
10359 segment->media_start = media_start;
10360 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10361 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10362 media_segments_count++;
10364 segment->media_start = GST_CLOCK_TIME_NONE;
10365 segment->media_stop = GST_CLOCK_TIME_NONE;
10367 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10369 if (rate_int <= 1) {
10370 /* 0 is not allowed, some programs write 1 instead of the floating point
10372 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10376 segment->rate = rate_int / 65536.0;
10379 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10380 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10381 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10382 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10383 segment_number, GST_TIME_ARGS (segment->time),
10384 GST_TIME_ARGS (segment->duration),
10385 GST_TIME_ARGS (segment->media_start), media_time,
10386 GST_TIME_ARGS (segment->media_stop),
10387 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10388 stream->timescale);
10389 if (segment->stop_time > qtdemux->segment.stop &&
10390 !qtdemux->upstream_format_is_time) {
10391 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10392 " extends to %" GST_TIME_FORMAT
10393 " past the end of the declared movie duration %" GST_TIME_FORMAT
10394 " movie segment will be extended", segment_number,
10395 GST_TIME_ARGS (segment->stop_time),
10396 GST_TIME_ARGS (qtdemux->segment.stop));
10397 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10400 buffer += entry_size;
10402 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10403 stream->n_segments = n_segments;
10404 if (media_segments_count != 1)
10405 allow_pushbased_edts = FALSE;
10409 /* push based does not handle segments, so act accordingly here,
10410 * and warn if applicable */
10411 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10412 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10413 /* remove and use default one below, we stream like it anyway */
10414 g_free (stream->segments);
10415 stream->segments = NULL;
10416 stream->n_segments = 0;
10419 /* no segments, create one to play the complete trak */
10420 if (stream->n_segments == 0) {
10421 GstClockTime stream_duration =
10422 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10424 if (stream->segments == NULL)
10425 stream->segments = g_new (QtDemuxSegment, 1);
10427 /* represent unknown our way */
10428 if (stream_duration == 0)
10429 stream_duration = GST_CLOCK_TIME_NONE;
10431 stream->segments[0].time = 0;
10432 stream->segments[0].stop_time = stream_duration;
10433 stream->segments[0].duration = stream_duration;
10434 stream->segments[0].media_start = 0;
10435 stream->segments[0].media_stop = stream_duration;
10436 stream->segments[0].rate = 1.0;
10437 stream->segments[0].trak_media_start = 0;
10439 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10440 GST_TIME_ARGS (stream_duration));
10441 stream->n_segments = 1;
10442 stream->dummy_segment = TRUE;
10444 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10450 * Parses the stsd atom of a svq3 trak looking for
10451 * the SMI and gama atoms.
10454 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10455 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10457 const guint8 *_gamma = NULL;
10458 GstBuffer *_seqh = NULL;
10459 const guint8 *stsd_data = stsd_entry_data;
10460 guint32 length = QT_UINT32 (stsd_data);
10464 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10470 version = QT_UINT16 (stsd_data);
10471 if (version == 3) {
10472 if (length >= 70) {
10475 while (length > 8) {
10476 guint32 fourcc, size;
10477 const guint8 *data;
10478 size = QT_UINT32 (stsd_data);
10479 fourcc = QT_FOURCC (stsd_data + 4);
10480 data = stsd_data + 8;
10483 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10484 "svq3 atom parsing");
10493 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10494 " for gama atom, expected 12", size);
10499 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10501 if (_seqh != NULL) {
10502 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10503 " found, ignoring");
10505 seqh_size = QT_UINT32 (data + 4);
10506 if (seqh_size > 0) {
10507 _seqh = gst_buffer_new_and_alloc (seqh_size);
10508 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10515 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10516 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10520 if (size <= length) {
10526 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10529 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10530 G_GUINT16_FORMAT, version);
10540 } else if (_seqh) {
10541 gst_buffer_unref (_seqh);
10546 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10549 GstByteReader dref;
10553 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10554 * atom that might contain a 'data' atom with the rtsp uri.
10555 * This case was reported in bug #597497, some info about
10556 * the hndl atom can be found in TN1195
10558 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10559 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10562 guint32 dref_num_entries = 0;
10563 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10564 gst_byte_reader_skip (&dref, 4) &&
10565 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10568 /* search dref entries for hndl atom */
10569 for (i = 0; i < dref_num_entries; i++) {
10570 guint32 size = 0, type;
10571 guint8 string_len = 0;
10572 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10573 qt_atom_parser_get_fourcc (&dref, &type)) {
10574 if (type == FOURCC_hndl) {
10575 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10577 /* skip data reference handle bytes and the
10578 * following pascal string and some extra 4
10579 * bytes I have no idea what are */
10580 if (!gst_byte_reader_skip (&dref, 4) ||
10581 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10582 !gst_byte_reader_skip (&dref, string_len + 4)) {
10583 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10587 /* iterate over the atoms to find the data atom */
10588 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10592 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10593 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10594 if (atom_type == FOURCC_data) {
10595 const guint8 *uri_aux = NULL;
10597 /* found the data atom that might contain the rtsp uri */
10598 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10599 "hndl atom, interpreting it as an URI");
10600 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10602 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10603 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10605 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10606 "didn't contain a rtsp address");
10608 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10613 /* skipping to the next entry */
10614 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10617 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10624 /* skip to the next entry */
10625 if (!gst_byte_reader_skip (&dref, size - 8))
10628 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10631 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10637 #define AMR_NB_ALL_MODES 0x81ff
10638 #define AMR_WB_ALL_MODES 0x83ff
10640 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10642 /* The 'damr' atom is of the form:
10644 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10645 * 32 b 8 b 16 b 8 b 8 b
10647 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10648 * represents the highest mode used in the stream (and thus the maximum
10649 * bitrate), with a couple of special cases as seen below.
10652 /* Map of frame type ID -> bitrate */
10653 static const guint nb_bitrates[] = {
10654 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10656 static const guint wb_bitrates[] = {
10657 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10663 gst_buffer_map (buf, &map, GST_MAP_READ);
10665 if (map.size != 0x11) {
10666 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10670 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10671 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10672 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10676 mode_set = QT_UINT16 (map.data + 13);
10678 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10679 max_mode = 7 + (wb ? 1 : 0);
10681 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10682 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10684 if (max_mode == -1) {
10685 GST_DEBUG ("No mode indication was found (mode set) = %x",
10690 gst_buffer_unmap (buf, &map);
10691 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10694 gst_buffer_unmap (buf, &map);
10699 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10700 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10703 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10709 if (gst_byte_reader_get_remaining (reader) < 36)
10712 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10713 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10714 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10715 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10716 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10717 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10718 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10719 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10720 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10722 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10723 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10724 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10726 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10727 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10729 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10730 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10737 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10738 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10745 * This macro will only compare value abdegh, it expects cfi to have already
10748 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10749 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10751 /* only handle the cases where the last column has standard values */
10752 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10753 const gchar *rotation_tag = NULL;
10755 /* no rotation needed */
10756 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10758 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10759 rotation_tag = "rotate-90";
10760 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10761 rotation_tag = "rotate-180";
10762 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10763 rotation_tag = "rotate-270";
10765 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10768 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10769 GST_STR_NULL (rotation_tag));
10770 if (rotation_tag != NULL) {
10771 if (*taglist == NULL)
10772 *taglist = gst_tag_list_new_empty ();
10773 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10774 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10777 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10782 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10783 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10787 GstBuffer *adrm_buf = NULL;
10788 QtDemuxAavdEncryptionInfo *info;
10790 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10791 if (G_UNLIKELY (!adrm)) {
10792 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10795 adrm_size = QT_UINT32 (adrm->data);
10796 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10798 stream->protection_scheme_type = FOURCC_aavd;
10800 if (!stream->protection_scheme_info)
10801 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10803 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10805 if (info->default_properties)
10806 gst_structure_free (info->default_properties);
10807 info->default_properties = gst_structure_new ("application/x-aavd",
10808 "encrypted", G_TYPE_BOOLEAN, TRUE,
10809 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10810 gst_buffer_unref (adrm_buf);
10812 *original_fmt = FOURCC_mp4a;
10816 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10817 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10818 * Common Encryption (cenc), the function will also parse the tenc box (defined
10819 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10820 * (typically an enc[v|a|t|s] sample entry); the function will set
10821 * @original_fmt to the fourcc of the original unencrypted stream format.
10822 * Returns TRUE if successful; FALSE otherwise. */
10824 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10825 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10831 QtDemuxCencSampleSetInfo *info;
10833 const guint8 *tenc_data;
10835 g_return_val_if_fail (qtdemux != NULL, FALSE);
10836 g_return_val_if_fail (stream != NULL, FALSE);
10837 g_return_val_if_fail (container != NULL, FALSE);
10838 g_return_val_if_fail (original_fmt != NULL, FALSE);
10840 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10841 if (G_UNLIKELY (!sinf)) {
10842 if (stream->protection_scheme_type == FOURCC_cenc
10843 || stream->protection_scheme_type == FOURCC_cbcs) {
10844 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10845 "mandatory for Common Encryption");
10851 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10852 if (G_UNLIKELY (!frma)) {
10853 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10857 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10858 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10859 GST_FOURCC_ARGS (*original_fmt));
10861 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10863 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10866 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10867 stream->protection_scheme_version =
10868 QT_UINT32 ((const guint8 *) schm->data + 16);
10870 GST_DEBUG_OBJECT (qtdemux,
10871 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10872 "protection_scheme_version: %#010x",
10873 GST_FOURCC_ARGS (stream->protection_scheme_type),
10874 stream->protection_scheme_version);
10876 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10878 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10881 if (stream->protection_scheme_type != FOURCC_cenc &&
10882 stream->protection_scheme_type != FOURCC_piff &&
10883 stream->protection_scheme_type != FOURCC_cbcs) {
10884 GST_ERROR_OBJECT (qtdemux,
10885 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10886 GST_FOURCC_ARGS (stream->protection_scheme_type));
10890 if (G_UNLIKELY (!stream->protection_scheme_info))
10891 stream->protection_scheme_info =
10892 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10894 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10896 if (stream->protection_scheme_type == FOURCC_cenc
10897 || stream->protection_scheme_type == FOURCC_cbcs) {
10898 guint8 is_encrypted;
10900 guint8 constant_iv_size = 0;
10901 const guint8 *default_kid;
10902 guint8 crypt_byte_block = 0;
10903 guint8 skip_byte_block = 0;
10904 const guint8 *constant_iv = NULL;
10906 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10908 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10909 "which is mandatory for Common Encryption");
10912 tenc_data = (const guint8 *) tenc->data + 12;
10913 is_encrypted = QT_UINT8 (tenc_data + 2);
10914 iv_size = QT_UINT8 (tenc_data + 3);
10915 default_kid = (tenc_data + 4);
10916 if (stream->protection_scheme_type == FOURCC_cbcs) {
10917 guint8 possible_pattern_info;
10918 if (iv_size == 0) {
10919 constant_iv_size = QT_UINT8 (tenc_data + 20);
10920 if (constant_iv_size != 8 && constant_iv_size != 16) {
10921 GST_ERROR_OBJECT (qtdemux,
10922 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10925 constant_iv = (tenc_data + 21);
10927 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10928 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10929 skip_byte_block = possible_pattern_info & 0x0f;
10931 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10932 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10933 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10934 } else if (stream->protection_scheme_type == FOURCC_piff) {
10936 static const guint8 piff_track_encryption_uuid[] = {
10937 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10938 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10941 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10943 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10944 "which is mandatory for Common Encryption");
10948 tenc_data = (const guint8 *) tenc->data + 8;
10949 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10950 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10951 GST_ERROR_OBJECT (qtdemux,
10952 "Unsupported track encryption box with uuid: %s", box_uuid);
10956 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10957 gst_byte_reader_init (&br, tenc_data, 20);
10958 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10959 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10962 stream->protection_scheme_type = FOURCC_cenc;
10969 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10970 QtDemuxStream ** stream2)
10972 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10976 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10981 /*parse svmi header if existing */
10982 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10984 guint32 len = QT_UINT32 ((guint8 *) svmi->data);
10985 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10987 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10988 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10989 guint8 frame_type, frame_layout;
10990 guint32 stereo_mono_change_count;
10995 /* MPEG-A stereo video */
10996 if (qtdemux->major_brand == FOURCC_ss02)
10997 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10999 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
11000 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
11001 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
11003 switch (frame_type) {
11005 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
11008 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
11011 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
11014 /* mode 3 is primary/secondary view sequence, ie
11015 * left/right views in separate tracks. See section 7.2
11016 * of ISO/IEC 23000-11:2009 */
11017 /* In the future this might be supported using related
11018 * streams, like an enhancement track - if files like this
11020 GST_FIXME_OBJECT (qtdemux,
11021 "Implement stereo video in separate streams");
11024 if ((frame_layout & 0x1) == 0)
11025 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
11027 GST_LOG_OBJECT (qtdemux,
11028 "StereoVideo: composition type: %u, is_left_first: %u",
11029 frame_type, frame_layout);
11031 if (stereo_mono_change_count > 1) {
11032 GST_FIXME_OBJECT (qtdemux,
11033 "Mixed-mono flags are not yet supported in qtdemux.");
11036 stream->multiview_mode = mode;
11037 stream->multiview_flags = flags;
11044 /* parse the traks.
11045 * With each track we associate a new QtDemuxStream that contains all the info
11047 * traks that do not decode to something (like strm traks) will not have a pad.
11050 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
11052 GstByteReader tkhd;
11066 QtDemuxStream *stream = NULL;
11067 const guint8 *stsd_data;
11068 const guint8 *stsd_entry_data;
11069 guint remaining_stsd_len;
11070 guint stsd_entry_count;
11072 guint16 lang_code; /* quicktime lang code or packed iso code */
11074 guint32 tkhd_flags = 0;
11075 guint8 tkhd_version = 0;
11076 guint32 w = 0, h = 0;
11077 guint value_size, stsd_len, len;
11081 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
11083 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
11084 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
11085 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
11088 /* pick between 64 or 32 bits */
11089 value_size = tkhd_version == 1 ? 8 : 4;
11090 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
11091 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
11094 /* Check if current moov has duplicated track_id */
11095 if (qtdemux_find_stream (qtdemux, track_id))
11096 goto existing_stream;
11098 stream = _create_stream (qtdemux, track_id);
11099 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11101 /* need defaults for fragments */
11102 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
11104 if ((tkhd_flags & 1) == 0)
11105 stream->disabled = TRUE;
11107 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
11108 tkhd_version, tkhd_flags, stream->track_id);
11110 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
11113 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
11114 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
11115 if (qtdemux->major_brand != FOURCC_mjp2 ||
11116 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
11120 len = QT_UINT32 ((guint8 *) mdhd->data);
11121 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
11122 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
11123 if (version == 0x01000000) {
11126 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
11127 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
11128 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
11132 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
11133 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
11134 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
11137 if (lang_code < 0x400) {
11138 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
11139 } else if (lang_code == 0x7fff) {
11140 stream->lang_id[0] = 0; /* unspecified */
11142 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11143 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11144 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11145 stream->lang_id[3] = 0;
11148 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11149 stream->timescale);
11150 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11152 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11153 lang_code, stream->lang_id);
11155 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11158 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11159 /* chapters track reference */
11160 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11162 gsize length = GST_READ_UINT32_BE (chap->data);
11163 if (qtdemux->chapters_track_id)
11164 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11166 if (length >= 12) {
11167 qtdemux->chapters_track_id =
11168 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11173 /* fragmented files may have bogus duration in moov */
11174 if (!qtdemux->fragmented &&
11175 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11176 guint64 tdur1, tdur2;
11178 /* don't overflow */
11179 tdur1 = stream->timescale * (guint64) qtdemux->duration;
11180 tdur2 = qtdemux->timescale * (guint64) stream->duration;
11183 * some of those trailers, nowadays, have prologue images that are
11184 * themselves video tracks as well. I haven't really found a way to
11185 * identify those yet, except for just looking at their duration. */
11186 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11187 GST_WARNING_OBJECT (qtdemux,
11188 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11189 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11190 "found, assuming preview image or something; skipping track",
11191 stream->duration, stream->timescale, qtdemux->duration,
11192 qtdemux->timescale);
11193 gst_qtdemux_stream_unref (stream);
11198 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11201 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11202 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11204 len = QT_UINT32 ((guint8 *) hdlr->data);
11206 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11207 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11208 GST_FOURCC_ARGS (stream->subtype));
11210 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11213 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11216 /* Parse out svmi (and later st3d/sv3d) atoms */
11217 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
11220 /* parse rest of tkhd */
11221 if (stream->subtype == FOURCC_vide) {
11224 /* version 1 uses some 64-bit ints */
11225 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11228 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11231 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11232 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11235 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11236 &stream->stream_tags);
11240 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11242 stsd_data = (const guint8 *) stsd->data;
11244 /* stsd should at least have one entry */
11245 stsd_len = QT_UINT32 (stsd_data);
11246 if (stsd_len < 24) {
11247 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11248 if (stream->subtype == FOURCC_vivo) {
11249 gst_qtdemux_stream_unref (stream);
11256 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11257 /* each stsd entry must contain at least 8 bytes */
11258 if (stream->stsd_entries_length == 0
11259 || stream->stsd_entries_length > stsd_len / 8) {
11260 stream->stsd_entries_length = 0;
11263 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11264 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
11265 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
11267 stsd_entry_data = stsd_data + 16;
11268 remaining_stsd_len = stsd_len - 16;
11269 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11271 gchar *codec = NULL;
11272 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11274 /* and that entry should fit within stsd */
11275 len = QT_UINT32 (stsd_entry_data);
11276 if (len > remaining_stsd_len)
11279 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11280 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
11281 GST_FOURCC_ARGS (entry->fourcc));
11282 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
11284 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11285 goto error_encrypted;
11287 if (fourcc == FOURCC_aavd) {
11288 if (stream->subtype != FOURCC_soun) {
11289 GST_ERROR_OBJECT (qtdemux,
11290 "Unexpeced stsd type 'aavd' outside 'soun' track");
11292 /* encrypted audio with sound sample description v0 */
11293 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11294 stream->protected = TRUE;
11295 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11296 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11300 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11301 /* FIXME this looks wrong, there might be multiple children
11302 * with the same type */
11303 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11304 stream->protected = TRUE;
11305 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11306 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11309 if (stream->subtype == FOURCC_vide) {
11314 gint depth, palette_size, palette_count;
11315 guint32 *palette_data = NULL;
11317 entry->sampled = TRUE;
11319 stream->display_width = w >> 16;
11320 stream->display_height = h >> 16;
11323 if (len < 86) /* TODO verify */
11326 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11327 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11328 entry->fps_n = 0; /* this is filled in later */
11329 entry->fps_d = 0; /* this is filled in later */
11330 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11331 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11333 /* if color_table_id is 0, ctab atom must follow; however some files
11334 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11335 * if color table is not present we'll correct the value */
11336 if (entry->color_table_id == 0 &&
11338 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11339 entry->color_table_id = -1;
11342 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11343 entry->width, entry->height, entry->bits_per_sample,
11344 entry->color_table_id);
11346 depth = entry->bits_per_sample;
11348 /* more than 32 bits means grayscale */
11349 gray = (depth > 32);
11350 /* low 32 bits specify the depth */
11353 /* different number of palette entries is determined by depth. */
11355 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11356 palette_count = (1 << depth);
11357 palette_size = palette_count * 4;
11359 if (entry->color_table_id) {
11360 switch (palette_count) {
11364 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11367 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11372 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11374 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11379 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11382 g_memdup2 (ff_qt_default_palette_256, palette_size);
11385 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11386 (_("The video in this file might not play correctly.")),
11387 ("unsupported palette depth %d", depth));
11391 guint i, j, start, end;
11397 start = QT_UINT32 (stsd_entry_data + offset + 70);
11398 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11399 end = QT_UINT16 (stsd_entry_data + offset + 76);
11401 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11402 start, end, palette_count);
11409 if (len < 94 + (end - start) * 8)
11412 /* palette is always the same size */
11413 palette_data = g_malloc0 (256 * 4);
11414 palette_size = 256 * 4;
11416 for (j = 0, i = start; i <= end; j++, i++) {
11417 guint32 a, r, g, b;
11419 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11420 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11421 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11422 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11424 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11425 (g & 0xff00) | (b >> 8);
11430 gst_caps_unref (entry->caps);
11433 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11435 if (G_UNLIKELY (!entry->caps)) {
11436 g_free (palette_data);
11437 goto unknown_stream;
11441 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11442 GST_TAG_VIDEO_CODEC, codec, NULL);
11447 if (palette_data) {
11450 if (entry->rgb8_palette)
11451 gst_memory_unref (entry->rgb8_palette);
11452 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11453 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11455 s = gst_caps_get_structure (entry->caps, 0);
11457 /* non-raw video has a palette_data property. raw video has the palette as
11458 * an extra plane that we append to the output buffers before we push
11460 if (!gst_structure_has_name (s, "video/x-raw")) {
11461 GstBuffer *palette;
11463 palette = gst_buffer_new ();
11464 gst_buffer_append_memory (palette, entry->rgb8_palette);
11465 entry->rgb8_palette = NULL;
11467 gst_caps_set_simple (entry->caps, "palette_data",
11468 GST_TYPE_BUFFER, palette, NULL);
11469 gst_buffer_unref (palette);
11471 } else if (palette_count != 0) {
11472 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11473 (NULL), ("Unsupported palette depth %d", depth));
11476 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11477 QT_UINT16 (stsd_entry_data + offset + 32));
11483 /* pick 'the' stsd child */
11484 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11485 // We should skip parsing the stsd for non-protected streams if
11486 // the entry doesn't match the fourcc, since they don't change
11487 // format. However, for protected streams we can have partial
11488 // encryption, where parts of the stream are encrypted and parts
11489 // not. For both parts of such streams, we should ensure the
11490 // esds overrides are parsed for both from the stsd.
11491 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11492 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11494 else if (!stream->protected)
11499 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11500 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11501 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11502 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11506 const guint8 *pasp_data = (const guint8 *) pasp->data;
11507 guint len = QT_UINT32 (pasp_data);
11510 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11511 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11513 CUR_STREAM (stream)->par_w = 0;
11514 CUR_STREAM (stream)->par_h = 0;
11517 CUR_STREAM (stream)->par_w = 0;
11518 CUR_STREAM (stream)->par_h = 0;
11522 const guint8 *fiel_data = (const guint8 *) fiel->data;
11523 guint len = QT_UINT32 (fiel_data);
11526 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11527 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11532 const guint8 *colr_data = (const guint8 *) colr->data;
11533 guint len = QT_UINT32 (colr_data);
11535 if (len == 19 || len == 18) {
11536 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11538 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11539 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11540 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11541 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11542 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11544 CUR_STREAM (stream)->colorimetry.primaries =
11545 gst_video_color_primaries_from_iso (primaries);
11546 CUR_STREAM (stream)->colorimetry.transfer =
11547 gst_video_transfer_function_from_iso (transfer_function);
11548 CUR_STREAM (stream)->colorimetry.matrix =
11549 gst_video_color_matrix_from_iso (matrix);
11550 CUR_STREAM (stream)->colorimetry.range =
11551 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11552 GST_VIDEO_COLOR_RANGE_16_235;
11554 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11557 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11562 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11563 stream->stream_tags);
11570 guint len = QT_UINT32 (stsd_entry_data);
11571 len = len <= 0x56 ? 0 : len - 0x56;
11572 const guint8 *avc_data = stsd_entry_data + 0x56;
11575 while (len >= 0x8) {
11578 if (QT_UINT32 (avc_data) <= 0x8)
11580 else if (QT_UINT32 (avc_data) <= len)
11581 size = QT_UINT32 (avc_data) - 0x8;
11586 /* No real data, so break out */
11589 switch (QT_FOURCC (avc_data + 0x4)) {
11592 /* parse, if found */
11595 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11597 /* First 4 bytes are the length of the atom, the next 4 bytes
11598 * are the fourcc, the next 1 byte is the version, and the
11599 * subsequent bytes are profile_tier_level structure like data. */
11600 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11601 avc_data + 8 + 1, size - 1);
11602 buf = gst_buffer_new_and_alloc (size);
11603 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11604 gst_caps_set_simple (entry->caps,
11605 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11606 gst_buffer_unref (buf);
11614 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11616 /* First 4 bytes are the length of the atom, the next 4 bytes
11617 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11618 * next 1 byte is the version, and the
11619 * subsequent bytes are sequence parameter set like data. */
11621 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11623 gst_codec_utils_h264_caps_set_level_and_profile
11624 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11626 buf = gst_buffer_new_and_alloc (size);
11627 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11628 gst_caps_set_simple (entry->caps,
11629 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11630 gst_buffer_unref (buf);
11636 guint avg_bitrate, max_bitrate;
11638 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11642 max_bitrate = QT_UINT32 (avc_data + 0xc);
11643 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11645 if (!max_bitrate && !avg_bitrate)
11648 /* Some muxers seem to swap the average and maximum bitrates
11649 * (I'm looking at you, YouTube), so we swap for sanity. */
11650 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11651 guint temp = avg_bitrate;
11653 avg_bitrate = max_bitrate;
11654 max_bitrate = temp;
11657 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11658 gst_tag_list_add (stream->stream_tags,
11659 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11660 max_bitrate, NULL);
11662 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11663 gst_tag_list_add (stream->stream_tags,
11664 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11676 avc_data += size + 8;
11687 guint len = QT_UINT32 (stsd_entry_data);
11688 len = len <= 0x56 ? 0 : len - 0x56;
11689 const guint8 *hevc_data = stsd_entry_data + 0x56;
11692 while (len >= 0x8) {
11695 if (QT_UINT32 (hevc_data) <= 0x8)
11697 else if (QT_UINT32 (hevc_data) <= len)
11698 size = QT_UINT32 (hevc_data) - 0x8;
11703 /* No real data, so break out */
11706 switch (QT_FOURCC (hevc_data + 0x4)) {
11709 /* parse, if found */
11712 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11714 /* First 4 bytes are the length of the atom, the next 4 bytes
11715 * are the fourcc, the next 1 byte is the version, and the
11716 * subsequent bytes are sequence parameter set like data. */
11717 gst_codec_utils_h265_caps_set_level_tier_and_profile
11718 (entry->caps, hevc_data + 8 + 1, size - 1);
11720 buf = gst_buffer_new_and_alloc (size);
11721 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11722 gst_caps_set_simple (entry->caps,
11723 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11724 gst_buffer_unref (buf);
11731 hevc_data += size + 8;
11744 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11745 GST_FOURCC_ARGS (fourcc));
11747 /* codec data might be in glbl extension atom */
11749 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11755 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11757 len = QT_UINT32 (data);
11760 buf = gst_buffer_new_and_alloc (len);
11761 gst_buffer_fill (buf, 0, data + 8, len);
11762 gst_caps_set_simple (entry->caps,
11763 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11764 gst_buffer_unref (buf);
11771 /* see annex I of the jpeg2000 spec */
11772 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11773 const guint8 *data;
11774 const gchar *colorspace = NULL;
11776 guint32 ncomp_map = 0;
11777 gint32 *comp_map = NULL;
11778 guint32 nchan_def = 0;
11779 gint32 *chan_def = NULL;
11781 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11782 /* some required atoms */
11783 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11786 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11790 /* number of components; redundant with info in codestream, but useful
11792 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11793 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11795 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11797 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11800 GST_DEBUG_OBJECT (qtdemux, "found colr");
11801 /* extract colour space info */
11802 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11803 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11805 colorspace = "sRGB";
11808 colorspace = "GRAY";
11811 colorspace = "sYUV";
11819 /* colr is required, and only values 16, 17, and 18 are specified,
11820 so error if we have no colorspace */
11823 /* extract component mapping */
11824 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11826 guint32 cmap_len = 0;
11828 cmap_len = QT_UINT32 (cmap->data);
11829 if (cmap_len >= 8) {
11830 /* normal box, subtract off header */
11832 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11833 if (cmap_len % 4 == 0) {
11834 ncomp_map = (cmap_len / 4);
11835 comp_map = g_new0 (gint32, ncomp_map);
11836 for (i = 0; i < ncomp_map; i++) {
11839 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11840 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11841 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11842 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11847 /* extract channel definitions */
11848 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11850 guint32 cdef_len = 0;
11852 cdef_len = QT_UINT32 (cdef->data);
11853 if (cdef_len >= 10) {
11854 /* normal box, subtract off header and len */
11856 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11857 if (cdef_len % 6 == 0) {
11858 nchan_def = (cdef_len / 6);
11859 chan_def = g_new0 (gint32, nchan_def);
11860 for (i = 0; i < nchan_def; i++)
11862 for (i = 0; i < nchan_def; i++) {
11863 guint16 cn, typ, asoc;
11864 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11865 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11866 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11867 if (cn < nchan_def) {
11870 chan_def[cn] = asoc;
11873 chan_def[cn] = 0; /* alpha */
11876 chan_def[cn] = -typ;
11884 gst_caps_set_simple (entry->caps,
11885 "num-components", G_TYPE_INT, ncomp, NULL);
11886 gst_caps_set_simple (entry->caps,
11887 "colorspace", G_TYPE_STRING, colorspace, NULL);
11890 GValue arr = { 0, };
11891 GValue elt = { 0, };
11893 g_value_init (&arr, GST_TYPE_ARRAY);
11894 g_value_init (&elt, G_TYPE_INT);
11895 for (i = 0; i < ncomp_map; i++) {
11896 g_value_set_int (&elt, comp_map[i]);
11897 gst_value_array_append_value (&arr, &elt);
11899 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11900 "component-map", &arr);
11901 g_value_unset (&elt);
11902 g_value_unset (&arr);
11907 GValue arr = { 0, };
11908 GValue elt = { 0, };
11910 g_value_init (&arr, GST_TYPE_ARRAY);
11911 g_value_init (&elt, G_TYPE_INT);
11912 for (i = 0; i < nchan_def; i++) {
11913 g_value_set_int (&elt, chan_def[i]);
11914 gst_value_array_append_value (&arr, &elt);
11916 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11917 "channel-definitions", &arr);
11918 g_value_unset (&elt);
11919 g_value_unset (&arr);
11923 /* some optional atoms */
11924 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11925 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11927 /* indicate possible fields in caps */
11929 data = (guint8 *) field->data + 8;
11931 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11932 (gint) * data, NULL);
11934 /* add codec_data if provided */
11939 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11940 data = prefix->data;
11941 len = QT_UINT32 (data);
11944 buf = gst_buffer_new_and_alloc (len);
11945 gst_buffer_fill (buf, 0, data + 8, len);
11946 gst_caps_set_simple (entry->caps,
11947 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11948 gst_buffer_unref (buf);
11957 GstBuffer *seqh = NULL;
11958 const guint8 *gamma_data = NULL;
11959 guint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11961 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11964 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11965 QT_FP32 (gamma_data), NULL);
11968 /* sorry for the bad name, but we don't know what this is, other
11969 * than its own fourcc */
11970 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11972 gst_buffer_unref (seqh);
11975 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11976 buf = gst_buffer_new_and_alloc (len);
11977 gst_buffer_fill (buf, 0, stsd_data, len);
11978 gst_caps_set_simple (entry->caps,
11979 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11980 gst_buffer_unref (buf);
11985 /* https://developer.apple.com/standards/qtff-2001.pdf,
11986 * page 92, "Video Sample Description", under table 3.1 */
11989 const gint compressor_offset =
11990 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11991 const gint min_size = compressor_offset + 32 + 2 + 2;
11994 guint16 color_table_id = 0;
11997 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11999 /* recover information on interlaced/progressive */
12000 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
12004 len = QT_UINT32 (jpeg->data);
12005 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
12007 if (len >= min_size) {
12008 gst_byte_reader_init (&br, jpeg->data, len);
12010 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
12011 gst_byte_reader_get_uint16_le (&br, &color_table_id);
12012 if (color_table_id != 0) {
12013 /* the spec says there can be concatenated chunks in the data, and we want
12014 * to find one called field. Walk through them. */
12015 gint offset = min_size;
12016 while (offset + 8 < len) {
12017 guint32 size = 0, tag;
12018 ok = gst_byte_reader_get_uint32_le (&br, &size);
12019 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
12020 if (!ok || size < 8) {
12021 GST_WARNING_OBJECT (qtdemux,
12022 "Failed to walk optional chunk list");
12025 GST_DEBUG_OBJECT (qtdemux,
12026 "Found optional %4.4s chunk, size %u",
12027 (const char *) &tag, size);
12028 if (tag == FOURCC_fiel) {
12029 guint8 n_fields = 0, ordering = 0;
12030 gst_byte_reader_get_uint8 (&br, &n_fields);
12031 gst_byte_reader_get_uint8 (&br, &ordering);
12032 if (n_fields == 1 || n_fields == 2) {
12033 GST_DEBUG_OBJECT (qtdemux,
12034 "Found fiel tag with %u fields, ordering %u",
12035 n_fields, ordering);
12037 gst_caps_set_simple (CUR_STREAM (stream)->caps,
12038 "interlace-mode", G_TYPE_STRING, "interleaved",
12041 GST_WARNING_OBJECT (qtdemux,
12042 "Found fiel tag with invalid fields (%u)", n_fields);
12048 GST_DEBUG_OBJECT (qtdemux,
12049 "Color table ID is 0, not trying to get interlacedness");
12052 GST_WARNING_OBJECT (qtdemux,
12053 "Length of jpeg chunk is too small, not trying to get interlacedness");
12061 gst_caps_set_simple (entry->caps,
12062 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
12068 GNode *xith, *xdxt;
12070 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
12071 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12075 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
12079 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
12080 /* collect the headers and store them in a stream list so that we can
12081 * send them out first */
12082 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
12092 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
12093 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12096 ovc1_data = ovc1->data;
12097 ovc1_len = QT_UINT32 (ovc1_data);
12098 if (ovc1_len <= 198) {
12099 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
12102 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
12103 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
12104 gst_caps_set_simple (entry->caps,
12105 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12106 gst_buffer_unref (buf);
12111 guint len = QT_UINT32 (stsd_entry_data);
12112 len = len <= 0x56 ? 0 : len - 0x56;
12113 const guint8 *vc1_data = stsd_entry_data + 0x56;
12119 if (QT_UINT32 (vc1_data) <= 8)
12121 else if (QT_UINT32 (vc1_data) <= len)
12122 size = QT_UINT32 (vc1_data) - 8;
12127 /* No real data, so break out */
12130 switch (QT_FOURCC (vc1_data + 0x4)) {
12131 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
12135 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
12136 buf = gst_buffer_new_and_alloc (size);
12137 gst_buffer_fill (buf, 0, vc1_data + 8, size);
12138 gst_caps_set_simple (entry->caps,
12139 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12140 gst_buffer_unref (buf);
12147 vc1_data += size + 8;
12153 guint len = QT_UINT32 (stsd_entry_data);
12154 len = len <= 0x56 ? 0 : len - 0x56;
12155 const guint8 *av1_data = stsd_entry_data + 0x56;
12158 while (len >= 0x8) {
12161 if (QT_UINT32 (av1_data) <= 0x8)
12163 else if (QT_UINT32 (av1_data) <= len)
12164 size = QT_UINT32 (av1_data) - 0x8;
12169 /* No real data, so break out */
12172 switch (QT_FOURCC (av1_data + 0x4)) {
12175 /* parse, if found */
12177 guint8 pres_delay_field;
12179 GST_DEBUG_OBJECT (qtdemux,
12180 "found av1C codec_data in stsd of size %d", size);
12182 /* not enough data, just ignore and hope for the best */
12187 * 4 bytes: atom length
12192 * 1 bits: initial_presentation_delay_present
12193 * 4 bits: initial_presentation_delay (if present else reserved
12197 if (av1_data[9] != 0) {
12198 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
12202 /* We skip initial_presentation_delay* for now */
12203 pres_delay_field = *(av1_data + 12);
12204 if (pres_delay_field & (1 << 5)) {
12205 gst_caps_set_simple (entry->caps,
12206 "presentation-delay", G_TYPE_INT,
12207 (gint) (pres_delay_field & 0x0F) + 1, NULL);
12210 buf = gst_buffer_new_and_alloc (size - 5);
12211 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12212 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12213 gst_caps_set_simple (entry->caps,
12214 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12215 gst_buffer_unref (buf);
12224 av1_data += size + 8;
12230 /* TODO: Need to parse vpcC for VP8 codec too.
12231 * Note that VPCodecConfigurationBox (vpcC) is defined for
12232 * vp08, vp09, and vp10 fourcc. */
12235 guint len = QT_UINT32 (stsd_entry_data);
12236 len = len <= 0x56 ? 0 : len - 0x56;
12237 const guint8 *vpcc_data = stsd_entry_data + 0x56;
12240 while (len >= 0x8) {
12243 if (QT_UINT32 (vpcc_data) <= 0x8)
12245 else if (QT_UINT32 (vpcc_data) <= len)
12246 size = QT_UINT32 (vpcc_data) - 0x8;
12251 /* No real data, so break out */
12254 switch (QT_FOURCC (vpcc_data + 0x4)) {
12257 const gchar *profile_str = NULL;
12258 const gchar *chroma_format_str = NULL;
12261 guint8 chroma_format;
12262 GstVideoColorimetry cinfo;
12264 /* parse, if found */
12265 GST_DEBUG_OBJECT (qtdemux,
12266 "found vp codec_data in stsd of size %d", size);
12268 /* the meaning of "size" is length of the atom body, excluding
12269 * atom length and fourcc fields */
12274 * 4 bytes: atom length
12281 * 3 bits: chromaSubsampling
12282 * 1 bit: videoFullRangeFlag
12283 * 1 byte: colourPrimaries
12284 * 1 byte: transferCharacteristics
12285 * 1 byte: matrixCoefficients
12286 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
12287 * rest: codecIntializationData (not used for vp8 and vp9)
12290 if (vpcc_data[8] != 1) {
12291 GST_WARNING_OBJECT (qtdemux,
12292 "unknown vpcC version %d", vpcc_data[8]);
12296 profile = vpcc_data[12];
12315 gst_caps_set_simple (entry->caps,
12316 "profile", G_TYPE_STRING, profile_str, NULL);
12319 /* skip level, the VP9 spec v0.6 defines only one level atm,
12320 * but webm spec define various ones. Add level to caps
12321 * if we really need it then */
12323 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12324 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12325 gst_caps_set_simple (entry->caps,
12326 "bit-depth-luma", G_TYPE_UINT, bitdepth,
12327 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12330 chroma_format = (vpcc_data[14] & 0xe) >> 1;
12331 switch (chroma_format) {
12334 chroma_format_str = "4:2:0";
12337 chroma_format_str = "4:2:2";
12340 chroma_format_str = "4:4:4";
12346 if (chroma_format_str) {
12347 gst_caps_set_simple (entry->caps,
12348 "chroma-format", G_TYPE_STRING, chroma_format_str,
12352 if ((vpcc_data[14] & 0x1) != 0)
12353 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12355 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12357 gst_video_color_primaries_from_iso (vpcc_data[15]);
12359 gst_video_transfer_function_from_iso (vpcc_data[16]);
12361 gst_video_color_matrix_from_iso (vpcc_data[17]);
12363 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12364 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12365 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12366 /* set this only if all values are known, otherwise this
12367 * might overwrite valid ones parsed from other color box */
12368 CUR_STREAM (stream)->colorimetry = cinfo;
12377 vpcc_data += size + 8;
12387 GST_INFO_OBJECT (qtdemux,
12388 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12389 GST_FOURCC_ARGS (fourcc), entry->caps);
12391 } else if (stream->subtype == FOURCC_soun) {
12393 guint version, samplesize;
12394 guint16 compression_id;
12395 gboolean amrwb = FALSE;
12398 /* sample description entry (16) + sound sample description v0 (20) */
12402 version = QT_UINT32 (stsd_entry_data + offset);
12403 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12404 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12405 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12406 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12408 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12409 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12410 QT_UINT32 (stsd_entry_data + offset + 4));
12411 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12412 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12413 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12414 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12415 QT_UINT16 (stsd_entry_data + offset + 14));
12416 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12418 if (compression_id == 0xfffe)
12419 entry->sampled = TRUE;
12421 /* first assume uncompressed audio */
12422 entry->bytes_per_sample = samplesize / 8;
12423 entry->samples_per_frame = entry->n_channels;
12424 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12425 entry->samples_per_packet = entry->samples_per_frame;
12426 entry->bytes_per_packet = entry->bytes_per_sample;
12430 if (version == 0x00010000) {
12431 /* sample description entry (16) + sound sample description v1 (20+16) */
12435 /* take information from here over the normal sample description */
12436 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12437 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12438 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12439 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12441 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12442 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12443 entry->samples_per_packet);
12444 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12445 entry->bytes_per_packet);
12446 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12447 entry->bytes_per_frame);
12448 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12449 entry->bytes_per_sample);
12451 if (!entry->sampled && entry->bytes_per_packet) {
12452 entry->samples_per_frame = (entry->bytes_per_frame /
12453 entry->bytes_per_packet) * entry->samples_per_packet;
12454 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12455 entry->samples_per_frame);
12457 } else if (version == 0x00020000) {
12458 /* sample description entry (16) + sound sample description v2 (56) */
12462 /* take information from here over the normal sample description */
12463 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12464 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12465 entry->samples_per_frame = entry->n_channels;
12466 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12467 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12468 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12469 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12471 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12472 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12473 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12474 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12475 entry->bytes_per_sample * 8);
12476 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12477 QT_UINT32 (stsd_entry_data + offset + 24));
12478 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12479 entry->bytes_per_packet);
12480 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12481 entry->samples_per_packet);
12482 } else if (version != 0x00000) {
12483 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12488 /* Yes, these have to be hard-coded */
12491 entry->samples_per_packet = 6;
12492 entry->bytes_per_packet = 1;
12493 entry->bytes_per_frame = 1 * entry->n_channels;
12494 entry->bytes_per_sample = 1;
12495 entry->samples_per_frame = 6 * entry->n_channels;
12500 entry->samples_per_packet = 3;
12501 entry->bytes_per_packet = 1;
12502 entry->bytes_per_frame = 1 * entry->n_channels;
12503 entry->bytes_per_sample = 1;
12504 entry->samples_per_frame = 3 * entry->n_channels;
12509 entry->samples_per_packet = 64;
12510 entry->bytes_per_packet = 34;
12511 entry->bytes_per_frame = 34 * entry->n_channels;
12512 entry->bytes_per_sample = 2;
12513 entry->samples_per_frame = 64 * entry->n_channels;
12519 entry->samples_per_packet = 1;
12520 entry->bytes_per_packet = 1;
12521 entry->bytes_per_frame = 1 * entry->n_channels;
12522 entry->bytes_per_sample = 1;
12523 entry->samples_per_frame = 1 * entry->n_channels;
12528 entry->samples_per_packet = 160;
12529 entry->bytes_per_packet = 33;
12530 entry->bytes_per_frame = 33 * entry->n_channels;
12531 entry->bytes_per_sample = 2;
12532 entry->samples_per_frame = 160 * entry->n_channels;
12535 /* fix up any invalid header information from above */
12540 /* Sometimes these are set to 0 in the sound sample descriptions so
12541 * let's try to infer useful values from the other information we
12542 * have available */
12543 if (entry->bytes_per_sample == 0)
12544 entry->bytes_per_sample =
12545 entry->bytes_per_frame / entry->n_channels;
12546 if (entry->bytes_per_sample == 0)
12547 entry->bytes_per_sample = samplesize / 8;
12549 if (entry->bytes_per_frame == 0)
12550 entry->bytes_per_frame =
12551 entry->bytes_per_sample * entry->n_channels;
12553 if (entry->bytes_per_packet == 0)
12554 entry->bytes_per_packet = entry->bytes_per_sample;
12556 if (entry->samples_per_frame == 0)
12557 entry->samples_per_frame = entry->n_channels;
12559 if (entry->samples_per_packet == 0)
12560 entry->samples_per_packet = entry->samples_per_frame;
12570 entry->bytes_per_sample = 3;
12574 entry->bytes_per_sample = 4;
12577 entry->bytes_per_sample = 8;
12580 entry->bytes_per_sample = 2;
12583 g_assert_not_reached ();
12586 entry->samples_per_frame = entry->n_channels;
12587 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12588 entry->samples_per_packet = entry->samples_per_frame;
12589 entry->bytes_per_packet = entry->bytes_per_sample;
12597 gst_caps_unref (entry->caps);
12599 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12600 stsd_entry_data + 32, len - 16, &codec);
12611 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12613 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12615 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12617 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12620 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12621 const gchar *format_str;
12625 format_str = (enda_value) ? "S24LE" : "S24BE";
12628 format_str = (enda_value) ? "S32LE" : "S32BE";
12631 format_str = (enda_value) ? "F32LE" : "F32BE";
12634 format_str = (enda_value) ? "F64LE" : "F64BE";
12637 g_assert_not_reached ();
12640 gst_caps_set_simple (entry->caps,
12641 "format", G_TYPE_STRING, format_str, NULL);
12647 const guint8 *owma_data;
12648 const gchar *codec_name = NULL;
12652 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12653 /* FIXME this should also be gst_riff_strf_auds,
12654 * but the latter one is actually missing bits-per-sample :( */
12659 gint32 nSamplesPerSec;
12660 gint32 nAvgBytesPerSec;
12661 gint16 nBlockAlign;
12662 gint16 wBitsPerSample;
12665 WAVEFORMATEX *wfex;
12667 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12668 owma_data = stsd_entry_data;
12669 owma_len = QT_UINT32 (owma_data);
12670 if (owma_len <= 54) {
12671 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12674 wfex = (WAVEFORMATEX *) (owma_data + 36);
12675 buf = gst_buffer_new_and_alloc (owma_len - 54);
12676 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12677 if (wfex->wFormatTag == 0x0161) {
12678 codec_name = "Windows Media Audio";
12680 } else if (wfex->wFormatTag == 0x0162) {
12681 codec_name = "Windows Media Audio 9 Pro";
12683 } else if (wfex->wFormatTag == 0x0163) {
12684 codec_name = "Windows Media Audio 9 Lossless";
12685 /* is that correct? gstffmpegcodecmap.c is missing it, but
12686 * fluendo codec seems to support it */
12690 gst_caps_set_simple (entry->caps,
12691 "codec_data", GST_TYPE_BUFFER, buf,
12692 "wmaversion", G_TYPE_INT, version,
12693 "block_align", G_TYPE_INT,
12694 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12695 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12696 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12697 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12698 gst_buffer_unref (buf);
12702 codec = g_strdup (codec_name);
12708 guint len = QT_UINT32 (stsd_entry_data);
12709 len = len <= offset ? 0 : len - offset;
12710 const guint8 *wfex_data = stsd_entry_data + offset;
12711 const gchar *codec_name = NULL;
12713 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12714 /* FIXME this should also be gst_riff_strf_auds,
12715 * but the latter one is actually missing bits-per-sample :( */
12720 gint32 nSamplesPerSec;
12721 gint32 nAvgBytesPerSec;
12722 gint16 nBlockAlign;
12723 gint16 wBitsPerSample;
12728 /* FIXME: unify with similar wavformatex parsing code above */
12729 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12735 if (QT_UINT32 (wfex_data) <= 0x8)
12737 else if (QT_UINT32 (wfex_data) <= len)
12738 size = QT_UINT32 (wfex_data) - 8;
12743 /* No real data, so break out */
12746 switch (QT_FOURCC (wfex_data + 4)) {
12747 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12749 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12754 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12755 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12756 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12757 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12758 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12759 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12760 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12762 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12763 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12764 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12765 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12766 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12767 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12769 if (wfex.wFormatTag == 0x0161) {
12770 codec_name = "Windows Media Audio";
12772 } else if (wfex.wFormatTag == 0x0162) {
12773 codec_name = "Windows Media Audio 9 Pro";
12775 } else if (wfex.wFormatTag == 0x0163) {
12776 codec_name = "Windows Media Audio 9 Lossless";
12777 /* is that correct? gstffmpegcodecmap.c is missing it, but
12778 * fluendo codec seems to support it */
12782 gst_caps_set_simple (entry->caps,
12783 "wmaversion", G_TYPE_INT, version,
12784 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12785 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12786 "width", G_TYPE_INT, wfex.wBitsPerSample,
12787 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12789 if (size > wfex.cbSize) {
12792 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12793 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12794 size - wfex.cbSize);
12795 gst_caps_set_simple (entry->caps,
12796 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12797 gst_buffer_unref (buf);
12799 GST_WARNING_OBJECT (qtdemux, "no codec data");
12804 codec = g_strdup (codec_name);
12812 wfex_data += size + 8;
12818 const guint8 *dops_data;
12819 guint8 *channel_mapping = NULL;
12822 guint8 channel_mapping_family;
12823 guint8 stream_count;
12824 guint8 coupled_count;
12827 version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12829 dops_data = stsd_entry_data + 51;
12831 dops_data = stsd_entry_data + 35;
12833 channels = GST_READ_UINT8 (dops_data + 10);
12834 rate = GST_READ_UINT32_LE (dops_data + 13);
12835 channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12836 stream_count = GST_READ_UINT8 (dops_data + 20);
12837 coupled_count = GST_READ_UINT8 (dops_data + 21);
12839 if (channels > 0) {
12840 channel_mapping = g_malloc (channels * sizeof (guint8));
12841 for (i = 0; i < channels; i++)
12842 channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12845 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12846 channel_mapping_family, stream_count, coupled_count,
12848 g_free (channel_mapping);
12859 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12860 GST_TAG_AUDIO_CODEC, codec, NULL);
12864 /* some bitrate info may have ended up in caps */
12865 s = gst_caps_get_structure (entry->caps, 0);
12866 gst_structure_get_int (s, "bitrate", &bitrate);
12868 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12869 GST_TAG_BITRATE, bitrate, NULL);
12873 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12874 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12875 if (stream->protected) {
12876 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12877 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12879 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12889 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12891 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12893 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12897 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12898 16 bits is a byte-swapped wave-style codec identifier,
12899 and we can find a WAVE header internally to a 'wave' atom here.
12900 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12901 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12904 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12905 if (len < offset + 20) {
12906 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12908 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12909 const guint8 *data = stsd_entry_data + offset + 16;
12911 GNode *waveheadernode;
12913 wavenode = g_node_new ((guint8 *) data);
12914 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12915 const guint8 *waveheader;
12918 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12919 if (waveheadernode) {
12920 waveheader = (const guint8 *) waveheadernode->data;
12921 headerlen = QT_UINT32 (waveheader);
12923 if (headerlen > 8) {
12924 gst_riff_strf_auds *header = NULL;
12925 GstBuffer *headerbuf;
12931 headerbuf = gst_buffer_new_and_alloc (headerlen);
12932 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12934 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12935 headerbuf, &header, &extra)) {
12936 gst_caps_unref (entry->caps);
12937 /* FIXME: Need to do something with the channel reorder map */
12939 gst_riff_create_audio_caps (header->format, NULL, header,
12940 extra, NULL, NULL, NULL);
12943 gst_buffer_unref (extra);
12948 GST_DEBUG ("Didn't find waveheadernode for this codec");
12950 g_node_destroy (wavenode);
12953 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12954 stream->stream_tags);
12958 /* FIXME: what is in the chunk? */
12961 gint len = QT_UINT32 (stsd_data);
12963 /* seems to be always = 116 = 0x74 */
12969 gint len = QT_UINT32 (stsd_entry_data);
12972 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12974 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12975 gst_caps_set_simple (entry->caps,
12976 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12977 gst_buffer_unref (buf);
12979 gst_caps_set_simple (entry->caps,
12980 "samplesize", G_TYPE_INT, samplesize, NULL);
12985 GNode *alac, *wave = NULL;
12987 /* apparently, m4a has this atom appended directly in the stsd entry,
12988 * while mov has it in a wave atom */
12989 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12991 /* alac now refers to stsd entry atom */
12992 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12994 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12996 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12999 const guint8 *alac_data = alac->data;
13000 gint len = QT_UINT32 (alac->data);
13004 GST_DEBUG_OBJECT (qtdemux,
13005 "discarding alac atom with unexpected len %d", len);
13007 /* codec-data contains alac atom size and prefix,
13008 * ffmpeg likes it that way, not quite gst-ish though ...*/
13009 buf = gst_buffer_new_and_alloc (len);
13010 gst_buffer_fill (buf, 0, alac->data, len);
13011 gst_caps_set_simple (entry->caps,
13012 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13013 gst_buffer_unref (buf);
13015 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
13016 entry->n_channels = QT_UINT8 (alac_data + 21);
13017 entry->rate = QT_UINT32 (alac_data + 32);
13018 samplesize = QT_UINT8 (alac_data + 16 + 1);
13021 gst_caps_set_simple (entry->caps,
13022 "samplesize", G_TYPE_INT, samplesize, NULL);
13027 /* The codingname of the sample entry is 'fLaC' */
13028 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
13031 /* The 'dfLa' box is added to the sample entry to convey
13032 initializing information for the decoder. */
13033 const GNode *dfla =
13034 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
13037 const guint32 len = QT_UINT32 (dfla->data);
13039 /* Must contain at least dfLa box header (12),
13040 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
13042 GST_DEBUG_OBJECT (qtdemux,
13043 "discarding dfla atom with unexpected len %d", len);
13045 /* skip dfLa header to get the METADATA_BLOCKs */
13046 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
13047 const guint32 metadata_blocks_len = len - 12;
13049 gchar *stream_marker = g_strdup ("fLaC");
13050 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
13051 strlen (stream_marker));
13054 guint32 remainder = 0;
13055 guint32 block_size = 0;
13056 gboolean is_last = FALSE;
13058 GValue array = G_VALUE_INIT;
13059 GValue value = G_VALUE_INIT;
13061 g_value_init (&array, GST_TYPE_ARRAY);
13062 g_value_init (&value, GST_TYPE_BUFFER);
13064 gst_value_set_buffer (&value, block);
13065 gst_value_array_append_value (&array, &value);
13066 g_value_reset (&value);
13068 gst_buffer_unref (block);
13070 /* check there's at least one METADATA_BLOCK_HEADER's worth
13071 * of data, and we haven't already finished parsing */
13072 while (!is_last && ((index + 3) < metadata_blocks_len)) {
13073 remainder = metadata_blocks_len - index;
13075 /* add the METADATA_BLOCK_HEADER size to the signalled size */
13077 (metadata_blocks[index + 1] << 16) +
13078 (metadata_blocks[index + 2] << 8) +
13079 metadata_blocks[index + 3];
13081 /* be careful not to read off end of box */
13082 if (block_size > remainder) {
13086 is_last = metadata_blocks[index] >> 7;
13088 block = gst_buffer_new_and_alloc (block_size);
13090 gst_buffer_fill (block, 0, &metadata_blocks[index],
13093 gst_value_set_buffer (&value, block);
13094 gst_value_array_append_value (&array, &value);
13095 g_value_reset (&value);
13097 gst_buffer_unref (block);
13099 index += block_size;
13102 /* only append the metadata if we successfully read all of it */
13104 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
13105 (stream)->caps, 0), "streamheader", &array);
13107 GST_WARNING_OBJECT (qtdemux,
13108 "discarding all METADATA_BLOCKs due to invalid "
13109 "block_size %d at idx %d, rem %d", block_size, index,
13113 g_value_unset (&value);
13114 g_value_unset (&array);
13116 /* The sample rate obtained from the stsd may not be accurate
13117 * since it cannot represent rates greater than 65535Hz, so
13118 * override that value with the sample rate from the
13119 * METADATA_BLOCK_STREAMINFO block */
13120 CUR_STREAM (stream)->rate =
13121 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
13132 gint len = QT_UINT32 (stsd_entry_data);
13135 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
13138 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
13140 /* If we have enough data, let's try to get the 'damr' atom. See
13141 * the 3GPP container spec (26.244) for more details. */
13142 if ((len - 0x34) > 8 &&
13143 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
13144 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13145 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
13148 gst_caps_set_simple (entry->caps,
13149 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13150 gst_buffer_unref (buf);
13156 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
13157 gint len = QT_UINT32 (stsd_entry_data);
13158 guint16 sound_version = 0;
13159 /* FIXME: Can this be determined somehow? There doesn't seem to be
13160 * anything in mp4a atom that specifis compression */
13162 guint16 channels = entry->n_channels;
13163 guint32 time_scale = (guint32) entry->rate;
13164 gint sample_rate_index = -1;
13167 sound_version = QT_UINT16 (stsd_entry_data + 16);
13169 if (sound_version == 1) {
13170 channels = QT_UINT16 (stsd_entry_data + 24);
13171 time_scale = QT_UINT32 (stsd_entry_data + 30);
13173 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
13177 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
13181 sample_rate_index =
13182 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
13183 if (sample_rate_index >= 0 && channels > 0) {
13184 guint8 codec_data[2];
13187 /* build AAC codec data */
13188 codec_data[0] = profile << 3;
13189 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
13190 codec_data[1] = (sample_rate_index & 0x01) << 7;
13191 codec_data[1] |= (channels & 0xF) << 3;
13193 buf = gst_buffer_new_and_alloc (2);
13194 gst_buffer_fill (buf, 0, codec_data, 2);
13195 gst_caps_set_simple (entry->caps,
13196 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13197 gst_buffer_unref (buf);
13207 /* Fully handled elsewhere */
13210 GST_INFO_OBJECT (qtdemux,
13211 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13215 GST_INFO_OBJECT (qtdemux,
13216 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13217 GST_FOURCC_ARGS (fourcc), entry->caps);
13219 } else if (stream->subtype == FOURCC_strm) {
13220 if (fourcc == FOURCC_rtsp) {
13221 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
13223 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
13224 GST_FOURCC_ARGS (fourcc));
13225 goto unknown_stream;
13227 entry->sampled = TRUE;
13228 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
13229 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
13230 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
13232 entry->sampled = TRUE;
13233 entry->sparse = TRUE;
13236 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13239 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13240 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13245 /* hunt for sort-of codec data */
13249 GNode *mp4s = NULL;
13250 GNode *esds = NULL;
13252 /* look for palette in a stsd->mp4s->esds sub-atom */
13253 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
13255 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
13256 if (esds == NULL) {
13258 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13262 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13263 stream->stream_tags);
13267 GST_INFO_OBJECT (qtdemux,
13268 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13271 GST_INFO_OBJECT (qtdemux,
13272 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13273 GST_FOURCC_ARGS (fourcc), entry->caps);
13274 } else if (stream->subtype == FOURCC_meta) {
13275 entry->sampled = TRUE;
13276 entry->sparse = TRUE;
13279 qtdemux_meta_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13282 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13283 GST_TAG_CODEC, codec, NULL);
13288 GST_INFO_OBJECT (qtdemux,
13289 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13290 GST_FOURCC_ARGS (fourcc), entry->caps);
13292 /* everything in 1 sample */
13293 entry->sampled = TRUE;
13296 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13299 if (entry->caps == NULL)
13300 goto unknown_stream;
13303 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13304 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13310 /* promote to sampled format */
13311 if (entry->fourcc == FOURCC_samr) {
13312 /* force mono 8000 Hz for AMR */
13313 entry->sampled = TRUE;
13314 entry->n_channels = 1;
13315 entry->rate = 8000;
13316 } else if (entry->fourcc == FOURCC_sawb) {
13317 /* force mono 16000 Hz for AMR-WB */
13318 entry->sampled = TRUE;
13319 entry->n_channels = 1;
13320 entry->rate = 16000;
13321 } else if (entry->fourcc == FOURCC_mp4a) {
13322 entry->sampled = TRUE;
13326 stsd_entry_data += len;
13327 remaining_stsd_len -= len;
13331 /* collect sample information */
13332 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13333 goto samples_failed;
13335 if (qtdemux->fragmented) {
13338 /* need all moov samples as basis; probably not many if any at all */
13339 /* prevent moof parsing taking of at this time */
13340 offset = qtdemux->moof_offset;
13341 qtdemux->moof_offset = 0;
13342 if (stream->n_samples &&
13343 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13344 qtdemux->moof_offset = offset;
13345 goto samples_failed;
13347 qtdemux->moof_offset = offset;
13348 /* movie duration more reliable in this case (e.g. mehd) */
13349 if (qtdemux->segment.duration &&
13350 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13352 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13355 /* configure segments */
13356 if (!qtdemux_parse_segments (qtdemux, stream, trak))
13357 goto segments_failed;
13359 /* add some language tag, if useful */
13360 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13361 strcmp (stream->lang_id, "und")) {
13362 const gchar *lang_code;
13364 /* convert ISO 639-2 code to ISO 639-1 */
13365 lang_code = gst_tag_get_language_code (stream->lang_id);
13366 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13367 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13370 /* Check for UDTA tags */
13371 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13372 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13375 /* Insert and sort new stream in track-id order.
13376 * This will help in comparing old/new streams during stream update check */
13377 g_ptr_array_add (qtdemux->active_streams, stream);
13378 g_ptr_array_sort (qtdemux->active_streams,
13379 (GCompareFunc) qtdemux_track_id_compare_func);
13380 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13381 QTDEMUX_N_STREAMS (qtdemux));
13388 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13389 (_("This file is corrupt and cannot be played.")), (NULL));
13391 gst_qtdemux_stream_unref (stream);
13396 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13397 gst_qtdemux_stream_unref (stream);
13403 /* we posted an error already */
13404 /* free stbl sub-atoms */
13405 gst_qtdemux_stbl_free (stream);
13406 gst_qtdemux_stream_unref (stream);
13411 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13417 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13418 GST_FOURCC_ARGS (stream->subtype));
13419 gst_qtdemux_stream_unref (stream);
13424 /* If we can estimate the overall bitrate, and don't have information about the
13425 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13426 * the overall bitrate minus the sum of the bitrates of all other streams. This
13427 * should be useful for the common case where we have one audio and one video
13428 * stream and can estimate the bitrate of one, but not the other. */
13430 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13432 QtDemuxStream *stream = NULL;
13433 gint64 size, sys_bitrate, sum_bitrate = 0;
13434 GstClockTime duration;
13438 if (qtdemux->fragmented)
13441 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13443 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13445 GST_DEBUG_OBJECT (qtdemux,
13446 "Size in bytes of the stream not known - bailing");
13450 /* Subtract the header size */
13451 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13452 size, qtdemux->header_size);
13454 if (size < qtdemux->header_size)
13457 size = size - qtdemux->header_size;
13459 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13460 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13464 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13465 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13466 switch (str->subtype) {
13469 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13470 CUR_STREAM (str)->caps);
13471 /* retrieve bitrate, prefer avg then max */
13473 if (str->stream_tags) {
13474 if (gst_tag_list_get_uint (str->stream_tags,
13475 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13476 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13477 if (gst_tag_list_get_uint (str->stream_tags,
13478 GST_TAG_NOMINAL_BITRATE, &bitrate))
13479 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13480 if (gst_tag_list_get_uint (str->stream_tags,
13481 GST_TAG_BITRATE, &bitrate))
13482 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13485 sum_bitrate += bitrate;
13488 GST_DEBUG_OBJECT (qtdemux,
13489 ">1 stream with unknown bitrate - bailing");
13496 /* For other subtypes, we assume no significant impact on bitrate */
13502 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13506 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13508 if (sys_bitrate < sum_bitrate) {
13509 /* This can happen, since sum_bitrate might be derived from maximum
13510 * bitrates and not average bitrates */
13511 GST_DEBUG_OBJECT (qtdemux,
13512 "System bitrate less than sum bitrate - bailing");
13516 bitrate = sys_bitrate - sum_bitrate;
13517 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13518 ", Stream bitrate = %u", sys_bitrate, bitrate);
13520 if (!stream->stream_tags)
13521 stream->stream_tags = gst_tag_list_new_empty ();
13523 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13525 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13526 GST_TAG_BITRATE, bitrate, NULL);
13529 static GstFlowReturn
13530 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13532 GstFlowReturn ret = GST_FLOW_OK;
13535 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13537 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13538 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13539 guint32 sample_num = 0;
13541 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13542 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13544 if (qtdemux->fragmented && qtdemux->pullbased) {
13545 /* need all moov samples first */
13546 GST_OBJECT_LOCK (qtdemux);
13547 while (stream->n_samples == 0)
13548 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13550 GST_OBJECT_UNLOCK (qtdemux);
13552 /* discard any stray moof */
13553 qtdemux->moof_offset = 0;
13556 /* prepare braking */
13557 if (ret != GST_FLOW_ERROR)
13560 /* in pull mode, we should have parsed some sample info by now;
13561 * and quite some code will not handle no samples.
13562 * in push mode, we'll just have to deal with it */
13563 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13564 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13565 g_ptr_array_remove_index (qtdemux->active_streams, i);
13568 } else if (stream->track_id == qtdemux->chapters_track_id &&
13569 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13570 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13571 so that it doesn't look like a subtitle track */
13572 g_ptr_array_remove_index (qtdemux->active_streams, i);
13577 /* parse the initial sample for use in setting the frame rate cap */
13578 while (sample_num == 0 && sample_num < stream->n_samples) {
13579 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13589 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13591 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13595 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13599 /* Different length, updated */
13600 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13603 /* streams in list are sorted in track-id order */
13604 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13605 /* Different stream-id, updated */
13606 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13607 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13615 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13616 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13618 /* Connect old stream's srcpad to new stream */
13619 newstream->pad = oldstream->pad;
13620 oldstream->pad = NULL;
13622 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13623 * case we need to force one through */
13624 newstream->new_stream = newstream->pad != NULL
13625 && GST_PAD_IS_EOS (newstream->pad);
13627 return gst_qtdemux_configure_stream (qtdemux, newstream);
13631 qtdemux_update_streams (GstQTDemux * qtdemux)
13634 g_assert (qtdemux->streams_aware);
13636 /* At below, figure out which stream in active_streams has identical stream-id
13637 * with that of in old_streams. If there is matching stream-id,
13638 * corresponding newstream will not be exposed again,
13639 * but demux will reuse srcpad of matched old stream
13641 * active_streams : newly created streams from the latest moov
13642 * old_streams : existing streams (belong to previous moov)
13645 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13646 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13647 QtDemuxStream *oldstream = NULL;
13650 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13651 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13653 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13654 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13655 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13657 /* null pad stream cannot be reused */
13658 if (oldstream->pad == NULL)
13663 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13665 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13668 /* we don't need to preserve order of old streams */
13669 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13673 /* now we have all info and can expose */
13674 list = stream->stream_tags;
13675 stream->stream_tags = NULL;
13676 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13684 /* Must be called with expose lock */
13685 static GstFlowReturn
13686 qtdemux_expose_streams (GstQTDemux * qtdemux)
13690 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13692 if (!qtdemux_is_streams_update (qtdemux)) {
13693 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13694 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13695 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13696 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13697 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13698 return GST_FLOW_ERROR;
13701 g_ptr_array_set_size (qtdemux->old_streams, 0);
13702 qtdemux->need_segment = TRUE;
13704 return GST_FLOW_OK;
13707 if (qtdemux->streams_aware) {
13708 if (!qtdemux_update_streams (qtdemux))
13709 return GST_FLOW_ERROR;
13711 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13712 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13715 /* now we have all info and can expose */
13716 list = stream->stream_tags;
13717 stream->stream_tags = NULL;
13718 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13719 return GST_FLOW_ERROR;
13724 gst_qtdemux_guess_bitrate (qtdemux);
13726 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13728 /* If we have still old_streams, it's no more used stream */
13729 for (i = 0; i < qtdemux->old_streams->len; i++) {
13730 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13735 event = gst_event_new_eos ();
13736 if (qtdemux->segment_seqnum)
13737 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13739 gst_pad_push_event (stream->pad, event);
13743 g_ptr_array_set_size (qtdemux->old_streams, 0);
13745 /* check if we should post a redirect in case there is a single trak
13746 * and it is a redirecting trak */
13747 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13748 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13751 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13752 "an external content");
13753 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13754 gst_structure_new ("redirect",
13755 "new-location", G_TYPE_STRING,
13756 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13757 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13758 g_free (qtdemux->redirect_location);
13759 qtdemux->redirect_location =
13760 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13763 g_ptr_array_foreach (qtdemux->active_streams,
13764 (GFunc) qtdemux_do_allocation, qtdemux);
13766 qtdemux->need_segment = TRUE;
13768 qtdemux->exposed = TRUE;
13769 return GST_FLOW_OK;
13774 GstStructure *structure; /* helper for sort function */
13776 guint min_req_bitrate;
13777 guint min_req_qt_version;
13781 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13783 GstQtReference *ref_a = (GstQtReference *) a;
13784 GstQtReference *ref_b = (GstQtReference *) b;
13786 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13787 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13789 /* known bitrates go before unknown; higher bitrates go first */
13790 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13793 /* sort the redirects and post a message for the application.
13796 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13798 GstQtReference *best;
13801 GValue list_val = { 0, };
13804 g_assert (references != NULL);
13806 references = g_list_sort (references, qtdemux_redirects_sort_func);
13808 best = (GstQtReference *) references->data;
13810 g_value_init (&list_val, GST_TYPE_LIST);
13812 for (l = references; l != NULL; l = l->next) {
13813 GstQtReference *ref = (GstQtReference *) l->data;
13814 GValue struct_val = { 0, };
13816 ref->structure = gst_structure_new ("redirect",
13817 "new-location", G_TYPE_STRING, ref->location, NULL);
13819 if (ref->min_req_bitrate > 0) {
13820 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13821 ref->min_req_bitrate, NULL);
13824 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13825 g_value_set_boxed (&struct_val, ref->structure);
13826 gst_value_list_append_value (&list_val, &struct_val);
13827 g_value_unset (&struct_val);
13828 /* don't free anything here yet, since we need best->structure below */
13831 g_assert (best != NULL);
13832 s = gst_structure_copy (best->structure);
13834 if (g_list_length (references) > 1) {
13835 gst_structure_set_value (s, "locations", &list_val);
13838 g_value_unset (&list_val);
13840 for (l = references; l != NULL; l = l->next) {
13841 GstQtReference *ref = (GstQtReference *) l->data;
13843 gst_structure_free (ref->structure);
13844 g_free (ref->location);
13847 g_list_free (references);
13849 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13850 g_free (qtdemux->redirect_location);
13851 qtdemux->redirect_location =
13852 g_strdup (gst_structure_get_string (s, "new-location"));
13853 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13854 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13857 /* look for redirect nodes, collect all redirect information and
13861 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13863 GNode *rmra, *rmda, *rdrf;
13865 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13867 GList *redirects = NULL;
13869 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13871 GstQtReference ref = { NULL, NULL, 0, 0 };
13872 GNode *rmdr, *rmvc;
13874 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13875 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13876 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13877 ref.min_req_bitrate);
13880 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13881 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13882 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13884 #ifndef GST_DISABLE_GST_DEBUG
13885 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13887 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13889 GST_LOG_OBJECT (qtdemux,
13890 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13891 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13892 bitmask, check_type);
13893 if (package == FOURCC_qtim && check_type == 0) {
13894 ref.min_req_qt_version = version;
13898 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13904 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13905 if (ref_len > 20) {
13906 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13907 ref_data = (guint8 *) rdrf->data + 20;
13908 if (ref_type == FOURCC_alis) {
13909 guint record_len, record_version, fn_len;
13911 if (ref_len > 70) {
13912 /* MacOSX alias record, google for alias-layout.txt */
13913 record_len = QT_UINT16 (ref_data + 4);
13914 record_version = QT_UINT16 (ref_data + 4 + 2);
13915 fn_len = QT_UINT8 (ref_data + 50);
13916 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13917 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13920 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13923 } else if (ref_type == FOURCC_url_) {
13924 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13926 GST_DEBUG_OBJECT (qtdemux,
13927 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13928 GST_FOURCC_ARGS (ref_type));
13930 if (ref.location != NULL) {
13931 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13933 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13935 GST_WARNING_OBJECT (qtdemux,
13936 "Failed to extract redirect location from rdrf atom");
13939 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13943 /* look for others */
13944 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13947 if (redirects != NULL) {
13948 qtdemux_process_redirects (qtdemux, redirects);
13954 static GstTagList *
13955 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13959 if (tags == NULL) {
13960 tags = gst_tag_list_new_empty ();
13961 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13964 if (qtdemux->major_brand == FOURCC_mjp2)
13965 fmt = "Motion JPEG 2000";
13966 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13968 else if (qtdemux->major_brand == FOURCC_qt__)
13970 else if (qtdemux->fragmented)
13973 fmt = "ISO MP4/M4A";
13975 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13976 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13978 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13984 /* we have read the complete moov node now.
13985 * This function parses all of the relevant info, creates the traks and
13986 * prepares all data structures for playback
13989 qtdemux_parse_tree (GstQTDemux * qtdemux)
13996 guint64 creation_time;
13997 GstDateTime *datetime = NULL;
14000 /* make sure we have a usable taglist */
14001 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14003 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
14004 if (mvhd == NULL) {
14005 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
14006 return qtdemux_parse_redirects (qtdemux);
14009 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
14010 if (version == 1) {
14011 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
14012 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
14013 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
14014 } else if (version == 0) {
14015 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
14016 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
14017 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
14019 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
14023 /* Moving qt creation time (secs since 1904) to unix time */
14024 if (creation_time != 0) {
14025 /* Try to use epoch first as it should be faster and more commonly found */
14026 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
14029 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
14030 /* some data cleansing sanity */
14031 now_s = g_get_real_time () / G_USEC_PER_SEC;
14032 if (now_s + 24 * 3600 < creation_time) {
14033 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
14035 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
14038 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
14039 GDateTime *dt, *dt_local;
14041 dt = g_date_time_add_seconds (base_dt, creation_time);
14042 dt_local = g_date_time_to_local (dt);
14043 datetime = gst_date_time_new_from_g_date_time (dt_local);
14045 g_date_time_unref (base_dt);
14046 g_date_time_unref (dt);
14050 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
14051 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
14053 gst_date_time_unref (datetime);
14056 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
14057 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
14059 /* check for fragmented file and get some (default) data */
14060 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
14063 GstByteReader mehd_data;
14065 /* let track parsing or anyone know weird stuff might happen ... */
14066 qtdemux->fragmented = TRUE;
14068 /* compensate for total duration */
14069 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
14071 qtdemux_parse_mehd (qtdemux, &mehd_data);
14074 /* Update the movie segment duration, unless it was directly given to us
14075 * by upstream. Otherwise let it as is, as we don't want to mangle the
14076 * duration provided by upstream that may come e.g. from a MPD file. */
14077 if (!qtdemux->upstream_format_is_time) {
14078 GstClockTime duration;
14079 /* set duration in the segment info */
14080 gst_qtdemux_get_duration (qtdemux, &duration);
14081 qtdemux->segment.duration = duration;
14082 /* also do not exceed duration; stop is set that way post seek anyway,
14083 * and segment activation falls back to duration,
14084 * whereas loop only checks stop, so let's align this here as well */
14085 qtdemux->segment.stop = duration;
14088 /* parse all traks */
14089 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
14091 qtdemux_parse_trak (qtdemux, trak);
14092 /* iterate all siblings */
14093 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
14096 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14099 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
14101 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14103 GST_LOG_OBJECT (qtdemux, "No udta node found.");
14106 /* maybe also some tags in meta box */
14107 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
14109 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
14110 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14112 GST_LOG_OBJECT (qtdemux, "No meta node found.");
14115 /* parse any protection system info */
14116 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
14118 /* Unref old protection events if we are going to receive new ones. */
14119 qtdemux_clear_protection_events_on_all_streams (qtdemux);
14122 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
14123 qtdemux_parse_pssh (qtdemux, pssh);
14124 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
14127 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
14132 /* taken from ffmpeg */
14134 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14146 len = (len << 7) | (c & 0x7f);
14155 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14156 gsize codec_data_size)
14158 GList *list = NULL;
14159 guint8 *p = codec_data;
14160 gint i, offset, num_packets;
14161 guint *length, last;
14163 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14165 if (codec_data == NULL || codec_data_size == 0)
14168 /* start of the stream and vorbis audio or theora video, need to
14169 * send the codec_priv data as first three packets */
14170 num_packets = p[0] + 1;
14171 GST_DEBUG_OBJECT (qtdemux,
14172 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14173 (guint) num_packets, codec_data_size);
14175 /* Let's put some limits, Don't think there even is a xiph codec
14176 * with more than 3-4 headers */
14177 if (G_UNLIKELY (num_packets > 16)) {
14178 GST_WARNING_OBJECT (qtdemux,
14179 "Unlikely number of xiph headers, most likely not valid");
14183 length = g_alloca (num_packets * sizeof (guint));
14187 /* first packets, read length values */
14188 for (i = 0; i < num_packets - 1; i++) {
14190 while (offset < codec_data_size) {
14191 length[i] += p[offset];
14192 if (p[offset++] != 0xff)
14197 if (offset + last > codec_data_size)
14200 /* last packet is the remaining size */
14201 length[i] = codec_data_size - offset - last;
14203 for (i = 0; i < num_packets; i++) {
14206 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14208 if (offset + length[i] > codec_data_size)
14211 hdr = gst_buffer_new_memdup (p + offset, length[i]);
14212 list = g_list_append (list, hdr);
14214 offset += length[i];
14223 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14229 /* this can change the codec originally present in @list */
14231 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14232 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14234 int len = QT_UINT32 (esds->data);
14235 guint8 *ptr = esds->data;
14236 guint8 *end = ptr + len;
14238 guint8 *data_ptr = NULL;
14240 guint8 object_type_id = 0;
14241 guint8 stream_type = 0;
14242 const char *codec_name = NULL;
14243 GstCaps *caps = NULL;
14245 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14247 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14249 while (ptr + 1 < end) {
14250 tag = QT_UINT8 (ptr);
14251 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14253 len = read_descr_size (ptr, end, &ptr);
14254 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14256 /* Check the stated amount of data is available for reading */
14257 if (len < 0 || ptr + len > end)
14261 case ES_DESCRIPTOR_TAG:
14262 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14263 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14266 case DECODER_CONFIG_DESC_TAG:{
14267 guint max_bitrate, avg_bitrate;
14269 object_type_id = QT_UINT8 (ptr);
14270 stream_type = QT_UINT8 (ptr + 1) >> 2;
14271 max_bitrate = QT_UINT32 (ptr + 5);
14272 avg_bitrate = QT_UINT32 (ptr + 9);
14273 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14274 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14275 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14276 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14277 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14278 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14279 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14280 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14282 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14283 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14284 avg_bitrate, NULL);
14289 case DECODER_SPECIFIC_INFO_TAG:
14290 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14291 if (object_type_id == 0xe0 && len == 0x40) {
14297 GST_DEBUG_OBJECT (qtdemux,
14298 "Have VOBSUB palette. Creating palette event");
14299 /* move to decConfigDescr data and read palette */
14301 for (i = 0; i < 16; i++) {
14302 clut[i] = QT_UINT32 (data);
14306 s = gst_structure_new ("application/x-gst-dvd", "event",
14307 G_TYPE_STRING, "dvd-spu-clut-change",
14308 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14309 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14310 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14311 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14312 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14313 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14314 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14315 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14318 /* store event and trigger custom processing */
14319 stream->pending_event =
14320 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14322 /* Generic codec_data handler puts it on the caps */
14329 case SL_CONFIG_DESC_TAG:
14330 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14334 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14336 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14342 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14343 * in use, and should also be used to override some other parameters for some
14345 switch (object_type_id) {
14346 case 0x20: /* MPEG-4 */
14347 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14348 * profile_and_level_indication */
14349 if (data_ptr != NULL && data_len >= 5 &&
14350 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14351 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14352 data_ptr + 4, data_len - 4);
14354 break; /* Nothing special needed here */
14355 case 0x21: /* H.264 */
14356 codec_name = "H.264 / AVC";
14357 caps = gst_caps_new_simple ("video/x-h264",
14358 "stream-format", G_TYPE_STRING, "avc",
14359 "alignment", G_TYPE_STRING, "au", NULL);
14361 case 0x40: /* AAC (any) */
14362 case 0x66: /* AAC Main */
14363 case 0x67: /* AAC LC */
14364 case 0x68: /* AAC SSR */
14365 /* Override channels and rate based on the codec_data, as it's often
14367 /* Only do so for basic setup without HE-AAC extension */
14368 if (data_ptr && data_len == 2) {
14369 guint channels, rate;
14371 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14373 entry->n_channels = channels;
14375 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14377 entry->rate = rate;
14380 /* Set level and profile if possible */
14381 if (data_ptr != NULL && data_len >= 2) {
14382 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14383 data_ptr, data_len);
14385 const gchar *profile_str = NULL;
14388 guint8 *codec_data;
14389 gint rate_idx, profile;
14391 /* No codec_data, let's invent something.
14392 * FIXME: This is wrong for SBR! */
14394 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14396 buffer = gst_buffer_new_and_alloc (2);
14397 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14398 codec_data = map.data;
14401 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14404 switch (object_type_id) {
14406 profile_str = "main";
14410 profile_str = "lc";
14414 profile_str = "ssr";
14422 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14424 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14426 gst_buffer_unmap (buffer, &map);
14427 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14428 GST_TYPE_BUFFER, buffer, NULL);
14429 gst_buffer_unref (buffer);
14432 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14433 G_TYPE_STRING, profile_str, NULL);
14437 case 0x60: /* MPEG-2, various profiles */
14443 codec_name = "MPEG-2 video";
14444 caps = gst_caps_new_simple ("video/mpeg",
14445 "mpegversion", G_TYPE_INT, 2,
14446 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14448 case 0x69: /* MPEG-2 BC audio */
14449 case 0x6B: /* MPEG-1 audio */
14450 caps = gst_caps_new_simple ("audio/mpeg",
14451 "mpegversion", G_TYPE_INT, 1, NULL);
14452 codec_name = "MPEG-1 audio";
14454 case 0x6A: /* MPEG-1 */
14455 codec_name = "MPEG-1 video";
14456 caps = gst_caps_new_simple ("video/mpeg",
14457 "mpegversion", G_TYPE_INT, 1,
14458 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14460 case 0x6C: /* MJPEG */
14462 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14464 codec_name = "Motion-JPEG";
14466 case 0x6D: /* PNG */
14468 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14470 codec_name = "PNG still images";
14472 case 0x6E: /* JPEG2000 */
14473 codec_name = "JPEG-2000";
14474 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14476 case 0xA4: /* Dirac */
14477 codec_name = "Dirac";
14478 caps = gst_caps_new_empty_simple ("video/x-dirac");
14480 case 0xA5: /* AC3 */
14481 codec_name = "AC-3 audio";
14482 caps = gst_caps_new_simple ("audio/x-ac3",
14483 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14485 case 0xA9: /* AC3 */
14486 codec_name = "DTS audio";
14487 caps = gst_caps_new_simple ("audio/x-dts",
14488 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14491 if (stream_type == 0x05 && data_ptr) {
14493 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14496 GValue arr_val = G_VALUE_INIT;
14497 GValue buf_val = G_VALUE_INIT;
14500 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14501 codec_name = "Vorbis";
14502 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14503 g_value_init (&arr_val, GST_TYPE_ARRAY);
14504 g_value_init (&buf_val, GST_TYPE_BUFFER);
14505 for (tmp = headers; tmp; tmp = tmp->next) {
14506 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14507 gst_value_array_append_value (&arr_val, &buf_val);
14509 s = gst_caps_get_structure (caps, 0);
14510 gst_structure_take_value (s, "streamheader", &arr_val);
14511 g_value_unset (&buf_val);
14512 g_list_free (headers);
14519 case 0xE1: /* QCELP */
14520 /* QCELP, the codec_data is a riff tag (little endian) with
14521 * 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). */
14522 caps = gst_caps_new_empty_simple ("audio/qcelp");
14523 codec_name = "QCELP";
14529 /* If we have a replacement caps, then change our caps for this stream */
14531 gst_caps_unref (entry->caps);
14532 entry->caps = caps;
14535 if (codec_name && list)
14536 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14537 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14539 /* Add the codec_data attribute to caps, if we have it */
14543 buffer = gst_buffer_new_and_alloc (data_len);
14544 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14546 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14547 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14549 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14551 gst_buffer_unref (buffer);
14556 static inline GstCaps *
14557 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14561 char *s, fourstr[5];
14563 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14564 for (i = 0; i < 4; i++) {
14565 if (!g_ascii_isalnum (fourstr[i]))
14568 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14569 caps = gst_caps_new_empty_simple (s);
14574 #define _codec(name) \
14576 if (codec_name) { \
14577 *codec_name = g_strdup (name); \
14582 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14583 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14584 const guint8 * stsd_entry_data, gchar ** codec_name)
14586 GstCaps *caps = NULL;
14587 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14591 _codec ("PNG still images");
14592 caps = gst_caps_new_empty_simple ("image/png");
14595 _codec ("JPEG still images");
14597 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14600 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14601 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14602 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14603 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14604 _codec ("Motion-JPEG");
14606 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14609 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14610 _codec ("Motion-JPEG format B");
14611 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14614 _codec ("JPEG-2000");
14615 /* override to what it should be according to spec, avoid palette_data */
14616 entry->bits_per_sample = 24;
14617 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14620 _codec ("Sorensen video v.3");
14621 caps = gst_caps_new_simple ("video/x-svq",
14622 "svqversion", G_TYPE_INT, 3, NULL);
14624 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14625 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14626 _codec ("Sorensen video v.1");
14627 caps = gst_caps_new_simple ("video/x-svq",
14628 "svqversion", G_TYPE_INT, 1, NULL);
14630 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14631 caps = gst_caps_new_empty_simple ("video/x-raw");
14632 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14633 _codec ("Windows Raw RGB");
14634 stream->alignment = 32;
14640 bps = QT_UINT16 (stsd_entry_data + 82);
14643 format = GST_VIDEO_FORMAT_RGB15;
14646 format = GST_VIDEO_FORMAT_RGB16;
14649 format = GST_VIDEO_FORMAT_RGB;
14652 format = GST_VIDEO_FORMAT_ARGB;
14660 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14661 format = GST_VIDEO_FORMAT_I420;
14663 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14664 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14665 format = GST_VIDEO_FORMAT_I420;
14668 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14669 format = GST_VIDEO_FORMAT_UYVY;
14671 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14672 format = GST_VIDEO_FORMAT_v308;
14674 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14675 format = GST_VIDEO_FORMAT_v216;
14678 format = GST_VIDEO_FORMAT_v210;
14680 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14681 format = GST_VIDEO_FORMAT_r210;
14683 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14684 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14685 format = GST_VIDEO_FORMAT_v410;
14688 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14689 * but different order than AYUV
14690 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14691 format = GST_VIDEO_FORMAT_v408;
14694 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14695 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14696 _codec ("MPEG-1 video");
14697 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14698 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14700 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14701 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14702 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14703 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14704 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14705 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14706 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14707 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14708 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14709 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14710 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14711 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14712 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14713 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14714 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14715 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14716 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14717 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14718 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14719 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14720 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14721 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14722 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14723 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14724 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14725 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14726 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14727 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14728 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14729 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14730 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14731 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14732 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14733 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14734 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14735 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14736 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14737 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14738 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14739 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14740 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14741 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14742 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14743 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14744 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14745 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14746 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14747 _codec ("MPEG-2 video");
14748 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14749 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14751 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14752 _codec ("GIF still images");
14753 caps = gst_caps_new_empty_simple ("image/gif");
14756 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14758 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14760 /* ffmpeg uses the height/width props, don't know why */
14761 caps = gst_caps_new_simple ("video/x-h263",
14762 "variant", G_TYPE_STRING, "itu", NULL);
14766 _codec ("MPEG-4 video");
14767 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14768 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14770 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14771 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14772 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14773 caps = gst_caps_new_simple ("video/x-msmpeg",
14774 "msmpegversion", G_TYPE_INT, 43, NULL);
14776 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14778 caps = gst_caps_new_simple ("video/x-divx",
14779 "divxversion", G_TYPE_INT, 3, NULL);
14781 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14782 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14784 caps = gst_caps_new_simple ("video/x-divx",
14785 "divxversion", G_TYPE_INT, 4, NULL);
14787 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14789 caps = gst_caps_new_simple ("video/x-divx",
14790 "divxversion", G_TYPE_INT, 5, NULL);
14793 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14795 caps = gst_caps_new_simple ("video/x-ffv",
14796 "ffvversion", G_TYPE_INT, 1, NULL);
14799 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14800 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14805 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14806 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14807 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14811 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14812 _codec ("Cinepak");
14813 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14815 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14816 _codec ("Apple QuickDraw");
14817 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14819 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14820 _codec ("Apple video");
14821 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14826 _codec ("H.264 / AVC");
14827 caps = gst_caps_new_simple ("video/x-h264",
14828 "stream-format", G_TYPE_STRING, "avc",
14829 "alignment", G_TYPE_STRING, "au", NULL);
14833 _codec ("H.264 / AVC");
14834 caps = gst_caps_new_simple ("video/x-h264",
14835 "stream-format", G_TYPE_STRING, "avc3",
14836 "alignment", G_TYPE_STRING, "au", NULL);
14850 _codec ("H.264 / AVC");
14851 caps = gst_caps_new_simple ("video/x-h264",
14852 "stream-format", G_TYPE_STRING, "byte-stream",
14853 "alignment", G_TYPE_STRING, "au", NULL);
14858 _codec ("H.265 / HEVC");
14859 caps = gst_caps_new_simple ("video/x-h265",
14860 "stream-format", G_TYPE_STRING, "hvc1",
14861 "alignment", G_TYPE_STRING, "au", NULL);
14865 _codec ("H.265 / HEVC");
14866 caps = gst_caps_new_simple ("video/x-h265",
14867 "stream-format", G_TYPE_STRING, "hev1",
14868 "alignment", G_TYPE_STRING, "au", NULL);
14871 _codec ("Run-length encoding");
14872 caps = gst_caps_new_simple ("video/x-rle",
14873 "layout", G_TYPE_STRING, "quicktime", NULL);
14876 _codec ("Run-length encoding");
14877 caps = gst_caps_new_simple ("video/x-rle",
14878 "layout", G_TYPE_STRING, "microsoft", NULL);
14880 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14881 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14882 _codec ("Indeo Video 3");
14883 caps = gst_caps_new_simple ("video/x-indeo",
14884 "indeoversion", G_TYPE_INT, 3, NULL);
14886 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14887 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14888 _codec ("Intel Video 4");
14889 caps = gst_caps_new_simple ("video/x-indeo",
14890 "indeoversion", G_TYPE_INT, 4, NULL);
14894 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14895 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14896 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14897 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14898 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14899 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14900 _codec ("DV Video");
14901 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14902 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14904 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14905 case FOURCC_dv5p: /* DVCPRO50 PAL */
14906 _codec ("DVCPro50 Video");
14907 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14908 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14910 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14911 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14912 _codec ("DVCProHD Video");
14913 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14914 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14916 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14917 _codec ("Apple Graphics (SMC)");
14918 caps = gst_caps_new_empty_simple ("video/x-smc");
14920 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14922 caps = gst_caps_new_empty_simple ("video/x-vp3");
14924 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14925 _codec ("VP6 Flash");
14926 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14930 caps = gst_caps_new_empty_simple ("video/x-theora");
14931 /* theora uses one byte of padding in the data stream because it does not
14932 * allow 0 sized packets while theora does */
14933 entry->padding = 1;
14937 caps = gst_caps_new_empty_simple ("video/x-dirac");
14939 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14940 _codec ("TIFF still images");
14941 caps = gst_caps_new_empty_simple ("image/tiff");
14943 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14944 _codec ("Apple Intermediate Codec");
14945 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14947 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14948 _codec ("AVID DNxHD");
14949 caps = gst_caps_from_string ("video/x-dnxhd");
14953 _codec ("On2 VP8");
14954 caps = gst_caps_from_string ("video/x-vp8");
14957 _codec ("Google VP9");
14958 caps = gst_caps_from_string ("video/x-vp9");
14961 _codec ("Apple ProRes LT");
14963 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14967 _codec ("Apple ProRes HQ");
14969 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14973 _codec ("Apple ProRes");
14975 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14979 _codec ("Apple ProRes Proxy");
14981 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14985 _codec ("Apple ProRes 4444");
14987 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14990 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14991 if (entry->bits_per_sample > 0) {
14992 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14997 _codec ("Apple ProRes 4444 XQ");
14999 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15002 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
15003 if (entry->bits_per_sample > 0) {
15004 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
15009 _codec ("GoPro CineForm");
15010 caps = gst_caps_from_string ("video/x-cineform");
15015 caps = gst_caps_new_simple ("video/x-wmv",
15016 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
15020 caps = gst_caps_new_simple ("video/x-av1",
15021 "stream-format", G_TYPE_STRING, "obu-stream",
15022 "alignment", G_TYPE_STRING, "tu", NULL);
15024 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
15027 caps = _get_unknown_codec_name ("video", fourcc);
15032 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
15035 gst_video_info_init (&info);
15036 gst_video_info_set_format (&info, format, entry->width, entry->height);
15038 caps = gst_video_info_to_caps (&info);
15039 *codec_name = gst_pb_utils_get_codec_description (caps);
15041 /* enable clipping for raw video streams */
15042 stream->need_clip = TRUE;
15043 stream->alignment = 32;
15050 round_up_pow2 (guint n)
15062 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15063 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
15064 int len, gchar ** codec_name)
15067 const GstStructure *s;
15070 GstAudioFormat format = 0;
15073 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15075 depth = entry->bytes_per_packet * 8;
15078 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
15080 /* 8-bit audio is unsigned */
15082 format = GST_AUDIO_FORMAT_U8;
15083 /* otherwise it's signed and big-endian just like 'twos' */
15085 endian = G_BIG_ENDIAN;
15092 endian = G_LITTLE_ENDIAN;
15095 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
15097 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
15101 caps = gst_caps_new_simple ("audio/x-raw",
15102 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15103 "layout", G_TYPE_STRING, "interleaved", NULL);
15104 stream->alignment = GST_ROUND_UP_8 (depth);
15105 stream->alignment = round_up_pow2 (stream->alignment);
15109 _codec ("Raw 64-bit floating-point audio");
15110 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15112 caps = gst_caps_new_simple ("audio/x-raw",
15113 "format", G_TYPE_STRING, "F64BE",
15114 "layout", G_TYPE_STRING, "interleaved", NULL);
15115 stream->alignment = 8;
15118 _codec ("Raw 32-bit floating-point audio");
15119 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15121 caps = gst_caps_new_simple ("audio/x-raw",
15122 "format", G_TYPE_STRING, "F32BE",
15123 "layout", G_TYPE_STRING, "interleaved", NULL);
15124 stream->alignment = 4;
15127 _codec ("Raw 24-bit PCM audio");
15128 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15130 caps = gst_caps_new_simple ("audio/x-raw",
15131 "format", G_TYPE_STRING, "S24BE",
15132 "layout", G_TYPE_STRING, "interleaved", NULL);
15133 stream->alignment = 4;
15136 _codec ("Raw 32-bit PCM audio");
15137 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15139 caps = gst_caps_new_simple ("audio/x-raw",
15140 "format", G_TYPE_STRING, "S32BE",
15141 "layout", G_TYPE_STRING, "interleaved", NULL);
15142 stream->alignment = 4;
15145 _codec ("Raw 16-bit PCM audio");
15146 caps = gst_caps_new_simple ("audio/x-raw",
15147 "format", G_TYPE_STRING, "S16LE",
15148 "layout", G_TYPE_STRING, "interleaved", NULL);
15149 stream->alignment = 2;
15152 _codec ("Mu-law audio");
15153 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
15156 _codec ("A-law audio");
15157 caps = gst_caps_new_empty_simple ("audio/x-alaw");
15161 _codec ("Microsoft ADPCM");
15162 /* Microsoft ADPCM-ACM code 2 */
15163 caps = gst_caps_new_simple ("audio/x-adpcm",
15164 "layout", G_TYPE_STRING, "microsoft", NULL);
15168 _codec ("DVI/IMA ADPCM");
15169 caps = gst_caps_new_simple ("audio/x-adpcm",
15170 "layout", G_TYPE_STRING, "dvi", NULL);
15174 _codec ("DVI/Intel IMA ADPCM");
15175 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15176 caps = gst_caps_new_simple ("audio/x-adpcm",
15177 "layout", G_TYPE_STRING, "quicktime", NULL);
15181 /* MPEG layer 3, CBR only (pre QT4.1) */
15184 _codec ("MPEG-1 layer 3");
15185 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15186 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15187 "mpegversion", G_TYPE_INT, 1, NULL);
15189 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15190 _codec ("MPEG-1 layer 2");
15192 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15193 "mpegversion", G_TYPE_INT, 1, NULL);
15196 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15197 _codec ("EAC-3 audio");
15198 caps = gst_caps_new_simple ("audio/x-eac3",
15199 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15200 entry->sampled = TRUE;
15202 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15204 _codec ("AC-3 audio");
15205 caps = gst_caps_new_simple ("audio/x-ac3",
15206 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15207 entry->sampled = TRUE;
15209 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15210 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15211 _codec ("DTS audio");
15212 caps = gst_caps_new_simple ("audio/x-dts",
15213 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15214 entry->sampled = TRUE;
15216 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15217 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15218 _codec ("DTS-HD audio");
15219 caps = gst_caps_new_simple ("audio/x-dts",
15220 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15221 entry->sampled = TRUE;
15225 caps = gst_caps_new_simple ("audio/x-mace",
15226 "maceversion", G_TYPE_INT, 3, NULL);
15230 caps = gst_caps_new_simple ("audio/x-mace",
15231 "maceversion", G_TYPE_INT, 6, NULL);
15233 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15235 caps = gst_caps_new_empty_simple ("application/ogg");
15237 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15238 _codec ("DV audio");
15239 caps = gst_caps_new_empty_simple ("audio/x-dv");
15242 _codec ("MPEG-4 AAC audio");
15243 caps = gst_caps_new_simple ("audio/mpeg",
15244 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15245 "stream-format", G_TYPE_STRING, "raw", NULL);
15247 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15248 _codec ("QDesign Music");
15249 caps = gst_caps_new_empty_simple ("audio/x-qdm");
15252 _codec ("QDesign Music v.2");
15253 /* FIXME: QDesign music version 2 (no constant) */
15254 if (FALSE && data) {
15255 caps = gst_caps_new_simple ("audio/x-qdm2",
15256 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15257 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15258 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15260 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15264 _codec ("GSM audio");
15265 caps = gst_caps_new_empty_simple ("audio/x-gsm");
15268 _codec ("AMR audio");
15269 caps = gst_caps_new_empty_simple ("audio/AMR");
15272 _codec ("AMR-WB audio");
15273 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15276 _codec ("Quicktime IMA ADPCM");
15277 caps = gst_caps_new_simple ("audio/x-adpcm",
15278 "layout", G_TYPE_STRING, "quicktime", NULL);
15281 _codec ("Apple lossless audio");
15282 caps = gst_caps_new_empty_simple ("audio/x-alac");
15285 _codec ("Free Lossless Audio Codec");
15286 caps = gst_caps_new_simple ("audio/x-flac",
15287 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15289 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15290 _codec ("QualComm PureVoice");
15291 caps = gst_caps_from_string ("audio/qcelp");
15296 caps = gst_caps_new_empty_simple ("audio/x-wma");
15300 caps = gst_caps_new_empty_simple ("audio/x-opus");
15307 GstAudioFormat format;
15310 FLAG_IS_FLOAT = 0x1,
15311 FLAG_IS_BIG_ENDIAN = 0x2,
15312 FLAG_IS_SIGNED = 0x4,
15313 FLAG_IS_PACKED = 0x8,
15314 FLAG_IS_ALIGNED_HIGH = 0x10,
15315 FLAG_IS_NON_INTERLEAVED = 0x20
15317 _codec ("Raw LPCM audio");
15319 if (data && len >= 36) {
15320 depth = QT_UINT32 (data + 24);
15321 flags = QT_UINT32 (data + 28);
15322 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15324 if ((flags & FLAG_IS_FLOAT) == 0) {
15329 if ((flags & FLAG_IS_ALIGNED_HIGH))
15332 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15333 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15334 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15335 caps = gst_caps_new_simple ("audio/x-raw",
15336 "format", G_TYPE_STRING,
15338 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15339 "UNKNOWN", "layout", G_TYPE_STRING,
15340 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15341 "interleaved", NULL);
15342 stream->alignment = GST_ROUND_UP_8 (depth);
15343 stream->alignment = round_up_pow2 (stream->alignment);
15348 if (flags & FLAG_IS_BIG_ENDIAN)
15349 format = GST_AUDIO_FORMAT_F64BE;
15351 format = GST_AUDIO_FORMAT_F64LE;
15353 if (flags & FLAG_IS_BIG_ENDIAN)
15354 format = GST_AUDIO_FORMAT_F32BE;
15356 format = GST_AUDIO_FORMAT_F32LE;
15358 caps = gst_caps_new_simple ("audio/x-raw",
15359 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15360 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15361 "non-interleaved" : "interleaved", NULL);
15362 stream->alignment = width / 8;
15366 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15369 caps = gst_caps_new_empty_simple ("audio/x-ac4");
15372 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15376 caps = _get_unknown_codec_name ("audio", fourcc);
15382 GstCaps *templ_caps =
15383 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15384 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15385 gst_caps_unref (caps);
15386 gst_caps_unref (templ_caps);
15387 caps = intersection;
15390 /* enable clipping for raw audio streams */
15391 s = gst_caps_get_structure (caps, 0);
15392 name = gst_structure_get_name (s);
15393 if (g_str_has_prefix (name, "audio/x-raw")) {
15394 stream->need_clip = TRUE;
15395 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15396 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15397 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15398 stream->max_buffer_size);
15404 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15405 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15406 const guint8 * stsd_entry_data, gchar ** codec_name)
15410 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15414 _codec ("DVD subtitle");
15415 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15416 stream->process_func = gst_qtdemux_process_buffer_dvd;
15419 _codec ("Quicktime timed text");
15422 _codec ("3GPP timed text");
15424 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15426 /* actual text piece needs to be extracted */
15427 stream->process_func = gst_qtdemux_process_buffer_text;
15430 _codec ("XML subtitles");
15431 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15436 const gchar *buf = "WEBVTT\n\n";
15438 _codec ("WebVTT subtitles");
15439 caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15440 stream->process_func = gst_qtdemux_process_buffer_wvtt;
15442 /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15443 buffer = gst_buffer_new_and_alloc (8);
15444 gst_buffer_fill (buffer, 0, buf, 8);
15445 stream->buffers = g_slist_append (stream->buffers, buffer);
15450 _codec ("CEA 608 Closed Caption");
15452 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15453 G_TYPE_STRING, "s334-1a", NULL);
15454 stream->process_func = gst_qtdemux_process_buffer_clcp;
15455 stream->need_split = TRUE;
15458 _codec ("CEA 708 Closed Caption");
15460 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15461 G_TYPE_STRING, "cdp", NULL);
15462 stream->process_func = gst_qtdemux_process_buffer_clcp;
15467 caps = _get_unknown_codec_name ("text", fourcc);
15475 qtdemux_meta_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15476 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15477 const guint8 * stsd_entry_data, gchar ** codec_name)
15479 GstCaps *caps = NULL;
15481 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15485 gsize size = QT_UINT32 (stsd_entry_data);
15486 GstByteReader reader = GST_BYTE_READER_INIT (stsd_entry_data, size);
15487 const gchar *content_encoding;
15488 const gchar *namespaces;
15489 const gchar *schema_locations;
15491 if (!gst_byte_reader_skip (&reader, 8 + 6 + 2)) {
15492 GST_WARNING_OBJECT (qtdemux, "Too short metx sample entry");
15496 if (!gst_byte_reader_get_string (&reader, &content_encoding) ||
15497 !gst_byte_reader_get_string (&reader, &namespaces) ||
15498 !gst_byte_reader_get_string (&reader, &schema_locations)) {
15499 GST_WARNING_OBJECT (qtdemux, "Too short metx sample entry");
15503 if (strstr (namespaces, "http://www.onvif.org/ver10/schema") != 0) {
15504 if (content_encoding == NULL || *content_encoding == '\0'
15505 || g_ascii_strcasecmp (content_encoding, "xml") == 0) {
15506 _codec ("ONVIF Timed XML MetaData");
15508 gst_caps_new_simple ("application/x-onvif-metadata", "parsed",
15509 G_TYPE_BOOLEAN, TRUE, NULL);
15511 GST_DEBUG_OBJECT (qtdemux, "Unknown content encoding: %s",
15515 GST_DEBUG_OBJECT (qtdemux, "Unknown metadata namespaces: %s",
15526 caps = _get_unknown_codec_name ("meta", fourcc);
15532 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15533 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15534 const guint8 * stsd_entry_data, gchar ** codec_name)
15540 _codec ("MPEG 1 video");
15541 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15542 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15552 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15553 const gchar * system_id)
15557 if (!qtdemux->protection_system_ids)
15558 qtdemux->protection_system_ids =
15559 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15560 /* Check whether we already have an entry for this system ID. */
15561 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15562 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15563 if (g_ascii_strcasecmp (system_id, id) == 0) {
15567 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15568 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,