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, guint 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 /* subsequent fragments extend stream */
3482 stream->samples[stream->n_samples - 1].timestamp +
3483 stream->samples[stream->n_samples - 1].duration;
3485 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3486 * difference (1 sec.) between decode_ts and timestamp, prefer the
3488 if (has_tfdt && !qtdemux->upstream_format_is_time
3489 && ABSDIFF (decode_ts, timestamp) >
3490 MAX (stream->duration_last_moof / 2,
3491 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3492 GST_INFO_OBJECT (qtdemux,
3493 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3494 ") are significantly different (more than %" GST_TIME_FORMAT
3495 "), using decode_ts",
3496 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3497 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3498 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3499 MAX (stream->duration_last_moof / 2,
3500 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3501 timestamp = decode_ts;
3504 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3505 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3506 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3510 initial_offset = *running_offset;
3512 sample = stream->samples + stream->n_samples;
3513 for (i = 0; i < samples_count; i++) {
3514 guint32 dur, size, sflags;
3517 /* first read sample data */
3518 if (flags & TR_SAMPLE_DURATION) {
3519 dur = QT_UINT32 (data + dur_offset);
3521 dur = d_sample_duration;
3523 if (flags & TR_SAMPLE_SIZE) {
3524 size = QT_UINT32 (data + size_offset);
3526 size = d_sample_size;
3528 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3530 sflags = first_flags;
3532 sflags = d_sample_flags;
3534 } else if (flags & TR_SAMPLE_FLAGS) {
3535 sflags = QT_UINT32 (data + flags_offset);
3537 sflags = d_sample_flags;
3540 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3541 /* Read offsets as signed numbers regardless of trun version as very
3542 * high offsets are unlikely and there are files out there that use
3543 * version=0 truns with negative offsets */
3544 ct = QT_UINT32 (data + ct_offset);
3546 /* FIXME: Set offset to 0 for "no decode samples". This needs
3547 * to be handled in a codec specific manner ideally. */
3548 if (ct == G_MININT32)
3555 /* fill the sample information */
3556 sample->offset = *running_offset;
3557 sample->pts_offset = ct;
3558 sample->size = size;
3559 sample->timestamp = timestamp;
3560 sample->duration = dur;
3561 /* sample-is-difference-sample */
3562 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3563 * now idea how it relates to bitfield other than massive LE/BE confusion */
3564 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3565 *running_offset += size;
3567 stream->duration_moof += dur;
3574 /* Shift PTS/DTS to allow for negative composition offsets while keeping
3575 * A/V sync in place. This is similar to the code handling ctts/cslg in the
3576 * non-fragmented case.
3579 stream->cslg_shift = -min_ct;
3581 stream->cslg_shift = 0;
3583 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
3584 stream->cslg_shift);
3586 /* Update total duration if needed */
3587 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3589 /* Pre-emptively figure out size of mdat based on trun information.
3590 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3591 * size, else we will still be able to use this when dealing with gap'ed
3593 qtdemux->mdatleft = *running_offset - initial_offset;
3594 qtdemux->mdatoffset = initial_offset;
3595 qtdemux->mdatsize = qtdemux->mdatleft;
3597 stream->n_samples += samples_count;
3598 stream->n_samples_moof += samples_count;
3600 if (stream->pending_seek != NULL)
3601 stream->pending_seek = NULL;
3607 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3612 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3618 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3619 "be larger than %uMB (broken file?)", stream->n_samples,
3620 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3625 /* find stream with @id */
3626 static inline QtDemuxStream *
3627 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3629 QtDemuxStream *stream;
3633 if (G_UNLIKELY (!id)) {
3634 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3638 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3639 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3640 if (stream->track_id == id)
3643 if (qtdemux->mss_mode) {
3644 /* mss should have only 1 stream anyway */
3645 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3652 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3653 guint32 * fragment_number)
3655 if (!gst_byte_reader_skip (mfhd, 4))
3657 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3662 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3668 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3669 QtDemuxStream ** stream, guint32 * default_sample_duration,
3670 guint32 * default_sample_size, guint32 * default_sample_flags,
3671 gint64 * base_offset)
3674 guint32 track_id = 0;
3676 if (!gst_byte_reader_skip (tfhd, 1) ||
3677 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3680 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3683 *stream = qtdemux_find_stream (qtdemux, track_id);
3684 if (G_UNLIKELY (!*stream))
3685 goto unknown_stream;
3687 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3688 *base_offset = qtdemux->moof_offset;
3690 if (flags & TF_BASE_DATA_OFFSET)
3691 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3694 /* obtain stream defaults */
3695 if (qtdemux_parse_trex (qtdemux, *stream,
3696 default_sample_duration, default_sample_size, default_sample_flags)) {
3698 /* Default sample description index is only valid if trex parsing succeeded */
3699 (*stream)->stsd_sample_description_id =
3700 (*stream)->def_sample_description_index - 1;
3703 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3704 guint32 sample_description_index;
3705 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3707 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3710 if (qtdemux->mss_mode) {
3711 /* mss has no stsd entry */
3712 (*stream)->stsd_sample_description_id = 0;
3715 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3716 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3719 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3720 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3723 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3724 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3731 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3736 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3742 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3743 guint64 * decode_time)
3745 guint32 version = 0;
3747 if (!gst_byte_reader_get_uint32_be (br, &version))
3752 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3755 guint32 dec_time = 0;
3756 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3758 *decode_time = dec_time;
3761 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3768 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3773 /* Returns a pointer to a GstStructure containing the properties of
3774 * the stream sample identified by @sample_index. The caller must unref
3775 * the returned object after use. Returns NULL if unsuccessful. */
3776 static GstStructure *
3777 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3778 QtDemuxStream * stream, guint sample_index)
3780 QtDemuxCencSampleSetInfo *info = NULL;
3782 g_return_val_if_fail (stream != NULL, NULL);
3783 g_return_val_if_fail (stream->protected, NULL);
3784 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3786 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3788 /* Currently, cenc properties for groups of samples are not supported, so
3789 * simply return a copy of the default sample properties */
3790 return gst_structure_copy (info->default_properties);
3793 /* Parses the sizes of sample auxiliary information contained within a stream,
3794 * as given in a saiz box. Returns array of sample_count guint8 size values,
3795 * or NULL on failure */
3797 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3798 GstByteReader * br, guint32 * sample_count)
3802 guint8 default_info_size;
3804 g_return_val_if_fail (qtdemux != NULL, NULL);
3805 g_return_val_if_fail (stream != NULL, NULL);
3806 g_return_val_if_fail (br != NULL, NULL);
3807 g_return_val_if_fail (sample_count != NULL, NULL);
3809 if (!gst_byte_reader_get_uint32_be (br, &flags))
3813 /* aux_info_type and aux_info_type_parameter are ignored */
3814 if (!gst_byte_reader_skip (br, 8))
3818 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3820 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3822 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3824 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3827 if (default_info_size == 0) {
3828 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3832 info_sizes = g_new (guint8, *sample_count);
3833 memset (info_sizes, default_info_size, *sample_count);
3839 /* Parses the offset of sample auxiliary information contained within a stream,
3840 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3842 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3843 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3848 guint32 aux_info_type = 0;
3849 guint32 aux_info_type_parameter = 0;
3850 guint32 entry_count;
3853 const guint8 *aux_info_type_data = NULL;
3855 g_return_val_if_fail (qtdemux != NULL, FALSE);
3856 g_return_val_if_fail (stream != NULL, FALSE);
3857 g_return_val_if_fail (br != NULL, FALSE);
3858 g_return_val_if_fail (offset != NULL, FALSE);
3860 if (!gst_byte_reader_get_uint8 (br, &version))
3863 if (!gst_byte_reader_get_uint24_be (br, &flags))
3868 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3870 aux_info_type = QT_FOURCC (aux_info_type_data);
3872 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3874 } else if (stream->protected) {
3875 aux_info_type = stream->protection_scheme_type;
3877 aux_info_type = CUR_STREAM (stream)->fourcc;
3881 *info_type = aux_info_type;
3882 if (info_type_parameter)
3883 *info_type_parameter = aux_info_type_parameter;
3885 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3886 "aux_info_type_parameter: %#06x",
3887 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3889 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3892 if (entry_count != 1) {
3893 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3898 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3900 *offset = (guint64) off_32;
3902 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3907 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3912 qtdemux_gst_structure_free (GstStructure * gststructure)
3915 gst_structure_free (gststructure);
3919 /* Parses auxiliary information relating to samples protected using
3920 * Common Encryption (cenc); the format of this information
3921 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3924 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3925 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3927 QtDemuxCencSampleSetInfo *ss_info = NULL;
3930 GPtrArray *old_crypto_info = NULL;
3931 guint old_entries = 0;
3933 g_return_val_if_fail (qtdemux != NULL, FALSE);
3934 g_return_val_if_fail (stream != NULL, FALSE);
3935 g_return_val_if_fail (br != NULL, FALSE);
3936 g_return_val_if_fail (stream->protected, FALSE);
3937 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3939 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3941 if (ss_info->crypto_info) {
3942 old_crypto_info = ss_info->crypto_info;
3943 /* Count number of non-null entries remaining at the tail end */
3944 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3945 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3951 ss_info->crypto_info =
3952 g_ptr_array_new_full (sample_count + old_entries,
3953 (GDestroyNotify) qtdemux_gst_structure_free);
3955 /* We preserve old entries because we parse the next moof in advance
3956 * of consuming all samples from the previous moof, and otherwise
3957 * we'd discard the corresponding crypto info for the samples
3958 * from the previous fragment. */
3960 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3962 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3963 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3965 g_ptr_array_index (old_crypto_info, i) = NULL;
3969 if (old_crypto_info) {
3970 /* Everything now belongs to the new array */
3971 g_ptr_array_free (old_crypto_info, TRUE);
3974 for (i = 0; i < sample_count; ++i) {
3975 GstStructure *properties;
3976 guint16 n_subsamples = 0;
3980 gboolean could_read_iv;
3982 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3983 if (properties == NULL) {
3984 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3987 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3988 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3989 gst_structure_free (properties);
3993 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3994 if (could_read_iv) {
3995 buf = gst_buffer_new_wrapped (data, iv_size);
3996 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3997 gst_buffer_unref (buf);
3998 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3999 const GValue *constant_iv_size_value =
4000 gst_structure_get_value (properties, "constant_iv_size");
4001 const GValue *constant_iv_value =
4002 gst_structure_get_value (properties, "iv");
4003 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
4004 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
4005 gst_structure_free (properties);
4008 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
4009 gst_structure_remove_field (properties, "constant_iv_size");
4010 } else if (stream->protection_scheme_type == FOURCC_cenc) {
4011 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
4012 gst_structure_free (properties);
4015 size = info_sizes[i];
4016 if (size > iv_size) {
4017 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
4018 || !(n_subsamples > 0)) {
4019 gst_structure_free (properties);
4020 GST_ERROR_OBJECT (qtdemux,
4021 "failed to get subsample count for sample %u", i);
4024 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
4025 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
4026 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
4028 gst_structure_free (properties);
4031 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
4033 gst_structure_free (properties);
4036 gst_structure_set (properties,
4037 "subsample_count", G_TYPE_UINT, n_subsamples,
4038 "subsamples", GST_TYPE_BUFFER, buf, NULL);
4039 gst_buffer_unref (buf);
4041 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
4043 g_ptr_array_add (ss_info->crypto_info, properties);
4048 /* Converts a UUID in raw byte form to a string representation, as defined in
4049 * RFC 4122. The caller takes ownership of the returned string and is
4050 * responsible for freeing it after use. */
4052 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
4054 const guint8 *uuid = (const guint8 *) uuid_bytes;
4056 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
4057 "%02x%02x-%02x%02x%02x%02x%02x%02x",
4058 uuid[0], uuid[1], uuid[2], uuid[3],
4059 uuid[4], uuid[5], uuid[6], uuid[7],
4060 uuid[8], uuid[9], uuid[10], uuid[11],
4061 uuid[12], uuid[13], uuid[14], uuid[15]);
4064 /* Parses a Protection System Specific Header box (pssh), as defined in the
4065 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
4066 * information needed by a specific content protection system in order to
4067 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
4070 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4072 gchar *sysid_string;
4073 guint32 pssh_size = QT_UINT32 (node->data);
4074 GstBuffer *pssh = NULL;
4075 GstEvent *event = NULL;
4076 guint32 parent_box_type;
4079 if (G_UNLIKELY (pssh_size < 32U)) {
4080 GST_ERROR_OBJECT (qtdemux, "invalid box size");
4085 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4087 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4089 pssh = gst_buffer_new_memdup (node->data, pssh_size);
4090 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4091 gst_buffer_get_size (pssh));
4093 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4095 /* Push an event containing the pssh box onto the queues of all streams. */
4096 event = gst_event_new_protection (sysid_string, pssh,
4097 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4098 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4099 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4100 GST_TRACE_OBJECT (qtdemux,
4101 "adding protection event for stream %s and system %s",
4102 stream->stream_id, sysid_string);
4103 g_queue_push_tail (&stream->protection_scheme_event_queue,
4104 gst_event_ref (event));
4106 g_free (sysid_string);
4107 gst_event_unref (event);
4108 gst_buffer_unref (pssh);
4113 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4114 guint64 moof_offset, QtDemuxStream * stream)
4116 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4118 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4119 GNode *saiz_node, *saio_node, *pssh_node;
4120 GstByteReader saiz_data, saio_data;
4121 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4122 gint64 base_offset, running_offset;
4124 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4126 /* NOTE @stream ignored */
4128 moof_node = g_node_new ((guint8 *) buffer);
4129 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4130 qtdemux_node_dump (qtdemux, moof_node);
4132 /* Get fragment number from mfhd and check it's valid */
4134 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4135 if (mfhd_node == NULL)
4137 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4139 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4141 /* unknown base_offset to start with */
4142 base_offset = running_offset = -1;
4143 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4145 guint64 decode_time = 0;
4147 /* Fragment Header node */
4149 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4153 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4154 &ds_size, &ds_flags, &base_offset))
4157 /* The following code assumes at most a single set of sample auxiliary
4158 * data in the fragment (consisting of a saiz box and a corresponding saio
4159 * box); in theory, however, there could be multiple sets of sample
4160 * auxiliary data in a fragment. */
4162 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4165 guint32 info_type = 0;
4167 guint32 info_type_parameter = 0;
4169 g_free (qtdemux->cenc_aux_info_sizes);
4171 qtdemux->cenc_aux_info_sizes =
4172 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4173 &qtdemux->cenc_aux_sample_count);
4174 if (qtdemux->cenc_aux_info_sizes == NULL) {
4175 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4179 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4182 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4183 g_free (qtdemux->cenc_aux_info_sizes);
4184 qtdemux->cenc_aux_info_sizes = NULL;
4188 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4189 &info_type, &info_type_parameter, &offset))) {
4190 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4191 g_free (qtdemux->cenc_aux_info_sizes);
4192 qtdemux->cenc_aux_info_sizes = NULL;
4195 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4196 offset += (guint64) (base_offset - qtdemux->moof_offset);
4197 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4198 && info_type_parameter == 0U) {
4200 if (offset > length) {
4201 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4202 qtdemux->cenc_aux_info_offset = offset;
4204 gst_byte_reader_init (&br, buffer + offset, length - offset);
4205 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4206 qtdemux->cenc_aux_info_sizes,
4207 qtdemux->cenc_aux_sample_count)) {
4208 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4209 g_free (qtdemux->cenc_aux_info_sizes);
4210 qtdemux->cenc_aux_info_sizes = NULL;
4218 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4221 /* We'll use decode_time to interpolate timestamps
4222 * in case the input timestamps are missing */
4223 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4225 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4226 " (%" GST_TIME_FORMAT ")", decode_time,
4227 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4228 decode_time) : GST_CLOCK_TIME_NONE));
4230 /* Discard the fragment buffer timestamp info to avoid using it.
4231 * Rely on tfdt instead as it is more accurate than the timestamp
4232 * that is fetched from a manifest/playlist and is usually
4234 qtdemux->fragment_start = -1;
4237 if (G_UNLIKELY (!stream)) {
4238 /* we lost track of offset, we'll need to regain it,
4239 * but can delay complaining until later or avoid doing so altogether */
4243 if (G_UNLIKELY (base_offset < -1))
4246 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4248 if (!qtdemux->pullbased) {
4249 /* Sample tables can grow enough to be problematic if the system memory
4250 * is very low (e.g. embedded devices) and the videos very long
4251 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4252 * Fortunately, we can easily discard them for each new fragment when
4253 * we know qtdemux will not receive seeks outside of the current fragment.
4254 * adaptivedemux honors this assumption.
4255 * This optimization is also useful for applications that use qtdemux as
4256 * a push-based simple demuxer, like Media Source Extensions. */
4257 gst_qtdemux_stream_flush_samples_data (stream);
4260 /* initialise moof sample data */
4261 stream->n_samples_moof = 0;
4262 stream->duration_last_moof = stream->duration_moof;
4263 stream->duration_moof = 0;
4265 /* Track Run node */
4267 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4270 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4271 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4272 &running_offset, decode_time, (tfdt_node != NULL));
4273 /* iterate all siblings */
4274 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4276 /* don't use tfdt for subsequent trun as it only refers to the first */
4280 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4282 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4283 guint32 box_length = QT_UINT32 (uuid_buffer);
4285 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4288 /* if no new base_offset provided for next traf,
4289 * base is end of current traf */
4290 base_offset = running_offset;
4291 running_offset = -1;
4293 if (stream->n_samples_moof && stream->duration_moof)
4294 stream->new_caps = TRUE;
4297 /* iterate all siblings */
4298 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4301 /* parse any protection system info */
4302 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4304 /* Unref old protection events if we are going to receive new ones. */
4305 qtdemux_clear_protection_events_on_all_streams (qtdemux);
4308 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4309 qtdemux_parse_pssh (qtdemux, pssh_node);
4310 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4313 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4314 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4316 /* Unless the user has explicitly requested another seek, perform an
4317 * internal seek to the time specified in the tfdt.
4319 * This way if the user opens a file where the first tfdt is 1 hour
4320 * into the presentation, they will not have to wait 1 hour for run
4321 * time to catch up and actual playback to start. */
4324 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4325 "performing an internal seek to %" GST_TIME_FORMAT,
4326 GST_TIME_ARGS (min_dts));
4328 qtdemux->segment.start = min_dts;
4329 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4331 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4332 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4333 stream->time_position = min_dts;
4336 /* Before this code was run a segment was already sent when the moov was
4337 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4338 * be emitted after a moov, and we can emit a second segment anyway for
4339 * special cases like this. */
4340 qtdemux->need_segment = TRUE;
4343 qtdemux->first_moof_already_parsed = TRUE;
4345 g_node_destroy (moof_node);
4350 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4355 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4360 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4365 g_node_destroy (moof_node);
4366 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4367 (_("This file is corrupt and cannot be played.")), (NULL));
4373 /* might be used if some day we actually use mfra & co
4374 * for random access to fragments,
4375 * but that will require quite some modifications and much less relying
4376 * on a sample array */
4380 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4382 QtDemuxStream *stream;
4383 guint32 ver_flags, track_id, len, num_entries, i;
4384 guint value_size, traf_size, trun_size, sample_size;
4385 guint64 time = 0, moof_offset = 0;
4387 GstBuffer *buf = NULL;
4392 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4394 if (!gst_byte_reader_skip (&tfra, 8))
4397 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4400 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4401 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4402 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4405 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4407 stream = qtdemux_find_stream (qtdemux, track_id);
4409 goto unknown_trackid;
4411 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4412 sample_size = (len & 3) + 1;
4413 trun_size = ((len & 12) >> 2) + 1;
4414 traf_size = ((len & 48) >> 4) + 1;
4416 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4417 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4419 if (num_entries == 0)
4422 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4423 value_size + value_size + traf_size + trun_size + sample_size))
4426 g_free (stream->ra_entries);
4427 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4428 stream->n_ra_entries = num_entries;
4430 for (i = 0; i < num_entries; i++) {
4431 qt_atom_parser_get_offset (&tfra, value_size, &time);
4432 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4433 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4434 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4435 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4437 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4439 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4440 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4442 stream->ra_entries[i].ts = time;
4443 stream->ra_entries[i].moof_offset = moof_offset;
4445 /* don't want to go through the entire file and read all moofs at startup */
4447 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4448 if (ret != GST_FLOW_OK)
4450 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4451 moof_offset, stream);
4452 gst_buffer_unref (buf);
4456 check_update_duration (qtdemux, time);
4463 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4468 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4473 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4479 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4481 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4482 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4483 GstBuffer *mfro = NULL, *mfra = NULL;
4485 gboolean ret = FALSE;
4486 GNode *mfra_node, *tfra_node;
4487 guint64 mfra_offset = 0;
4488 guint32 fourcc, mfra_size;
4491 /* query upstream size in bytes */
4492 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4493 goto size_query_failed;
4495 /* mfro box should be at the very end of the file */
4496 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4497 if (flow != GST_FLOW_OK)
4500 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4502 fourcc = QT_FOURCC (mfro_map.data + 4);
4503 if (fourcc != FOURCC_mfro)
4506 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4507 if (mfro_map.size < 16)
4508 goto invalid_mfro_size;
4510 mfra_size = QT_UINT32 (mfro_map.data + 12);
4511 if (mfra_size >= len)
4512 goto invalid_mfra_size;
4514 mfra_offset = len - mfra_size;
4516 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4517 mfra_offset, mfra_size);
4519 /* now get and parse mfra box */
4520 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4521 if (flow != GST_FLOW_OK)
4524 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4526 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4527 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4529 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4532 qtdemux_parse_tfra (qtdemux, tfra_node);
4533 /* iterate all siblings */
4534 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4536 g_node_destroy (mfra_node);
4538 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4544 if (mfro_map.memory != NULL)
4545 gst_buffer_unmap (mfro, &mfro_map);
4546 gst_buffer_unref (mfro);
4549 if (mfra_map.memory != NULL)
4550 gst_buffer_unmap (mfra, &mfra_map);
4551 gst_buffer_unref (mfra);
4558 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4563 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4568 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4573 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4579 add_offset (guint64 offset, guint64 advance)
4581 /* Avoid 64-bit overflow by clamping */
4582 if (offset > G_MAXUINT64 - advance)
4584 return offset + advance;
4587 static GstFlowReturn
4588 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4592 GstBuffer *buf = NULL;
4593 GstFlowReturn ret = GST_FLOW_OK;
4594 guint64 cur_offset = qtdemux->offset;
4597 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4598 if (G_UNLIKELY (ret != GST_FLOW_OK))
4600 gst_buffer_map (buf, &map, GST_MAP_READ);
4601 if (G_LIKELY (map.size >= 8))
4602 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4603 gst_buffer_unmap (buf, &map);
4604 gst_buffer_unref (buf);
4606 /* maybe we already got most we needed, so only consider this eof */
4607 if (G_UNLIKELY (length == 0)) {
4608 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4609 (_("Invalid atom size.")),
4610 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4611 GST_FOURCC_ARGS (fourcc)));
4618 /* record for later parsing when needed */
4619 if (!qtdemux->moof_offset) {
4620 qtdemux->moof_offset = qtdemux->offset;
4622 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4625 qtdemux->offset += length; /* skip moof and keep going */
4627 if (qtdemux->got_moov) {
4628 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4640 GST_LOG_OBJECT (qtdemux,
4641 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4642 GST_FOURCC_ARGS (fourcc), cur_offset);
4643 qtdemux->offset = add_offset (qtdemux->offset, length);
4648 GstBuffer *moov = NULL;
4650 if (qtdemux->got_moov) {
4651 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4652 qtdemux->offset = add_offset (qtdemux->offset, length);
4656 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4657 if (ret != GST_FLOW_OK)
4659 gst_buffer_map (moov, &map, GST_MAP_READ);
4661 if (length != map.size) {
4662 /* Some files have a 'moov' atom at the end of the file which contains
4663 * a terminal 'free' atom where the body of the atom is missing.
4664 * Check for, and permit, this special case.
4666 if (map.size >= 8) {
4667 guint8 *final_data = map.data + (map.size - 8);
4668 guint32 final_length = QT_UINT32 (final_data);
4669 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4671 if (final_fourcc == FOURCC_free
4672 && map.size + final_length - 8 == length) {
4673 /* Ok, we've found that special case. Allocate a new buffer with
4674 * that free atom actually present. */
4675 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4676 gst_buffer_fill (newmoov, 0, map.data, map.size);
4677 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4678 gst_buffer_unmap (moov, &map);
4679 gst_buffer_unref (moov);
4681 gst_buffer_map (moov, &map, GST_MAP_READ);
4686 if (length != map.size) {
4687 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4688 (_("This file is incomplete and cannot be played.")),
4689 ("We got less than expected (received %" G_GSIZE_FORMAT
4690 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4691 (guint) length, cur_offset));
4692 gst_buffer_unmap (moov, &map);
4693 gst_buffer_unref (moov);
4694 ret = GST_FLOW_ERROR;
4697 qtdemux->offset += length;
4699 qtdemux_parse_moov (qtdemux, map.data, length);
4700 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4702 qtdemux_parse_tree (qtdemux);
4703 if (qtdemux->moov_node_compressed) {
4704 g_node_destroy (qtdemux->moov_node_compressed);
4705 g_free (qtdemux->moov_node->data);
4707 qtdemux->moov_node_compressed = NULL;
4708 g_node_destroy (qtdemux->moov_node);
4709 qtdemux->moov_node = NULL;
4710 gst_buffer_unmap (moov, &map);
4711 gst_buffer_unref (moov);
4712 qtdemux->got_moov = TRUE;
4718 GstBuffer *ftyp = NULL;
4720 /* extract major brand; might come in handy for ISO vs QT issues */
4721 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4722 if (ret != GST_FLOW_OK)
4724 qtdemux->offset += length;
4725 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4726 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4727 gst_buffer_unmap (ftyp, &map);
4728 gst_buffer_unref (ftyp);
4733 GstBuffer *styp = NULL;
4735 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &styp);
4736 if (ret != GST_FLOW_OK)
4738 qtdemux->offset += length;
4739 gst_buffer_map (styp, &map, GST_MAP_READ);
4740 qtdemux_parse_styp (qtdemux, map.data, map.size);
4741 gst_buffer_unmap (styp, &map);
4742 gst_buffer_unref (styp);
4747 GstBuffer *uuid = NULL;
4749 /* uuid are extension atoms */
4750 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4751 if (ret != GST_FLOW_OK)
4753 qtdemux->offset += length;
4754 gst_buffer_map (uuid, &map, GST_MAP_READ);
4755 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4756 gst_buffer_unmap (uuid, &map);
4757 gst_buffer_unref (uuid);
4762 GstBuffer *sidx = NULL;
4763 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4764 if (ret != GST_FLOW_OK)
4766 qtdemux->offset += length;
4767 gst_buffer_map (sidx, &map, GST_MAP_READ);
4768 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4769 gst_buffer_unmap (sidx, &map);
4770 gst_buffer_unref (sidx);
4775 GstBuffer *meta = NULL;
4776 GNode *node, *child;
4777 GstByteReader child_data;
4778 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &meta);
4779 if (ret != GST_FLOW_OK)
4781 qtdemux->offset += length;
4782 gst_buffer_map (meta, &map, GST_MAP_READ);
4784 node = g_node_new (map.data);
4786 qtdemux_parse_node (qtdemux, node, map.data, map.size);
4788 /* Parse ONVIF Export File Format CorrectStartTime box if available */
4790 qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb,
4792 qtdemux_parse_cstb (qtdemux, &child_data);
4795 g_node_destroy (node);
4797 gst_buffer_unmap (meta, &map);
4798 gst_buffer_unref (meta);
4803 GstBuffer *unknown = NULL;
4805 GST_LOG_OBJECT (qtdemux,
4806 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4807 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4809 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4810 if (ret != GST_FLOW_OK)
4812 gst_buffer_map (unknown, &map, GST_MAP_READ);
4813 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4814 gst_buffer_unmap (unknown, &map);
4815 gst_buffer_unref (unknown);
4816 qtdemux->offset += length;
4822 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4823 /* digested all data, show what we have */
4824 qtdemux_prepare_streams (qtdemux);
4825 QTDEMUX_EXPOSE_LOCK (qtdemux);
4826 ret = qtdemux_expose_streams (qtdemux);
4827 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4829 qtdemux->state = QTDEMUX_STATE_MOVIE;
4830 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4837 /* Seeks to the previous keyframe of the indexed stream and
4838 * aligns other streams with respect to the keyframe timestamp
4839 * of indexed stream. Only called in case of Reverse Playback
4841 static GstFlowReturn
4842 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4844 guint32 seg_idx = 0, k_index = 0;
4845 guint32 ref_seg_idx, ref_k_index;
4846 GstClockTime k_pos = 0, last_stop = 0;
4847 QtDemuxSegment *seg = NULL;
4848 QtDemuxStream *ref_str = NULL;
4849 guint64 seg_media_start_mov; /* segment media start time in mov format */
4853 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4854 * and finally align all the other streams on that timestamp with their
4855 * respective keyframes */
4856 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4857 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4859 /* No candidate yet, take the first stream */
4865 /* So that stream has a segment, we prefer video streams */
4866 if (str->subtype == FOURCC_vide) {
4872 if (G_UNLIKELY (!ref_str)) {
4873 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4877 if (G_UNLIKELY (!ref_str->from_sample)) {
4878 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4882 /* So that stream has been playing from from_sample to to_sample. We will
4883 * get the timestamp of the previous sample and search for a keyframe before
4884 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4885 if (ref_str->subtype == FOURCC_vide) {
4886 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4887 ref_str->from_sample - 1, FALSE);
4889 if (ref_str->from_sample >= 10)
4890 k_index = ref_str->from_sample - 10;
4896 ref_str->samples[k_index].timestamp +
4897 ref_str->samples[k_index].pts_offset;
4899 /* get current segment for that stream */
4900 seg = &ref_str->segments[ref_str->segment_index];
4901 /* Use segment start in original timescale for comparisons */
4902 seg_media_start_mov = seg->trak_media_start;
4904 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4905 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4906 k_index, target_ts, seg_media_start_mov,
4907 GST_TIME_ARGS (seg->media_start));
4909 /* Crawl back through segments to find the one containing this I frame */
4910 while (target_ts < seg_media_start_mov) {
4911 GST_DEBUG_OBJECT (qtdemux,
4912 "keyframe position (sample %u) is out of segment %u " " target %"
4913 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4914 ref_str->segment_index, target_ts, seg_media_start_mov);
4916 if (G_UNLIKELY (!ref_str->segment_index)) {
4917 /* Reached first segment, let's consider it's EOS */
4920 ref_str->segment_index--;
4921 seg = &ref_str->segments[ref_str->segment_index];
4922 /* Use segment start in original timescale for comparisons */
4923 seg_media_start_mov = seg->trak_media_start;
4925 /* Calculate time position of the keyframe and where we should stop */
4927 QTSTREAMTIME_TO_GSTTIME (ref_str,
4928 target_ts - seg->trak_media_start) + seg->time;
4930 QTSTREAMTIME_TO_GSTTIME (ref_str,
4931 ref_str->samples[ref_str->from_sample].timestamp -
4932 seg->trak_media_start) + seg->time;
4934 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4935 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4936 k_index, GST_TIME_ARGS (k_pos));
4938 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4939 qtdemux->segment.position = last_stop;
4940 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4941 GST_TIME_ARGS (last_stop));
4943 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4944 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4948 ref_seg_idx = ref_str->segment_index;
4949 ref_k_index = k_index;
4951 /* Align them all on this */
4952 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4954 GstClockTime seg_time = 0;
4955 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4957 /* aligning reference stream again might lead to backing up to yet another
4958 * keyframe (due to timestamp rounding issues),
4959 * potentially putting more load on downstream; so let's try to avoid */
4960 if (str == ref_str) {
4961 seg_idx = ref_seg_idx;
4962 seg = &str->segments[seg_idx];
4963 k_index = ref_k_index;
4964 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4965 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4967 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4968 GST_DEBUG_OBJECT (qtdemux,
4969 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4970 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4972 /* get segment and time in the segment */
4973 seg = &str->segments[seg_idx];
4974 seg_time = k_pos - seg->time;
4976 /* get the media time in the segment.
4977 * No adjustment for empty "filler" segments */
4978 if (seg->media_start != GST_CLOCK_TIME_NONE)
4979 seg_time += seg->media_start;
4981 /* get the index of the sample with media time */
4982 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4983 GST_DEBUG_OBJECT (qtdemux,
4984 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4985 GST_TIME_ARGS (seg_time), index);
4987 /* find previous keyframe */
4988 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4991 /* Remember until where we want to go */
4992 str->to_sample = str->from_sample - 1;
4993 /* Define our time position */
4995 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4996 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4997 if (seg->media_start != GST_CLOCK_TIME_NONE)
4998 str->time_position -= seg->media_start;
5000 /* Now seek back in time */
5001 gst_qtdemux_move_stream (qtdemux, str, k_index);
5002 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
5003 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
5004 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
5010 return GST_FLOW_EOS;
5014 * Gets the current qt segment start, stop and position for the
5015 * given time offset. This is used in update_segment()
5018 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
5019 QtDemuxStream * stream, GstClockTime offset,
5020 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
5022 GstClockTime seg_time;
5023 GstClockTime start, stop, time;
5024 QtDemuxSegment *segment;
5026 segment = &stream->segments[stream->segment_index];
5028 /* get time in this segment */
5029 seg_time = (offset - segment->time) * segment->rate;
5031 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
5032 GST_TIME_ARGS (seg_time));
5034 if (G_UNLIKELY (seg_time > segment->duration)) {
5035 GST_LOG_OBJECT (stream->pad,
5036 "seg_time > segment->duration %" GST_TIME_FORMAT,
5037 GST_TIME_ARGS (segment->duration));
5038 seg_time = segment->duration;
5041 /* qtdemux->segment.stop is in outside-time-realm, whereas
5042 * segment->media_stop is in track-time-realm.
5044 * In order to compare the two, we need to bring segment.stop
5045 * into the track-time-realm
5047 * FIXME - does this comment still hold? Don't see any conversion here */
5049 stop = qtdemux->segment.stop;
5050 if (stop == GST_CLOCK_TIME_NONE)
5051 stop = qtdemux->segment.duration;
5052 if (stop == GST_CLOCK_TIME_NONE)
5053 stop = segment->media_stop;
5056 MIN (segment->media_stop, stop - segment->time + segment->media_start);
5058 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5059 start = segment->time + seg_time;
5061 stop = start - seg_time + segment->duration;
5062 } else if (qtdemux->segment.rate >= 0) {
5063 start = MIN (segment->media_start + seg_time, stop);
5066 if (segment->media_start >= qtdemux->segment.start) {
5067 time = segment->time;
5069 time = segment->time + (qtdemux->segment.start - segment->media_start);
5072 start = MAX (segment->media_start, qtdemux->segment.start);
5073 stop = MIN (segment->media_start + seg_time, stop);
5082 * Updates the qt segment used for the stream and pushes a new segment event
5083 * downstream on this stream's pad.
5086 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5087 gint seg_idx, GstClockTime offset, GstClockTime * _start,
5088 GstClockTime * _stop)
5090 QtDemuxSegment *segment;
5091 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
5095 /* update the current segment */
5096 stream->segment_index = seg_idx;
5098 /* get the segment */
5099 segment = &stream->segments[seg_idx];
5101 if (G_UNLIKELY (offset < segment->time)) {
5102 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
5103 GST_TIME_ARGS (segment->time));
5107 /* segment lies beyond total indicated duration */
5108 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5109 segment->time > qtdemux->segment.duration)) {
5110 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5111 " < segment->time %" GST_TIME_FORMAT,
5112 GST_TIME_ARGS (qtdemux->segment.duration),
5113 GST_TIME_ARGS (segment->time));
5117 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5118 &start, &stop, &time);
5120 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5121 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5122 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5124 /* combine global rate with that of the segment */
5125 rate = segment->rate * qtdemux->segment.rate;
5127 /* Copy flags from main segment */
5128 stream->segment.flags = qtdemux->segment.flags;
5130 /* update the segment values used for clipping */
5131 stream->segment.offset = qtdemux->segment.offset;
5132 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5133 stream->segment.applied_rate = qtdemux->segment.applied_rate;
5134 stream->segment.rate = rate;
5135 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5136 stream->cslg_shift);
5138 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5139 stream->cslg_shift);
5141 stream->segment.stop = stop;
5142 stream->segment.time = time;
5143 stream->segment.position = stream->segment.start;
5145 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5148 /* now prepare and send the segment */
5150 event = gst_event_new_segment (&stream->segment);
5151 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5152 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5154 gst_pad_push_event (stream->pad, event);
5155 /* assume we can send more data now */
5156 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5157 /* clear to send tags on this pad now */
5158 gst_qtdemux_push_tags (qtdemux, stream);
5169 /* activate the given segment number @seg_idx of @stream at time @offset.
5170 * @offset is an absolute global position over all the segments.
5172 * This will push out a NEWSEGMENT event with the right values and
5173 * position the stream index to the first decodable sample before
5177 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5178 guint32 seg_idx, GstClockTime offset)
5180 QtDemuxSegment *segment;
5181 guint32 index, kf_index;
5182 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5184 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5185 seg_idx, GST_TIME_ARGS (offset));
5187 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5191 segment = &stream->segments[stream->segment_index];
5193 /* in the fragmented case, we pick a fragment that starts before our
5194 * desired position and rely on downstream to wait for a keyframe
5195 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5196 * tfra entries tells us which trun/sample the key unit is in, but we don't
5197 * make use of this additional information at the moment) */
5198 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5199 stream->to_sample = G_MAXUINT32;
5202 /* well, it will be taken care of below */
5203 qtdemux->fragmented_seek_pending = FALSE;
5204 /* FIXME ideally the do_fragmented_seek can be done right here,
5205 * rather than at loop level
5206 * (which might even allow handling edit lists in a fragmented file) */
5209 /* We don't need to look for a sample in push-based */
5210 if (!qtdemux->pullbased)
5213 /* and move to the keyframe before the indicated media time of the
5215 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5216 if (qtdemux->segment.rate >= 0) {
5217 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5218 stream->to_sample = G_MAXUINT32;
5219 GST_DEBUG_OBJECT (stream->pad,
5220 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5221 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5222 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5224 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5225 stream->to_sample = index;
5226 GST_DEBUG_OBJECT (stream->pad,
5227 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5228 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5229 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5232 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5233 "this is an empty segment");
5237 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5238 * encountered an error and printed a message so we return appropriately */
5242 /* we're at the right spot */
5243 if (index == stream->sample_index) {
5244 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5248 /* find keyframe of the target index */
5249 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5251 /* go back two frames to provide lead-in for non-raw audio decoders */
5252 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5253 guint32 lead_in = 2;
5254 guint32 old_index = kf_index;
5255 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5257 if (gst_structure_has_name (s, "audio/mpeg")) {
5259 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5260 && mpegversion == 1) {
5261 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5266 kf_index = MAX (kf_index, lead_in) - lead_in;
5267 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5268 GST_DEBUG_OBJECT (stream->pad,
5269 "Moving backwards %u frames to ensure sufficient sound lead-in",
5270 old_index - kf_index);
5272 kf_index = old_index;
5276 /* if we move forwards, we don't have to go back to the previous
5277 * keyframe since we already sent that. We can also just jump to
5278 * the keyframe right before the target index if there is one. */
5279 if (index > stream->sample_index) {
5280 /* moving forwards check if we move past a keyframe */
5281 if (kf_index > stream->sample_index) {
5282 GST_DEBUG_OBJECT (stream->pad,
5283 "moving forwards to keyframe at %u "
5284 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5286 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5287 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5288 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5290 GST_DEBUG_OBJECT (stream->pad,
5291 "moving forwards, keyframe at %u "
5292 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5294 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5295 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5298 GST_DEBUG_OBJECT (stream->pad,
5299 "moving backwards to %sframe at %u "
5300 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5301 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5302 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5303 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5304 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5310 /* prepare to get the current sample of @stream, getting essential values.
5312 * This function will also prepare and send the segment when needed.
5314 * Return FALSE if the stream is EOS.
5319 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5320 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5321 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5322 gboolean * keyframe)
5324 QtDemuxSample *sample;
5325 GstClockTime time_position;
5328 g_return_val_if_fail (stream != NULL, FALSE);
5330 time_position = stream->time_position;
5331 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5334 seg_idx = stream->segment_index;
5335 if (G_UNLIKELY (seg_idx == -1)) {
5336 /* find segment corresponding to time_position if we are looking
5338 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5341 /* different segment, activate it, sample_index will be set. */
5342 if (G_UNLIKELY (stream->segment_index != seg_idx))
5343 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5345 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5346 segments[stream->segment_index]))) {
5347 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5349 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5350 " prepare empty sample");
5353 *pts = *dts = time_position;
5354 *duration = seg->duration - (time_position - seg->time);
5361 if (stream->sample_index == -1)
5362 stream->sample_index = 0;
5364 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5365 stream->sample_index, stream->n_samples);
5367 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5368 if (!qtdemux->fragmented)
5371 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5375 GST_OBJECT_LOCK (qtdemux);
5376 flow = qtdemux_add_fragmented_samples (qtdemux);
5377 GST_OBJECT_UNLOCK (qtdemux);
5379 if (flow != GST_FLOW_OK)
5382 while (stream->sample_index >= stream->n_samples);
5385 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5386 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5387 stream->sample_index);
5391 /* now get the info for the sample we're at */
5392 sample = &stream->samples[stream->sample_index];
5394 *dts = QTSAMPLE_DTS (stream, sample);
5395 *pts = QTSAMPLE_PTS (stream, sample);
5396 *offset = sample->offset;
5397 *size = sample->size;
5398 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5399 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5406 stream->time_position = GST_CLOCK_TIME_NONE;
5411 /* move to the next sample in @stream.
5413 * Moves to the next segment when needed.
5416 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5418 QtDemuxSample *sample;
5419 QtDemuxSegment *segment;
5421 /* get current segment */
5422 segment = &stream->segments[stream->segment_index];
5424 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5425 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5429 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5430 /* Mark the stream as EOS */
5431 GST_DEBUG_OBJECT (qtdemux,
5432 "reached max allowed sample %u, mark EOS", stream->to_sample);
5433 stream->time_position = GST_CLOCK_TIME_NONE;
5437 /* move to next sample */
5438 stream->sample_index++;
5439 stream->offset_in_sample = 0;
5441 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5444 /* reached the last sample, we need the next segment */
5445 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5448 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5449 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5450 stream->sample_index);
5454 /* get next sample */
5455 sample = &stream->samples[stream->sample_index];
5457 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5458 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5459 GST_TIME_ARGS (segment->media_stop));
5461 /* see if we are past the segment */
5462 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5465 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5466 /* inside the segment, update time_position, looks very familiar to
5467 * GStreamer segments, doesn't it? */
5468 stream->time_position =
5469 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5471 /* not yet in segment, time does not yet increment. This means
5472 * that we are still prerolling keyframes to the decoder so it can
5473 * decode the first sample of the segment. */
5474 stream->time_position = segment->time;
5478 /* move to the next segment */
5481 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5483 if (stream->segment_index == stream->n_segments - 1) {
5484 /* are we at the end of the last segment, we're EOS */
5485 stream->time_position = GST_CLOCK_TIME_NONE;
5487 /* else we're only at the end of the current segment */
5488 stream->time_position = segment->stop_time;
5490 /* make sure we select a new segment */
5492 /* accumulate previous segments */
5493 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5494 stream->accumulated_base +=
5495 (stream->segment.stop -
5496 stream->segment.start) / ABS (stream->segment.rate);
5498 stream->segment_index = -1;
5503 gst_qtdemux_sync_streams (GstQTDemux * demux)
5507 if (QTDEMUX_N_STREAMS (demux) <= 1)
5510 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5511 QtDemuxStream *stream;
5512 GstClockTime end_time;
5514 stream = QTDEMUX_NTH_STREAM (demux, i);
5519 /* TODO advance time on subtitle streams here, if any some day */
5521 /* some clips/trailers may have unbalanced streams at the end,
5522 * so send EOS on shorter stream to prevent stalling others */
5524 /* do not mess with EOS if SEGMENT seeking */
5525 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5528 if (demux->pullbased) {
5529 /* loop mode is sample time based */
5530 if (!STREAM_IS_EOS (stream))
5533 /* push mode is byte position based */
5534 if (stream->n_samples &&
5535 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5539 if (stream->sent_eos)
5542 /* only act if some gap */
5543 end_time = stream->segments[stream->n_segments - 1].stop_time;
5544 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5545 ", stream end: %" GST_TIME_FORMAT,
5546 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5547 if (GST_CLOCK_TIME_IS_VALID (end_time)
5548 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5551 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5552 GST_PAD_NAME (stream->pad));
5553 stream->sent_eos = TRUE;
5554 event = gst_event_new_eos ();
5555 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5556 gst_event_set_seqnum (event, demux->segment_seqnum);
5557 gst_pad_push_event (stream->pad, event);
5562 /* EOS and NOT_LINKED need to be combined. This means that we return:
5564 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5565 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5567 static GstFlowReturn
5568 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5571 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5574 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5577 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5579 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5583 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5584 * completely clipped
5586 * Should be used only with raw buffers */
5588 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5591 guint64 start, stop, cstart, cstop, diff;
5592 GstClockTime pts, duration;
5594 gint num_rate, denom_rate;
5599 osize = size = gst_buffer_get_size (buf);
5602 /* depending on the type, setup the clip parameters */
5603 if (stream->subtype == FOURCC_soun) {
5604 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5605 num_rate = GST_SECOND;
5606 denom_rate = (gint) CUR_STREAM (stream)->rate;
5608 } else if (stream->subtype == FOURCC_vide) {
5610 num_rate = CUR_STREAM (stream)->fps_n;
5611 denom_rate = CUR_STREAM (stream)->fps_d;
5616 if (frame_size <= 0)
5617 goto bad_frame_size;
5619 /* we can only clip if we have a valid pts */
5620 pts = GST_BUFFER_PTS (buf);
5621 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5624 duration = GST_BUFFER_DURATION (buf);
5626 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5628 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5632 stop = start + duration;
5634 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5635 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5638 /* see if some clipping happened */
5639 diff = cstart - start;
5645 /* bring clipped time to samples and to bytes */
5646 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5649 GST_DEBUG_OBJECT (qtdemux,
5650 "clipping start to %" GST_TIME_FORMAT " %"
5651 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5657 diff = stop - cstop;
5662 /* bring clipped time to samples and then to bytes */
5663 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5665 GST_DEBUG_OBJECT (qtdemux,
5666 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5667 " bytes", GST_TIME_ARGS (cstop), diff);
5672 if (offset != 0 || size != osize)
5673 gst_buffer_resize (buf, offset, size);
5675 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5676 GST_BUFFER_PTS (buf) = pts;
5677 GST_BUFFER_DURATION (buf) = duration;
5681 /* dropped buffer */
5684 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5689 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5694 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5699 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5700 gst_buffer_unref (buf);
5706 gst_qtdemux_align_buffer (GstQTDemux * demux,
5707 GstBuffer * buffer, gsize alignment)
5711 gst_buffer_map (buffer, &map, GST_MAP_READ);
5713 if (map.size < sizeof (guintptr)) {
5714 gst_buffer_unmap (buffer, &map);
5718 if (((guintptr) map.data) & (alignment - 1)) {
5719 GstBuffer *new_buffer;
5720 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5722 new_buffer = gst_buffer_new_allocate (NULL,
5723 gst_buffer_get_size (buffer), ¶ms);
5725 /* Copy data "by hand", so ensure alignment is kept: */
5726 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5728 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5729 GST_DEBUG_OBJECT (demux,
5730 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5733 gst_buffer_unmap (buffer, &map);
5734 gst_buffer_unref (buffer);
5739 gst_buffer_unmap (buffer, &map);
5744 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5750 /* We are converting from pairs to triplets */
5751 *res = ccpair_size / 2 * 3;
5752 storage = g_malloc (*res);
5753 for (i = 0; i * 2 < ccpair_size; i += 1) {
5754 /* FIXME: Use line offset 0 as we simply can't know here */
5756 storage[i * 3] = 0x80 | 0x00;
5758 storage[i * 3] = 0x00 | 0x00;
5759 storage[i * 3 + 1] = ccpair[i * 2];
5760 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5767 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5771 guint32 atom_length, fourcc;
5772 QtDemuxStreamStsdEntry *stsd_entry;
5774 GST_MEMDUMP ("caption atom", data, size);
5776 /* There might be multiple atoms */
5781 atom_length = QT_UINT32 (data);
5782 fourcc = QT_FOURCC (data + 4);
5783 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5786 GST_DEBUG_OBJECT (stream->pad, "here");
5788 /* Check if we have something compatible */
5789 stsd_entry = CUR_STREAM (stream);
5790 switch (stsd_entry->fourcc) {
5792 guint8 *cdat = NULL, *cdt2 = NULL;
5793 gsize cdat_size = 0, cdt2_size = 0;
5794 /* Should be cdat or cdt2 */
5795 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5796 GST_WARNING_OBJECT (stream->pad,
5797 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5798 GST_FOURCC_ARGS (fourcc));
5802 /* Convert to S334-1 Annex A byte triplet */
5803 if (fourcc == FOURCC_cdat)
5804 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5806 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5807 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5810 /* Check for another atom ? */
5811 if (size > atom_length + 8) {
5812 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5813 if (size >= atom_length + new_atom_length) {
5814 fourcc = QT_FOURCC (data + atom_length + 4);
5815 if (fourcc == FOURCC_cdat) {
5818 convert_to_s334_1a (data + atom_length + 8,
5819 new_atom_length - 8, 1, &cdat_size);
5821 GST_WARNING_OBJECT (stream->pad,
5822 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5826 convert_to_s334_1a (data + atom_length + 8,
5827 new_atom_length - 8, 2, &cdt2_size);
5829 GST_WARNING_OBJECT (stream->pad,
5830 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5835 *cclen = cdat_size + cdt2_size;
5836 res = g_malloc (*cclen);
5838 memcpy (res, cdat, cdat_size);
5840 memcpy (res + cdat_size, cdt2, cdt2_size);
5846 if (fourcc != FOURCC_ccdp) {
5847 GST_WARNING_OBJECT (stream->pad,
5848 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5849 GST_FOURCC_ARGS (fourcc));
5852 *cclen = atom_length - 8;
5853 res = g_memdup2 (data + 8, *cclen);
5856 /* Keep this here in case other closed caption formats are added */
5857 g_assert_not_reached ();
5861 GST_MEMDUMP ("Output", res, *cclen);
5866 GST_WARNING ("[cdat] atom is too small or invalid");
5870 /* Handle Closed Caption sample buffers.
5871 * The input buffer metadata must be writable,
5872 * but time/duration etc not yet set and need not be preserved */
5874 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5877 GstBuffer *outbuf = NULL;
5882 gst_buffer_map (buf, &map, GST_MAP_READ);
5884 /* empty buffer is sent to terminate previous subtitle */
5885 if (map.size <= 2) {
5886 gst_buffer_unmap (buf, &map);
5887 gst_buffer_unref (buf);
5891 /* For closed caption, we need to extract the information from the
5892 * [cdat],[cdt2] or [ccdp] atom */
5893 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5894 gst_buffer_unmap (buf, &map);
5896 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5897 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5899 /* Conversion failed or there's nothing */
5901 gst_buffer_unref (buf);
5906 /* DVD subpicture specific sample handling.
5907 * the input buffer metadata must be writable,
5908 * but time/duration etc not yet set and need not be preserved */
5910 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5913 /* send a one time dvd clut event */
5914 if (stream->pending_event && stream->pad)
5915 gst_pad_push_event (stream->pad, stream->pending_event);
5916 stream->pending_event = NULL;
5918 /* empty buffer is sent to terminate previous subtitle */
5919 if (gst_buffer_get_size (buf) <= 2) {
5920 gst_buffer_unref (buf);
5924 /* That's all the processing needed for subpictures */
5928 /* Timed text formats
5929 * the input buffer metadata must be writable,
5930 * but time/duration etc not yet set and need not be preserved */
5932 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5935 GstBuffer *outbuf = NULL;
5940 /* not many cases for now */
5941 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5942 stream->subtype != FOURCC_sbtl)) {
5946 gst_buffer_map (buf, &map, GST_MAP_READ);
5948 /* empty buffer is sent to terminate previous subtitle */
5949 if (map.size <= 2) {
5950 gst_buffer_unmap (buf, &map);
5951 gst_buffer_unref (buf);
5955 nsize = GST_READ_UINT16_BE (map.data);
5956 nsize = MIN (nsize, map.size - 2);
5958 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5961 /* takes care of UTF-8 validation or UTF-16 recognition,
5962 * no other encoding expected */
5963 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5964 gst_buffer_unmap (buf, &map);
5967 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5968 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5970 /* this should not really happen unless the subtitle is corrupted */
5972 gst_buffer_unref (buf);
5974 /* FIXME ? convert optional subsequent style info to markup */
5979 /* WebVTT sample handling according to 14496-30 */
5981 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5984 GstBuffer *outbuf = NULL;
5987 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5988 g_assert_not_reached (); /* The buffer must be mappable */
5991 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5992 GstEvent *gap = NULL;
5993 /* Push a gap event */
5994 stream->segment.position = GST_BUFFER_PTS (buf);
5996 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5997 gst_pad_push_event (stream->pad, gap);
5999 if (GST_BUFFER_DURATION_IS_VALID (buf))
6000 stream->segment.position += GST_BUFFER_DURATION (buf);
6003 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
6004 GST_BUFFER_DURATION (buf), map.data, map.size);
6005 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
6008 gst_buffer_unmap (buf, &map);
6009 gst_buffer_unref (buf);
6014 static GstFlowReturn
6015 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6018 GstFlowReturn ret = GST_FLOW_OK;
6019 GstClockTime pts, duration;
6021 if (stream->need_clip)
6022 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
6024 if (G_UNLIKELY (buf == NULL))
6027 if (G_UNLIKELY (stream->discont)) {
6028 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6029 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
6030 stream->discont = FALSE;
6032 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6035 GST_LOG_OBJECT (qtdemux,
6036 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
6037 ", duration %" GST_TIME_FORMAT " on pad %s",
6038 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
6039 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
6040 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
6042 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
6043 GstStructure *crypto_info;
6044 QtDemuxAavdEncryptionInfo *info =
6045 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
6047 crypto_info = gst_structure_copy (info->default_properties);
6048 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6049 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
6052 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
6053 || stream->protection_scheme_type == FOURCC_cbcs)) {
6054 GstStructure *crypto_info;
6055 QtDemuxCencSampleSetInfo *info =
6056 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6060 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
6061 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
6062 GST_PTR_FORMAT, event);
6063 gst_pad_push_event (stream->pad, event);
6066 if (info->crypto_info == NULL) {
6067 if (stream->protection_scheme_type == FOURCC_cbcs) {
6068 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
6069 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
6070 GST_ERROR_OBJECT (qtdemux,
6071 "failed to attach cbcs metadata to buffer");
6072 qtdemux_gst_structure_free (crypto_info);
6074 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
6077 GST_DEBUG_OBJECT (qtdemux,
6078 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
6081 /* The end of the crypto_info array matches our n_samples position,
6082 * so count backward from there */
6083 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
6084 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
6085 /* steal structure from array */
6086 crypto_info = g_ptr_array_index (info->crypto_info, index);
6087 g_ptr_array_index (info->crypto_info, index) = NULL;
6088 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
6089 info->crypto_info->len);
6090 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6091 GST_ERROR_OBJECT (qtdemux,
6092 "failed to attach cenc metadata to buffer");
6094 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
6095 index, stream->sample_index);
6100 if (stream->alignment > 1)
6101 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6103 pts = GST_BUFFER_PTS (buf);
6104 duration = GST_BUFFER_DURATION (buf);
6106 ret = gst_pad_push (stream->pad, buf);
6108 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6109 /* mark position in stream, we'll need this to know when to send GAP event */
6110 stream->segment.position = pts + duration;
6118 static GstFlowReturn
6119 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6122 GstFlowReturn ret = GST_FLOW_OK;
6124 if (stream->subtype == FOURCC_clcp
6125 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6127 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6128 guint n_triplets, i;
6129 guint field1_off = 0, field2_off = 0;
6131 /* We have to split CEA608 buffers so that each outgoing buffer contains
6132 * one byte pair per field according to the framerate of the video track.
6134 * If there is only a single byte pair per field we don't have to do
6138 gst_buffer_map (buf, &map, GST_MAP_READ);
6140 n_triplets = map.size / 3;
6141 for (i = 0; i < n_triplets; i++) {
6142 if (map.data[3 * i] & 0x80)
6148 g_assert (n_field1 || n_field2);
6150 /* If there's more than 1 frame we have to split, otherwise we can just
6152 if (n_field1 > 1 || n_field2 > 1) {
6154 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6155 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6157 for (i = 0; i < n_output_buffers; i++) {
6159 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6163 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6164 outptr = outmap.data;
6167 gboolean found = FALSE;
6169 while (map.data + field1_off < map.data + map.size) {
6170 if (map.data[field1_off] & 0x80) {
6171 memcpy (outptr, &map.data[field1_off], 3);
6180 const guint8 empty[] = { 0x80, 0x80, 0x80 };
6182 memcpy (outptr, empty, 3);
6189 gboolean found = FALSE;
6191 while (map.data + field2_off < map.data + map.size) {
6192 if ((map.data[field2_off] & 0x80) == 0) {
6193 memcpy (outptr, &map.data[field2_off], 3);
6202 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6204 memcpy (outptr, empty, 3);
6210 gst_buffer_unmap (outbuf, &outmap);
6212 GST_BUFFER_PTS (outbuf) =
6213 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6214 GST_SECOND * CUR_STREAM (stream)->fps_d,
6215 CUR_STREAM (stream)->fps_n);
6216 GST_BUFFER_DURATION (outbuf) =
6217 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6218 CUR_STREAM (stream)->fps_n);
6219 GST_BUFFER_OFFSET (outbuf) = -1;
6220 GST_BUFFER_OFFSET_END (outbuf) = -1;
6222 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6224 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6227 gst_buffer_unmap (buf, &map);
6228 gst_buffer_unref (buf);
6230 gst_buffer_unmap (buf, &map);
6231 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6234 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6240 /* Sets a buffer's attributes properly and pushes it downstream.
6241 * Also checks for additional actions and custom processing that may
6242 * need to be done first.
6244 static GstFlowReturn
6245 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6246 QtDemuxStream * stream, GstBuffer * buf,
6247 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6248 gboolean keyframe, GstClockTime position, guint64 byte_position)
6250 GstFlowReturn ret = GST_FLOW_OK;
6252 /* offset the timestamps according to the edit list */
6254 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6258 gst_buffer_map (buf, &map, GST_MAP_READ);
6259 url = g_strndup ((gchar *) map.data, map.size);
6260 gst_buffer_unmap (buf, &map);
6261 if (url != NULL && strlen (url) != 0) {
6262 /* we have RTSP redirect now */
6263 g_free (qtdemux->redirect_location);
6264 qtdemux->redirect_location = g_strdup (url);
6265 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6266 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6267 gst_structure_new ("redirect",
6268 "new-location", G_TYPE_STRING, url, NULL)));
6270 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6276 /* position reporting */
6277 if (qtdemux->segment.rate >= 0) {
6278 qtdemux->segment.position = position;
6279 gst_qtdemux_sync_streams (qtdemux);
6282 if (G_UNLIKELY (!stream->pad)) {
6283 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6284 gst_buffer_unref (buf);
6288 /* send out pending buffers */
6289 while (stream->buffers) {
6290 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6292 if (G_UNLIKELY (stream->discont)) {
6293 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6294 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6295 stream->discont = FALSE;
6297 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6300 if (stream->alignment > 1)
6301 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6302 gst_pad_push (stream->pad, buffer);
6304 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6307 /* we're going to modify the metadata */
6308 buf = gst_buffer_make_writable (buf);
6310 if (qtdemux->start_utc_time != GST_CLOCK_TIME_NONE) {
6311 static GstStaticCaps unix_caps = GST_STATIC_CAPS ("timestamp/x-unix");
6312 GstCaps *caps = gst_static_caps_get (&unix_caps);
6313 gst_buffer_add_reference_timestamp_meta (buf, caps,
6314 pts + qtdemux->start_utc_time - stream->cslg_shift,
6315 GST_CLOCK_TIME_NONE);
6316 gst_caps_unref (caps);
6319 GST_BUFFER_DTS (buf) = dts;
6320 GST_BUFFER_PTS (buf) = pts;
6321 GST_BUFFER_DURATION (buf) = duration;
6322 GST_BUFFER_OFFSET (buf) = -1;
6323 GST_BUFFER_OFFSET_END (buf) = -1;
6325 if (G_UNLIKELY (stream->process_func))
6326 buf = stream->process_func (qtdemux, stream, buf);
6333 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6334 stream->on_keyframe = FALSE;
6336 stream->on_keyframe = TRUE;
6339 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6340 gst_buffer_append_memory (buf,
6341 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6343 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6344 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6347 if (G_UNLIKELY (qtdemux->element_index)) {
6348 GstClockTime stream_time;
6351 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6353 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6354 GST_LOG_OBJECT (qtdemux,
6355 "adding association %" GST_TIME_FORMAT "-> %"
6356 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6357 gst_index_add_association (qtdemux->element_index,
6359 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6360 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6361 GST_FORMAT_BYTES, byte_position, NULL);
6366 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6372 static const QtDemuxRandomAccessEntry *
6373 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6374 GstClockTime pos, gboolean after)
6376 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6377 guint n_entries = stream->n_ra_entries;
6380 /* we assume the table is sorted */
6381 for (i = 0; i < n_entries; ++i) {
6382 if (entries[i].ts > pos)
6386 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6387 * probably okay to assume that the index lists the very first fragment */
6394 return &entries[i - 1];
6398 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6400 const QtDemuxRandomAccessEntry *best_entry = NULL;
6403 GST_OBJECT_LOCK (qtdemux);
6405 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6407 /* first see if we can determine where to go to using mfra,
6408 * before we start clearing things */
6409 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6410 const QtDemuxRandomAccessEntry *entry;
6411 QtDemuxStream *stream;
6412 gboolean is_audio_or_video;
6414 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6416 if (stream->ra_entries == NULL)
6419 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6420 is_audio_or_video = TRUE;
6422 is_audio_or_video = FALSE;
6425 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6426 stream->time_position, !is_audio_or_video);
6428 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6429 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6431 stream->pending_seek = entry;
6433 /* decide position to jump to just based on audio/video tracks, not subs */
6434 if (!is_audio_or_video)
6437 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6441 /* no luck, will handle seek otherwise */
6442 if (best_entry == NULL) {
6443 GST_OBJECT_UNLOCK (qtdemux);
6447 /* ok, now we can prepare for processing as of located moof */
6448 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6449 QtDemuxStream *stream;
6451 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6453 g_free (stream->samples);
6454 stream->samples = NULL;
6455 stream->n_samples = 0;
6456 stream->stbl_index = -1; /* no samples have yet been parsed */
6457 stream->sample_index = -1;
6459 if (stream->protection_scheme_info) {
6460 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6461 if (stream->protection_scheme_type == FOURCC_cenc
6462 || stream->protection_scheme_type == FOURCC_cbcs) {
6463 QtDemuxCencSampleSetInfo *info =
6464 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6465 if (info->crypto_info) {
6466 g_ptr_array_free (info->crypto_info, TRUE);
6467 info->crypto_info = NULL;
6473 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6474 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6475 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6476 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6478 qtdemux->moof_offset = best_entry->moof_offset;
6480 qtdemux_add_fragmented_samples (qtdemux);
6482 GST_OBJECT_UNLOCK (qtdemux);
6486 static GstFlowReturn
6487 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6489 GstFlowReturn ret = GST_FLOW_OK;
6490 GstBuffer *buf = NULL;
6491 QtDemuxStream *stream, *target_stream = NULL;
6492 GstClockTime min_time;
6494 GstClockTime dts = GST_CLOCK_TIME_NONE;
6495 GstClockTime pts = GST_CLOCK_TIME_NONE;
6496 GstClockTime duration = 0;
6497 gboolean keyframe = FALSE;
6498 guint sample_size = 0;
6499 guint num_samples = 1;
6504 if (qtdemux->fragmented_seek_pending) {
6505 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6506 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6507 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6508 qtdemux->fragmented_seek_pending = FALSE;
6510 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6514 /* Figure out the next stream sample to output, min_time is expressed in
6515 * global time and runs over the edit list segments. */
6516 min_time = G_MAXUINT64;
6517 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6518 GstClockTime position;
6520 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6521 position = stream->time_position;
6523 if (!GST_CLOCK_TIME_IS_VALID (position))
6526 if (stream->segment_index != -1) {
6527 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6528 position += segment->media_start;
6531 /* position of -1 is EOS */
6532 if (position < min_time) {
6533 min_time = position;
6534 target_stream = stream;
6538 if (G_UNLIKELY (target_stream == NULL)) {
6539 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6543 /* check for segment end */
6544 if (G_UNLIKELY (qtdemux->segment.stop != -1
6545 && qtdemux->segment.rate >= 0
6546 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6547 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6548 target_stream->time_position = GST_CLOCK_TIME_NONE;
6552 /* fetch info for the current sample of this stream */
6553 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, target_stream,
6554 &empty, &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6557 /* Send catche-up GAP event for each other stream if required.
6558 * This logic will be applied only for positive rate */
6559 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux) &&
6560 qtdemux->segment.rate >= 0; i++) {
6561 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6563 if (stream == target_stream ||
6564 !GST_CLOCK_TIME_IS_VALID (stream->segment.stop) ||
6565 !GST_CLOCK_TIME_IS_VALID (stream->segment.position))
6569 GstClockTime gap_threshold;
6570 /* kind of running time with offset segment.base and segment.start */
6571 GstClockTime pseudo_target_time = target_stream->segment.base;
6572 GstClockTime pseudo_cur_time = stream->segment.base;
6574 /* make sure positive offset, segment.position can be smallr than
6575 * segment.start for some reasons */
6576 if (target_stream->segment.position >= target_stream->segment.start) {
6577 pseudo_target_time +=
6578 (target_stream->segment.position - target_stream->segment.start);
6581 if (stream->segment.position >= stream->segment.start)
6582 pseudo_cur_time += (stream->segment.position - stream->segment.start);
6584 /* Only send gap events on non-subtitle streams if lagging way behind. */
6585 if (stream->subtype == FOURCC_subp
6586 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6587 stream->subtype == FOURCC_wvtt)
6588 gap_threshold = 1 * GST_SECOND;
6590 gap_threshold = 3 * GST_SECOND;
6592 /* send gap events until the stream catches up */
6593 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6594 while (GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6595 pseudo_cur_time < (G_MAXUINT64 - gap_threshold) &&
6596 pseudo_cur_time + gap_threshold < pseudo_target_time) {
6598 gst_event_new_gap (stream->segment.position, gap_threshold);
6599 GST_LOG_OBJECT (stream->pad, "Sending %" GST_PTR_FORMAT, gap);
6601 gst_pad_push_event (stream->pad, gap);
6602 stream->segment.position += gap_threshold;
6603 pseudo_cur_time += gap_threshold;
6608 stream = target_stream;
6610 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6611 if (stream->new_caps) {
6612 gst_qtdemux_configure_stream (qtdemux, stream);
6613 qtdemux_do_allocation (stream, qtdemux);
6616 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6617 if (G_UNLIKELY (qtdemux->segment.
6618 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6619 if (stream->subtype == FOURCC_vide) {
6621 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6624 } else if (qtdemux->trickmode_interval > 0) {
6625 GstClockTimeDiff interval;
6627 if (qtdemux->segment.rate > 0)
6628 interval = stream->time_position - stream->last_keyframe_dts;
6630 interval = stream->last_keyframe_dts - stream->time_position;
6632 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6633 && interval < qtdemux->trickmode_interval) {
6634 GST_LOG_OBJECT (qtdemux,
6635 "Skipping keyframe within interval on track-id %u",
6639 stream->last_keyframe_dts = stream->time_position;
6645 GST_DEBUG_OBJECT (qtdemux,
6646 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6647 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6648 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6649 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6650 GST_TIME_ARGS (duration));
6652 if (G_UNLIKELY (empty)) {
6653 /* empty segment, push a gap if there's a second or more
6654 * difference and move to the next one */
6655 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6656 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6657 stream->segment.position = pts + duration;
6661 /* hmm, empty sample, skip and move to next sample */
6662 if (G_UNLIKELY (sample_size <= 0))
6665 /* last pushed sample was out of boundary, goto next sample */
6666 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6669 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6670 GST_DEBUG_OBJECT (qtdemux,
6671 "size %d larger than stream max_buffer_size %d, trimming",
6672 sample_size, stream->max_buffer_size);
6674 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6675 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6676 && sample_size < stream->min_buffer_size) {
6677 guint start_sample_index = stream->sample_index;
6678 guint accumulated_size = sample_size;
6679 guint64 expected_next_offset = offset + sample_size;
6681 GST_DEBUG_OBJECT (qtdemux,
6682 "size %d smaller than stream min_buffer_size %d, combining with the next",
6683 sample_size, stream->min_buffer_size);
6685 while (stream->sample_index < stream->to_sample
6686 && stream->sample_index + 1 < stream->n_samples) {
6687 const QtDemuxSample *next_sample;
6689 /* Increment temporarily */
6690 stream->sample_index++;
6692 /* Failed to parse sample so let's go back to the previous one that was
6693 * still successful */
6694 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6695 stream->sample_index--;
6699 next_sample = &stream->samples[stream->sample_index];
6701 /* Not contiguous with the previous sample so let's go back to the
6702 * previous one that was still successful */
6703 if (next_sample->offset != expected_next_offset) {
6704 stream->sample_index--;
6708 accumulated_size += next_sample->size;
6709 expected_next_offset += next_sample->size;
6710 if (accumulated_size >= stream->min_buffer_size)
6714 num_samples = stream->sample_index + 1 - start_sample_index;
6715 stream->sample_index = start_sample_index;
6716 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6717 num_samples, accumulated_size);
6718 size = accumulated_size;
6723 if (qtdemux->cenc_aux_info_offset > 0) {
6726 GstBuffer *aux_info = NULL;
6728 /* pull the data stored before the sample */
6730 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6731 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6732 if (G_UNLIKELY (ret != GST_FLOW_OK))
6734 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6735 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6736 gst_byte_reader_init (&br, map.data + 8, map.size);
6737 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6738 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6739 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6740 gst_buffer_unmap (aux_info, &map);
6741 gst_buffer_unref (aux_info);
6742 ret = GST_FLOW_ERROR;
6745 gst_buffer_unmap (aux_info, &map);
6746 gst_buffer_unref (aux_info);
6749 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6752 if (stream->use_allocator) {
6753 /* if we have a per-stream allocator, use it */
6754 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6757 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6759 if (G_UNLIKELY (ret != GST_FLOW_OK))
6762 /* Update for both splitting and combining of samples */
6763 if (size != sample_size) {
6764 pts += gst_util_uint64_scale_int (GST_SECOND,
6765 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6768 gst_util_uint64_scale_int (GST_SECOND,
6769 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6772 gst_util_uint64_scale_int (GST_SECOND,
6773 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6776 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6777 dts, pts, duration, keyframe, min_time, offset);
6779 if (size < sample_size) {
6780 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6781 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6783 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6785 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6786 if (time_position >= segment->media_start) {
6787 /* inside the segment, update time_position, looks very familiar to
6788 * GStreamer segments, doesn't it? */
6789 stream->time_position = (time_position - segment->media_start) +
6792 /* not yet in segment, time does not yet increment. This means
6793 * that we are still prerolling keyframes to the decoder so it can
6794 * decode the first sample of the segment. */
6795 stream->time_position = segment->time;
6797 } else if (size > sample_size) {
6798 /* Increase to the last sample we already pulled so that advancing
6799 * below brings us to the next sample we need to pull */
6800 stream->sample_index += num_samples - 1;
6804 GST_OBJECT_LOCK (qtdemux);
6805 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6806 GST_OBJECT_UNLOCK (qtdemux);
6807 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6808 * we have no more data for the pad to push */
6809 if (ret == GST_FLOW_EOS)
6812 stream->offset_in_sample += size;
6813 if (stream->offset_in_sample >= sample_size) {
6814 gst_qtdemux_advance_sample (qtdemux, stream);
6819 gst_qtdemux_advance_sample (qtdemux, stream);
6827 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6833 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6834 /* EOS will be raised if all are EOS */
6841 gst_qtdemux_loop (GstPad * pad)
6843 GstQTDemux *qtdemux;
6847 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6849 cur_offset = qtdemux->offset;
6850 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6851 cur_offset, qt_demux_state_string (qtdemux->state));
6853 switch (qtdemux->state) {
6854 case QTDEMUX_STATE_INITIAL:
6855 case QTDEMUX_STATE_HEADER:
6856 ret = gst_qtdemux_loop_state_header (qtdemux);
6858 case QTDEMUX_STATE_MOVIE:
6859 ret = gst_qtdemux_loop_state_movie (qtdemux);
6860 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6861 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6869 /* if something went wrong, pause */
6870 if (ret != GST_FLOW_OK)
6874 gst_object_unref (qtdemux);
6880 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6881 (NULL), ("streaming stopped, invalid state"));
6882 gst_pad_pause_task (pad);
6883 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6888 const gchar *reason = gst_flow_get_name (ret);
6890 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6892 gst_pad_pause_task (pad);
6894 /* fatal errors need special actions */
6896 if (ret == GST_FLOW_EOS) {
6897 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6898 /* we have no streams, post an error */
6899 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6901 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6904 if ((stop = qtdemux->segment.stop) == -1)
6905 stop = qtdemux->segment.duration;
6907 if (qtdemux->segment.rate >= 0) {
6908 GstMessage *message;
6911 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6912 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6913 GST_FORMAT_TIME, stop);
6914 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6915 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6916 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6917 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6919 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6920 gst_qtdemux_push_event (qtdemux, event);
6922 GstMessage *message;
6925 /* For Reverse Playback */
6926 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6927 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6928 GST_FORMAT_TIME, qtdemux->segment.start);
6929 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6930 qtdemux->segment.start);
6931 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6932 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6933 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6935 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6936 gst_qtdemux_push_event (qtdemux, event);
6941 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6942 event = gst_event_new_eos ();
6943 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6944 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6945 gst_qtdemux_push_event (qtdemux, event);
6947 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6948 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6949 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6958 * Returns if there are samples to be played.
6961 has_next_entry (GstQTDemux * demux)
6963 QtDemuxStream *stream;
6966 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6968 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6969 stream = QTDEMUX_NTH_STREAM (demux, i);
6971 if (stream->sample_index == -1) {
6972 stream->sample_index = 0;
6973 stream->offset_in_sample = 0;
6976 if (stream->sample_index >= stream->n_samples) {
6977 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6980 GST_DEBUG_OBJECT (demux, "Found a sample");
6984 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6991 * Returns the size of the first entry at the current offset.
6992 * If -1, there are none (which means EOS or empty file).
6995 next_entry_size (GstQTDemux * demux)
6997 QtDemuxStream *stream, *target_stream = NULL;
6998 guint64 smalloffs = (guint64) - 1;
6999 QtDemuxSample *sample;
7002 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
7005 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7006 stream = QTDEMUX_NTH_STREAM (demux, i);
7008 if (stream->sample_index == -1) {
7009 stream->sample_index = 0;
7010 stream->offset_in_sample = 0;
7013 if (stream->sample_index >= stream->n_samples) {
7014 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
7018 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
7019 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
7020 stream->sample_index);
7024 sample = &stream->samples[stream->sample_index];
7026 GST_LOG_OBJECT (demux,
7027 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
7028 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
7029 stream->sample_index, sample->offset, sample->size);
7031 if (((smalloffs == -1)
7032 || (sample->offset < smalloffs)) && (sample->size)) {
7033 smalloffs = sample->offset;
7034 target_stream = stream;
7041 GST_LOG_OBJECT (demux,
7042 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
7043 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
7045 stream = target_stream;
7046 sample = &stream->samples[stream->sample_index];
7048 if (sample->offset >= demux->offset) {
7049 demux->todrop = sample->offset - demux->offset;
7050 return sample->size + demux->todrop;
7053 GST_DEBUG_OBJECT (demux,
7054 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
7059 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
7061 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
7063 gst_element_post_message (GST_ELEMENT_CAST (demux),
7064 gst_message_new_element (GST_OBJECT_CAST (demux),
7065 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
7069 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
7074 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
7077 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
7078 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
7079 GST_SEEK_TYPE_NONE, -1);
7081 /* store seqnum to drop flush events, they don't need to reach downstream */
7082 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
7083 res = gst_pad_push_event (demux->sinkpad, event);
7084 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
7089 /* check for seekable upstream, above and beyond a mere query */
7091 gst_qtdemux_check_seekability (GstQTDemux * demux)
7094 gboolean seekable = FALSE;
7095 gint64 start = -1, stop = -1;
7097 if (demux->upstream_size)
7100 if (demux->upstream_format_is_time)
7103 query = gst_query_new_seeking (GST_FORMAT_BYTES);
7104 if (!gst_pad_peer_query (demux->sinkpad, query)) {
7105 GST_DEBUG_OBJECT (demux, "seeking query failed");
7109 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
7111 /* try harder to query upstream size if we didn't get it the first time */
7112 if (seekable && stop == -1) {
7113 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
7114 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
7117 /* if upstream doesn't know the size, it's likely that it's not seekable in
7118 * practice even if it technically may be seekable */
7119 if (seekable && (start != 0 || stop <= start)) {
7120 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
7125 gst_query_unref (query);
7127 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
7128 G_GUINT64_FORMAT ")", seekable, start, stop);
7129 demux->upstream_seekable = seekable;
7130 demux->upstream_size = seekable ? stop : -1;
7134 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
7136 g_return_if_fail (bytes <= demux->todrop);
7138 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
7139 gst_adapter_flush (demux->adapter, bytes);
7140 demux->neededbytes -= bytes;
7141 demux->offset += bytes;
7142 demux->todrop -= bytes;
7145 /* PUSH-MODE only: Send a segment, if not done already. */
7147 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
7149 if (G_UNLIKELY (demux->need_segment)) {
7152 if (!demux->upstream_format_is_time) {
7153 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
7155 GstEvent *segment_event;
7156 segment_event = gst_event_new_segment (&demux->segment);
7157 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
7158 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
7159 gst_qtdemux_push_event (demux, segment_event);
7162 demux->need_segment = FALSE;
7164 /* clear to send tags on all streams */
7165 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7166 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7167 gst_qtdemux_push_tags (demux, stream);
7168 if (CUR_STREAM (stream)->sparse) {
7169 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
7170 gst_pad_push_event (stream->pad,
7171 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7177 /* Used for push mode only. */
7179 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7180 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7182 GstClockTime ts, dur;
7186 stream->segments[segment_index].duration - (pos -
7187 stream->segments[segment_index].time);
7188 stream->time_position += dur;
7190 /* Only gaps with a duration of at least one second are propagated.
7191 * Same workaround as in pull mode.
7192 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7193 if (dur >= GST_SECOND) {
7195 gap = gst_event_new_gap (ts, dur);
7197 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7198 "segment: %" GST_PTR_FORMAT, gap);
7199 gst_pad_push_event (stream->pad, gap);
7203 static GstFlowReturn
7204 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7208 demux = GST_QTDEMUX (parent);
7210 GST_DEBUG_OBJECT (demux,
7211 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7212 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7213 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7214 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7215 gst_buffer_get_size (inbuf), demux->offset);
7217 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7218 gboolean is_gap_input = FALSE;
7221 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7223 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7224 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7227 /* Check if we can land back on our feet in the case where upstream is
7228 * handling the seeking/pushing of samples with gaps in between (like
7229 * in the case of trick-mode DASH for example) */
7230 if (demux->upstream_format_is_time
7231 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7232 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7234 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7235 GST_LOG_OBJECT (demux,
7236 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7237 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7239 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7240 stream, GST_BUFFER_OFFSET (inbuf));
7242 QtDemuxSample *sample = &stream->samples[res];
7243 GST_LOG_OBJECT (demux,
7244 "Checking if sample %d from track-id %u is valid (offset:%"
7245 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7246 stream->track_id, sample->offset, sample->size);
7247 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7248 GST_LOG_OBJECT (demux,
7249 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7251 is_gap_input = TRUE;
7252 /* We can go back to standard playback mode */
7253 demux->state = QTDEMUX_STATE_MOVIE;
7254 /* Remember which sample this stream is at */
7255 stream->sample_index = res;
7256 /* Finally update all push-based values to the expected values */
7257 demux->neededbytes = stream->samples[res].size;
7258 demux->offset = GST_BUFFER_OFFSET (inbuf);
7260 demux->mdatsize - demux->offset + demux->mdatoffset;
7265 if (!is_gap_input) {
7266 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7267 /* Reset state if it's a real discont */
7268 demux->neededbytes = 16;
7269 demux->state = QTDEMUX_STATE_INITIAL;
7270 demux->offset = GST_BUFFER_OFFSET (inbuf);
7271 gst_adapter_clear (demux->adapter);
7274 /* Reverse fragmented playback, need to flush all we have before
7275 * consuming a new fragment.
7276 * The samples array have the timestamps calculated by accumulating the
7277 * durations but this won't work for reverse playback of fragments as
7278 * the timestamps of a subsequent fragment should be smaller than the
7279 * previously received one. */
7280 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7281 gst_qtdemux_process_adapter (demux, TRUE);
7282 g_ptr_array_foreach (demux->active_streams,
7283 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7287 gst_adapter_push (demux->adapter, inbuf);
7289 GST_DEBUG_OBJECT (demux,
7290 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7291 demux->neededbytes, gst_adapter_available (demux->adapter));
7293 return gst_qtdemux_process_adapter (demux, FALSE);
7296 static GstFlowReturn
7297 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7299 GstFlowReturn ret = GST_FLOW_OK;
7301 /* we never really mean to buffer that much */
7302 if (demux->neededbytes == -1) {
7306 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7307 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7309 #ifndef GST_DISABLE_GST_DEBUG
7311 guint64 discont_offset, distance_from_discont;
7313 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7314 distance_from_discont =
7315 gst_adapter_distance_from_discont (demux->adapter);
7317 GST_DEBUG_OBJECT (demux,
7318 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7319 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7320 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7321 demux->offset, discont_offset, distance_from_discont);
7325 switch (demux->state) {
7326 case QTDEMUX_STATE_INITIAL:{
7331 gst_qtdemux_check_seekability (demux);
7333 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7335 /* get fourcc/length, set neededbytes */
7336 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7338 gst_adapter_unmap (demux->adapter);
7340 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7341 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7343 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7344 (_("This file is invalid and cannot be played.")),
7345 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7346 GST_FOURCC_ARGS (fourcc)));
7347 ret = GST_FLOW_ERROR;
7350 if (fourcc == FOURCC_mdat) {
7351 gint next_entry = next_entry_size (demux);
7352 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7353 || !demux->fragmented)) {
7354 /* we have the headers, start playback */
7355 demux->state = QTDEMUX_STATE_MOVIE;
7356 demux->neededbytes = next_entry;
7357 demux->mdatleft = size;
7358 demux->mdatsize = demux->mdatleft;
7360 /* no headers yet, try to get them */
7363 guint64 old, target;
7366 old = demux->offset;
7367 target = old + size;
7369 /* try to jump over the atom with a seek */
7370 /* only bother if it seems worth doing so,
7371 * and avoids possible upstream/server problems */
7372 if (demux->upstream_seekable &&
7373 demux->upstream_size > 4 * (1 << 20)) {
7374 res = qtdemux_seek_offset (demux, target);
7376 GST_DEBUG_OBJECT (demux, "skipping seek");
7381 GST_DEBUG_OBJECT (demux, "seek success");
7382 /* remember the offset fo the first mdat so we can seek back to it
7383 * after we have the headers */
7384 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7385 demux->first_mdat = old;
7386 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7389 /* seek worked, continue reading */
7390 demux->offset = target;
7391 demux->neededbytes = 16;
7392 demux->state = QTDEMUX_STATE_INITIAL;
7394 /* seek failed, need to buffer */
7395 demux->offset = old;
7396 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7397 /* there may be multiple mdat (or alike) buffers */
7399 if (demux->mdatbuffer)
7400 bs = gst_buffer_get_size (demux->mdatbuffer);
7403 if (size + bs > 10 * (1 << 20))
7405 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7406 demux->neededbytes = size;
7407 if (!demux->mdatbuffer)
7408 demux->mdatoffset = demux->offset;
7411 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7412 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7413 (_("This file is invalid and cannot be played.")),
7414 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7415 GST_FOURCC_ARGS (fourcc), size));
7416 ret = GST_FLOW_ERROR;
7419 /* this means we already started buffering and still no moov header,
7420 * let's continue buffering everything till we get moov */
7421 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7422 || fourcc == FOURCC_moof))
7424 demux->neededbytes = size;
7425 demux->state = QTDEMUX_STATE_HEADER;
7429 case QTDEMUX_STATE_HEADER:{
7433 GST_DEBUG_OBJECT (demux, "In header");
7435 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7437 /* parse the header */
7438 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7440 if (fourcc == FOURCC_moov) {
7441 /* in usual fragmented setup we could try to scan for more
7442 * and end up at the the moov (after mdat) again */
7443 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7445 || demux->last_moov_offset == demux->offset)) {
7446 GST_DEBUG_OBJECT (demux,
7447 "Skipping moov atom as we have (this) one already");
7449 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7451 if (demux->got_moov && demux->fragmented) {
7452 GST_DEBUG_OBJECT (demux,
7453 "Got a second moov, clean up data from old one");
7454 if (demux->moov_node_compressed) {
7455 g_node_destroy (demux->moov_node_compressed);
7456 if (demux->moov_node)
7457 g_free (demux->moov_node->data);
7459 demux->moov_node_compressed = NULL;
7460 if (demux->moov_node)
7461 g_node_destroy (demux->moov_node);
7462 demux->moov_node = NULL;
7463 demux->start_utc_time = GST_CLOCK_TIME_NONE;
7466 demux->last_moov_offset = demux->offset;
7468 /* Update streams with new moov */
7469 gst_qtdemux_stream_concat (demux,
7470 demux->old_streams, demux->active_streams);
7472 qtdemux_parse_moov (demux, data, demux->neededbytes);
7473 qtdemux_node_dump (demux, demux->moov_node);
7474 qtdemux_parse_tree (demux);
7475 qtdemux_prepare_streams (demux);
7476 QTDEMUX_EXPOSE_LOCK (demux);
7477 qtdemux_expose_streams (demux);
7478 QTDEMUX_EXPOSE_UNLOCK (demux);
7480 demux->got_moov = TRUE;
7482 gst_qtdemux_check_send_pending_segment (demux);
7484 if (demux->moov_node_compressed) {
7485 g_node_destroy (demux->moov_node_compressed);
7486 g_free (demux->moov_node->data);
7488 demux->moov_node_compressed = NULL;
7489 g_node_destroy (demux->moov_node);
7490 demux->moov_node = NULL;
7491 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7493 } else if (fourcc == FOURCC_moof) {
7494 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7496 GstClockTime prev_pts;
7497 guint64 prev_offset;
7498 guint64 adapter_discont_offset, adapter_discont_dist;
7500 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7503 * The timestamp of the moof buffer is relevant as some scenarios
7504 * won't have the initial timestamp in the atoms. Whenever a new
7505 * buffer has started, we get that buffer's PTS and use it as a base
7506 * timestamp for the trun entries.
7508 * To keep track of the current buffer timestamp and starting point
7509 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7510 * from the beginning of the buffer, with the distance and demux->offset
7511 * we know if it is still the same buffer or not.
7513 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7514 prev_offset = demux->offset - dist;
7515 if (demux->fragment_start_offset == -1
7516 || prev_offset > demux->fragment_start_offset) {
7517 demux->fragment_start_offset = prev_offset;
7518 demux->fragment_start = prev_pts;
7519 GST_DEBUG_OBJECT (demux,
7520 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7521 GST_TIME_FORMAT, demux->fragment_start_offset,
7522 GST_TIME_ARGS (demux->fragment_start));
7525 /* We can't use prev_offset() here because this would require
7526 * upstream to set consistent and correct offsets on all buffers
7527 * since the discont. Nothing ever did that in the past and we
7528 * would break backwards compatibility here then.
7529 * Instead take the offset we had at the last discont and count
7530 * the bytes from there. This works with old code as there would
7531 * be no discont between moov and moof, and also works with
7532 * adaptivedemux which correctly sets offset and will set the
7533 * DISCONT flag accordingly when needed.
7535 * We also only do this for upstream TIME segments as otherwise
7536 * there are potential backwards compatibility problems with
7537 * seeking in PUSH mode and upstream providing inconsistent
7539 adapter_discont_offset =
7540 gst_adapter_offset_at_discont (demux->adapter);
7541 adapter_discont_dist =
7542 gst_adapter_distance_from_discont (demux->adapter);
7544 GST_DEBUG_OBJECT (demux,
7545 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7546 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7547 demux->offset, adapter_discont_offset, adapter_discont_dist);
7549 if (demux->upstream_format_is_time) {
7550 demux->moof_offset = adapter_discont_offset;
7551 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7552 demux->moof_offset += adapter_discont_dist;
7553 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7554 demux->moof_offset = demux->offset;
7556 demux->moof_offset = demux->offset;
7559 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7560 demux->moof_offset, NULL)) {
7561 gst_adapter_unmap (demux->adapter);
7562 ret = GST_FLOW_ERROR;
7566 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7567 if (demux->mss_mode && !demux->exposed) {
7568 QTDEMUX_EXPOSE_LOCK (demux);
7569 qtdemux_expose_streams (demux);
7570 QTDEMUX_EXPOSE_UNLOCK (demux);
7573 gst_qtdemux_check_send_pending_segment (demux);
7575 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7577 } else if (fourcc == FOURCC_ftyp) {
7578 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7579 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7580 } else if (fourcc == FOURCC_uuid) {
7581 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7582 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7583 } else if (fourcc == FOURCC_sidx) {
7584 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7585 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7586 } else if (fourcc == FOURCC_meta) {
7587 GNode *node, *child;
7588 GstByteReader child_data;
7590 node = g_node_new ((gpointer) data);
7591 qtdemux_parse_node (demux, node, data, demux->neededbytes);
7593 /* Parse ONVIF Export File Format CorrectStartTime box if available */
7595 qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb,
7597 qtdemux_parse_cstb (demux, &child_data);
7600 g_node_destroy (node);
7604 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7608 /* [free] and [skip] are padding atoms */
7609 GST_DEBUG_OBJECT (demux,
7610 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7611 GST_FOURCC_ARGS (fourcc));
7614 GST_WARNING_OBJECT (demux,
7615 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7616 GST_FOURCC_ARGS (fourcc));
7617 /* Let's jump that one and go back to initial state */
7621 gst_adapter_unmap (demux->adapter);
7624 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7625 gsize remaining_data_size = 0;
7627 /* the mdat was before the header */
7628 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7629 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7630 /* restore our adapter/offset view of things with upstream;
7631 * put preceding buffered data ahead of current moov data.
7632 * This should also handle evil mdat, moov, mdat cases and alike */
7633 gst_adapter_flush (demux->adapter, demux->neededbytes);
7635 /* Store any remaining data after the mdat for later usage */
7636 remaining_data_size = gst_adapter_available (demux->adapter);
7637 if (remaining_data_size > 0) {
7638 g_assert (demux->restoredata_buffer == NULL);
7639 demux->restoredata_buffer =
7640 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7641 demux->restoredata_offset = demux->offset + demux->neededbytes;
7642 GST_DEBUG_OBJECT (demux,
7643 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7644 G_GUINT64_FORMAT, remaining_data_size,
7645 demux->restoredata_offset);
7648 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7649 demux->mdatbuffer = NULL;
7650 demux->offset = demux->mdatoffset;
7651 demux->neededbytes = next_entry_size (demux);
7652 demux->state = QTDEMUX_STATE_MOVIE;
7653 demux->mdatleft = gst_adapter_available (demux->adapter);
7654 demux->mdatsize = demux->mdatleft;
7656 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7657 gst_adapter_flush (demux->adapter, demux->neededbytes);
7659 /* only go back to the mdat if there are samples to play */
7660 if (demux->got_moov && demux->first_mdat != -1
7661 && has_next_entry (demux)) {
7664 /* we need to seek back */
7665 res = qtdemux_seek_offset (demux, demux->first_mdat);
7667 demux->offset = demux->first_mdat;
7669 GST_DEBUG_OBJECT (demux, "Seek back failed");
7672 demux->offset += demux->neededbytes;
7674 demux->neededbytes = 16;
7675 demux->state = QTDEMUX_STATE_INITIAL;
7680 case QTDEMUX_STATE_BUFFER_MDAT:{
7684 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7686 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7687 gst_buffer_extract (buf, 0, fourcc, 4);
7688 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7689 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7690 if (demux->mdatbuffer)
7691 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7693 demux->mdatbuffer = buf;
7694 demux->offset += demux->neededbytes;
7695 demux->neededbytes = 16;
7696 demux->state = QTDEMUX_STATE_INITIAL;
7697 gst_qtdemux_post_progress (demux, 1, 1);
7701 case QTDEMUX_STATE_MOVIE:{
7702 QtDemuxStream *stream = NULL;
7703 QtDemuxSample *sample;
7704 GstClockTime dts, pts, duration;
7708 GST_DEBUG_OBJECT (demux,
7709 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7711 if (demux->fragmented) {
7712 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7714 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7715 /* if needed data starts within this atom,
7716 * then it should not exceed this atom */
7717 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7718 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7719 (_("This file is invalid and cannot be played.")),
7720 ("sample data crosses atom boundary"));
7721 ret = GST_FLOW_ERROR;
7724 demux->mdatleft -= demux->neededbytes;
7726 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7727 /* so we are dropping more than left in this atom */
7728 gst_qtdemux_drop_data (demux, demux->mdatleft);
7729 demux->mdatleft = 0;
7731 /* need to resume atom parsing so we do not miss any other pieces */
7732 demux->state = QTDEMUX_STATE_INITIAL;
7733 demux->neededbytes = 16;
7735 /* check if there was any stored post mdat data from previous buffers */
7736 if (demux->restoredata_buffer) {
7737 g_assert (gst_adapter_available (demux->adapter) == 0);
7739 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7740 demux->restoredata_buffer = NULL;
7741 demux->offset = demux->restoredata_offset;
7748 if (demux->todrop) {
7749 if (demux->cenc_aux_info_offset > 0) {
7753 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7754 data = gst_adapter_map (demux->adapter, demux->todrop);
7755 gst_byte_reader_init (&br, data + 8, demux->todrop);
7756 if (!qtdemux_parse_cenc_aux_info (demux,
7757 QTDEMUX_NTH_STREAM (demux, 0), &br,
7758 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7759 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7760 ret = GST_FLOW_ERROR;
7761 gst_adapter_unmap (demux->adapter);
7762 g_free (demux->cenc_aux_info_sizes);
7763 demux->cenc_aux_info_sizes = NULL;
7766 demux->cenc_aux_info_offset = 0;
7767 g_free (demux->cenc_aux_info_sizes);
7768 demux->cenc_aux_info_sizes = NULL;
7769 gst_adapter_unmap (demux->adapter);
7771 gst_qtdemux_drop_data (demux, demux->todrop);
7775 /* initial newsegment sent here after having added pads,
7776 * possible others in sink_event */
7777 gst_qtdemux_check_send_pending_segment (demux);
7779 /* Figure out which stream this packet belongs to */
7780 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7781 stream = QTDEMUX_NTH_STREAM (demux, i);
7782 if (stream->sample_index >= stream->n_samples) {
7783 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7787 GST_LOG_OBJECT (demux,
7788 "Checking track-id %u (sample_index:%d / offset:%"
7789 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7790 stream->sample_index,
7791 stream->samples[stream->sample_index].offset,
7792 stream->samples[stream->sample_index].size);
7794 if (stream->samples[stream->sample_index].offset == demux->offset)
7798 if (G_UNLIKELY (stream == NULL))
7799 goto unknown_stream;
7801 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7803 if (stream->new_caps) {
7804 gst_qtdemux_configure_stream (demux, stream);
7807 /* Put data in a buffer, set timestamps, caps, ... */
7808 sample = &stream->samples[stream->sample_index];
7810 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7811 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7812 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7814 dts = QTSAMPLE_DTS (stream, sample);
7815 pts = QTSAMPLE_PTS (stream, sample);
7816 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7817 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7819 /* check for segment end */
7820 if (G_UNLIKELY (demux->segment.stop != -1
7821 && demux->segment.stop <= pts && stream->on_keyframe)
7822 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7823 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7824 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7826 /* skip this data, stream is EOS */
7827 gst_adapter_flush (demux->adapter, demux->neededbytes);
7828 demux->offset += demux->neededbytes;
7830 /* check if all streams are eos */
7832 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7833 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7842 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7844 /* FIXME: should either be an assert or a plain check */
7845 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7847 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7848 dts, pts, duration, keyframe, dts, demux->offset);
7852 GST_OBJECT_LOCK (demux);
7853 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7854 GST_OBJECT_UNLOCK (demux);
7856 /* skip this data, stream is EOS */
7857 gst_adapter_flush (demux->adapter, demux->neededbytes);
7860 stream->sample_index++;
7861 stream->offset_in_sample = 0;
7863 /* update current offset and figure out size of next buffer */
7864 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7865 demux->offset, demux->neededbytes);
7866 demux->offset += demux->neededbytes;
7867 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7871 if (ret == GST_FLOW_EOS) {
7872 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7873 demux->neededbytes = -1;
7877 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7878 if (demux->fragmented) {
7879 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7880 /* there may be more to follow, only finish this atom */
7881 demux->todrop = demux->mdatleft;
7882 demux->neededbytes = demux->todrop;
7887 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7888 goto non_ok_unlinked_flow;
7897 /* when buffering movie data, at least show user something is happening */
7898 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7899 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7900 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7901 demux->neededbytes);
7908 non_ok_unlinked_flow:
7910 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7911 gst_flow_get_name (ret));
7916 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7917 ret = GST_FLOW_ERROR;
7922 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7928 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7929 (NULL), ("qtdemuxer invalid state %d", demux->state));
7930 ret = GST_FLOW_ERROR;
7935 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7936 (NULL), ("no 'moov' atom within the first 10 MB"));
7937 ret = GST_FLOW_ERROR;
7943 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7948 query = gst_query_new_scheduling ();
7950 if (!gst_pad_peer_query (sinkpad, query)) {
7951 gst_query_unref (query);
7955 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7956 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7957 gst_query_unref (query);
7962 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7963 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7967 GST_DEBUG_OBJECT (sinkpad, "activating push");
7968 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7973 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7974 GstPadMode mode, gboolean active)
7977 GstQTDemux *demux = GST_QTDEMUX (parent);
7980 case GST_PAD_MODE_PUSH:
7981 demux->pullbased = FALSE;
7984 case GST_PAD_MODE_PULL:
7986 demux->pullbased = TRUE;
7987 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7990 res = gst_pad_stop_task (sinkpad);
8002 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
8008 memset (&z, 0, sizeof (z));
8013 if ((ret = inflateInit (&z)) != Z_OK) {
8014 GST_ERROR ("inflateInit() returned %d", ret);
8018 z.next_in = z_buffer;
8019 z.avail_in = z_length;
8021 buffer = (guint8 *) g_malloc (*length);
8022 z.avail_out = *length;
8023 z.next_out = (Bytef *) buffer;
8025 ret = inflate (&z, Z_NO_FLUSH);
8026 if (ret == Z_STREAM_END) {
8028 } else if (ret != Z_OK) {
8029 GST_WARNING ("inflate() returned %d", ret);
8033 if (*length > G_MAXUINT - 4096 || *length > QTDEMUX_MAX_SAMPLE_INDEX_SIZE) {
8034 GST_WARNING ("too big decompressed data");
8040 buffer = (guint8 *) g_realloc (buffer, *length);
8041 z.next_out = (Bytef *) (buffer + z.total_out);
8042 z.avail_out += *length - z.total_out;
8043 } while (z.avail_in > 0);
8045 if (ret != Z_STREAM_END) {
8050 *length = z.total_out;
8057 #endif /* HAVE_ZLIB */
8060 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
8064 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
8066 /* counts as header data */
8067 qtdemux->header_size += length;
8069 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
8070 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
8072 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
8079 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
8080 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
8081 if (dcom == NULL || cmvd == NULL)
8082 goto invalid_compression;
8084 dcom_len = QT_UINT32 (dcom->data);
8086 goto invalid_compression;
8088 method = QT_FOURCC ((guint8 *) dcom->data + 8);
8092 guint uncompressed_length;
8093 guint compressed_length;
8097 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
8099 goto invalid_compression;
8101 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
8102 compressed_length = cmvd_len - 12;
8103 GST_LOG ("length = %u", uncompressed_length);
8106 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
8107 compressed_length, &uncompressed_length);
8110 qtdemux->moov_node_compressed = qtdemux->moov_node;
8111 qtdemux->moov_node = g_node_new (buf);
8113 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
8114 uncompressed_length);
8118 #endif /* HAVE_ZLIB */
8120 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
8121 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
8128 invalid_compression:
8130 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
8136 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
8139 while (G_UNLIKELY (buf < end)) {
8143 if (G_UNLIKELY (buf + 4 > end)) {
8144 GST_LOG_OBJECT (qtdemux, "buffer overrun");
8147 len = QT_UINT32 (buf);
8148 if (G_UNLIKELY (len == 0)) {
8149 GST_LOG_OBJECT (qtdemux, "empty container");
8152 if (G_UNLIKELY (len < 8)) {
8153 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
8156 if (G_UNLIKELY (len > (end - buf))) {
8157 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
8158 (gint) (end - buf));
8162 child = g_node_new ((guint8 *) buf);
8163 g_node_append (node, child);
8164 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
8165 qtdemux_parse_node (qtdemux, child, buf, len);
8173 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
8176 int len = QT_UINT32 (xdxt->data);
8177 guint8 *buf = xdxt->data;
8178 guint8 *end = buf + len;
8181 /* skip size and type */
8189 size = QT_UINT32 (buf);
8190 type = QT_FOURCC (buf + 4);
8192 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
8194 if (buf + size > end || size <= 0)
8200 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8201 GST_FOURCC_ARGS (type));
8205 buffer = gst_buffer_new_and_alloc (size);
8206 gst_buffer_fill (buffer, 0, buf, size);
8207 stream->buffers = g_slist_append (stream->buffers, buffer);
8208 GST_LOG_OBJECT (qtdemux, "parsing theora header");
8211 buffer = gst_buffer_new_and_alloc (size);
8212 gst_buffer_fill (buffer, 0, buf, size);
8213 stream->buffers = g_slist_append (stream->buffers, buffer);
8214 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
8217 buffer = gst_buffer_new_and_alloc (size);
8218 gst_buffer_fill (buffer, 0, buf, size);
8219 stream->buffers = g_slist_append (stream->buffers, buffer);
8220 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
8223 GST_WARNING_OBJECT (qtdemux,
8224 "unknown theora cookie %" GST_FOURCC_FORMAT,
8225 GST_FOURCC_ARGS (type));
8234 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8238 guint32 node_length = 0;
8239 const QtNodeType *type;
8242 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8244 if (G_UNLIKELY (length < 8))
8245 goto not_enough_data;
8247 node_length = QT_UINT32 (buffer);
8248 fourcc = QT_FOURCC (buffer + 4);
8250 /* ignore empty nodes */
8251 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8254 type = qtdemux_type_get (fourcc);
8256 end = buffer + length;
8258 GST_LOG_OBJECT (qtdemux,
8259 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8260 GST_FOURCC_ARGS (fourcc), node_length, type->name);
8262 if (node_length > length)
8263 goto broken_atom_size;
8265 if (type->flags & QT_FLAG_CONTAINER) {
8266 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8271 if (node_length < 20) {
8272 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8275 GST_DEBUG_OBJECT (qtdemux,
8276 "parsing stsd (sample table, sample description) atom");
8277 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8278 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8290 /* also read alac (or whatever) in stead of mp4a in the following,
8291 * since a similar layout is used in other cases as well */
8292 if (fourcc == FOURCC_mp4a)
8294 else if (fourcc == FOURCC_fLaC)
8299 /* There are two things we might encounter here: a true mp4a atom, and
8300 an mp4a entry in an stsd atom. The latter is what we're interested
8301 in, and it looks like an atom, but isn't really one. The true mp4a
8302 atom is short, so we detect it based on length here. */
8303 if (length < min_size) {
8304 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8305 GST_FOURCC_ARGS (fourcc));
8309 /* 'version' here is the sound sample description version. Types 0 and
8310 1 are documented in the QTFF reference, but type 2 is not: it's
8311 described in Apple header files instead (struct SoundDescriptionV2
8313 version = QT_UINT16 (buffer + 16);
8315 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8316 GST_FOURCC_ARGS (fourcc), version);
8318 /* parse any esds descriptors */
8330 GST_WARNING_OBJECT (qtdemux,
8331 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8332 GST_FOURCC_ARGS (fourcc), version);
8337 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8365 /* codec_data is contained inside these atoms, which all have
8366 * the same format. */
8367 /* video sample description size is 86 bytes without extension.
8368 * node_length have to be bigger than 86 bytes because video sample
8369 * description can include extensions such as esds, fiel, glbl, etc. */
8370 if (node_length < 86) {
8371 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8372 " sample description length too short (%u < 86)",
8373 GST_FOURCC_ARGS (fourcc), node_length);
8377 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8378 GST_FOURCC_ARGS (fourcc));
8380 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8382 * revision level (2 bytes) : must be set to 0. */
8383 version = QT_UINT32 (buffer + 16);
8384 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8386 /* compressor name : PASCAL string and informative purposes
8387 * first byte : the number of bytes to be displayed.
8388 * it has to be less than 32 because it is reserved
8389 * space of 32 bytes total including itself. */
8390 str_len = QT_UINT8 (buffer + 50);
8392 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8393 (char *) buffer + 51);
8395 GST_WARNING_OBJECT (qtdemux,
8396 "compressorname length too big (%u > 31)", str_len);
8398 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8400 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8405 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8407 /* You are reading this correctly. QTFF specifies that the
8408 * metadata atom is a short atom, whereas ISO BMFF specifies
8409 * it's a full atom. But since so many people are doing things
8410 * differently, we actually peek into the atom to see which
8413 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8414 GST_FOURCC_ARGS (fourcc));
8417 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8418 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8419 * starts with a 'hdlr' atom */
8420 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8421 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8422 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8423 * with version/flags both set to zero */
8424 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8426 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8431 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8432 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8433 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8442 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8443 GST_FOURCC_ARGS (fourcc));
8447 version = QT_UINT32 (buffer + 12);
8448 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8455 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8460 if (length < offset) {
8461 GST_WARNING_OBJECT (qtdemux,
8462 "skipping too small %" GST_FOURCC_FORMAT " box",
8463 GST_FOURCC_ARGS (fourcc));
8466 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8472 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8477 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8482 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8486 if (!strcmp (type->name, "unknown"))
8487 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8491 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8492 GST_FOURCC_ARGS (fourcc));
8498 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8499 (_("This file is corrupt and cannot be played.")),
8500 ("Not enough data for an atom header, got only %u bytes", length));
8505 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8506 (_("This file is corrupt and cannot be played.")),
8507 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8508 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8515 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8517 /* FIXME: This can only reliably work if demuxers have a
8518 * separate streaming thread per srcpad. This should be
8519 * done in a demuxer base class, which integrates parts
8522 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8527 query = gst_query_new_allocation (stream->caps, FALSE);
8529 if (!gst_pad_peer_query (stream->pad, query)) {
8530 /* not a problem, just debug a little */
8531 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8534 if (stream->allocator)
8535 gst_object_unref (stream->allocator);
8537 if (gst_query_get_n_allocation_params (query) > 0) {
8538 /* try the allocator */
8539 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8541 stream->use_allocator = TRUE;
8543 stream->allocator = NULL;
8544 gst_allocation_params_init (&stream->params);
8545 stream->use_allocator = FALSE;
8547 gst_query_unref (query);
8552 pad_query (const GValue * item, GValue * value, gpointer user_data)
8554 GstPad *pad = g_value_get_object (item);
8555 GstQuery *query = user_data;
8558 res = gst_pad_peer_query (pad, query);
8561 g_value_set_boolean (value, TRUE);
8565 GST_INFO_OBJECT (pad, "pad peer query failed");
8570 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8571 GstPadDirection direction)
8574 GstIteratorFoldFunction func = pad_query;
8575 GValue res = { 0, };
8577 g_value_init (&res, G_TYPE_BOOLEAN);
8578 g_value_set_boolean (&res, FALSE);
8581 if (direction == GST_PAD_SRC)
8582 it = gst_element_iterate_src_pads (element);
8584 it = gst_element_iterate_sink_pads (element);
8586 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8587 gst_iterator_resync (it);
8589 gst_iterator_free (it);
8591 return g_value_get_boolean (&res);
8595 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8596 QtDemuxStream * stream)
8600 GstElement *element = GST_ELEMENT (qtdemux);
8602 gchar **filtered_sys_ids;
8603 GValue event_list = G_VALUE_INIT;
8606 /* 1. Check if we already have the context. */
8607 if (qtdemux->preferred_protection_system_id != NULL) {
8608 GST_LOG_OBJECT (element,
8609 "already have the protection context, no need to request it again");
8613 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8614 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8615 (const gchar **) qtdemux->protection_system_ids->pdata);
8617 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8618 qtdemux->protection_system_ids->len - 1);
8619 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8620 "decryptors for %u of them, running context request",
8621 qtdemux->protection_system_ids->len,
8622 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8625 if (stream->protection_scheme_event_queue.length) {
8626 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8627 stream->protection_scheme_event_queue.length);
8628 walk = stream->protection_scheme_event_queue.tail;
8630 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8631 qtdemux->protection_event_queue.length);
8632 walk = qtdemux->protection_event_queue.tail;
8635 g_value_init (&event_list, GST_TYPE_LIST);
8636 for (; walk; walk = g_list_previous (walk)) {
8637 GValue event_value = G_VALUE_INIT;
8638 g_value_init (&event_value, GST_TYPE_EVENT);
8639 g_value_set_boxed (&event_value, walk->data);
8640 gst_value_list_append_and_take_value (&event_list, &event_value);
8643 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8644 * check if downstream already has a context of the specific type
8645 * 2b) Query upstream as above.
8647 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8648 st = gst_query_writable_structure (query);
8649 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8650 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8652 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8653 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8654 gst_query_parse_context (query, &ctxt);
8655 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8656 gst_element_set_context (element, ctxt);
8657 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8658 gst_query_parse_context (query, &ctxt);
8659 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8660 gst_element_set_context (element, ctxt);
8662 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8663 * the required context type and afterwards check if a
8664 * usable context was set now as in 1). The message could
8665 * be handled by the parent bins of the element and the
8670 GST_INFO_OBJECT (element, "posting need context message");
8671 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8672 "drm-preferred-decryption-system-id");
8673 st = (GstStructure *) gst_message_get_structure (msg);
8674 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8675 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8678 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8679 gst_element_post_message (element, msg);
8682 g_strfreev (filtered_sys_ids);
8683 g_value_unset (&event_list);
8684 gst_query_unref (query);
8688 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8689 QtDemuxStream * stream)
8692 const gchar *selected_system = NULL;
8694 g_return_val_if_fail (qtdemux != NULL, FALSE);
8695 g_return_val_if_fail (stream != NULL, FALSE);
8696 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8699 if (stream->protection_scheme_type == FOURCC_aavd) {
8700 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8701 if (!gst_structure_has_name (s, "application/x-aavd")) {
8702 gst_structure_set (s,
8703 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8705 gst_structure_set_name (s, "application/x-aavd");
8710 if (stream->protection_scheme_type != FOURCC_cenc
8711 && stream->protection_scheme_type != FOURCC_cbcs) {
8712 GST_ERROR_OBJECT (qtdemux,
8713 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8714 GST_FOURCC_ARGS (stream->protection_scheme_type));
8718 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8719 if (!gst_structure_has_name (s, "application/x-cenc")) {
8720 gst_structure_set (s,
8721 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8722 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8723 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8725 gst_structure_set_name (s, "application/x-cenc");
8728 if (qtdemux->protection_system_ids == NULL) {
8729 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8730 "cenc protection system information has been found, not setting a "
8731 "protection system UUID");
8735 gst_qtdemux_request_protection_context (qtdemux, stream);
8736 if (qtdemux->preferred_protection_system_id != NULL) {
8737 const gchar *preferred_system_array[] =
8738 { qtdemux->preferred_protection_system_id, NULL };
8740 selected_system = gst_protection_select_system (preferred_system_array);
8742 if (selected_system) {
8743 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8744 qtdemux->preferred_protection_system_id);
8746 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8747 "because there is no available decryptor",
8748 qtdemux->preferred_protection_system_id);
8752 if (!selected_system) {
8753 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8754 selected_system = gst_protection_select_system ((const gchar **)
8755 qtdemux->protection_system_ids->pdata);
8756 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8757 qtdemux->protection_system_ids->len - 1);
8760 if (!selected_system) {
8761 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8762 "suitable decryptor element has been found");
8766 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8769 gst_structure_set (s,
8770 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8777 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8779 /* fps is calculated base on the duration of the average framerate since
8780 * qt does not have a fixed framerate. */
8781 gboolean fps_available = TRUE;
8782 guint32 first_duration = 0;
8784 if (stream->n_samples > 0)
8785 first_duration = stream->samples[0].duration;
8787 if ((stream->n_samples == 1 && first_duration == 0)
8788 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8790 CUR_STREAM (stream)->fps_n = 0;
8791 CUR_STREAM (stream)->fps_d = 1;
8793 if (stream->duration == 0 || stream->n_samples < 2) {
8794 CUR_STREAM (stream)->fps_n = stream->timescale;
8795 CUR_STREAM (stream)->fps_d = 1;
8796 fps_available = FALSE;
8798 GstClockTime avg_duration;
8802 /* duration and n_samples can be updated for fragmented format
8803 * so, framerate of fragmented format is calculated using data in a moof */
8804 if (qtdemux->fragmented && stream->n_samples_moof > 0
8805 && stream->duration_moof > 0) {
8806 n_samples = stream->n_samples_moof;
8807 duration = stream->duration_moof;
8809 n_samples = stream->n_samples;
8810 duration = stream->duration;
8813 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8814 /* stream->duration is guint64, timescale, n_samples are guint32 */
8816 gst_util_uint64_scale_round (duration -
8817 first_duration, GST_SECOND,
8818 (guint64) (stream->timescale) * (n_samples - 1));
8820 GST_LOG_OBJECT (qtdemux,
8821 "Calculating avg sample duration based on stream (or moof) duration %"
8823 " minus first sample %u, leaving %d samples gives %"
8824 GST_TIME_FORMAT, duration, first_duration,
8825 n_samples - 1, GST_TIME_ARGS (avg_duration));
8828 gst_video_guess_framerate (avg_duration,
8829 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8831 GST_DEBUG_OBJECT (qtdemux,
8832 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8833 stream->timescale, CUR_STREAM (stream)->fps_n,
8834 CUR_STREAM (stream)->fps_d);
8838 return fps_available;
8842 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8844 if (stream->subtype == FOURCC_vide) {
8845 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8847 if (CUR_STREAM (stream)->caps) {
8848 CUR_STREAM (stream)->caps =
8849 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8851 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8852 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8853 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8854 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8856 /* set framerate if calculated framerate is reliable */
8857 if (fps_available) {
8858 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8859 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8860 CUR_STREAM (stream)->fps_d, NULL);
8863 /* calculate pixel-aspect-ratio using display width and height */
8864 GST_DEBUG_OBJECT (qtdemux,
8865 "video size %dx%d, target display size %dx%d",
8866 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8867 stream->display_width, stream->display_height);
8868 /* qt file might have pasp atom */
8869 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8870 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8871 CUR_STREAM (stream)->par_h);
8872 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8873 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8874 CUR_STREAM (stream)->par_h, NULL);
8875 } else if (stream->display_width > 0 && stream->display_height > 0
8876 && CUR_STREAM (stream)->width > 0
8877 && CUR_STREAM (stream)->height > 0) {
8880 /* calculate the pixel aspect ratio using the display and pixel w/h */
8881 n = stream->display_width * CUR_STREAM (stream)->height;
8882 d = stream->display_height * CUR_STREAM (stream)->width;
8885 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8886 CUR_STREAM (stream)->par_w = n;
8887 CUR_STREAM (stream)->par_h = d;
8888 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8889 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8890 CUR_STREAM (stream)->par_h, NULL);
8893 if (CUR_STREAM (stream)->interlace_mode > 0) {
8894 if (CUR_STREAM (stream)->interlace_mode == 1) {
8895 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8896 G_TYPE_STRING, "progressive", NULL);
8897 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8898 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8899 G_TYPE_STRING, "interleaved", NULL);
8900 if (CUR_STREAM (stream)->field_order == 9) {
8901 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8902 G_TYPE_STRING, "top-field-first", NULL);
8903 } else if (CUR_STREAM (stream)->field_order == 14) {
8904 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8905 G_TYPE_STRING, "bottom-field-first", NULL);
8910 /* Create incomplete colorimetry here if needed */
8911 if (CUR_STREAM (stream)->colorimetry.range ||
8912 CUR_STREAM (stream)->colorimetry.matrix ||
8913 CUR_STREAM (stream)->colorimetry.transfer
8914 || CUR_STREAM (stream)->colorimetry.primaries) {
8915 gchar *colorimetry =
8916 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8917 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8918 G_TYPE_STRING, colorimetry, NULL);
8919 g_free (colorimetry);
8922 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8923 guint par_w = 1, par_h = 1;
8925 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8926 par_w = CUR_STREAM (stream)->par_w;
8927 par_h = CUR_STREAM (stream)->par_h;
8930 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8931 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8933 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8936 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8937 "multiview-mode", G_TYPE_STRING,
8938 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8939 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8940 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8945 else if (stream->subtype == FOURCC_soun) {
8946 if (CUR_STREAM (stream)->caps) {
8947 CUR_STREAM (stream)->caps =
8948 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8949 if (CUR_STREAM (stream)->rate > 0)
8950 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8951 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8952 if (CUR_STREAM (stream)->n_channels > 0)
8953 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8954 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8955 if (CUR_STREAM (stream)->n_channels > 2) {
8956 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8957 * correctly; this is just the minimum we can do - assume
8958 * we don't actually have any channel positions. */
8959 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8960 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8965 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8966 const GstStructure *s;
8967 QtDemuxStream *fps_stream = NULL;
8968 gboolean fps_available = FALSE;
8970 /* CEA608 closed caption tracks are a bit special in that each sample
8971 * can contain CCs for multiple frames, and CCs can be omitted and have to
8972 * be inferred from the duration of the sample then.
8974 * As such we take the framerate from the (first) video track here for
8975 * CEA608 as there must be one CC byte pair for every video frame
8976 * according to the spec.
8978 * For CEA708 all is fine and there is one sample per frame.
8981 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8982 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8985 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8986 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8988 if (tmp->subtype == FOURCC_vide) {
8995 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8996 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8997 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
9000 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
9001 fps_stream = stream;
9004 CUR_STREAM (stream)->caps =
9005 gst_caps_make_writable (CUR_STREAM (stream)->caps);
9007 /* set framerate if calculated framerate is reliable */
9008 if (fps_available) {
9009 gst_caps_set_simple (CUR_STREAM (stream)->caps,
9010 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
9011 CUR_STREAM (stream)->fps_d, NULL);
9016 gboolean forward_collection = FALSE;
9017 GstCaps *prev_caps = NULL;
9019 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
9020 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
9021 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
9022 gst_pad_set_active (stream->pad, TRUE);
9024 gst_pad_use_fixed_caps (stream->pad);
9026 if (stream->protected) {
9027 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
9028 GST_ERROR_OBJECT (qtdemux,
9029 "Failed to configure protected stream caps.");
9034 if (stream->new_stream) {
9036 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
9039 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
9042 gst_event_parse_stream_flags (event, &stream_flags);
9043 if (gst_event_parse_group_id (event, &qtdemux->group_id))
9044 qtdemux->have_group_id = TRUE;
9046 qtdemux->have_group_id = FALSE;
9047 gst_event_unref (event);
9048 } else if (!qtdemux->have_group_id) {
9049 qtdemux->have_group_id = TRUE;
9050 qtdemux->group_id = gst_util_group_id_next ();
9053 stream->new_stream = FALSE;
9054 event = gst_event_new_stream_start (stream->stream_id);
9055 if (qtdemux->have_group_id)
9056 gst_event_set_group_id (event, qtdemux->group_id);
9057 if (stream->disabled)
9058 stream_flags |= GST_STREAM_FLAG_UNSELECT;
9059 if (CUR_STREAM (stream)->sparse) {
9060 stream_flags |= GST_STREAM_FLAG_SPARSE;
9062 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
9064 gst_event_set_stream_flags (event, stream_flags);
9065 gst_pad_push_event (stream->pad, event);
9067 forward_collection = TRUE;
9070 prev_caps = gst_pad_get_current_caps (stream->pad);
9072 if (CUR_STREAM (stream)->caps) {
9074 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
9075 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
9076 CUR_STREAM (stream)->caps);
9077 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
9079 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
9082 GST_WARNING_OBJECT (qtdemux, "stream without caps");
9086 gst_caps_unref (prev_caps);
9087 stream->new_caps = FALSE;
9089 if (forward_collection) {
9090 /* Forward upstream collection and selection if any */
9091 GstEvent *upstream_event = gst_pad_get_sticky_event (qtdemux->sinkpad,
9092 GST_EVENT_STREAM_COLLECTION, 0);
9094 gst_pad_push_event (stream->pad, upstream_event);
9101 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
9102 QtDemuxStream * stream)
9104 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
9107 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
9108 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
9109 if (G_UNLIKELY (stream->stsd_sample_description_id >=
9110 stream->stsd_entries_length)) {
9111 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
9112 (_("This file is invalid and cannot be played.")),
9113 ("New sample description id is out of bounds (%d >= %d)",
9114 stream->stsd_sample_description_id, stream->stsd_entries_length));
9116 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
9117 stream->new_caps = TRUE;
9122 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
9123 QtDemuxStream * stream, GstTagList * list)
9125 gboolean ret = TRUE;
9127 if (stream->subtype == FOURCC_vide) {
9128 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9131 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9134 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9135 gst_object_unref (stream->pad);
9141 qtdemux->n_video_streams++;
9142 } else if (stream->subtype == FOURCC_soun) {
9143 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
9146 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9148 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9149 gst_object_unref (stream->pad);
9154 qtdemux->n_audio_streams++;
9155 } else if (stream->subtype == FOURCC_strm) {
9156 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9157 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9158 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9159 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
9160 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9163 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9165 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9166 gst_object_unref (stream->pad);
9171 qtdemux->n_sub_streams++;
9172 } else if (stream->subtype == FOURCC_meta) {
9173 gchar *name = g_strdup_printf ("meta_%u", qtdemux->n_meta_streams);
9176 gst_pad_new_from_static_template (&gst_qtdemux_metasrc_template, name);
9178 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9179 gst_object_unref (stream->pad);
9184 qtdemux->n_meta_streams++;
9185 } else if (CUR_STREAM (stream)->caps) {
9186 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9189 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9191 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9192 gst_object_unref (stream->pad);
9197 qtdemux->n_video_streams++;
9199 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9206 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9207 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9208 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9209 GST_OBJECT_LOCK (qtdemux);
9210 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9211 GST_OBJECT_UNLOCK (qtdemux);
9213 if (stream->stream_tags)
9214 gst_tag_list_unref (stream->stream_tags);
9215 stream->stream_tags = list;
9217 /* global tags go on each pad anyway */
9218 stream->send_global_tags = TRUE;
9219 /* send upstream GST_EVENT_PROTECTION events that were received before
9220 this source pad was created */
9221 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9222 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9226 gst_tag_list_unref (list);
9230 /* find next atom with @fourcc starting at @offset */
9231 static GstFlowReturn
9232 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9233 guint64 * length, guint32 fourcc)
9239 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9240 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9246 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9247 if (G_UNLIKELY (ret != GST_FLOW_OK))
9249 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9252 gst_buffer_unref (buf);
9255 gst_buffer_map (buf, &map, GST_MAP_READ);
9256 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9257 gst_buffer_unmap (buf, &map);
9258 gst_buffer_unref (buf);
9260 if (G_UNLIKELY (*length == 0)) {
9261 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9262 ret = GST_FLOW_ERROR;
9266 if (lfourcc == fourcc) {
9267 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9268 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9271 GST_LOG_OBJECT (qtdemux,
9272 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9273 GST_FOURCC_ARGS (lfourcc), *offset);
9274 if (*offset == G_MAXUINT64)
9284 /* might simply have had last one */
9285 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9290 /* should only do something in pull mode */
9291 /* call with OBJECT lock */
9292 static GstFlowReturn
9293 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9295 guint64 length, offset;
9296 GstBuffer *buf = NULL;
9297 GstFlowReturn ret = GST_FLOW_OK;
9298 GstFlowReturn res = GST_FLOW_OK;
9301 offset = qtdemux->moof_offset;
9302 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9305 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9306 return GST_FLOW_EOS;
9309 /* best not do pull etc with lock held */
9310 GST_OBJECT_UNLOCK (qtdemux);
9312 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9313 if (ret != GST_FLOW_OK)
9316 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9317 if (G_UNLIKELY (ret != GST_FLOW_OK))
9319 gst_buffer_map (buf, &map, GST_MAP_READ);
9320 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9321 gst_buffer_unmap (buf, &map);
9322 gst_buffer_unref (buf);
9327 gst_buffer_unmap (buf, &map);
9328 gst_buffer_unref (buf);
9332 /* look for next moof */
9333 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9334 if (G_UNLIKELY (ret != GST_FLOW_OK))
9338 GST_OBJECT_LOCK (qtdemux);
9340 qtdemux->moof_offset = offset;
9346 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9348 res = GST_FLOW_ERROR;
9353 /* maybe upstream temporarily flushing */
9354 if (ret != GST_FLOW_FLUSHING) {
9355 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9358 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9359 /* resume at current position next time */
9367 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9371 gint32 stts_duration;
9372 GstByteWriter stsc, stts, stsz;
9374 /* Each sample has a different size, which we don't support for merging */
9375 if (stream->sample_size == 0) {
9376 GST_DEBUG_OBJECT (qtdemux,
9377 "Not all samples have the same size, not merging");
9381 /* The stream has a ctts table, we don't support that */
9382 if (stream->ctts_present) {
9383 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9387 /* If there's a sync sample table also ignore this stream */
9388 if (stream->stps_present || stream->stss_present) {
9389 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9393 /* If chunks are considered samples already ignore this stream */
9394 if (stream->chunks_are_samples) {
9395 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9399 /* Require that all samples have the same duration */
9400 if (stream->n_sample_times > 1) {
9401 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9405 /* Parse the stts to get the sample duration and number of samples */
9406 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9407 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9409 /* Parse the number of chunks from the stco manually because the
9410 * reader is already behind that */
9411 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9413 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9416 /* Now parse stsc, convert chunks into single samples and generate a
9417 * new stsc, stts and stsz from this information */
9418 gst_byte_writer_init (&stsc);
9419 gst_byte_writer_init (&stts);
9420 gst_byte_writer_init (&stsz);
9422 /* Note: we skip fourccs, size, version, flags and other fields of the new
9423 * atoms as the byte readers with them are already behind that position
9424 * anyway and only update the values of those inside the stream directly.
9426 stream->n_sample_times = 0;
9427 stream->n_samples = 0;
9428 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9430 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9432 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9433 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9434 sample_description_id =
9435 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9437 if (i == stream->n_samples_per_chunk - 1) {
9438 /* +1 because first_chunk is 1-based */
9439 last_chunk = num_chunks + 1;
9441 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9444 GST_DEBUG_OBJECT (qtdemux,
9445 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9446 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9448 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9449 /* One sample in this chunk */
9450 gst_byte_writer_put_uint32_be (&stsc, 1);
9451 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9453 /* For each chunk write a stts and stsz entry now */
9454 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9455 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9456 for (j = first_chunk; j < last_chunk; j++) {
9457 gst_byte_writer_put_uint32_be (&stsz,
9458 stream->sample_size * samples_per_chunk);
9461 stream->n_sample_times += 1;
9462 stream->n_samples += last_chunk - first_chunk;
9465 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9467 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9468 stream->n_samples, stream->n_sample_times);
9470 /* We don't have a fixed sample size anymore */
9471 stream->sample_size = 0;
9473 /* Free old data for the atoms */
9474 g_free ((gpointer) stream->stsz.data);
9475 stream->stsz.data = NULL;
9476 g_free ((gpointer) stream->stsc.data);
9477 stream->stsc.data = NULL;
9478 g_free ((gpointer) stream->stts.data);
9479 stream->stts.data = NULL;
9481 /* Store new data and replace byte readers */
9482 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9483 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9484 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9485 stream->stts.size = gst_byte_writer_get_size (&stts);
9486 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9487 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9488 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9489 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9490 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9493 /* initialise bytereaders for stbl sub-atoms */
9495 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9497 stream->stbl_index = -1; /* no samples have yet been parsed */
9498 stream->sample_index = -1;
9500 /* time-to-sample atom */
9501 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9504 /* copy atom data into a new buffer for later use */
9505 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9507 /* skip version + flags */
9508 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9509 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9511 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9513 /* make sure there's enough data */
9514 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9515 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9516 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9517 stream->n_sample_times);
9518 if (!stream->n_sample_times)
9522 /* sync sample atom */
9523 stream->stps_present = FALSE;
9524 if ((stream->stss_present =
9525 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9526 &stream->stss) ? TRUE : FALSE) == TRUE) {
9527 /* copy atom data into a new buffer for later use */
9528 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9530 /* skip version + flags */
9531 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9532 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9535 if (stream->n_sample_syncs) {
9536 /* make sure there's enough data */
9537 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9541 /* partial sync sample atom */
9542 if ((stream->stps_present =
9543 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9544 &stream->stps) ? TRUE : FALSE) == TRUE) {
9545 /* copy atom data into a new buffer for later use */
9546 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9548 /* skip version + flags */
9549 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9550 !gst_byte_reader_get_uint32_be (&stream->stps,
9551 &stream->n_sample_partial_syncs))
9554 /* if there are no entries, the stss table contains the real
9556 if (stream->n_sample_partial_syncs) {
9557 /* make sure there's enough data */
9558 if (!qt_atom_parser_has_chunks (&stream->stps,
9559 stream->n_sample_partial_syncs, 4))
9566 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9569 /* copy atom data into a new buffer for later use */
9570 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9572 /* skip version + flags */
9573 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9574 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9577 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9580 if (!stream->n_samples)
9583 /* sample-to-chunk atom */
9584 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9587 /* copy atom data into a new buffer for later use */
9588 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9590 /* skip version + flags */
9591 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9592 !gst_byte_reader_get_uint32_be (&stream->stsc,
9593 &stream->n_samples_per_chunk))
9596 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9597 stream->n_samples_per_chunk);
9599 /* make sure there's enough data */
9600 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9606 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9607 stream->co_size = sizeof (guint32);
9608 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9610 stream->co_size = sizeof (guint64);
9614 /* copy atom data into a new buffer for later use */
9615 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9617 /* skip version + flags */
9618 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9621 /* chunks_are_samples == TRUE means treat chunks as samples */
9622 stream->chunks_are_samples = stream->sample_size
9623 && !CUR_STREAM (stream)->sampled;
9624 if (stream->chunks_are_samples) {
9625 /* treat chunks as samples */
9626 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9629 /* skip number of entries */
9630 if (!gst_byte_reader_skip (&stream->stco, 4))
9633 /* make sure there are enough data in the stsz atom */
9634 if (!stream->sample_size) {
9635 /* different sizes for each sample */
9636 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9641 /* composition time-to-sample */
9642 if ((stream->ctts_present =
9643 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9644 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9645 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9646 guint8 ctts_version;
9647 gboolean checked_ctts = FALSE;
9649 /* copy atom data into a new buffer for later use */
9650 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9652 /* version 1 has signed offsets */
9653 if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9657 if (!gst_byte_reader_skip (&stream->ctts, 3)
9658 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9659 &stream->n_composition_times))
9662 /* make sure there's enough data */
9663 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9667 /* This is optional, if missing we iterate the ctts */
9668 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9669 guint8 cslg_version;
9671 /* cslg version 1 has 64 bit fields */
9672 if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9676 if (!gst_byte_reader_skip (&cslg, 3))
9679 if (cslg_version == 0) {
9680 gint32 composition_to_dts_shift;
9682 if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9685 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9687 gint64 composition_to_dts_shift;
9689 if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9692 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9695 gint32 cslg_least = 0;
9696 guint num_entries, pos;
9699 pos = gst_byte_reader_get_pos (&stream->ctts);
9700 num_entries = stream->n_composition_times;
9702 checked_ctts = TRUE;
9704 stream->cslg_shift = 0;
9706 for (i = 0; i < num_entries; i++) {
9709 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9710 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9711 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9712 * slightly inaccurate PTS could be more usable than corrupted one */
9713 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9714 && ABS (offset) / 2 > stream->duration)) {
9715 GST_WARNING_OBJECT (qtdemux,
9716 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9717 " larger than duration %" G_GUINT64_FORMAT, offset,
9720 stream->cslg_shift = 0;
9721 stream->ctts_present = FALSE;
9725 /* Don't consider "no decode samples" with offset G_MININT32
9726 * for the DTS/PTS shift */
9727 if (offset != G_MININT32 && offset < cslg_least)
9728 cslg_least = offset;
9732 stream->cslg_shift = -cslg_least;
9734 stream->cslg_shift = 0;
9736 /* reset the reader so we can generate sample table */
9737 gst_byte_reader_set_pos (&stream->ctts, pos);
9740 /* Check if ctts values are looking reasonable if that didn't happen above */
9741 if (!checked_ctts) {
9742 guint num_entries, pos;
9745 pos = gst_byte_reader_get_pos (&stream->ctts);
9746 num_entries = stream->n_composition_times;
9748 for (i = 0; i < num_entries; i++) {
9751 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9752 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9753 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9754 * slightly inaccurate PTS could be more usable than corrupted one */
9755 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9756 && ABS (offset) / 2 > stream->duration)) {
9757 GST_WARNING_OBJECT (qtdemux,
9758 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9759 " larger than duration %" G_GUINT64_FORMAT, offset,
9762 stream->cslg_shift = 0;
9763 stream->ctts_present = FALSE;
9768 /* reset the reader so we can generate sample table */
9769 gst_byte_reader_set_pos (&stream->ctts, pos);
9772 /* Ensure the cslg_shift value is consistent so we can use it
9773 * unconditionally to produce TS and Segment */
9774 stream->cslg_shift = 0;
9777 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
9778 stream->cslg_shift);
9780 /* For raw audio streams especially we might want to merge the samples
9781 * to not output one audio sample per buffer. We're doing this here
9782 * before allocating the sample tables so that from this point onwards
9783 * the number of container samples are static */
9784 if (stream->min_buffer_size > 0) {
9785 qtdemux_merge_sample_table (qtdemux, stream);
9789 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9790 stream->n_samples, (guint) sizeof (QtDemuxSample),
9791 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9793 if (stream->n_samples >=
9794 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9795 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9796 "be larger than %uMB (broken file?)", stream->n_samples,
9797 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9801 g_assert (stream->samples == NULL);
9802 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9803 if (!stream->samples) {
9804 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9813 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9814 (_("This file is corrupt and cannot be played.")), (NULL));
9819 gst_qtdemux_stbl_free (stream);
9820 if (!qtdemux->fragmented) {
9821 /* not quite good */
9822 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9825 /* may pick up samples elsewhere */
9831 /* collect samples from the next sample to be parsed up to sample @n for @stream
9832 * by reading the info from @stbl
9834 * This code can be executed from both the streaming thread and the seeking
9835 * thread so it takes the object lock to protect itself
9838 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9841 QtDemuxSample *samples, *first, *cur, *last;
9842 guint32 n_samples_per_chunk;
9845 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9846 GST_FOURCC_FORMAT ", pad %s",
9847 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9848 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9850 n_samples = stream->n_samples;
9853 goto out_of_samples;
9855 GST_OBJECT_LOCK (qtdemux);
9856 if (n <= stream->stbl_index)
9857 goto already_parsed;
9859 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9861 if (!stream->stsz.data) {
9862 /* so we already parsed and passed all the moov samples;
9863 * onto fragmented ones */
9864 g_assert (qtdemux->fragmented);
9868 /* pointer to the sample table */
9869 samples = stream->samples;
9871 /* starts from -1, moves to the next sample index to parse */
9872 stream->stbl_index++;
9874 /* keep track of the first and last sample to fill */
9875 first = &samples[stream->stbl_index];
9878 if (!stream->chunks_are_samples) {
9879 /* set the sample sizes */
9880 if (stream->sample_size == 0) {
9881 /* different sizes for each sample */
9882 for (cur = first; cur <= last; cur++) {
9883 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9884 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9885 (guint) (cur - samples), cur->size);
9888 /* samples have the same size */
9889 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9890 for (cur = first; cur <= last; cur++)
9891 cur->size = stream->sample_size;
9895 n_samples_per_chunk = stream->n_samples_per_chunk;
9898 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9901 if (stream->stsc_chunk_index >= stream->last_chunk
9902 || stream->stsc_chunk_index < stream->first_chunk) {
9903 stream->first_chunk =
9904 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9905 stream->samples_per_chunk =
9906 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9908 stream->stsd_sample_description_id =
9909 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9911 /* chunk numbers are counted from 1 it seems */
9912 if (G_UNLIKELY (stream->first_chunk == 0))
9915 --stream->first_chunk;
9917 /* the last chunk of each entry is calculated by taking the first chunk
9918 * of the next entry; except if there is no next, where we fake it with
9920 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9921 stream->last_chunk = G_MAXUINT32;
9923 stream->last_chunk =
9924 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9925 if (G_UNLIKELY (stream->last_chunk == 0))
9928 --stream->last_chunk;
9931 GST_LOG_OBJECT (qtdemux,
9932 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9933 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9934 stream->samples_per_chunk, stream->stsd_sample_description_id);
9936 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9939 if (stream->last_chunk != G_MAXUINT32) {
9940 if (!qt_atom_parser_peek_sub (&stream->stco,
9941 stream->first_chunk * stream->co_size,
9942 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9947 stream->co_chunk = stream->stco;
9948 if (!gst_byte_reader_skip (&stream->co_chunk,
9949 stream->first_chunk * stream->co_size))
9953 stream->stsc_chunk_index = stream->first_chunk;
9956 last_chunk = stream->last_chunk;
9958 if (stream->chunks_are_samples) {
9959 cur = &samples[stream->stsc_chunk_index];
9961 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9964 stream->stsc_chunk_index = j;
9969 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9972 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9973 "%" G_GUINT64_FORMAT, j, cur->offset);
9975 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9976 CUR_STREAM (stream)->bytes_per_frame > 0) {
9978 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9979 CUR_STREAM (stream)->samples_per_frame *
9980 CUR_STREAM (stream)->bytes_per_frame;
9982 cur->size = stream->samples_per_chunk;
9985 GST_DEBUG_OBJECT (qtdemux,
9986 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9987 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9988 stream->stco_sample_index)), cur->size);
9990 cur->timestamp = stream->stco_sample_index;
9991 cur->duration = stream->samples_per_chunk;
9992 cur->keyframe = TRUE;
9995 stream->stco_sample_index += stream->samples_per_chunk;
9997 stream->stsc_chunk_index = j;
9999 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
10000 guint32 samples_per_chunk;
10001 guint64 chunk_offset;
10003 if (!stream->stsc_sample_index
10004 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
10005 &stream->chunk_offset))
10008 samples_per_chunk = stream->samples_per_chunk;
10009 chunk_offset = stream->chunk_offset;
10011 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
10012 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
10013 G_GUINT64_FORMAT " and size %d",
10014 (guint) (cur - samples), chunk_offset, cur->size);
10016 cur->offset = chunk_offset;
10017 chunk_offset += cur->size;
10020 if (G_UNLIKELY (cur > last)) {
10022 stream->stsc_sample_index = k + 1;
10023 stream->chunk_offset = chunk_offset;
10024 stream->stsc_chunk_index = j;
10028 stream->stsc_sample_index = 0;
10030 stream->stsc_chunk_index = j;
10032 stream->stsc_index++;
10035 if (stream->chunks_are_samples)
10039 guint32 n_sample_times;
10041 n_sample_times = stream->n_sample_times;
10044 for (i = stream->stts_index; i < n_sample_times; i++) {
10045 guint32 stts_samples;
10046 gint32 stts_duration;
10049 if (stream->stts_sample_index >= stream->stts_samples
10050 || !stream->stts_sample_index) {
10052 stream->stts_samples =
10053 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10054 stream->stts_duration =
10055 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10057 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
10058 i, stream->stts_samples, stream->stts_duration);
10060 stream->stts_sample_index = 0;
10063 stts_samples = stream->stts_samples;
10064 stts_duration = stream->stts_duration;
10065 stts_time = stream->stts_time;
10067 for (j = stream->stts_sample_index; j < stts_samples; j++) {
10068 GST_DEBUG_OBJECT (qtdemux,
10069 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
10070 (guint) (cur - samples), j,
10071 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
10073 cur->timestamp = stts_time;
10074 cur->duration = stts_duration;
10076 /* avoid 32-bit wrap-around,
10077 * but still mind possible 'negative' duration */
10078 stts_time += (gint64) stts_duration;
10081 if (G_UNLIKELY (cur > last)) {
10083 stream->stts_time = stts_time;
10084 stream->stts_sample_index = j + 1;
10085 if (stream->stts_sample_index >= stream->stts_samples)
10086 stream->stts_index++;
10090 stream->stts_sample_index = 0;
10091 stream->stts_time = stts_time;
10092 stream->stts_index++;
10094 /* fill up empty timestamps with the last timestamp, this can happen when
10095 * the last samples do not decode and so we don't have timestamps for them.
10096 * We however look at the last timestamp to estimate the track length so we
10097 * need something in here. */
10098 for (; cur < last; cur++) {
10099 GST_DEBUG_OBJECT (qtdemux,
10100 "fill sample %d: timestamp %" GST_TIME_FORMAT,
10101 (guint) (cur - samples),
10102 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
10103 cur->timestamp = stream->stts_time;
10104 cur->duration = -1;
10109 /* sample sync, can be NULL */
10110 if (stream->stss_present == TRUE) {
10111 guint32 n_sample_syncs;
10113 n_sample_syncs = stream->n_sample_syncs;
10115 if (!n_sample_syncs) {
10116 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
10117 stream->all_keyframe = TRUE;
10119 for (i = stream->stss_index; i < n_sample_syncs; i++) {
10120 /* note that the first sample is index 1, not 0 */
10123 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
10125 if (G_LIKELY (index > 0 && index <= n_samples)) {
10127 samples[index].keyframe = TRUE;
10128 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10129 /* and exit if we have enough samples */
10130 if (G_UNLIKELY (index >= n)) {
10137 stream->stss_index = i;
10140 /* stps marks partial sync frames like open GOP I-Frames */
10141 if (stream->stps_present == TRUE) {
10142 guint32 n_sample_partial_syncs;
10144 n_sample_partial_syncs = stream->n_sample_partial_syncs;
10146 /* if there are no entries, the stss table contains the real
10148 if (n_sample_partial_syncs) {
10149 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
10150 /* note that the first sample is index 1, not 0 */
10153 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
10155 if (G_LIKELY (index > 0 && index <= n_samples)) {
10157 samples[index].keyframe = TRUE;
10158 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10159 /* and exit if we have enough samples */
10160 if (G_UNLIKELY (index >= n)) {
10167 stream->stps_index = i;
10171 /* no stss, all samples are keyframes */
10172 stream->all_keyframe = TRUE;
10173 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10178 /* composition time to sample */
10179 if (stream->ctts_present == TRUE) {
10180 guint32 n_composition_times;
10181 guint32 ctts_count;
10182 gint32 ctts_soffset;
10184 /* Fill in the pts_offsets */
10186 n_composition_times = stream->n_composition_times;
10188 for (i = stream->ctts_index; i < n_composition_times; i++) {
10189 if (stream->ctts_sample_index >= stream->ctts_count
10190 || !stream->ctts_sample_index) {
10191 stream->ctts_count =
10192 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10193 stream->ctts_soffset =
10194 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10195 stream->ctts_sample_index = 0;
10198 ctts_count = stream->ctts_count;
10199 ctts_soffset = stream->ctts_soffset;
10201 /* FIXME: Set offset to 0 for "no decode samples". This needs
10202 * to be handled in a codec specific manner ideally. */
10203 if (ctts_soffset == G_MININT32)
10206 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10207 cur->pts_offset = ctts_soffset;
10210 if (G_UNLIKELY (cur > last)) {
10212 stream->ctts_sample_index = j + 1;
10216 stream->ctts_sample_index = 0;
10217 stream->ctts_index++;
10221 stream->stbl_index = n;
10222 /* if index has been completely parsed, free data that is no-longer needed */
10223 if (n + 1 == stream->n_samples) {
10224 gst_qtdemux_stbl_free (stream);
10225 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10226 if (qtdemux->pullbased) {
10227 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10228 while (n + 1 == stream->n_samples)
10229 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10233 GST_OBJECT_UNLOCK (qtdemux);
10240 GST_LOG_OBJECT (qtdemux,
10241 "Tried to parse up to sample %u but this sample has already been parsed",
10243 /* if fragmented, there may be more */
10244 if (qtdemux->fragmented && n == stream->stbl_index)
10246 GST_OBJECT_UNLOCK (qtdemux);
10252 GST_LOG_OBJECT (qtdemux,
10253 "Tried to parse up to sample %u but there are only %u samples", n + 1,
10254 stream->n_samples);
10255 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10256 (_("This file is corrupt and cannot be played.")), (NULL));
10261 GST_OBJECT_UNLOCK (qtdemux);
10262 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10263 (_("This file is corrupt and cannot be played.")), (NULL));
10268 /* collect all segment info for @stream.
10271 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10275 /* accept edts if they contain gaps at start and there is only
10276 * one media segment */
10277 gboolean allow_pushbased_edts = TRUE;
10278 gint media_segments_count = 0;
10280 /* parse and prepare segment info from the edit list */
10281 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10282 stream->n_segments = 0;
10283 stream->segments = NULL;
10284 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10287 guint segment_number, entry_size;
10289 GstClockTime stime;
10290 const guint8 *buffer;
10294 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10295 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10298 buffer = elst->data;
10300 size = QT_UINT32 (buffer);
10301 /* version, flags, n_segments */
10303 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10306 version = QT_UINT8 (buffer + 8);
10307 entry_size = (version == 1) ? 20 : 12;
10309 n_segments = QT_UINT32 (buffer + 12);
10311 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10312 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10316 /* we might allocate a bit too much, at least allocate 1 segment */
10317 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10319 /* segments always start from 0 */
10323 for (segment_number = 0; segment_number < n_segments; segment_number++) {
10325 guint64 media_time;
10326 gboolean empty_edit = FALSE;
10327 QtDemuxSegment *segment;
10329 GstClockTime media_start = GST_CLOCK_TIME_NONE;
10331 if (version == 1) {
10332 media_time = QT_UINT64 (buffer + 8);
10333 duration = QT_UINT64 (buffer);
10334 if (media_time == G_MAXUINT64)
10337 media_time = QT_UINT32 (buffer + 4);
10338 duration = QT_UINT32 (buffer);
10339 if (media_time == G_MAXUINT32)
10344 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10346 segment = &stream->segments[segment_number];
10348 /* time and duration expressed in global timescale */
10349 segment->time = stime;
10350 if (duration != 0 || empty_edit) {
10351 /* edge case: empty edits with duration=zero are treated here.
10352 * (files should not have these anyway). */
10354 /* add non scaled values so we don't cause roundoff errors */
10356 stime = QTTIME_TO_GSTTIME (qtdemux, time);
10357 segment->duration = stime - segment->time;
10359 /* zero duration does not imply media_start == media_stop
10360 * but, only specify media_start. The edit ends with the track. */
10361 stime = segment->duration = GST_CLOCK_TIME_NONE;
10362 /* Don't allow more edits after this one. */
10363 n_segments = segment_number + 1;
10365 segment->stop_time = stime;
10367 segment->trak_media_start = media_time;
10368 /* media_time expressed in stream timescale */
10370 segment->media_start = media_start;
10371 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10372 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10373 media_segments_count++;
10375 segment->media_start = GST_CLOCK_TIME_NONE;
10376 segment->media_stop = GST_CLOCK_TIME_NONE;
10378 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10380 if (rate_int <= 1) {
10381 /* 0 is not allowed, some programs write 1 instead of the floating point
10383 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10387 segment->rate = rate_int / 65536.0;
10390 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10391 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10392 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10393 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10394 segment_number, GST_TIME_ARGS (segment->time),
10395 GST_TIME_ARGS (segment->duration),
10396 GST_TIME_ARGS (segment->media_start), media_time,
10397 GST_TIME_ARGS (segment->media_stop),
10398 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10399 stream->timescale);
10400 if (segment->stop_time > qtdemux->segment.stop &&
10401 !qtdemux->upstream_format_is_time) {
10402 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10403 " extends to %" GST_TIME_FORMAT
10404 " past the end of the declared movie duration %" GST_TIME_FORMAT
10405 " movie segment will be extended", segment_number,
10406 GST_TIME_ARGS (segment->stop_time),
10407 GST_TIME_ARGS (qtdemux->segment.stop));
10408 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10411 buffer += entry_size;
10413 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10414 stream->n_segments = n_segments;
10415 if (media_segments_count != 1)
10416 allow_pushbased_edts = FALSE;
10420 /* push based does not handle segments, so act accordingly here,
10421 * and warn if applicable */
10422 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10423 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10424 /* remove and use default one below, we stream like it anyway */
10425 g_free (stream->segments);
10426 stream->segments = NULL;
10427 stream->n_segments = 0;
10430 /* no segments, create one to play the complete trak */
10431 if (stream->n_segments == 0) {
10432 GstClockTime stream_duration =
10433 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10435 if (stream->segments == NULL)
10436 stream->segments = g_new (QtDemuxSegment, 1);
10438 /* represent unknown our way */
10439 if (stream_duration == 0)
10440 stream_duration = GST_CLOCK_TIME_NONE;
10442 stream->segments[0].time = 0;
10443 stream->segments[0].stop_time = stream_duration;
10444 stream->segments[0].duration = stream_duration;
10445 stream->segments[0].media_start = 0;
10446 stream->segments[0].media_stop = stream_duration;
10447 stream->segments[0].rate = 1.0;
10448 stream->segments[0].trak_media_start = 0;
10450 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10451 GST_TIME_ARGS (stream_duration));
10452 stream->n_segments = 1;
10453 stream->dummy_segment = TRUE;
10455 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10461 * Parses the stsd atom of a svq3 trak looking for
10462 * the SMI and gama atoms.
10465 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10466 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10468 const guint8 *_gamma = NULL;
10469 GstBuffer *_seqh = NULL;
10470 const guint8 *stsd_data = stsd_entry_data;
10471 guint32 length = QT_UINT32 (stsd_data);
10475 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10481 version = QT_UINT16 (stsd_data);
10482 if (version == 3) {
10483 if (length >= 70) {
10486 while (length > 8) {
10487 guint32 fourcc, size;
10488 const guint8 *data;
10489 size = QT_UINT32 (stsd_data);
10490 fourcc = QT_FOURCC (stsd_data + 4);
10491 data = stsd_data + 8;
10494 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10495 "svq3 atom parsing");
10504 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10505 " for gama atom, expected 12", size);
10510 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10512 if (_seqh != NULL) {
10513 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10514 " found, ignoring");
10516 seqh_size = QT_UINT32 (data + 4);
10517 if (seqh_size > 0) {
10518 _seqh = gst_buffer_new_and_alloc (seqh_size);
10519 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10526 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10527 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10531 if (size <= length) {
10537 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10540 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10541 G_GUINT16_FORMAT, version);
10551 } else if (_seqh) {
10552 gst_buffer_unref (_seqh);
10557 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10560 GstByteReader dref;
10564 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10565 * atom that might contain a 'data' atom with the rtsp uri.
10566 * This case was reported in bug #597497, some info about
10567 * the hndl atom can be found in TN1195
10569 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10570 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10573 guint32 dref_num_entries = 0;
10574 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10575 gst_byte_reader_skip (&dref, 4) &&
10576 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10579 /* search dref entries for hndl atom */
10580 for (i = 0; i < dref_num_entries; i++) {
10581 guint32 size = 0, type;
10582 guint8 string_len = 0;
10583 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10584 qt_atom_parser_get_fourcc (&dref, &type)) {
10585 if (type == FOURCC_hndl) {
10586 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10588 /* skip data reference handle bytes and the
10589 * following pascal string and some extra 4
10590 * bytes I have no idea what are */
10591 if (!gst_byte_reader_skip (&dref, 4) ||
10592 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10593 !gst_byte_reader_skip (&dref, string_len + 4)) {
10594 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10598 /* iterate over the atoms to find the data atom */
10599 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10603 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10604 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10605 if (atom_type == FOURCC_data) {
10606 const guint8 *uri_aux = NULL;
10608 /* found the data atom that might contain the rtsp uri */
10609 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10610 "hndl atom, interpreting it as an URI");
10611 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10613 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10614 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10616 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10617 "didn't contain a rtsp address");
10619 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10624 /* skipping to the next entry */
10625 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10628 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10635 /* skip to the next entry */
10636 if (!gst_byte_reader_skip (&dref, size - 8))
10639 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10642 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10648 #define AMR_NB_ALL_MODES 0x81ff
10649 #define AMR_WB_ALL_MODES 0x83ff
10651 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10653 /* The 'damr' atom is of the form:
10655 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10656 * 32 b 8 b 16 b 8 b 8 b
10658 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10659 * represents the highest mode used in the stream (and thus the maximum
10660 * bitrate), with a couple of special cases as seen below.
10663 /* Map of frame type ID -> bitrate */
10664 static const guint nb_bitrates[] = {
10665 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10667 static const guint wb_bitrates[] = {
10668 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10674 gst_buffer_map (buf, &map, GST_MAP_READ);
10676 if (map.size != 0x11) {
10677 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10681 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10682 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10683 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10687 mode_set = QT_UINT16 (map.data + 13);
10689 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10690 max_mode = 7 + (wb ? 1 : 0);
10692 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10693 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10695 if (max_mode == -1) {
10696 GST_DEBUG ("No mode indication was found (mode set) = %x",
10701 gst_buffer_unmap (buf, &map);
10702 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10705 gst_buffer_unmap (buf, &map);
10710 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10711 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10714 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10720 if (gst_byte_reader_get_remaining (reader) < 36)
10723 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10724 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10725 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10726 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10727 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10728 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10729 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10730 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10731 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10733 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10734 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10735 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10737 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10738 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10740 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10741 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10748 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10749 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10756 * This macro will only compare value abdegh, it expects cfi to have already
10759 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10760 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10762 /* only handle the cases where the last column has standard values */
10763 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10764 const gchar *rotation_tag = NULL;
10766 /* no rotation needed */
10767 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10769 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10770 rotation_tag = "rotate-90";
10771 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10772 rotation_tag = "rotate-180";
10773 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10774 rotation_tag = "rotate-270";
10776 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10779 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10780 GST_STR_NULL (rotation_tag));
10781 if (rotation_tag != NULL) {
10782 if (*taglist == NULL)
10783 *taglist = gst_tag_list_new_empty ();
10784 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10785 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10788 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10793 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10794 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10798 GstBuffer *adrm_buf = NULL;
10799 QtDemuxAavdEncryptionInfo *info;
10801 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10802 if (G_UNLIKELY (!adrm)) {
10803 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10806 adrm_size = QT_UINT32 (adrm->data);
10807 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10809 stream->protection_scheme_type = FOURCC_aavd;
10811 if (!stream->protection_scheme_info)
10812 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10814 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10816 if (info->default_properties)
10817 gst_structure_free (info->default_properties);
10818 info->default_properties = gst_structure_new ("application/x-aavd",
10819 "encrypted", G_TYPE_BOOLEAN, TRUE,
10820 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10821 gst_buffer_unref (adrm_buf);
10823 *original_fmt = FOURCC_mp4a;
10827 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10828 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10829 * Common Encryption (cenc), the function will also parse the tenc box (defined
10830 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10831 * (typically an enc[v|a|t|s] sample entry); the function will set
10832 * @original_fmt to the fourcc of the original unencrypted stream format.
10833 * Returns TRUE if successful; FALSE otherwise. */
10835 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10836 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10842 QtDemuxCencSampleSetInfo *info;
10844 const guint8 *tenc_data;
10846 g_return_val_if_fail (qtdemux != NULL, FALSE);
10847 g_return_val_if_fail (stream != NULL, FALSE);
10848 g_return_val_if_fail (container != NULL, FALSE);
10849 g_return_val_if_fail (original_fmt != NULL, FALSE);
10851 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10852 if (G_UNLIKELY (!sinf)) {
10853 if (stream->protection_scheme_type == FOURCC_cenc
10854 || stream->protection_scheme_type == FOURCC_cbcs) {
10855 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10856 "mandatory for Common Encryption");
10862 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10863 if (G_UNLIKELY (!frma)) {
10864 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10868 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10869 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10870 GST_FOURCC_ARGS (*original_fmt));
10872 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10874 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10877 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10878 stream->protection_scheme_version =
10879 QT_UINT32 ((const guint8 *) schm->data + 16);
10881 GST_DEBUG_OBJECT (qtdemux,
10882 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10883 "protection_scheme_version: %#010x",
10884 GST_FOURCC_ARGS (stream->protection_scheme_type),
10885 stream->protection_scheme_version);
10887 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10889 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10892 if (stream->protection_scheme_type != FOURCC_cenc &&
10893 stream->protection_scheme_type != FOURCC_piff &&
10894 stream->protection_scheme_type != FOURCC_cbcs) {
10895 GST_ERROR_OBJECT (qtdemux,
10896 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10897 GST_FOURCC_ARGS (stream->protection_scheme_type));
10901 if (G_UNLIKELY (!stream->protection_scheme_info))
10902 stream->protection_scheme_info =
10903 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10905 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10907 if (stream->protection_scheme_type == FOURCC_cenc
10908 || stream->protection_scheme_type == FOURCC_cbcs) {
10909 guint8 is_encrypted;
10911 guint8 constant_iv_size = 0;
10912 const guint8 *default_kid;
10913 guint8 crypt_byte_block = 0;
10914 guint8 skip_byte_block = 0;
10915 const guint8 *constant_iv = NULL;
10917 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10919 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10920 "which is mandatory for Common Encryption");
10923 tenc_data = (const guint8 *) tenc->data + 12;
10924 is_encrypted = QT_UINT8 (tenc_data + 2);
10925 iv_size = QT_UINT8 (tenc_data + 3);
10926 default_kid = (tenc_data + 4);
10927 if (stream->protection_scheme_type == FOURCC_cbcs) {
10928 guint8 possible_pattern_info;
10929 if (iv_size == 0) {
10930 constant_iv_size = QT_UINT8 (tenc_data + 20);
10931 if (constant_iv_size != 8 && constant_iv_size != 16) {
10932 GST_ERROR_OBJECT (qtdemux,
10933 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10936 constant_iv = (tenc_data + 21);
10938 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10939 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10940 skip_byte_block = possible_pattern_info & 0x0f;
10942 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10943 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10944 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10945 } else if (stream->protection_scheme_type == FOURCC_piff) {
10947 static const guint8 piff_track_encryption_uuid[] = {
10948 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10949 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10952 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10954 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10955 "which is mandatory for Common Encryption");
10959 tenc_data = (const guint8 *) tenc->data + 8;
10960 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10961 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10962 GST_ERROR_OBJECT (qtdemux,
10963 "Unsupported track encryption box with uuid: %s", box_uuid);
10967 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10968 gst_byte_reader_init (&br, tenc_data, 20);
10969 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10970 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10973 stream->protection_scheme_type = FOURCC_cenc;
10980 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10981 QtDemuxStream ** stream2)
10983 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10987 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10992 /*parse svmi header if existing */
10993 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10995 guint32 len = QT_UINT32 ((guint8 *) svmi->data);
10996 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10998 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10999 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
11000 guint8 frame_type, frame_layout;
11001 guint32 stereo_mono_change_count;
11006 /* MPEG-A stereo video */
11007 if (qtdemux->major_brand == FOURCC_ss02)
11008 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
11010 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
11011 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
11012 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
11014 switch (frame_type) {
11016 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
11019 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
11022 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
11025 /* mode 3 is primary/secondary view sequence, ie
11026 * left/right views in separate tracks. See section 7.2
11027 * of ISO/IEC 23000-11:2009 */
11028 /* In the future this might be supported using related
11029 * streams, like an enhancement track - if files like this
11031 GST_FIXME_OBJECT (qtdemux,
11032 "Implement stereo video in separate streams");
11035 if ((frame_layout & 0x1) == 0)
11036 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
11038 GST_LOG_OBJECT (qtdemux,
11039 "StereoVideo: composition type: %u, is_left_first: %u",
11040 frame_type, frame_layout);
11042 if (stereo_mono_change_count > 1) {
11043 GST_FIXME_OBJECT (qtdemux,
11044 "Mixed-mono flags are not yet supported in qtdemux.");
11047 stream->multiview_mode = mode;
11048 stream->multiview_flags = flags;
11055 /* parse the traks.
11056 * With each track we associate a new QtDemuxStream that contains all the info
11058 * traks that do not decode to something (like strm traks) will not have a pad.
11061 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
11063 GstByteReader tkhd;
11077 QtDemuxStream *stream = NULL;
11078 const guint8 *stsd_data;
11079 const guint8 *stsd_entry_data;
11080 guint remaining_stsd_len;
11081 guint stsd_entry_count;
11083 guint16 lang_code; /* quicktime lang code or packed iso code */
11085 guint32 tkhd_flags = 0;
11086 guint8 tkhd_version = 0;
11087 guint32 w = 0, h = 0;
11088 guint value_size, stsd_len, len;
11092 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
11094 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
11095 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
11096 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
11099 /* pick between 64 or 32 bits */
11100 value_size = tkhd_version == 1 ? 8 : 4;
11101 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
11102 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
11105 /* Check if current moov has duplicated track_id */
11106 if (qtdemux_find_stream (qtdemux, track_id))
11107 goto existing_stream;
11109 stream = _create_stream (qtdemux, track_id);
11110 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11112 /* need defaults for fragments */
11113 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
11115 if ((tkhd_flags & 1) == 0)
11116 stream->disabled = TRUE;
11118 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
11119 tkhd_version, tkhd_flags, stream->track_id);
11121 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
11124 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
11125 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
11126 if (qtdemux->major_brand != FOURCC_mjp2 ||
11127 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
11131 len = QT_UINT32 ((guint8 *) mdhd->data);
11132 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
11133 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
11134 if (version == 0x01000000) {
11137 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
11138 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
11139 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
11143 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
11144 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
11145 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
11148 if (lang_code < 0x400) {
11149 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
11150 } else if (lang_code == 0x7fff) {
11151 stream->lang_id[0] = 0; /* unspecified */
11153 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11154 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11155 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11156 stream->lang_id[3] = 0;
11159 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11160 stream->timescale);
11161 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11163 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11164 lang_code, stream->lang_id);
11166 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11169 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11170 /* chapters track reference */
11171 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11173 gsize length = GST_READ_UINT32_BE (chap->data);
11174 if (qtdemux->chapters_track_id)
11175 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11177 if (length >= 12) {
11178 qtdemux->chapters_track_id =
11179 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11184 /* fragmented files may have bogus duration in moov */
11185 if (!qtdemux->fragmented &&
11186 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11187 guint64 tdur1, tdur2;
11189 /* don't overflow */
11190 tdur1 = stream->timescale * (guint64) qtdemux->duration;
11191 tdur2 = qtdemux->timescale * (guint64) stream->duration;
11194 * some of those trailers, nowadays, have prologue images that are
11195 * themselves video tracks as well. I haven't really found a way to
11196 * identify those yet, except for just looking at their duration. */
11197 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11198 GST_WARNING_OBJECT (qtdemux,
11199 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11200 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11201 "found, assuming preview image or something; skipping track",
11202 stream->duration, stream->timescale, qtdemux->duration,
11203 qtdemux->timescale);
11204 gst_qtdemux_stream_unref (stream);
11209 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11212 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11213 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11215 len = QT_UINT32 ((guint8 *) hdlr->data);
11217 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11218 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11219 GST_FOURCC_ARGS (stream->subtype));
11221 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11224 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11227 /* Parse out svmi (and later st3d/sv3d) atoms */
11228 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
11231 /* parse rest of tkhd */
11232 if (stream->subtype == FOURCC_vide) {
11235 /* version 1 uses some 64-bit ints */
11236 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11239 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11242 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11243 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11246 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11247 &stream->stream_tags);
11251 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11253 stsd_data = (const guint8 *) stsd->data;
11255 /* stsd should at least have one entry */
11256 stsd_len = QT_UINT32 (stsd_data);
11257 if (stsd_len < 24) {
11258 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11259 if (stream->subtype == FOURCC_vivo) {
11260 gst_qtdemux_stream_unref (stream);
11267 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11268 /* each stsd entry must contain at least 8 bytes */
11269 if (stream->stsd_entries_length == 0
11270 || stream->stsd_entries_length > stsd_len / 8) {
11271 stream->stsd_entries_length = 0;
11274 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11275 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
11276 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
11278 stsd_entry_data = stsd_data + 16;
11279 remaining_stsd_len = stsd_len - 16;
11280 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11282 gchar *codec = NULL;
11283 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11285 /* and that entry should fit within stsd */
11286 len = QT_UINT32 (stsd_entry_data);
11287 if (len > remaining_stsd_len)
11290 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11291 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
11292 GST_FOURCC_ARGS (entry->fourcc));
11293 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
11295 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11296 goto error_encrypted;
11298 if (fourcc == FOURCC_aavd) {
11299 if (stream->subtype != FOURCC_soun) {
11300 GST_ERROR_OBJECT (qtdemux,
11301 "Unexpeced stsd type 'aavd' outside 'soun' track");
11303 /* encrypted audio with sound sample description v0 */
11304 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11305 stream->protected = TRUE;
11306 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11307 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11311 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11312 /* FIXME this looks wrong, there might be multiple children
11313 * with the same type */
11314 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11315 stream->protected = TRUE;
11316 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11317 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11320 if (stream->subtype == FOURCC_vide) {
11325 gint depth, palette_size, palette_count;
11326 guint32 *palette_data = NULL;
11328 entry->sampled = TRUE;
11330 stream->display_width = w >> 16;
11331 stream->display_height = h >> 16;
11334 if (len < 86) /* TODO verify */
11337 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11338 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11339 entry->fps_n = 0; /* this is filled in later */
11340 entry->fps_d = 0; /* this is filled in later */
11341 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11342 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11344 /* if color_table_id is 0, ctab atom must follow; however some files
11345 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11346 * if color table is not present we'll correct the value */
11347 if (entry->color_table_id == 0 &&
11349 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11350 entry->color_table_id = -1;
11353 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11354 entry->width, entry->height, entry->bits_per_sample,
11355 entry->color_table_id);
11357 depth = entry->bits_per_sample;
11359 /* more than 32 bits means grayscale */
11360 gray = (depth > 32);
11361 /* low 32 bits specify the depth */
11364 /* different number of palette entries is determined by depth. */
11366 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11367 palette_count = (1 << depth);
11368 palette_size = palette_count * 4;
11370 if (entry->color_table_id) {
11371 switch (palette_count) {
11375 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11378 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11383 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11385 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11390 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11393 g_memdup2 (ff_qt_default_palette_256, palette_size);
11396 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11397 (_("The video in this file might not play correctly.")),
11398 ("unsupported palette depth %d", depth));
11402 guint i, j, start, end;
11408 start = QT_UINT32 (stsd_entry_data + offset + 70);
11409 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11410 end = QT_UINT16 (stsd_entry_data + offset + 76);
11412 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11413 start, end, palette_count);
11420 if (len < 94 + (end - start) * 8)
11423 /* palette is always the same size */
11424 palette_data = g_malloc0 (256 * 4);
11425 palette_size = 256 * 4;
11427 for (j = 0, i = start; i <= end; j++, i++) {
11428 guint32 a, r, g, b;
11430 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11431 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11432 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11433 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11435 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11436 (g & 0xff00) | (b >> 8);
11441 gst_caps_unref (entry->caps);
11444 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11446 if (G_UNLIKELY (!entry->caps)) {
11447 g_free (palette_data);
11448 goto unknown_stream;
11452 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11453 GST_TAG_VIDEO_CODEC, codec, NULL);
11458 if (palette_data) {
11461 if (entry->rgb8_palette)
11462 gst_memory_unref (entry->rgb8_palette);
11463 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11464 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11466 s = gst_caps_get_structure (entry->caps, 0);
11468 /* non-raw video has a palette_data property. raw video has the palette as
11469 * an extra plane that we append to the output buffers before we push
11471 if (!gst_structure_has_name (s, "video/x-raw")) {
11472 GstBuffer *palette;
11474 palette = gst_buffer_new ();
11475 gst_buffer_append_memory (palette, entry->rgb8_palette);
11476 entry->rgb8_palette = NULL;
11478 gst_caps_set_simple (entry->caps, "palette_data",
11479 GST_TYPE_BUFFER, palette, NULL);
11480 gst_buffer_unref (palette);
11482 } else if (palette_count != 0) {
11483 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11484 (NULL), ("Unsupported palette depth %d", depth));
11487 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11488 QT_UINT16 (stsd_entry_data + offset + 32));
11494 /* pick 'the' stsd child */
11495 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11496 // We should skip parsing the stsd for non-protected streams if
11497 // the entry doesn't match the fourcc, since they don't change
11498 // format. However, for protected streams we can have partial
11499 // encryption, where parts of the stream are encrypted and parts
11500 // not. For both parts of such streams, we should ensure the
11501 // esds overrides are parsed for both from the stsd.
11502 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11503 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11505 else if (!stream->protected)
11510 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11511 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11512 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11513 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11517 const guint8 *pasp_data = (const guint8 *) pasp->data;
11518 guint len = QT_UINT32 (pasp_data);
11521 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11522 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11524 CUR_STREAM (stream)->par_w = 0;
11525 CUR_STREAM (stream)->par_h = 0;
11528 CUR_STREAM (stream)->par_w = 0;
11529 CUR_STREAM (stream)->par_h = 0;
11533 const guint8 *fiel_data = (const guint8 *) fiel->data;
11534 guint len = QT_UINT32 (fiel_data);
11537 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11538 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11543 const guint8 *colr_data = (const guint8 *) colr->data;
11544 guint len = QT_UINT32 (colr_data);
11546 if (len == 19 || len == 18) {
11547 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11549 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11550 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11551 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11552 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11553 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11555 CUR_STREAM (stream)->colorimetry.primaries =
11556 gst_video_color_primaries_from_iso (primaries);
11557 CUR_STREAM (stream)->colorimetry.transfer =
11558 gst_video_transfer_function_from_iso (transfer_function);
11559 CUR_STREAM (stream)->colorimetry.matrix =
11560 gst_video_color_matrix_from_iso (matrix);
11561 CUR_STREAM (stream)->colorimetry.range =
11562 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11563 GST_VIDEO_COLOR_RANGE_16_235;
11565 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11568 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11573 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11574 stream->stream_tags);
11581 guint len = QT_UINT32 (stsd_entry_data);
11582 len = len <= 0x56 ? 0 : len - 0x56;
11583 const guint8 *avc_data = stsd_entry_data + 0x56;
11586 while (len >= 0x8) {
11589 if (QT_UINT32 (avc_data) <= 0x8)
11591 else if (QT_UINT32 (avc_data) <= len)
11592 size = QT_UINT32 (avc_data) - 0x8;
11597 /* No real data, so break out */
11600 switch (QT_FOURCC (avc_data + 0x4)) {
11603 /* parse, if found */
11606 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11608 /* First 4 bytes are the length of the atom, the next 4 bytes
11609 * are the fourcc, the next 1 byte is the version, and the
11610 * subsequent bytes are profile_tier_level structure like data. */
11611 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11612 avc_data + 8 + 1, size - 1);
11613 buf = gst_buffer_new_and_alloc (size);
11614 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11615 gst_caps_set_simple (entry->caps,
11616 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11617 gst_buffer_unref (buf);
11625 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11627 /* First 4 bytes are the length of the atom, the next 4 bytes
11628 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11629 * next 1 byte is the version, and the
11630 * subsequent bytes are sequence parameter set like data. */
11632 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11634 gst_codec_utils_h264_caps_set_level_and_profile
11635 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11637 buf = gst_buffer_new_and_alloc (size);
11638 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11639 gst_caps_set_simple (entry->caps,
11640 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11641 gst_buffer_unref (buf);
11647 guint avg_bitrate, max_bitrate;
11649 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11653 max_bitrate = QT_UINT32 (avc_data + 0xc);
11654 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11656 if (!max_bitrate && !avg_bitrate)
11659 /* Some muxers seem to swap the average and maximum bitrates
11660 * (I'm looking at you, YouTube), so we swap for sanity. */
11661 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11662 guint temp = avg_bitrate;
11664 avg_bitrate = max_bitrate;
11665 max_bitrate = temp;
11668 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11669 gst_tag_list_add (stream->stream_tags,
11670 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11671 max_bitrate, NULL);
11673 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11674 gst_tag_list_add (stream->stream_tags,
11675 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11687 avc_data += size + 8;
11698 guint len = QT_UINT32 (stsd_entry_data);
11699 len = len <= 0x56 ? 0 : len - 0x56;
11700 const guint8 *hevc_data = stsd_entry_data + 0x56;
11703 while (len >= 0x8) {
11706 if (QT_UINT32 (hevc_data) <= 0x8)
11708 else if (QT_UINT32 (hevc_data) <= len)
11709 size = QT_UINT32 (hevc_data) - 0x8;
11714 /* No real data, so break out */
11717 switch (QT_FOURCC (hevc_data + 0x4)) {
11720 /* parse, if found */
11723 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11725 /* First 4 bytes are the length of the atom, the next 4 bytes
11726 * are the fourcc, the next 1 byte is the version, and the
11727 * subsequent bytes are sequence parameter set like data. */
11728 gst_codec_utils_h265_caps_set_level_tier_and_profile
11729 (entry->caps, hevc_data + 8 + 1, size - 1);
11731 buf = gst_buffer_new_and_alloc (size);
11732 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11733 gst_caps_set_simple (entry->caps,
11734 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11735 gst_buffer_unref (buf);
11742 hevc_data += size + 8;
11755 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11756 GST_FOURCC_ARGS (fourcc));
11758 /* codec data might be in glbl extension atom */
11760 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11766 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11768 len = QT_UINT32 (data);
11771 buf = gst_buffer_new_and_alloc (len);
11772 gst_buffer_fill (buf, 0, data + 8, len);
11773 gst_caps_set_simple (entry->caps,
11774 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11775 gst_buffer_unref (buf);
11782 /* see annex I of the jpeg2000 spec */
11783 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11784 const guint8 *data;
11785 const gchar *colorspace = NULL;
11787 guint32 ncomp_map = 0;
11788 gint32 *comp_map = NULL;
11789 guint32 nchan_def = 0;
11790 gint32 *chan_def = NULL;
11792 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11793 /* some required atoms */
11794 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11797 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11801 /* number of components; redundant with info in codestream, but useful
11803 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11804 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11806 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11808 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11811 GST_DEBUG_OBJECT (qtdemux, "found colr");
11812 /* extract colour space info */
11813 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11814 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11816 colorspace = "sRGB";
11819 colorspace = "GRAY";
11822 colorspace = "sYUV";
11830 /* colr is required, and only values 16, 17, and 18 are specified,
11831 so error if we have no colorspace */
11834 /* extract component mapping */
11835 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11837 guint32 cmap_len = 0;
11839 cmap_len = QT_UINT32 (cmap->data);
11840 if (cmap_len >= 8) {
11841 /* normal box, subtract off header */
11843 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11844 if (cmap_len % 4 == 0) {
11845 ncomp_map = (cmap_len / 4);
11846 comp_map = g_new0 (gint32, ncomp_map);
11847 for (i = 0; i < ncomp_map; i++) {
11850 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11851 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11852 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11853 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11858 /* extract channel definitions */
11859 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11861 guint32 cdef_len = 0;
11863 cdef_len = QT_UINT32 (cdef->data);
11864 if (cdef_len >= 10) {
11865 /* normal box, subtract off header and len */
11867 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11868 if (cdef_len % 6 == 0) {
11869 nchan_def = (cdef_len / 6);
11870 chan_def = g_new0 (gint32, nchan_def);
11871 for (i = 0; i < nchan_def; i++)
11873 for (i = 0; i < nchan_def; i++) {
11874 guint16 cn, typ, asoc;
11875 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11876 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11877 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11878 if (cn < nchan_def) {
11881 chan_def[cn] = asoc;
11884 chan_def[cn] = 0; /* alpha */
11887 chan_def[cn] = -typ;
11895 gst_caps_set_simple (entry->caps,
11896 "num-components", G_TYPE_INT, ncomp, NULL);
11897 gst_caps_set_simple (entry->caps,
11898 "colorspace", G_TYPE_STRING, colorspace, NULL);
11901 GValue arr = { 0, };
11902 GValue elt = { 0, };
11904 g_value_init (&arr, GST_TYPE_ARRAY);
11905 g_value_init (&elt, G_TYPE_INT);
11906 for (i = 0; i < ncomp_map; i++) {
11907 g_value_set_int (&elt, comp_map[i]);
11908 gst_value_array_append_value (&arr, &elt);
11910 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11911 "component-map", &arr);
11912 g_value_unset (&elt);
11913 g_value_unset (&arr);
11918 GValue arr = { 0, };
11919 GValue elt = { 0, };
11921 g_value_init (&arr, GST_TYPE_ARRAY);
11922 g_value_init (&elt, G_TYPE_INT);
11923 for (i = 0; i < nchan_def; i++) {
11924 g_value_set_int (&elt, chan_def[i]);
11925 gst_value_array_append_value (&arr, &elt);
11927 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11928 "channel-definitions", &arr);
11929 g_value_unset (&elt);
11930 g_value_unset (&arr);
11934 /* some optional atoms */
11935 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11936 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11938 /* indicate possible fields in caps */
11940 data = (guint8 *) field->data + 8;
11942 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11943 (gint) * data, NULL);
11945 /* add codec_data if provided */
11950 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11951 data = prefix->data;
11952 len = QT_UINT32 (data);
11955 buf = gst_buffer_new_and_alloc (len);
11956 gst_buffer_fill (buf, 0, data + 8, len);
11957 gst_caps_set_simple (entry->caps,
11958 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11959 gst_buffer_unref (buf);
11968 GstBuffer *seqh = NULL;
11969 const guint8 *gamma_data = NULL;
11970 guint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11972 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11975 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11976 QT_FP32 (gamma_data), NULL);
11979 /* sorry for the bad name, but we don't know what this is, other
11980 * than its own fourcc */
11981 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11983 gst_buffer_unref (seqh);
11986 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11987 buf = gst_buffer_new_and_alloc (len);
11988 gst_buffer_fill (buf, 0, stsd_data, len);
11989 gst_caps_set_simple (entry->caps,
11990 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11991 gst_buffer_unref (buf);
11996 /* https://developer.apple.com/standards/qtff-2001.pdf,
11997 * page 92, "Video Sample Description", under table 3.1 */
12000 const gint compressor_offset =
12001 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
12002 const gint min_size = compressor_offset + 32 + 2 + 2;
12005 guint16 color_table_id = 0;
12008 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
12010 /* recover information on interlaced/progressive */
12011 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
12015 len = QT_UINT32 (jpeg->data);
12016 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
12018 if (len >= min_size) {
12019 gst_byte_reader_init (&br, jpeg->data, len);
12021 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
12022 gst_byte_reader_get_uint16_le (&br, &color_table_id);
12023 if (color_table_id != 0) {
12024 /* the spec says there can be concatenated chunks in the data, and we want
12025 * to find one called field. Walk through them. */
12026 gint offset = min_size;
12027 while (offset + 8 < len) {
12028 guint32 size = 0, tag;
12029 ok = gst_byte_reader_get_uint32_le (&br, &size);
12030 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
12031 if (!ok || size < 8) {
12032 GST_WARNING_OBJECT (qtdemux,
12033 "Failed to walk optional chunk list");
12036 GST_DEBUG_OBJECT (qtdemux,
12037 "Found optional %4.4s chunk, size %u",
12038 (const char *) &tag, size);
12039 if (tag == FOURCC_fiel) {
12040 guint8 n_fields = 0, ordering = 0;
12041 gst_byte_reader_get_uint8 (&br, &n_fields);
12042 gst_byte_reader_get_uint8 (&br, &ordering);
12043 if (n_fields == 1 || n_fields == 2) {
12044 GST_DEBUG_OBJECT (qtdemux,
12045 "Found fiel tag with %u fields, ordering %u",
12046 n_fields, ordering);
12048 gst_caps_set_simple (CUR_STREAM (stream)->caps,
12049 "interlace-mode", G_TYPE_STRING, "interleaved",
12052 GST_WARNING_OBJECT (qtdemux,
12053 "Found fiel tag with invalid fields (%u)", n_fields);
12059 GST_DEBUG_OBJECT (qtdemux,
12060 "Color table ID is 0, not trying to get interlacedness");
12063 GST_WARNING_OBJECT (qtdemux,
12064 "Length of jpeg chunk is too small, not trying to get interlacedness");
12072 gst_caps_set_simple (entry->caps,
12073 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
12079 GNode *xith, *xdxt;
12081 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
12082 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12086 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
12090 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
12091 /* collect the headers and store them in a stream list so that we can
12092 * send them out first */
12093 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
12103 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
12104 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12107 ovc1_data = ovc1->data;
12108 ovc1_len = QT_UINT32 (ovc1_data);
12109 if (ovc1_len <= 198) {
12110 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
12113 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
12114 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
12115 gst_caps_set_simple (entry->caps,
12116 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12117 gst_buffer_unref (buf);
12122 guint len = QT_UINT32 (stsd_entry_data);
12123 len = len <= 0x56 ? 0 : len - 0x56;
12124 const guint8 *vc1_data = stsd_entry_data + 0x56;
12130 if (QT_UINT32 (vc1_data) <= 8)
12132 else if (QT_UINT32 (vc1_data) <= len)
12133 size = QT_UINT32 (vc1_data) - 8;
12138 /* No real data, so break out */
12141 switch (QT_FOURCC (vc1_data + 0x4)) {
12142 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
12146 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
12147 buf = gst_buffer_new_and_alloc (size);
12148 gst_buffer_fill (buf, 0, vc1_data + 8, size);
12149 gst_caps_set_simple (entry->caps,
12150 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12151 gst_buffer_unref (buf);
12158 vc1_data += size + 8;
12164 guint len = QT_UINT32 (stsd_entry_data);
12165 len = len <= 0x56 ? 0 : len - 0x56;
12166 const guint8 *av1_data = stsd_entry_data + 0x56;
12169 while (len >= 0x8) {
12172 if (QT_UINT32 (av1_data) <= 0x8)
12174 else if (QT_UINT32 (av1_data) <= len)
12175 size = QT_UINT32 (av1_data) - 0x8;
12180 /* No real data, so break out */
12183 switch (QT_FOURCC (av1_data + 0x4)) {
12186 /* parse, if found */
12188 guint8 pres_delay_field;
12190 GST_DEBUG_OBJECT (qtdemux,
12191 "found av1C codec_data in stsd of size %d", size);
12193 /* not enough data, just ignore and hope for the best */
12198 * 4 bytes: atom length
12203 * 1 bits: initial_presentation_delay_present
12204 * 4 bits: initial_presentation_delay (if present else reserved
12208 if (av1_data[9] != 0) {
12209 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
12213 /* We skip initial_presentation_delay* for now */
12214 pres_delay_field = *(av1_data + 12);
12215 if (pres_delay_field & (1 << 5)) {
12216 gst_caps_set_simple (entry->caps,
12217 "presentation-delay", G_TYPE_INT,
12218 (gint) (pres_delay_field & 0x0F) + 1, NULL);
12221 buf = gst_buffer_new_and_alloc (size - 5);
12222 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12223 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12224 gst_caps_set_simple (entry->caps,
12225 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12226 gst_buffer_unref (buf);
12235 av1_data += size + 8;
12241 /* TODO: Need to parse vpcC for VP8 codec too.
12242 * Note that VPCodecConfigurationBox (vpcC) is defined for
12243 * vp08, vp09, and vp10 fourcc. */
12246 guint len = QT_UINT32 (stsd_entry_data);
12247 len = len <= 0x56 ? 0 : len - 0x56;
12248 const guint8 *vpcc_data = stsd_entry_data + 0x56;
12251 while (len >= 0x8) {
12254 if (QT_UINT32 (vpcc_data) <= 0x8)
12256 else if (QT_UINT32 (vpcc_data) <= len)
12257 size = QT_UINT32 (vpcc_data) - 0x8;
12262 /* No real data, so break out */
12265 switch (QT_FOURCC (vpcc_data + 0x4)) {
12268 const gchar *profile_str = NULL;
12269 const gchar *chroma_format_str = NULL;
12272 guint8 chroma_format;
12273 GstVideoColorimetry cinfo;
12275 /* parse, if found */
12276 GST_DEBUG_OBJECT (qtdemux,
12277 "found vp codec_data in stsd of size %d", size);
12279 /* the meaning of "size" is length of the atom body, excluding
12280 * atom length and fourcc fields */
12285 * 4 bytes: atom length
12292 * 3 bits: chromaSubsampling
12293 * 1 bit: videoFullRangeFlag
12294 * 1 byte: colourPrimaries
12295 * 1 byte: transferCharacteristics
12296 * 1 byte: matrixCoefficients
12297 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
12298 * rest: codecIntializationData (not used for vp8 and vp9)
12301 if (vpcc_data[8] != 1) {
12302 GST_WARNING_OBJECT (qtdemux,
12303 "unknown vpcC version %d", vpcc_data[8]);
12307 profile = vpcc_data[12];
12326 gst_caps_set_simple (entry->caps,
12327 "profile", G_TYPE_STRING, profile_str, NULL);
12330 /* skip level, the VP9 spec v0.6 defines only one level atm,
12331 * but webm spec define various ones. Add level to caps
12332 * if we really need it then */
12334 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12335 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12336 gst_caps_set_simple (entry->caps,
12337 "bit-depth-luma", G_TYPE_UINT, bitdepth,
12338 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12341 chroma_format = (vpcc_data[14] & 0xe) >> 1;
12342 switch (chroma_format) {
12345 chroma_format_str = "4:2:0";
12348 chroma_format_str = "4:2:2";
12351 chroma_format_str = "4:4:4";
12357 if (chroma_format_str) {
12358 gst_caps_set_simple (entry->caps,
12359 "chroma-format", G_TYPE_STRING, chroma_format_str,
12363 if ((vpcc_data[14] & 0x1) != 0)
12364 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12366 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12368 gst_video_color_primaries_from_iso (vpcc_data[15]);
12370 gst_video_transfer_function_from_iso (vpcc_data[16]);
12372 gst_video_color_matrix_from_iso (vpcc_data[17]);
12374 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12375 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12376 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12377 /* set this only if all values are known, otherwise this
12378 * might overwrite valid ones parsed from other color box */
12379 CUR_STREAM (stream)->colorimetry = cinfo;
12388 vpcc_data += size + 8;
12398 GST_INFO_OBJECT (qtdemux,
12399 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12400 GST_FOURCC_ARGS (fourcc), entry->caps);
12402 } else if (stream->subtype == FOURCC_soun) {
12404 guint version, samplesize;
12405 guint16 compression_id;
12406 gboolean amrwb = FALSE;
12409 /* sample description entry (16) + sound sample description v0 (20) */
12413 version = QT_UINT32 (stsd_entry_data + offset);
12414 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12415 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12416 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12417 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12419 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12420 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12421 QT_UINT32 (stsd_entry_data + offset + 4));
12422 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12423 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12424 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12425 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12426 QT_UINT16 (stsd_entry_data + offset + 14));
12427 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12429 if (compression_id == 0xfffe)
12430 entry->sampled = TRUE;
12432 /* first assume uncompressed audio */
12433 entry->bytes_per_sample = samplesize / 8;
12434 entry->samples_per_frame = entry->n_channels;
12435 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12436 entry->samples_per_packet = entry->samples_per_frame;
12437 entry->bytes_per_packet = entry->bytes_per_sample;
12441 if (version == 0x00010000) {
12442 /* sample description entry (16) + sound sample description v1 (20+16) */
12446 /* take information from here over the normal sample description */
12447 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12448 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12449 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12450 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12452 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12453 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12454 entry->samples_per_packet);
12455 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12456 entry->bytes_per_packet);
12457 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12458 entry->bytes_per_frame);
12459 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12460 entry->bytes_per_sample);
12462 if (!entry->sampled && entry->bytes_per_packet) {
12463 entry->samples_per_frame = (entry->bytes_per_frame /
12464 entry->bytes_per_packet) * entry->samples_per_packet;
12465 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12466 entry->samples_per_frame);
12468 } else if (version == 0x00020000) {
12469 /* sample description entry (16) + sound sample description v2 (56) */
12473 /* take information from here over the normal sample description */
12474 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12475 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12476 entry->samples_per_frame = entry->n_channels;
12477 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12478 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12479 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12480 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12482 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12483 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12484 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12485 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12486 entry->bytes_per_sample * 8);
12487 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12488 QT_UINT32 (stsd_entry_data + offset + 24));
12489 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12490 entry->bytes_per_packet);
12491 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12492 entry->samples_per_packet);
12493 } else if (version != 0x00000) {
12494 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12499 /* Yes, these have to be hard-coded */
12502 entry->samples_per_packet = 6;
12503 entry->bytes_per_packet = 1;
12504 entry->bytes_per_frame = 1 * entry->n_channels;
12505 entry->bytes_per_sample = 1;
12506 entry->samples_per_frame = 6 * entry->n_channels;
12511 entry->samples_per_packet = 3;
12512 entry->bytes_per_packet = 1;
12513 entry->bytes_per_frame = 1 * entry->n_channels;
12514 entry->bytes_per_sample = 1;
12515 entry->samples_per_frame = 3 * entry->n_channels;
12520 entry->samples_per_packet = 64;
12521 entry->bytes_per_packet = 34;
12522 entry->bytes_per_frame = 34 * entry->n_channels;
12523 entry->bytes_per_sample = 2;
12524 entry->samples_per_frame = 64 * entry->n_channels;
12530 entry->samples_per_packet = 1;
12531 entry->bytes_per_packet = 1;
12532 entry->bytes_per_frame = 1 * entry->n_channels;
12533 entry->bytes_per_sample = 1;
12534 entry->samples_per_frame = 1 * entry->n_channels;
12539 entry->samples_per_packet = 160;
12540 entry->bytes_per_packet = 33;
12541 entry->bytes_per_frame = 33 * entry->n_channels;
12542 entry->bytes_per_sample = 2;
12543 entry->samples_per_frame = 160 * entry->n_channels;
12546 /* fix up any invalid header information from above */
12551 /* Sometimes these are set to 0 in the sound sample descriptions so
12552 * let's try to infer useful values from the other information we
12553 * have available */
12554 if (entry->bytes_per_sample == 0)
12555 entry->bytes_per_sample =
12556 entry->bytes_per_frame / entry->n_channels;
12557 if (entry->bytes_per_sample == 0)
12558 entry->bytes_per_sample = samplesize / 8;
12560 if (entry->bytes_per_frame == 0)
12561 entry->bytes_per_frame =
12562 entry->bytes_per_sample * entry->n_channels;
12564 if (entry->bytes_per_packet == 0)
12565 entry->bytes_per_packet = entry->bytes_per_sample;
12567 if (entry->samples_per_frame == 0)
12568 entry->samples_per_frame = entry->n_channels;
12570 if (entry->samples_per_packet == 0)
12571 entry->samples_per_packet = entry->samples_per_frame;
12581 entry->bytes_per_sample = 3;
12585 entry->bytes_per_sample = 4;
12588 entry->bytes_per_sample = 8;
12591 entry->bytes_per_sample = 2;
12594 g_assert_not_reached ();
12597 entry->samples_per_frame = entry->n_channels;
12598 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12599 entry->samples_per_packet = entry->samples_per_frame;
12600 entry->bytes_per_packet = entry->bytes_per_sample;
12608 gst_caps_unref (entry->caps);
12610 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12611 stsd_entry_data + 32, len - 16, &codec);
12622 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12624 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12626 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12628 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12631 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12632 const gchar *format_str;
12636 format_str = (enda_value) ? "S24LE" : "S24BE";
12639 format_str = (enda_value) ? "S32LE" : "S32BE";
12642 format_str = (enda_value) ? "F32LE" : "F32BE";
12645 format_str = (enda_value) ? "F64LE" : "F64BE";
12648 g_assert_not_reached ();
12651 gst_caps_set_simple (entry->caps,
12652 "format", G_TYPE_STRING, format_str, NULL);
12658 const guint8 *owma_data;
12659 const gchar *codec_name = NULL;
12663 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12664 /* FIXME this should also be gst_riff_strf_auds,
12665 * but the latter one is actually missing bits-per-sample :( */
12670 gint32 nSamplesPerSec;
12671 gint32 nAvgBytesPerSec;
12672 gint16 nBlockAlign;
12673 gint16 wBitsPerSample;
12676 WAVEFORMATEX *wfex;
12678 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12679 owma_data = stsd_entry_data;
12680 owma_len = QT_UINT32 (owma_data);
12681 if (owma_len <= 54) {
12682 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12685 wfex = (WAVEFORMATEX *) (owma_data + 36);
12686 buf = gst_buffer_new_and_alloc (owma_len - 54);
12687 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12688 if (wfex->wFormatTag == 0x0161) {
12689 codec_name = "Windows Media Audio";
12691 } else if (wfex->wFormatTag == 0x0162) {
12692 codec_name = "Windows Media Audio 9 Pro";
12694 } else if (wfex->wFormatTag == 0x0163) {
12695 codec_name = "Windows Media Audio 9 Lossless";
12696 /* is that correct? gstffmpegcodecmap.c is missing it, but
12697 * fluendo codec seems to support it */
12701 gst_caps_set_simple (entry->caps,
12702 "codec_data", GST_TYPE_BUFFER, buf,
12703 "wmaversion", G_TYPE_INT, version,
12704 "block_align", G_TYPE_INT,
12705 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12706 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12707 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12708 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12709 gst_buffer_unref (buf);
12713 codec = g_strdup (codec_name);
12719 guint len = QT_UINT32 (stsd_entry_data);
12720 len = len <= offset ? 0 : len - offset;
12721 const guint8 *wfex_data = stsd_entry_data + offset;
12722 const gchar *codec_name = NULL;
12724 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12725 /* FIXME this should also be gst_riff_strf_auds,
12726 * but the latter one is actually missing bits-per-sample :( */
12731 gint32 nSamplesPerSec;
12732 gint32 nAvgBytesPerSec;
12733 gint16 nBlockAlign;
12734 gint16 wBitsPerSample;
12739 /* FIXME: unify with similar wavformatex parsing code above */
12740 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12746 if (QT_UINT32 (wfex_data) <= 0x8)
12748 else if (QT_UINT32 (wfex_data) <= len)
12749 size = QT_UINT32 (wfex_data) - 8;
12754 /* No real data, so break out */
12757 switch (QT_FOURCC (wfex_data + 4)) {
12758 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12760 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12765 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12766 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12767 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12768 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12769 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12770 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12771 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12773 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12774 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12775 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12776 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12777 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12778 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12780 if (wfex.wFormatTag == 0x0161) {
12781 codec_name = "Windows Media Audio";
12783 } else if (wfex.wFormatTag == 0x0162) {
12784 codec_name = "Windows Media Audio 9 Pro";
12786 } else if (wfex.wFormatTag == 0x0163) {
12787 codec_name = "Windows Media Audio 9 Lossless";
12788 /* is that correct? gstffmpegcodecmap.c is missing it, but
12789 * fluendo codec seems to support it */
12793 gst_caps_set_simple (entry->caps,
12794 "wmaversion", G_TYPE_INT, version,
12795 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12796 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12797 "width", G_TYPE_INT, wfex.wBitsPerSample,
12798 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12800 if (size > wfex.cbSize) {
12803 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12804 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12805 size - wfex.cbSize);
12806 gst_caps_set_simple (entry->caps,
12807 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12808 gst_buffer_unref (buf);
12810 GST_WARNING_OBJECT (qtdemux, "no codec data");
12815 codec = g_strdup (codec_name);
12823 wfex_data += size + 8;
12829 const guint8 *dops_data;
12830 guint8 *channel_mapping = NULL;
12833 guint8 channel_mapping_family;
12834 guint8 stream_count;
12835 guint8 coupled_count;
12838 version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12840 dops_data = stsd_entry_data + 51;
12842 dops_data = stsd_entry_data + 35;
12844 channels = GST_READ_UINT8 (dops_data + 10);
12845 rate = GST_READ_UINT32_LE (dops_data + 13);
12846 channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12847 stream_count = GST_READ_UINT8 (dops_data + 20);
12848 coupled_count = GST_READ_UINT8 (dops_data + 21);
12850 if (channels > 0) {
12851 channel_mapping = g_malloc (channels * sizeof (guint8));
12852 for (i = 0; i < channels; i++)
12853 channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12856 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12857 channel_mapping_family, stream_count, coupled_count,
12859 g_free (channel_mapping);
12870 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12871 GST_TAG_AUDIO_CODEC, codec, NULL);
12875 /* some bitrate info may have ended up in caps */
12876 s = gst_caps_get_structure (entry->caps, 0);
12877 gst_structure_get_int (s, "bitrate", &bitrate);
12879 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12880 GST_TAG_BITRATE, bitrate, NULL);
12884 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12885 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12886 if (stream->protected) {
12887 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12888 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12890 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12900 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12902 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12904 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12908 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12909 16 bits is a byte-swapped wave-style codec identifier,
12910 and we can find a WAVE header internally to a 'wave' atom here.
12911 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12912 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12915 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12916 if (len < offset + 20) {
12917 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12919 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12920 const guint8 *data = stsd_entry_data + offset + 16;
12922 GNode *waveheadernode;
12924 wavenode = g_node_new ((guint8 *) data);
12925 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12926 const guint8 *waveheader;
12929 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12930 if (waveheadernode) {
12931 waveheader = (const guint8 *) waveheadernode->data;
12932 headerlen = QT_UINT32 (waveheader);
12934 if (headerlen > 8) {
12935 gst_riff_strf_auds *header = NULL;
12936 GstBuffer *headerbuf;
12942 headerbuf = gst_buffer_new_and_alloc (headerlen);
12943 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12945 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12946 headerbuf, &header, &extra)) {
12947 gst_caps_unref (entry->caps);
12948 /* FIXME: Need to do something with the channel reorder map */
12950 gst_riff_create_audio_caps (header->format, NULL, header,
12951 extra, NULL, NULL, NULL);
12954 gst_buffer_unref (extra);
12959 GST_DEBUG ("Didn't find waveheadernode for this codec");
12961 g_node_destroy (wavenode);
12964 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12965 stream->stream_tags);
12969 /* FIXME: what is in the chunk? */
12972 gint len = QT_UINT32 (stsd_data);
12974 /* seems to be always = 116 = 0x74 */
12980 gint len = QT_UINT32 (stsd_entry_data);
12983 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12985 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12986 gst_caps_set_simple (entry->caps,
12987 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12988 gst_buffer_unref (buf);
12990 gst_caps_set_simple (entry->caps,
12991 "samplesize", G_TYPE_INT, samplesize, NULL);
12996 GNode *alac, *wave = NULL;
12998 /* apparently, m4a has this atom appended directly in the stsd entry,
12999 * while mov has it in a wave atom */
13000 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
13002 /* alac now refers to stsd entry atom */
13003 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
13005 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
13007 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
13010 const guint8 *alac_data = alac->data;
13011 gint len = QT_UINT32 (alac->data);
13015 GST_DEBUG_OBJECT (qtdemux,
13016 "discarding alac atom with unexpected len %d", len);
13018 /* codec-data contains alac atom size and prefix,
13019 * ffmpeg likes it that way, not quite gst-ish though ...*/
13020 buf = gst_buffer_new_and_alloc (len);
13021 gst_buffer_fill (buf, 0, alac->data, len);
13022 gst_caps_set_simple (entry->caps,
13023 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13024 gst_buffer_unref (buf);
13026 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
13027 entry->n_channels = QT_UINT8 (alac_data + 21);
13028 entry->rate = QT_UINT32 (alac_data + 32);
13029 samplesize = QT_UINT8 (alac_data + 16 + 1);
13032 gst_caps_set_simple (entry->caps,
13033 "samplesize", G_TYPE_INT, samplesize, NULL);
13038 /* The codingname of the sample entry is 'fLaC' */
13039 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
13042 /* The 'dfLa' box is added to the sample entry to convey
13043 initializing information for the decoder. */
13044 const GNode *dfla =
13045 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
13048 const guint32 len = QT_UINT32 (dfla->data);
13050 /* Must contain at least dfLa box header (12),
13051 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
13053 GST_DEBUG_OBJECT (qtdemux,
13054 "discarding dfla atom with unexpected len %d", len);
13056 /* skip dfLa header to get the METADATA_BLOCKs */
13057 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
13058 const guint32 metadata_blocks_len = len - 12;
13060 gchar *stream_marker = g_strdup ("fLaC");
13061 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
13062 strlen (stream_marker));
13065 guint32 remainder = 0;
13066 guint32 block_size = 0;
13067 gboolean is_last = FALSE;
13069 GValue array = G_VALUE_INIT;
13070 GValue value = G_VALUE_INIT;
13072 g_value_init (&array, GST_TYPE_ARRAY);
13073 g_value_init (&value, GST_TYPE_BUFFER);
13075 gst_value_set_buffer (&value, block);
13076 gst_value_array_append_value (&array, &value);
13077 g_value_reset (&value);
13079 gst_buffer_unref (block);
13081 /* check there's at least one METADATA_BLOCK_HEADER's worth
13082 * of data, and we haven't already finished parsing */
13083 while (!is_last && ((index + 3) < metadata_blocks_len)) {
13084 remainder = metadata_blocks_len - index;
13086 /* add the METADATA_BLOCK_HEADER size to the signalled size */
13088 (metadata_blocks[index + 1] << 16) +
13089 (metadata_blocks[index + 2] << 8) +
13090 metadata_blocks[index + 3];
13092 /* be careful not to read off end of box */
13093 if (block_size > remainder) {
13097 is_last = metadata_blocks[index] >> 7;
13099 block = gst_buffer_new_and_alloc (block_size);
13101 gst_buffer_fill (block, 0, &metadata_blocks[index],
13104 gst_value_set_buffer (&value, block);
13105 gst_value_array_append_value (&array, &value);
13106 g_value_reset (&value);
13108 gst_buffer_unref (block);
13110 index += block_size;
13113 /* only append the metadata if we successfully read all of it */
13115 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
13116 (stream)->caps, 0), "streamheader", &array);
13118 GST_WARNING_OBJECT (qtdemux,
13119 "discarding all METADATA_BLOCKs due to invalid "
13120 "block_size %d at idx %d, rem %d", block_size, index,
13124 g_value_unset (&value);
13125 g_value_unset (&array);
13127 /* The sample rate obtained from the stsd may not be accurate
13128 * since it cannot represent rates greater than 65535Hz, so
13129 * override that value with the sample rate from the
13130 * METADATA_BLOCK_STREAMINFO block */
13131 CUR_STREAM (stream)->rate =
13132 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
13143 gint len = QT_UINT32 (stsd_entry_data);
13146 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
13149 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
13151 /* If we have enough data, let's try to get the 'damr' atom. See
13152 * the 3GPP container spec (26.244) for more details. */
13153 if ((len - 0x34) > 8 &&
13154 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
13155 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13156 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
13159 gst_caps_set_simple (entry->caps,
13160 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13161 gst_buffer_unref (buf);
13167 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
13168 gint len = QT_UINT32 (stsd_entry_data);
13169 guint16 sound_version = 0;
13170 /* FIXME: Can this be determined somehow? There doesn't seem to be
13171 * anything in mp4a atom that specifis compression */
13173 guint16 channels = entry->n_channels;
13174 guint32 time_scale = (guint32) entry->rate;
13175 gint sample_rate_index = -1;
13178 sound_version = QT_UINT16 (stsd_entry_data + 16);
13180 if (sound_version == 1) {
13181 channels = QT_UINT16 (stsd_entry_data + 24);
13182 time_scale = QT_UINT32 (stsd_entry_data + 30);
13184 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
13188 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
13192 sample_rate_index =
13193 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
13194 if (sample_rate_index >= 0 && channels > 0) {
13195 guint8 codec_data[2];
13198 /* build AAC codec data */
13199 codec_data[0] = profile << 3;
13200 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
13201 codec_data[1] = (sample_rate_index & 0x01) << 7;
13202 codec_data[1] |= (channels & 0xF) << 3;
13204 buf = gst_buffer_new_and_alloc (2);
13205 gst_buffer_fill (buf, 0, codec_data, 2);
13206 gst_caps_set_simple (entry->caps,
13207 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13208 gst_buffer_unref (buf);
13218 /* Fully handled elsewhere */
13221 GST_INFO_OBJECT (qtdemux,
13222 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13226 GST_INFO_OBJECT (qtdemux,
13227 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13228 GST_FOURCC_ARGS (fourcc), entry->caps);
13230 } else if (stream->subtype == FOURCC_strm) {
13231 if (fourcc == FOURCC_rtsp) {
13232 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
13234 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
13235 GST_FOURCC_ARGS (fourcc));
13236 goto unknown_stream;
13238 entry->sampled = TRUE;
13239 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
13240 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
13241 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
13243 entry->sampled = TRUE;
13244 entry->sparse = TRUE;
13247 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13250 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13251 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13256 /* hunt for sort-of codec data */
13260 GNode *mp4s = NULL;
13261 GNode *esds = NULL;
13263 /* look for palette in a stsd->mp4s->esds sub-atom */
13264 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
13266 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
13267 if (esds == NULL) {
13269 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13273 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13274 stream->stream_tags);
13278 GST_INFO_OBJECT (qtdemux,
13279 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13282 GST_INFO_OBJECT (qtdemux,
13283 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13284 GST_FOURCC_ARGS (fourcc), entry->caps);
13285 } else if (stream->subtype == FOURCC_meta) {
13286 entry->sampled = TRUE;
13287 entry->sparse = TRUE;
13290 qtdemux_meta_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13293 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13294 GST_TAG_CODEC, codec, NULL);
13299 GST_INFO_OBJECT (qtdemux,
13300 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13301 GST_FOURCC_ARGS (fourcc), entry->caps);
13303 /* everything in 1 sample */
13304 entry->sampled = TRUE;
13307 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13310 if (entry->caps == NULL)
13311 goto unknown_stream;
13314 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13315 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13321 /* promote to sampled format */
13322 if (entry->fourcc == FOURCC_samr) {
13323 /* force mono 8000 Hz for AMR */
13324 entry->sampled = TRUE;
13325 entry->n_channels = 1;
13326 entry->rate = 8000;
13327 } else if (entry->fourcc == FOURCC_sawb) {
13328 /* force mono 16000 Hz for AMR-WB */
13329 entry->sampled = TRUE;
13330 entry->n_channels = 1;
13331 entry->rate = 16000;
13332 } else if (entry->fourcc == FOURCC_mp4a) {
13333 entry->sampled = TRUE;
13337 stsd_entry_data += len;
13338 remaining_stsd_len -= len;
13342 /* collect sample information */
13343 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13344 goto samples_failed;
13346 if (qtdemux->fragmented) {
13349 /* need all moov samples as basis; probably not many if any at all */
13350 /* prevent moof parsing taking of at this time */
13351 offset = qtdemux->moof_offset;
13352 qtdemux->moof_offset = 0;
13353 if (stream->n_samples &&
13354 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13355 qtdemux->moof_offset = offset;
13356 goto samples_failed;
13358 qtdemux->moof_offset = offset;
13359 /* movie duration more reliable in this case (e.g. mehd) */
13360 if (qtdemux->segment.duration &&
13361 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13363 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13366 /* configure segments */
13367 if (!qtdemux_parse_segments (qtdemux, stream, trak))
13368 goto segments_failed;
13370 /* add some language tag, if useful */
13371 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13372 strcmp (stream->lang_id, "und")) {
13373 const gchar *lang_code;
13375 /* convert ISO 639-2 code to ISO 639-1 */
13376 lang_code = gst_tag_get_language_code (stream->lang_id);
13377 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13378 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13381 /* Check for UDTA tags */
13382 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13383 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13386 /* Insert and sort new stream in track-id order.
13387 * This will help in comparing old/new streams during stream update check */
13388 g_ptr_array_add (qtdemux->active_streams, stream);
13389 g_ptr_array_sort (qtdemux->active_streams,
13390 (GCompareFunc) qtdemux_track_id_compare_func);
13391 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13392 QTDEMUX_N_STREAMS (qtdemux));
13399 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13400 (_("This file is corrupt and cannot be played.")), (NULL));
13402 gst_qtdemux_stream_unref (stream);
13407 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13408 gst_qtdemux_stream_unref (stream);
13414 /* we posted an error already */
13415 /* free stbl sub-atoms */
13416 gst_qtdemux_stbl_free (stream);
13417 gst_qtdemux_stream_unref (stream);
13422 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13428 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13429 GST_FOURCC_ARGS (stream->subtype));
13430 gst_qtdemux_stream_unref (stream);
13435 /* If we can estimate the overall bitrate, and don't have information about the
13436 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13437 * the overall bitrate minus the sum of the bitrates of all other streams. This
13438 * should be useful for the common case where we have one audio and one video
13439 * stream and can estimate the bitrate of one, but not the other. */
13441 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13443 QtDemuxStream *stream = NULL;
13444 gint64 size, sys_bitrate, sum_bitrate = 0;
13445 GstClockTime duration;
13449 if (qtdemux->fragmented)
13452 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13454 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13456 GST_DEBUG_OBJECT (qtdemux,
13457 "Size in bytes of the stream not known - bailing");
13461 /* Subtract the header size */
13462 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13463 size, qtdemux->header_size);
13465 if (size < qtdemux->header_size)
13468 size = size - qtdemux->header_size;
13470 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13471 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13475 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13476 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13477 switch (str->subtype) {
13480 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13481 CUR_STREAM (str)->caps);
13482 /* retrieve bitrate, prefer avg then max */
13484 if (str->stream_tags) {
13485 if (gst_tag_list_get_uint (str->stream_tags,
13486 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13487 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13488 if (gst_tag_list_get_uint (str->stream_tags,
13489 GST_TAG_NOMINAL_BITRATE, &bitrate))
13490 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13491 if (gst_tag_list_get_uint (str->stream_tags,
13492 GST_TAG_BITRATE, &bitrate))
13493 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13496 sum_bitrate += bitrate;
13499 GST_DEBUG_OBJECT (qtdemux,
13500 ">1 stream with unknown bitrate - bailing");
13507 /* For other subtypes, we assume no significant impact on bitrate */
13513 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13517 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13519 if (sys_bitrate < sum_bitrate) {
13520 /* This can happen, since sum_bitrate might be derived from maximum
13521 * bitrates and not average bitrates */
13522 GST_DEBUG_OBJECT (qtdemux,
13523 "System bitrate less than sum bitrate - bailing");
13527 bitrate = sys_bitrate - sum_bitrate;
13528 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13529 ", Stream bitrate = %u", sys_bitrate, bitrate);
13531 if (!stream->stream_tags)
13532 stream->stream_tags = gst_tag_list_new_empty ();
13534 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13536 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13537 GST_TAG_BITRATE, bitrate, NULL);
13540 static GstFlowReturn
13541 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13543 GstFlowReturn ret = GST_FLOW_OK;
13546 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13548 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13549 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13550 guint32 sample_num = 0;
13552 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13553 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13555 if (qtdemux->fragmented && qtdemux->pullbased) {
13556 /* need all moov samples first */
13557 GST_OBJECT_LOCK (qtdemux);
13558 while (stream->n_samples == 0)
13559 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13561 GST_OBJECT_UNLOCK (qtdemux);
13563 /* discard any stray moof */
13564 qtdemux->moof_offset = 0;
13567 /* prepare braking */
13568 if (ret != GST_FLOW_ERROR)
13571 /* in pull mode, we should have parsed some sample info by now;
13572 * and quite some code will not handle no samples.
13573 * in push mode, we'll just have to deal with it */
13574 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13575 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13576 g_ptr_array_remove_index (qtdemux->active_streams, i);
13579 } else if (stream->track_id == qtdemux->chapters_track_id &&
13580 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13581 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13582 so that it doesn't look like a subtitle track */
13583 g_ptr_array_remove_index (qtdemux->active_streams, i);
13588 /* parse the initial sample for use in setting the frame rate cap */
13589 while (sample_num == 0 && sample_num < stream->n_samples) {
13590 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13600 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13602 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13606 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13610 /* Different length, updated */
13611 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13614 /* streams in list are sorted in track-id order */
13615 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13616 /* Different stream-id, updated */
13617 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13618 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13626 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13627 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13629 /* Connect old stream's srcpad to new stream */
13630 newstream->pad = oldstream->pad;
13631 oldstream->pad = NULL;
13633 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13634 * case we need to force one through */
13635 newstream->new_stream = newstream->pad != NULL
13636 && GST_PAD_IS_EOS (newstream->pad);
13638 return gst_qtdemux_configure_stream (qtdemux, newstream);
13642 qtdemux_update_streams (GstQTDemux * qtdemux)
13645 g_assert (qtdemux->streams_aware);
13647 /* At below, figure out which stream in active_streams has identical stream-id
13648 * with that of in old_streams. If there is matching stream-id,
13649 * corresponding newstream will not be exposed again,
13650 * but demux will reuse srcpad of matched old stream
13652 * active_streams : newly created streams from the latest moov
13653 * old_streams : existing streams (belong to previous moov)
13656 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13657 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13658 QtDemuxStream *oldstream = NULL;
13661 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13662 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13664 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13665 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13666 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13668 /* null pad stream cannot be reused */
13669 if (oldstream->pad == NULL)
13674 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13676 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13679 /* we don't need to preserve order of old streams */
13680 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13684 /* now we have all info and can expose */
13685 list = stream->stream_tags;
13686 stream->stream_tags = NULL;
13687 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13695 /* Must be called with expose lock */
13696 static GstFlowReturn
13697 qtdemux_expose_streams (GstQTDemux * qtdemux)
13701 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13703 if (!qtdemux_is_streams_update (qtdemux)) {
13704 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13705 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13706 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13707 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13708 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13709 return GST_FLOW_ERROR;
13712 g_ptr_array_set_size (qtdemux->old_streams, 0);
13713 qtdemux->need_segment = TRUE;
13715 return GST_FLOW_OK;
13718 if (qtdemux->streams_aware) {
13719 if (!qtdemux_update_streams (qtdemux))
13720 return GST_FLOW_ERROR;
13722 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13723 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13726 /* now we have all info and can expose */
13727 list = stream->stream_tags;
13728 stream->stream_tags = NULL;
13729 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13730 return GST_FLOW_ERROR;
13735 gst_qtdemux_guess_bitrate (qtdemux);
13737 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13739 /* If we have still old_streams, it's no more used stream */
13740 for (i = 0; i < qtdemux->old_streams->len; i++) {
13741 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13746 event = gst_event_new_eos ();
13747 if (qtdemux->segment_seqnum)
13748 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13750 gst_pad_push_event (stream->pad, event);
13754 g_ptr_array_set_size (qtdemux->old_streams, 0);
13756 /* check if we should post a redirect in case there is a single trak
13757 * and it is a redirecting trak */
13758 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13759 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13762 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13763 "an external content");
13764 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13765 gst_structure_new ("redirect",
13766 "new-location", G_TYPE_STRING,
13767 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13768 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13769 g_free (qtdemux->redirect_location);
13770 qtdemux->redirect_location =
13771 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13774 g_ptr_array_foreach (qtdemux->active_streams,
13775 (GFunc) qtdemux_do_allocation, qtdemux);
13777 qtdemux->need_segment = TRUE;
13779 qtdemux->exposed = TRUE;
13780 return GST_FLOW_OK;
13785 GstStructure *structure; /* helper for sort function */
13787 guint min_req_bitrate;
13788 guint min_req_qt_version;
13792 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13794 GstQtReference *ref_a = (GstQtReference *) a;
13795 GstQtReference *ref_b = (GstQtReference *) b;
13797 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13798 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13800 /* known bitrates go before unknown; higher bitrates go first */
13801 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13804 /* sort the redirects and post a message for the application.
13807 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13809 GstQtReference *best;
13812 GValue list_val = { 0, };
13815 g_assert (references != NULL);
13817 references = g_list_sort (references, qtdemux_redirects_sort_func);
13819 best = (GstQtReference *) references->data;
13821 g_value_init (&list_val, GST_TYPE_LIST);
13823 for (l = references; l != NULL; l = l->next) {
13824 GstQtReference *ref = (GstQtReference *) l->data;
13825 GValue struct_val = { 0, };
13827 ref->structure = gst_structure_new ("redirect",
13828 "new-location", G_TYPE_STRING, ref->location, NULL);
13830 if (ref->min_req_bitrate > 0) {
13831 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13832 ref->min_req_bitrate, NULL);
13835 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13836 g_value_set_boxed (&struct_val, ref->structure);
13837 gst_value_list_append_value (&list_val, &struct_val);
13838 g_value_unset (&struct_val);
13839 /* don't free anything here yet, since we need best->structure below */
13842 g_assert (best != NULL);
13843 s = gst_structure_copy (best->structure);
13845 if (g_list_length (references) > 1) {
13846 gst_structure_set_value (s, "locations", &list_val);
13849 g_value_unset (&list_val);
13851 for (l = references; l != NULL; l = l->next) {
13852 GstQtReference *ref = (GstQtReference *) l->data;
13854 gst_structure_free (ref->structure);
13855 g_free (ref->location);
13858 g_list_free (references);
13860 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13861 g_free (qtdemux->redirect_location);
13862 qtdemux->redirect_location =
13863 g_strdup (gst_structure_get_string (s, "new-location"));
13864 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13865 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13868 /* look for redirect nodes, collect all redirect information and
13872 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13874 GNode *rmra, *rmda, *rdrf;
13876 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13878 GList *redirects = NULL;
13880 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13882 GstQtReference ref = { NULL, NULL, 0, 0 };
13883 GNode *rmdr, *rmvc;
13885 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13886 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13887 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13888 ref.min_req_bitrate);
13891 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13892 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13893 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13895 #ifndef GST_DISABLE_GST_DEBUG
13896 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13898 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13900 GST_LOG_OBJECT (qtdemux,
13901 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13902 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13903 bitmask, check_type);
13904 if (package == FOURCC_qtim && check_type == 0) {
13905 ref.min_req_qt_version = version;
13909 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13915 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13916 if (ref_len > 20) {
13917 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13918 ref_data = (guint8 *) rdrf->data + 20;
13919 if (ref_type == FOURCC_alis) {
13920 guint record_len, record_version, fn_len;
13922 if (ref_len > 70) {
13923 /* MacOSX alias record, google for alias-layout.txt */
13924 record_len = QT_UINT16 (ref_data + 4);
13925 record_version = QT_UINT16 (ref_data + 4 + 2);
13926 fn_len = QT_UINT8 (ref_data + 50);
13927 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13928 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13931 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13934 } else if (ref_type == FOURCC_url_) {
13935 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13937 GST_DEBUG_OBJECT (qtdemux,
13938 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13939 GST_FOURCC_ARGS (ref_type));
13941 if (ref.location != NULL) {
13942 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13944 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13946 GST_WARNING_OBJECT (qtdemux,
13947 "Failed to extract redirect location from rdrf atom");
13950 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13954 /* look for others */
13955 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13958 if (redirects != NULL) {
13959 qtdemux_process_redirects (qtdemux, redirects);
13965 static GstTagList *
13966 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13970 if (tags == NULL) {
13971 tags = gst_tag_list_new_empty ();
13972 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13975 if (qtdemux->major_brand == FOURCC_mjp2)
13976 fmt = "Motion JPEG 2000";
13977 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13979 else if (qtdemux->major_brand == FOURCC_qt__)
13981 else if (qtdemux->fragmented)
13984 fmt = "ISO MP4/M4A";
13986 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13987 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13989 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13995 /* we have read the complete moov node now.
13996 * This function parses all of the relevant info, creates the traks and
13997 * prepares all data structures for playback
14000 qtdemux_parse_tree (GstQTDemux * qtdemux)
14007 guint64 creation_time;
14008 GstDateTime *datetime = NULL;
14011 /* make sure we have a usable taglist */
14012 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14014 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
14015 if (mvhd == NULL) {
14016 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
14017 return qtdemux_parse_redirects (qtdemux);
14020 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
14021 if (version == 1) {
14022 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
14023 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
14024 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
14025 } else if (version == 0) {
14026 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
14027 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
14028 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
14030 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
14034 /* Moving qt creation time (secs since 1904) to unix time */
14035 if (creation_time != 0) {
14036 /* Try to use epoch first as it should be faster and more commonly found */
14037 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
14040 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
14041 /* some data cleansing sanity */
14042 now_s = g_get_real_time () / G_USEC_PER_SEC;
14043 if (now_s + 24 * 3600 < creation_time) {
14044 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
14046 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
14049 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
14050 GDateTime *dt, *dt_local;
14052 dt = g_date_time_add_seconds (base_dt, creation_time);
14053 dt_local = g_date_time_to_local (dt);
14054 datetime = gst_date_time_new_from_g_date_time (dt_local);
14056 g_date_time_unref (base_dt);
14057 g_date_time_unref (dt);
14061 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
14062 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
14064 gst_date_time_unref (datetime);
14067 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
14068 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
14070 /* check for fragmented file and get some (default) data */
14071 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
14074 GstByteReader mehd_data;
14076 /* let track parsing or anyone know weird stuff might happen ... */
14077 qtdemux->fragmented = TRUE;
14079 /* compensate for total duration */
14080 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
14082 qtdemux_parse_mehd (qtdemux, &mehd_data);
14085 /* Update the movie segment duration, unless it was directly given to us
14086 * by upstream. Otherwise let it as is, as we don't want to mangle the
14087 * duration provided by upstream that may come e.g. from a MPD file. */
14088 if (!qtdemux->upstream_format_is_time) {
14089 GstClockTime duration;
14090 /* set duration in the segment info */
14091 gst_qtdemux_get_duration (qtdemux, &duration);
14092 qtdemux->segment.duration = duration;
14093 /* also do not exceed duration; stop is set that way post seek anyway,
14094 * and segment activation falls back to duration,
14095 * whereas loop only checks stop, so let's align this here as well */
14096 qtdemux->segment.stop = duration;
14099 /* parse all traks */
14100 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
14102 qtdemux_parse_trak (qtdemux, trak);
14103 /* iterate all siblings */
14104 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
14107 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14110 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
14112 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14114 GST_LOG_OBJECT (qtdemux, "No udta node found.");
14117 /* maybe also some tags in meta box */
14118 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
14120 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
14121 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14123 GST_LOG_OBJECT (qtdemux, "No meta node found.");
14126 /* parse any protection system info */
14127 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
14129 /* Unref old protection events if we are going to receive new ones. */
14130 qtdemux_clear_protection_events_on_all_streams (qtdemux);
14133 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
14134 qtdemux_parse_pssh (qtdemux, pssh);
14135 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
14138 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
14143 /* taken from ffmpeg */
14145 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14157 len = (len << 7) | (c & 0x7f);
14166 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14167 gsize codec_data_size)
14169 GList *list = NULL;
14170 guint8 *p = codec_data;
14171 gint i, offset, num_packets;
14172 guint *length, last;
14174 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14176 if (codec_data == NULL || codec_data_size == 0)
14179 /* start of the stream and vorbis audio or theora video, need to
14180 * send the codec_priv data as first three packets */
14181 num_packets = p[0] + 1;
14182 GST_DEBUG_OBJECT (qtdemux,
14183 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14184 (guint) num_packets, codec_data_size);
14186 /* Let's put some limits, Don't think there even is a xiph codec
14187 * with more than 3-4 headers */
14188 if (G_UNLIKELY (num_packets > 16)) {
14189 GST_WARNING_OBJECT (qtdemux,
14190 "Unlikely number of xiph headers, most likely not valid");
14194 length = g_alloca (num_packets * sizeof (guint));
14198 /* first packets, read length values */
14199 for (i = 0; i < num_packets - 1; i++) {
14201 while (offset < codec_data_size) {
14202 length[i] += p[offset];
14203 if (p[offset++] != 0xff)
14208 if (offset + last > codec_data_size)
14211 /* last packet is the remaining size */
14212 length[i] = codec_data_size - offset - last;
14214 for (i = 0; i < num_packets; i++) {
14217 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14219 if (offset + length[i] > codec_data_size)
14222 hdr = gst_buffer_new_memdup (p + offset, length[i]);
14223 list = g_list_append (list, hdr);
14225 offset += length[i];
14234 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14240 /* this can change the codec originally present in @list */
14242 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14243 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14245 int len = QT_UINT32 (esds->data);
14246 guint8 *ptr = esds->data;
14247 guint8 *end = ptr + len;
14249 guint8 *data_ptr = NULL;
14251 guint8 object_type_id = 0;
14252 guint8 stream_type = 0;
14253 const char *codec_name = NULL;
14254 GstCaps *caps = NULL;
14256 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14258 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14260 while (ptr + 1 < end) {
14261 tag = QT_UINT8 (ptr);
14262 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14264 len = read_descr_size (ptr, end, &ptr);
14265 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14267 /* Check the stated amount of data is available for reading */
14268 if (len < 0 || ptr + len > end)
14272 case ES_DESCRIPTOR_TAG:
14273 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14274 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14277 case DECODER_CONFIG_DESC_TAG:{
14278 guint max_bitrate, avg_bitrate;
14280 object_type_id = QT_UINT8 (ptr);
14281 stream_type = QT_UINT8 (ptr + 1) >> 2;
14282 max_bitrate = QT_UINT32 (ptr + 5);
14283 avg_bitrate = QT_UINT32 (ptr + 9);
14284 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14285 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14286 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14287 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14288 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14289 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14290 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14291 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14293 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14294 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14295 avg_bitrate, NULL);
14300 case DECODER_SPECIFIC_INFO_TAG:
14301 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14302 if (object_type_id == 0xe0 && len == 0x40) {
14308 GST_DEBUG_OBJECT (qtdemux,
14309 "Have VOBSUB palette. Creating palette event");
14310 /* move to decConfigDescr data and read palette */
14312 for (i = 0; i < 16; i++) {
14313 clut[i] = QT_UINT32 (data);
14317 s = gst_structure_new ("application/x-gst-dvd", "event",
14318 G_TYPE_STRING, "dvd-spu-clut-change",
14319 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14320 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14321 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14322 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14323 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14324 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14325 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14326 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14329 /* store event and trigger custom processing */
14330 stream->pending_event =
14331 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14333 /* Generic codec_data handler puts it on the caps */
14340 case SL_CONFIG_DESC_TAG:
14341 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14345 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14347 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14353 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14354 * in use, and should also be used to override some other parameters for some
14356 switch (object_type_id) {
14357 case 0x20: /* MPEG-4 */
14358 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14359 * profile_and_level_indication */
14360 if (data_ptr != NULL && data_len >= 5 &&
14361 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14362 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14363 data_ptr + 4, data_len - 4);
14365 break; /* Nothing special needed here */
14366 case 0x21: /* H.264 */
14367 codec_name = "H.264 / AVC";
14368 caps = gst_caps_new_simple ("video/x-h264",
14369 "stream-format", G_TYPE_STRING, "avc",
14370 "alignment", G_TYPE_STRING, "au", NULL);
14372 case 0x40: /* AAC (any) */
14373 case 0x66: /* AAC Main */
14374 case 0x67: /* AAC LC */
14375 case 0x68: /* AAC SSR */
14376 /* Override channels and rate based on the codec_data, as it's often
14378 /* Only do so for basic setup without HE-AAC extension */
14379 if (data_ptr && data_len == 2) {
14380 guint channels, rate;
14382 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14384 entry->n_channels = channels;
14386 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14388 entry->rate = rate;
14391 /* Set level and profile if possible */
14392 if (data_ptr != NULL && data_len >= 2) {
14393 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14394 data_ptr, data_len);
14396 const gchar *profile_str = NULL;
14399 guint8 *codec_data;
14400 gint rate_idx, profile;
14402 /* No codec_data, let's invent something.
14403 * FIXME: This is wrong for SBR! */
14405 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14407 buffer = gst_buffer_new_and_alloc (2);
14408 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14409 codec_data = map.data;
14412 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14415 switch (object_type_id) {
14417 profile_str = "main";
14421 profile_str = "lc";
14425 profile_str = "ssr";
14433 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14435 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14437 gst_buffer_unmap (buffer, &map);
14438 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14439 GST_TYPE_BUFFER, buffer, NULL);
14440 gst_buffer_unref (buffer);
14443 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14444 G_TYPE_STRING, profile_str, NULL);
14448 case 0x60: /* MPEG-2, various profiles */
14454 codec_name = "MPEG-2 video";
14455 caps = gst_caps_new_simple ("video/mpeg",
14456 "mpegversion", G_TYPE_INT, 2,
14457 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14459 case 0x69: /* MPEG-2 BC audio */
14460 case 0x6B: /* MPEG-1 audio */
14461 caps = gst_caps_new_simple ("audio/mpeg",
14462 "mpegversion", G_TYPE_INT, 1, NULL);
14463 codec_name = "MPEG-1 audio";
14465 case 0x6A: /* MPEG-1 */
14466 codec_name = "MPEG-1 video";
14467 caps = gst_caps_new_simple ("video/mpeg",
14468 "mpegversion", G_TYPE_INT, 1,
14469 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14471 case 0x6C: /* MJPEG */
14473 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14475 codec_name = "Motion-JPEG";
14477 case 0x6D: /* PNG */
14479 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14481 codec_name = "PNG still images";
14483 case 0x6E: /* JPEG2000 */
14484 codec_name = "JPEG-2000";
14485 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14487 case 0xA4: /* Dirac */
14488 codec_name = "Dirac";
14489 caps = gst_caps_new_empty_simple ("video/x-dirac");
14491 case 0xA5: /* AC3 */
14492 codec_name = "AC-3 audio";
14493 caps = gst_caps_new_simple ("audio/x-ac3",
14494 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14496 case 0xA9: /* AC3 */
14497 codec_name = "DTS audio";
14498 caps = gst_caps_new_simple ("audio/x-dts",
14499 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14502 if (stream_type == 0x05 && data_ptr) {
14504 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14507 GValue arr_val = G_VALUE_INIT;
14508 GValue buf_val = G_VALUE_INIT;
14511 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14512 codec_name = "Vorbis";
14513 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14514 g_value_init (&arr_val, GST_TYPE_ARRAY);
14515 g_value_init (&buf_val, GST_TYPE_BUFFER);
14516 for (tmp = headers; tmp; tmp = tmp->next) {
14517 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14518 gst_value_array_append_value (&arr_val, &buf_val);
14520 s = gst_caps_get_structure (caps, 0);
14521 gst_structure_take_value (s, "streamheader", &arr_val);
14522 g_value_unset (&buf_val);
14523 g_list_free (headers);
14530 case 0xE1: /* QCELP */
14531 /* QCELP, the codec_data is a riff tag (little endian) with
14532 * 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). */
14533 caps = gst_caps_new_empty_simple ("audio/qcelp");
14534 codec_name = "QCELP";
14540 /* If we have a replacement caps, then change our caps for this stream */
14542 gst_caps_unref (entry->caps);
14543 entry->caps = caps;
14546 if (codec_name && list)
14547 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14548 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14550 /* Add the codec_data attribute to caps, if we have it */
14554 buffer = gst_buffer_new_and_alloc (data_len);
14555 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14557 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14558 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14560 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14562 gst_buffer_unref (buffer);
14567 static inline GstCaps *
14568 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14572 char *s, fourstr[5];
14574 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14575 for (i = 0; i < 4; i++) {
14576 if (!g_ascii_isalnum (fourstr[i]))
14579 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14580 caps = gst_caps_new_empty_simple (s);
14585 #define _codec(name) \
14587 if (codec_name) { \
14588 *codec_name = g_strdup (name); \
14593 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14594 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14595 const guint8 * stsd_entry_data, gchar ** codec_name)
14597 GstCaps *caps = NULL;
14598 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14602 _codec ("PNG still images");
14603 caps = gst_caps_new_empty_simple ("image/png");
14606 _codec ("JPEG still images");
14608 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14611 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14612 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14613 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14614 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14615 _codec ("Motion-JPEG");
14617 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14620 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14621 _codec ("Motion-JPEG format B");
14622 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14625 _codec ("JPEG-2000");
14626 /* override to what it should be according to spec, avoid palette_data */
14627 entry->bits_per_sample = 24;
14628 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14631 _codec ("Sorensen video v.3");
14632 caps = gst_caps_new_simple ("video/x-svq",
14633 "svqversion", G_TYPE_INT, 3, NULL);
14635 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14636 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14637 _codec ("Sorensen video v.1");
14638 caps = gst_caps_new_simple ("video/x-svq",
14639 "svqversion", G_TYPE_INT, 1, NULL);
14641 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14642 caps = gst_caps_new_empty_simple ("video/x-raw");
14643 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14644 _codec ("Windows Raw RGB");
14645 stream->alignment = 32;
14651 bps = QT_UINT16 (stsd_entry_data + 82);
14654 format = GST_VIDEO_FORMAT_RGB15;
14657 format = GST_VIDEO_FORMAT_RGB16;
14660 format = GST_VIDEO_FORMAT_RGB;
14663 format = GST_VIDEO_FORMAT_ARGB;
14671 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14672 format = GST_VIDEO_FORMAT_I420;
14674 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14675 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14676 format = GST_VIDEO_FORMAT_I420;
14679 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14680 format = GST_VIDEO_FORMAT_UYVY;
14682 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14683 format = GST_VIDEO_FORMAT_v308;
14685 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14686 format = GST_VIDEO_FORMAT_v216;
14689 format = GST_VIDEO_FORMAT_v210;
14691 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14692 format = GST_VIDEO_FORMAT_r210;
14694 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14695 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14696 format = GST_VIDEO_FORMAT_v410;
14699 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14700 * but different order than AYUV
14701 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14702 format = GST_VIDEO_FORMAT_v408;
14705 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14706 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14707 _codec ("MPEG-1 video");
14708 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14709 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14711 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14712 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14713 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14714 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14715 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14716 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14717 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14718 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14719 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14720 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14721 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14722 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14723 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14724 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14725 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14726 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14727 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14728 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14729 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14730 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14731 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14732 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14733 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14734 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14735 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14736 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14737 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14738 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14739 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14740 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14741 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14742 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14743 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14744 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14745 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14746 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14747 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14748 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14749 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14750 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14751 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14752 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14753 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14754 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14755 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14756 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14757 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14758 _codec ("MPEG-2 video");
14759 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14760 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14762 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14763 _codec ("GIF still images");
14764 caps = gst_caps_new_empty_simple ("image/gif");
14767 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14769 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14771 /* ffmpeg uses the height/width props, don't know why */
14772 caps = gst_caps_new_simple ("video/x-h263",
14773 "variant", G_TYPE_STRING, "itu", NULL);
14777 _codec ("MPEG-4 video");
14778 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14779 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14781 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14782 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14783 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14784 caps = gst_caps_new_simple ("video/x-msmpeg",
14785 "msmpegversion", G_TYPE_INT, 43, NULL);
14787 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14789 caps = gst_caps_new_simple ("video/x-divx",
14790 "divxversion", G_TYPE_INT, 3, NULL);
14792 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14793 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14795 caps = gst_caps_new_simple ("video/x-divx",
14796 "divxversion", G_TYPE_INT, 4, NULL);
14798 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14800 caps = gst_caps_new_simple ("video/x-divx",
14801 "divxversion", G_TYPE_INT, 5, NULL);
14804 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14806 caps = gst_caps_new_simple ("video/x-ffv",
14807 "ffvversion", G_TYPE_INT, 1, NULL);
14810 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14811 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14816 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14817 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14818 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14822 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14823 _codec ("Cinepak");
14824 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14826 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14827 _codec ("Apple QuickDraw");
14828 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14830 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14831 _codec ("Apple video");
14832 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14837 _codec ("H.264 / AVC");
14838 caps = gst_caps_new_simple ("video/x-h264",
14839 "stream-format", G_TYPE_STRING, "avc",
14840 "alignment", G_TYPE_STRING, "au", NULL);
14844 _codec ("H.264 / AVC");
14845 caps = gst_caps_new_simple ("video/x-h264",
14846 "stream-format", G_TYPE_STRING, "avc3",
14847 "alignment", G_TYPE_STRING, "au", NULL);
14852 _codec ("H.265 / HEVC");
14853 caps = gst_caps_new_simple ("video/x-h265",
14854 "stream-format", G_TYPE_STRING, "hvc1",
14855 "alignment", G_TYPE_STRING, "au", NULL);
14859 _codec ("H.265 / HEVC");
14860 caps = gst_caps_new_simple ("video/x-h265",
14861 "stream-format", G_TYPE_STRING, "hev1",
14862 "alignment", G_TYPE_STRING, "au", NULL);
14865 _codec ("Run-length encoding");
14866 caps = gst_caps_new_simple ("video/x-rle",
14867 "layout", G_TYPE_STRING, "quicktime", NULL);
14870 _codec ("Run-length encoding");
14871 caps = gst_caps_new_simple ("video/x-rle",
14872 "layout", G_TYPE_STRING, "microsoft", NULL);
14874 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14875 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14876 _codec ("Indeo Video 3");
14877 caps = gst_caps_new_simple ("video/x-indeo",
14878 "indeoversion", G_TYPE_INT, 3, NULL);
14880 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14881 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14882 _codec ("Intel Video 4");
14883 caps = gst_caps_new_simple ("video/x-indeo",
14884 "indeoversion", G_TYPE_INT, 4, NULL);
14888 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14889 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14890 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14891 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14892 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14893 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14894 _codec ("DV Video");
14895 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14896 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14898 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14899 case FOURCC_dv5p: /* DVCPRO50 PAL */
14900 _codec ("DVCPro50 Video");
14901 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14902 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14904 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14905 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14906 _codec ("DVCProHD Video");
14907 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14908 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14910 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14911 _codec ("Apple Graphics (SMC)");
14912 caps = gst_caps_new_empty_simple ("video/x-smc");
14914 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14916 caps = gst_caps_new_empty_simple ("video/x-vp3");
14918 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14919 _codec ("VP6 Flash");
14920 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14924 caps = gst_caps_new_empty_simple ("video/x-theora");
14925 /* theora uses one byte of padding in the data stream because it does not
14926 * allow 0 sized packets while theora does */
14927 entry->padding = 1;
14931 caps = gst_caps_new_empty_simple ("video/x-dirac");
14933 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14934 _codec ("TIFF still images");
14935 caps = gst_caps_new_empty_simple ("image/tiff");
14937 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14938 _codec ("Apple Intermediate Codec");
14939 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14941 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14942 _codec ("AVID DNxHD");
14943 caps = gst_caps_from_string ("video/x-dnxhd");
14947 _codec ("On2 VP8");
14948 caps = gst_caps_from_string ("video/x-vp8");
14951 _codec ("Google VP9");
14952 caps = gst_caps_from_string ("video/x-vp9");
14955 _codec ("Apple ProRes LT");
14957 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14961 _codec ("Apple ProRes HQ");
14963 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14967 _codec ("Apple ProRes");
14969 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14973 _codec ("Apple ProRes Proxy");
14975 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14979 _codec ("Apple ProRes 4444");
14981 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14984 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14985 if (entry->bits_per_sample > 0) {
14986 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14991 _codec ("Apple ProRes 4444 XQ");
14993 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14996 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14997 if (entry->bits_per_sample > 0) {
14998 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
15003 _codec ("GoPro CineForm");
15004 caps = gst_caps_from_string ("video/x-cineform");
15009 caps = gst_caps_new_simple ("video/x-wmv",
15010 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
15014 caps = gst_caps_new_simple ("video/x-av1",
15015 "alignment", G_TYPE_STRING, "tu", NULL);
15017 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
15020 caps = _get_unknown_codec_name ("video", fourcc);
15025 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
15028 gst_video_info_init (&info);
15029 gst_video_info_set_format (&info, format, entry->width, entry->height);
15031 caps = gst_video_info_to_caps (&info);
15032 *codec_name = gst_pb_utils_get_codec_description (caps);
15034 /* enable clipping for raw video streams */
15035 stream->need_clip = TRUE;
15036 stream->alignment = 32;
15043 round_up_pow2 (guint n)
15055 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15056 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
15057 int len, gchar ** codec_name)
15060 const GstStructure *s;
15063 GstAudioFormat format = 0;
15066 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15068 depth = entry->bytes_per_packet * 8;
15071 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
15073 /* 8-bit audio is unsigned */
15075 format = GST_AUDIO_FORMAT_U8;
15076 /* otherwise it's signed and big-endian just like 'twos' */
15078 endian = G_BIG_ENDIAN;
15085 endian = G_LITTLE_ENDIAN;
15088 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
15090 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
15094 caps = gst_caps_new_simple ("audio/x-raw",
15095 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15096 "layout", G_TYPE_STRING, "interleaved", NULL);
15097 stream->alignment = GST_ROUND_UP_8 (depth);
15098 stream->alignment = round_up_pow2 (stream->alignment);
15102 _codec ("Raw 64-bit floating-point audio");
15103 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15105 caps = gst_caps_new_simple ("audio/x-raw",
15106 "format", G_TYPE_STRING, "F64BE",
15107 "layout", G_TYPE_STRING, "interleaved", NULL);
15108 stream->alignment = 8;
15111 _codec ("Raw 32-bit floating-point audio");
15112 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15114 caps = gst_caps_new_simple ("audio/x-raw",
15115 "format", G_TYPE_STRING, "F32BE",
15116 "layout", G_TYPE_STRING, "interleaved", NULL);
15117 stream->alignment = 4;
15120 _codec ("Raw 24-bit PCM audio");
15121 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15123 caps = gst_caps_new_simple ("audio/x-raw",
15124 "format", G_TYPE_STRING, "S24BE",
15125 "layout", G_TYPE_STRING, "interleaved", NULL);
15126 stream->alignment = 4;
15129 _codec ("Raw 32-bit PCM audio");
15130 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15132 caps = gst_caps_new_simple ("audio/x-raw",
15133 "format", G_TYPE_STRING, "S32BE",
15134 "layout", G_TYPE_STRING, "interleaved", NULL);
15135 stream->alignment = 4;
15138 _codec ("Raw 16-bit PCM audio");
15139 caps = gst_caps_new_simple ("audio/x-raw",
15140 "format", G_TYPE_STRING, "S16LE",
15141 "layout", G_TYPE_STRING, "interleaved", NULL);
15142 stream->alignment = 2;
15145 _codec ("Mu-law audio");
15146 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
15149 _codec ("A-law audio");
15150 caps = gst_caps_new_empty_simple ("audio/x-alaw");
15154 _codec ("Microsoft ADPCM");
15155 /* Microsoft ADPCM-ACM code 2 */
15156 caps = gst_caps_new_simple ("audio/x-adpcm",
15157 "layout", G_TYPE_STRING, "microsoft", NULL);
15161 _codec ("DVI/IMA ADPCM");
15162 caps = gst_caps_new_simple ("audio/x-adpcm",
15163 "layout", G_TYPE_STRING, "dvi", NULL);
15167 _codec ("DVI/Intel IMA ADPCM");
15168 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15169 caps = gst_caps_new_simple ("audio/x-adpcm",
15170 "layout", G_TYPE_STRING, "quicktime", NULL);
15174 /* MPEG layer 3, CBR only (pre QT4.1) */
15177 _codec ("MPEG-1 layer 3");
15178 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15179 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15180 "mpegversion", G_TYPE_INT, 1, NULL);
15182 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15183 _codec ("MPEG-1 layer 2");
15185 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15186 "mpegversion", G_TYPE_INT, 1, NULL);
15189 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15190 _codec ("EAC-3 audio");
15191 caps = gst_caps_new_simple ("audio/x-eac3",
15192 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15193 entry->sampled = TRUE;
15195 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15197 _codec ("AC-3 audio");
15198 caps = gst_caps_new_simple ("audio/x-ac3",
15199 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15200 entry->sampled = TRUE;
15202 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15203 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15204 _codec ("DTS audio");
15205 caps = gst_caps_new_simple ("audio/x-dts",
15206 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15207 entry->sampled = TRUE;
15209 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15210 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15211 _codec ("DTS-HD audio");
15212 caps = gst_caps_new_simple ("audio/x-dts",
15213 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15214 entry->sampled = TRUE;
15218 caps = gst_caps_new_simple ("audio/x-mace",
15219 "maceversion", G_TYPE_INT, 3, NULL);
15223 caps = gst_caps_new_simple ("audio/x-mace",
15224 "maceversion", G_TYPE_INT, 6, NULL);
15226 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15228 caps = gst_caps_new_empty_simple ("application/ogg");
15230 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15231 _codec ("DV audio");
15232 caps = gst_caps_new_empty_simple ("audio/x-dv");
15235 _codec ("MPEG-4 AAC audio");
15236 caps = gst_caps_new_simple ("audio/mpeg",
15237 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15238 "stream-format", G_TYPE_STRING, "raw", NULL);
15240 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15241 _codec ("QDesign Music");
15242 caps = gst_caps_new_empty_simple ("audio/x-qdm");
15245 _codec ("QDesign Music v.2");
15246 /* FIXME: QDesign music version 2 (no constant) */
15247 if (FALSE && data) {
15248 caps = gst_caps_new_simple ("audio/x-qdm2",
15249 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15250 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15251 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15253 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15257 _codec ("GSM audio");
15258 caps = gst_caps_new_empty_simple ("audio/x-gsm");
15261 _codec ("AMR audio");
15262 caps = gst_caps_new_empty_simple ("audio/AMR");
15265 _codec ("AMR-WB audio");
15266 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15269 _codec ("Quicktime IMA ADPCM");
15270 caps = gst_caps_new_simple ("audio/x-adpcm",
15271 "layout", G_TYPE_STRING, "quicktime", NULL);
15274 _codec ("Apple lossless audio");
15275 caps = gst_caps_new_empty_simple ("audio/x-alac");
15278 _codec ("Free Lossless Audio Codec");
15279 caps = gst_caps_new_simple ("audio/x-flac",
15280 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15282 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15283 _codec ("QualComm PureVoice");
15284 caps = gst_caps_from_string ("audio/qcelp");
15289 caps = gst_caps_new_empty_simple ("audio/x-wma");
15293 caps = gst_caps_new_empty_simple ("audio/x-opus");
15300 GstAudioFormat format;
15303 FLAG_IS_FLOAT = 0x1,
15304 FLAG_IS_BIG_ENDIAN = 0x2,
15305 FLAG_IS_SIGNED = 0x4,
15306 FLAG_IS_PACKED = 0x8,
15307 FLAG_IS_ALIGNED_HIGH = 0x10,
15308 FLAG_IS_NON_INTERLEAVED = 0x20
15310 _codec ("Raw LPCM audio");
15312 if (data && len >= 36) {
15313 depth = QT_UINT32 (data + 24);
15314 flags = QT_UINT32 (data + 28);
15315 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15317 if ((flags & FLAG_IS_FLOAT) == 0) {
15322 if ((flags & FLAG_IS_ALIGNED_HIGH))
15325 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15326 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15327 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15328 caps = gst_caps_new_simple ("audio/x-raw",
15329 "format", G_TYPE_STRING,
15331 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15332 "UNKNOWN", "layout", G_TYPE_STRING,
15333 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15334 "interleaved", NULL);
15335 stream->alignment = GST_ROUND_UP_8 (depth);
15336 stream->alignment = round_up_pow2 (stream->alignment);
15341 if (flags & FLAG_IS_BIG_ENDIAN)
15342 format = GST_AUDIO_FORMAT_F64BE;
15344 format = GST_AUDIO_FORMAT_F64LE;
15346 if (flags & FLAG_IS_BIG_ENDIAN)
15347 format = GST_AUDIO_FORMAT_F32BE;
15349 format = GST_AUDIO_FORMAT_F32LE;
15351 caps = gst_caps_new_simple ("audio/x-raw",
15352 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15353 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15354 "non-interleaved" : "interleaved", NULL);
15355 stream->alignment = width / 8;
15359 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15362 caps = gst_caps_new_empty_simple ("audio/x-ac4");
15365 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15369 caps = _get_unknown_codec_name ("audio", fourcc);
15375 GstCaps *templ_caps =
15376 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15377 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15378 gst_caps_unref (caps);
15379 gst_caps_unref (templ_caps);
15380 caps = intersection;
15383 /* enable clipping for raw audio streams */
15384 s = gst_caps_get_structure (caps, 0);
15385 name = gst_structure_get_name (s);
15386 if (g_str_has_prefix (name, "audio/x-raw")) {
15387 stream->need_clip = TRUE;
15388 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15389 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15390 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15391 stream->max_buffer_size);
15397 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15398 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15399 const guint8 * stsd_entry_data, gchar ** codec_name)
15403 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15407 _codec ("DVD subtitle");
15408 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15409 stream->process_func = gst_qtdemux_process_buffer_dvd;
15412 _codec ("Quicktime timed text");
15415 _codec ("3GPP timed text");
15417 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15419 /* actual text piece needs to be extracted */
15420 stream->process_func = gst_qtdemux_process_buffer_text;
15423 _codec ("XML subtitles");
15424 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15429 const gchar *buf = "WEBVTT\n\n";
15431 _codec ("WebVTT subtitles");
15432 caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15433 stream->process_func = gst_qtdemux_process_buffer_wvtt;
15435 /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15436 buffer = gst_buffer_new_and_alloc (8);
15437 gst_buffer_fill (buffer, 0, buf, 8);
15438 stream->buffers = g_slist_append (stream->buffers, buffer);
15443 _codec ("CEA 608 Closed Caption");
15445 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15446 G_TYPE_STRING, "s334-1a", NULL);
15447 stream->process_func = gst_qtdemux_process_buffer_clcp;
15448 stream->need_split = TRUE;
15451 _codec ("CEA 708 Closed Caption");
15453 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15454 G_TYPE_STRING, "cdp", NULL);
15455 stream->process_func = gst_qtdemux_process_buffer_clcp;
15460 caps = _get_unknown_codec_name ("text", fourcc);
15468 qtdemux_meta_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15469 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15470 const guint8 * stsd_entry_data, gchar ** codec_name)
15472 GstCaps *caps = NULL;
15474 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15478 gsize size = QT_UINT32 (stsd_entry_data);
15479 GstByteReader reader = GST_BYTE_READER_INIT (stsd_entry_data, size);
15480 const gchar *content_encoding;
15481 const gchar *namespaces;
15482 const gchar *schema_locations;
15484 if (!gst_byte_reader_skip (&reader, 8 + 6 + 2)) {
15485 GST_WARNING_OBJECT (qtdemux, "Too short metx sample entry");
15489 if (!gst_byte_reader_get_string (&reader, &content_encoding) ||
15490 !gst_byte_reader_get_string (&reader, &namespaces) ||
15491 !gst_byte_reader_get_string (&reader, &schema_locations)) {
15492 GST_WARNING_OBJECT (qtdemux, "Too short metx sample entry");
15496 if (strstr (namespaces, "http://www.onvif.org/ver10/schema") != 0) {
15497 if (content_encoding == NULL || *content_encoding == '\0'
15498 || g_ascii_strcasecmp (content_encoding, "xml") == 0) {
15499 _codec ("ONVIF Timed XML MetaData");
15501 gst_caps_new_simple ("application/x-onvif-metadata", "parsed",
15502 G_TYPE_BOOLEAN, TRUE, NULL);
15504 GST_DEBUG_OBJECT (qtdemux, "Unknown content encoding: %s",
15508 GST_DEBUG_OBJECT (qtdemux, "Unknown metadata namespaces: %s",
15519 caps = _get_unknown_codec_name ("meta", fourcc);
15525 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15526 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15527 const guint8 * stsd_entry_data, gchar ** codec_name)
15533 _codec ("MPEG 1 video");
15534 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15535 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15545 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15546 const gchar * system_id)
15550 if (!qtdemux->protection_system_ids)
15551 qtdemux->protection_system_ids =
15552 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15553 /* Check whether we already have an entry for this system ID. */
15554 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15555 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15556 if (g_ascii_strcasecmp (system_id, id) == 0) {
15560 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15561 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,