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);
397 gst_qtdemux_class_init (GstQTDemuxClass * klass)
399 GObjectClass *gobject_class;
400 GstElementClass *gstelement_class;
402 gobject_class = (GObjectClass *) klass;
403 gstelement_class = (GstElementClass *) klass;
405 parent_class = g_type_class_peek_parent (klass);
407 gobject_class->dispose = gst_qtdemux_dispose;
408 gobject_class->finalize = gst_qtdemux_finalize;
410 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
412 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
413 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
415 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
417 gst_tag_register_musicbrainz_tags ();
419 gst_element_class_add_static_pad_template (gstelement_class,
420 &gst_qtdemux_sink_template);
421 gst_element_class_add_static_pad_template (gstelement_class,
422 &gst_qtdemux_videosrc_template);
423 gst_element_class_add_static_pad_template (gstelement_class,
424 &gst_qtdemux_audiosrc_template);
425 gst_element_class_add_static_pad_template (gstelement_class,
426 &gst_qtdemux_subsrc_template);
427 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
429 "Demultiplex a QuickTime file into audio and video streams",
430 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
432 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
437 gst_qtdemux_init (GstQTDemux * qtdemux)
440 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
441 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
442 gst_pad_set_activatemode_function (qtdemux->sinkpad,
443 qtdemux_sink_activate_mode);
444 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
445 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
446 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
447 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
449 qtdemux->adapter = gst_adapter_new ();
450 g_queue_init (&qtdemux->protection_event_queue);
451 qtdemux->flowcombiner = gst_flow_combiner_new ();
452 g_mutex_init (&qtdemux->expose_lock);
454 qtdemux->active_streams = g_ptr_array_new_with_free_func
455 ((GDestroyNotify) gst_qtdemux_stream_unref);
456 qtdemux->old_streams = g_ptr_array_new_with_free_func
457 ((GDestroyNotify) gst_qtdemux_stream_unref);
459 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
461 gst_qtdemux_reset (qtdemux, TRUE);
465 gst_qtdemux_finalize (GObject * object)
467 GstQTDemux *qtdemux = GST_QTDEMUX (object);
469 g_free (qtdemux->redirect_location);
471 G_OBJECT_CLASS (parent_class)->finalize (object);
475 gst_qtdemux_dispose (GObject * object)
477 GstQTDemux *qtdemux = GST_QTDEMUX (object);
479 if (qtdemux->adapter) {
480 g_object_unref (G_OBJECT (qtdemux->adapter));
481 qtdemux->adapter = NULL;
483 gst_tag_list_unref (qtdemux->tag_list);
484 gst_flow_combiner_free (qtdemux->flowcombiner);
485 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
487 g_queue_clear (&qtdemux->protection_event_queue);
489 g_free (qtdemux->cenc_aux_info_sizes);
490 qtdemux->cenc_aux_info_sizes = NULL;
491 g_mutex_clear (&qtdemux->expose_lock);
493 g_ptr_array_free (qtdemux->active_streams, TRUE);
494 g_ptr_array_free (qtdemux->old_streams, TRUE);
496 G_OBJECT_CLASS (parent_class)->dispose (object);
500 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
502 if (qtdemux->redirect_location) {
503 GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
504 (_("This file contains no playable streams.")),
505 ("no known streams found, a redirect message has been posted"),
506 ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
508 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
509 (_("This file contains no playable streams.")),
510 ("no known streams found"));
515 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
517 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
518 mem, size, 0, size, mem, free_func);
522 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
529 if (G_UNLIKELY (size == 0)) {
531 GstBuffer *tmp = NULL;
533 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
534 if (ret != GST_FLOW_OK)
537 gst_buffer_map (tmp, &map, GST_MAP_READ);
538 size = QT_UINT32 (map.data);
539 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
541 gst_buffer_unmap (tmp, &map);
542 gst_buffer_unref (tmp);
545 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
546 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
547 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
548 /* we're pulling header but already got most interesting bits,
549 * so never mind the rest (e.g. tags) (that much) */
550 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
554 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
555 (_("This file is invalid and cannot be played.")),
556 ("atom has bogus size %" G_GUINT64_FORMAT, size));
557 return GST_FLOW_ERROR;
561 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
563 if (G_UNLIKELY (flow != GST_FLOW_OK))
566 bsize = gst_buffer_get_size (*buf);
567 /* Catch short reads - we don't want any partial atoms */
568 if (G_UNLIKELY (bsize < size)) {
569 GST_WARNING_OBJECT (qtdemux,
570 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
571 gst_buffer_unref (*buf);
581 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
582 GstFormat src_format, gint64 src_value, GstFormat dest_format,
586 QtDemuxStream *stream = gst_pad_get_element_private (pad);
589 if (stream->subtype != FOURCC_vide) {
594 switch (src_format) {
595 case GST_FORMAT_TIME:
596 switch (dest_format) {
597 case GST_FORMAT_BYTES:{
598 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
604 *dest_value = stream->samples[index].offset;
606 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
607 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
608 GST_TIME_ARGS (src_value), *dest_value);
616 case GST_FORMAT_BYTES:
617 switch (dest_format) {
618 case GST_FORMAT_TIME:{
620 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
629 QTSTREAMTIME_TO_GSTTIME (stream,
630 stream->samples[index].timestamp);
631 GST_DEBUG_OBJECT (qtdemux,
632 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
633 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
652 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
654 gboolean res = FALSE;
656 *duration = GST_CLOCK_TIME_NONE;
658 if (qtdemux->duration != 0 &&
659 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
660 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
663 *duration = GST_CLOCK_TIME_NONE;
670 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
673 gboolean res = FALSE;
674 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
676 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
678 switch (GST_QUERY_TYPE (query)) {
679 case GST_QUERY_POSITION:{
682 gst_query_parse_position (query, &fmt, NULL);
683 if (fmt == GST_FORMAT_TIME
684 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
685 gst_query_set_position (query, GST_FORMAT_TIME,
686 qtdemux->segment.position);
691 case GST_QUERY_DURATION:{
694 gst_query_parse_duration (query, &fmt, NULL);
695 if (fmt == GST_FORMAT_TIME) {
696 /* First try to query upstream */
697 res = gst_pad_query_default (pad, parent, query);
699 GstClockTime duration;
700 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
701 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
708 case GST_QUERY_CONVERT:{
709 GstFormat src_fmt, dest_fmt;
710 gint64 src_value, dest_value = 0;
712 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
714 res = gst_qtdemux_src_convert (qtdemux, pad,
715 src_fmt, src_value, dest_fmt, &dest_value);
717 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
721 case GST_QUERY_FORMATS:
722 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
725 case GST_QUERY_SEEKING:{
729 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
731 if (fmt == GST_FORMAT_BYTES) {
732 /* We always refuse BYTES seeks from downstream */
736 /* try upstream first */
737 res = gst_pad_query_default (pad, parent, query);
740 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
741 if (fmt == GST_FORMAT_TIME) {
742 GstClockTime duration;
744 gst_qtdemux_get_duration (qtdemux, &duration);
746 if (!qtdemux->pullbased) {
749 /* we might be able with help from upstream */
751 q = gst_query_new_seeking (GST_FORMAT_BYTES);
752 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
753 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
754 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
758 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
764 case GST_QUERY_SEGMENT:
769 format = qtdemux->segment.format;
772 gst_segment_to_stream_time (&qtdemux->segment, format,
773 qtdemux->segment.start);
774 if ((stop = qtdemux->segment.stop) == -1)
775 stop = qtdemux->segment.duration;
777 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
779 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
784 res = gst_pad_query_default (pad, parent, query);
792 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
794 if (G_LIKELY (stream->pad)) {
795 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
796 GST_DEBUG_PAD_NAME (stream->pad));
798 if (!gst_tag_list_is_empty (stream->stream_tags)) {
799 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
800 stream->stream_tags);
801 gst_pad_push_event (stream->pad,
802 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
805 if (G_UNLIKELY (stream->send_global_tags)) {
806 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
808 gst_pad_push_event (stream->pad,
809 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
810 stream->send_global_tags = FALSE;
815 /* push event on all source pads; takes ownership of the event */
817 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
819 gboolean has_valid_stream = FALSE;
820 GstEventType etype = GST_EVENT_TYPE (event);
823 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
824 GST_EVENT_TYPE_NAME (event));
826 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
828 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
829 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
831 if ((pad = stream->pad)) {
832 has_valid_stream = TRUE;
834 if (etype == GST_EVENT_EOS) {
835 /* let's not send twice */
836 if (stream->sent_eos)
838 stream->sent_eos = TRUE;
841 gst_pad_push_event (pad, gst_event_ref (event));
845 gst_event_unref (event);
847 /* if it is EOS and there are no pads, post an error */
848 if (!has_valid_stream && etype == GST_EVENT_EOS) {
849 gst_qtdemux_post_no_playable_stream_error (qtdemux);
859 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
861 if ((gint64) s1->timestamp > *media_time)
863 if ((gint64) s1->timestamp == *media_time)
869 /* find the index of the sample that includes the data for @media_time using a
870 * binary search. Only to be called in optimized cases of linear search below.
872 * Returns the index of the sample with the corresponding *DTS*.
875 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
878 QtDemuxSample *result;
881 /* convert media_time to mov format */
883 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
885 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
886 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
887 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
889 if (G_LIKELY (result))
890 index = result - str->samples;
899 /* find the index of the sample that includes the data for @media_offset using a
902 * Returns the index of the sample.
905 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
906 QtDemuxStream * str, gint64 media_offset)
908 QtDemuxSample *result = str->samples;
911 if (result == NULL || str->n_samples == 0)
914 if (media_offset == result->offset)
918 while (index < str->n_samples - 1) {
919 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
922 if (media_offset < result->offset)
933 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
938 /* find the index of the sample that includes the data for @media_time using a
939 * linear search, and keeping in mind that not all samples may have been parsed
940 * yet. If possible, it will delegate to binary search.
942 * Returns the index of the sample.
945 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
946 GstClockTime media_time)
950 QtDemuxSample *sample;
952 /* convert media_time to mov format */
954 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
956 sample = str->samples;
957 if (mov_time == sample->timestamp + sample->pts_offset)
960 /* use faster search if requested time in already parsed range */
961 sample = str->samples + str->stbl_index;
962 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
963 index = gst_qtdemux_find_index (qtdemux, str, media_time);
964 sample = str->samples + index;
966 while (index < str->n_samples - 1) {
967 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
970 sample = str->samples + index + 1;
971 if (mov_time < sample->timestamp) {
972 sample = str->samples + index;
980 /* sample->timestamp is now <= media_time, need to find the corresponding
981 * PTS now by looking backwards */
982 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
984 sample = str->samples + index;
992 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
997 /* find the index of the keyframe needed to decode the sample at @index
998 * of stream @str, or of a subsequent keyframe (depending on @next)
1000 * Returns the index of the keyframe.
1003 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1004 guint32 index, gboolean next)
1006 guint32 new_index = index;
1008 if (index >= str->n_samples) {
1009 new_index = str->n_samples;
1013 /* all keyframes, return index */
1014 if (str->all_keyframe) {
1019 /* else search until we have a keyframe */
1020 while (new_index < str->n_samples) {
1021 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1024 if (str->samples[new_index].keyframe)
1036 if (new_index == str->n_samples) {
1037 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1042 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1043 "gave %u", next ? "after" : "before", index, new_index);
1050 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1055 /* find the segment for @time_position for @stream
1057 * Returns the index of the segment containing @time_position.
1058 * Returns the last segment and sets the @eos variable to TRUE
1059 * if the time is beyond the end. @eos may be NULL
1062 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1063 GstClockTime time_position)
1068 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1069 GST_TIME_ARGS (time_position));
1072 for (i = 0; i < stream->n_segments; i++) {
1073 QtDemuxSegment *segment = &stream->segments[i];
1075 GST_LOG_OBJECT (stream->pad,
1076 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1077 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1079 /* For the last segment we include stop_time in the last segment */
1080 if (i < stream->n_segments - 1) {
1081 if (segment->time <= time_position && time_position < segment->stop_time) {
1082 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1087 /* Last segment always matches */
1095 /* move the stream @str to the sample position @index.
1097 * Updates @str->sample_index and marks discontinuity if needed.
1100 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1103 /* no change needed */
1104 if (index == str->sample_index)
1107 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1110 /* position changed, we have a discont */
1111 str->sample_index = index;
1112 str->offset_in_sample = 0;
1113 /* Each time we move in the stream we store the position where we are
1115 str->from_sample = index;
1116 str->discont = TRUE;
1120 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1121 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1124 gint64 min_byte_offset = -1;
1127 min_offset = desired_time;
1129 /* for each stream, find the index of the sample in the segment
1130 * and move back to the previous keyframe. */
1131 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1133 guint32 index, kindex;
1135 GstClockTime media_start;
1136 GstClockTime media_time;
1137 GstClockTime seg_time;
1138 QtDemuxSegment *seg;
1139 gboolean empty_segment = FALSE;
1141 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1143 if (CUR_STREAM (str)->sparse && !use_sparse)
1146 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1147 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1149 /* get segment and time in the segment */
1150 seg = &str->segments[seg_idx];
1151 seg_time = (desired_time - seg->time) * seg->rate;
1153 while (QTSEGMENT_IS_EMPTY (seg)) {
1155 empty_segment = TRUE;
1156 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1159 if (seg_idx == str->n_segments)
1161 seg = &str->segments[seg_idx];
1164 if (seg_idx == str->n_segments) {
1165 /* FIXME track shouldn't have the last segment as empty, but if it
1166 * happens we better handle it */
1170 /* get the media time in the segment */
1171 media_start = seg->media_start + seg_time;
1173 /* get the index of the sample with media time */
1174 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1175 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1176 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1177 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1180 /* shift to next frame if we are looking for next keyframe */
1181 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1182 && index < str->stbl_index)
1185 if (!empty_segment) {
1186 /* find previous keyframe */
1187 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1189 /* we will settle for one before if none found after */
1190 if (next && kindex == -1)
1191 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1193 /* Update the requested time whenever a keyframe was found, to make it
1194 * accurate and avoid having the first buffer fall outside of the segment
1199 /* get timestamp of keyframe */
1200 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1201 GST_DEBUG_OBJECT (qtdemux,
1202 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1203 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1204 str->samples[kindex].offset);
1206 /* keyframes in the segment get a chance to change the
1207 * desired_offset. keyframes out of the segment are
1209 if (media_time >= seg->media_start) {
1210 GstClockTime seg_time;
1212 /* this keyframe is inside the segment, convert back to
1214 seg_time = (media_time - seg->media_start) + seg->time;
1215 if ((!next && (seg_time < min_offset)) ||
1216 (next && (seg_time > min_offset)))
1217 min_offset = seg_time;
1222 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1223 min_byte_offset = str->samples[index].offset;
1227 *key_time = min_offset;
1229 *key_offset = min_byte_offset;
1233 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1234 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1238 g_return_val_if_fail (format != NULL, FALSE);
1239 g_return_val_if_fail (cur != NULL, FALSE);
1240 g_return_val_if_fail (stop != NULL, FALSE);
1242 if (*format == GST_FORMAT_TIME)
1246 if (cur_type != GST_SEEK_TYPE_NONE)
1247 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1248 if (res && stop_type != GST_SEEK_TYPE_NONE)
1249 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1252 *format = GST_FORMAT_TIME;
1257 /* perform seek in push based mode:
1258 find BYTE position to move to based on time and delegate to upstream
1261 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1266 GstSeekType cur_type, stop_type;
1267 gint64 cur, stop, key_cur;
1270 gint64 original_stop;
1273 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1275 gst_event_parse_seek (event, &rate, &format, &flags,
1276 &cur_type, &cur, &stop_type, &stop);
1277 seqnum = gst_event_get_seqnum (event);
1279 /* Directly send the instant-rate-change event here before taking the
1280 * stream-lock so that it can be applied as soon as possible */
1281 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1284 /* instant rate change only supported if direction does not change. All
1285 * other requirements are already checked before creating the seek event
1286 * but let's double-check here to be sure */
1287 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1288 (qtdemux->segment.rate < 0 && rate > 0) ||
1289 cur_type != GST_SEEK_TYPE_NONE ||
1290 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1291 GST_ERROR_OBJECT (qtdemux,
1292 "Instant rate change seeks only supported in the "
1293 "same direction, without flushing and position change");
1297 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1298 (GstSegmentFlags) flags);
1299 gst_event_set_seqnum (ev, seqnum);
1300 gst_qtdemux_push_event (qtdemux, ev);
1304 /* only forward streaming and seeking is possible */
1306 goto unsupported_seek;
1308 /* convert to TIME if needed and possible */
1309 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1313 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1314 * the original stop position to use when upstream pushes the new segment
1316 original_stop = stop;
1319 /* find reasonable corresponding BYTE position,
1320 * also try to mind about keyframes, since we can not go back a bit for them
1322 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1323 * mostly just work, but let's not yet boldly go there ... */
1324 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1329 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1330 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1333 GST_OBJECT_LOCK (qtdemux);
1334 qtdemux->seek_offset = byte_cur;
1335 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1336 qtdemux->push_seek_start = cur;
1338 qtdemux->push_seek_start = key_cur;
1341 if (stop_type == GST_SEEK_TYPE_NONE) {
1342 qtdemux->push_seek_stop = qtdemux->segment.stop;
1344 qtdemux->push_seek_stop = original_stop;
1346 GST_OBJECT_UNLOCK (qtdemux);
1348 qtdemux->segment_seqnum = seqnum;
1349 /* BYTE seek event */
1350 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1352 gst_event_set_seqnum (event, seqnum);
1353 res = gst_pad_push_event (qtdemux->sinkpad, event);
1360 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1366 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1371 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1376 /* perform the seek.
1378 * We set all segment_indexes in the streams to unknown and
1379 * adjust the time_position to the desired position. this is enough
1380 * to trigger a segment switch in the streaming thread to start
1381 * streaming from the desired position.
1383 * Keyframe seeking is a little more complicated when dealing with
1384 * segments. Ideally we want to move to the previous keyframe in
1385 * the segment but there might not be a keyframe in the segment. In
1386 * fact, none of the segments could contain a keyframe. We take a
1387 * practical approach: seek to the previous keyframe in the segment,
1388 * if there is none, seek to the beginning of the segment.
1390 * Called with STREAM_LOCK
1393 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1394 guint32 seqnum, GstSeekFlags flags)
1396 gint64 desired_offset;
1399 desired_offset = segment->position;
1401 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1402 GST_TIME_ARGS (desired_offset));
1404 /* may not have enough fragmented info to do this adjustment,
1405 * and we can't scan (and probably should not) at this time with
1406 * possibly flushing upstream */
1407 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1409 gboolean next, before, after;
1411 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1412 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1413 next = after && !before;
1414 if (segment->rate < 0)
1417 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1419 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1420 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1421 desired_offset = min_offset;
1424 /* and set all streams to the final position */
1425 GST_OBJECT_LOCK (qtdemux);
1426 gst_flow_combiner_reset (qtdemux->flowcombiner);
1427 GST_OBJECT_UNLOCK (qtdemux);
1428 qtdemux->segment_seqnum = seqnum;
1429 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1430 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1432 stream->time_position = desired_offset;
1433 stream->accumulated_base = 0;
1434 stream->sample_index = -1;
1435 stream->offset_in_sample = 0;
1436 stream->segment_index = -1;
1437 stream->sent_eos = FALSE;
1438 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1440 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1441 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1443 segment->position = desired_offset;
1444 if (segment->rate >= 0) {
1445 segment->start = desired_offset;
1446 /* We need to update time as we update start in that direction */
1447 segment->time = desired_offset;
1449 /* we stop at the end */
1450 if (segment->stop == -1)
1451 segment->stop = segment->duration;
1453 segment->stop = desired_offset;
1456 if (qtdemux->fragmented)
1457 qtdemux->fragmented_seek_pending = TRUE;
1462 /* do a seek in pull based mode */
1464 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1469 GstSeekType cur_type, stop_type;
1471 gboolean flush, instant_rate_change;
1473 GstSegment seeksegment;
1474 guint32 seqnum = GST_SEQNUM_INVALID;
1475 GstEvent *flush_event;
1478 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1480 gst_event_parse_seek (event, &rate, &format, &flags,
1481 &cur_type, &cur, &stop_type, &stop);
1482 seqnum = gst_event_get_seqnum (event);
1484 /* we have to have a format as the segment format. Try to convert
1486 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1490 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1492 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1493 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1495 /* Directly send the instant-rate-change event here before taking the
1496 * stream-lock so that it can be applied as soon as possible */
1497 if (instant_rate_change) {
1500 /* instant rate change only supported if direction does not change. All
1501 * other requirements are already checked before creating the seek event
1502 * but let's double-check here to be sure */
1503 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1504 (qtdemux->segment.rate < 0 && rate > 0) ||
1505 cur_type != GST_SEEK_TYPE_NONE ||
1506 stop_type != GST_SEEK_TYPE_NONE || flush) {
1507 GST_ERROR_OBJECT (qtdemux,
1508 "Instant rate change seeks only supported in the "
1509 "same direction, without flushing and position change");
1513 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1514 (GstSegmentFlags) flags);
1515 gst_event_set_seqnum (ev, seqnum);
1516 gst_qtdemux_push_event (qtdemux, ev);
1520 /* stop streaming, either by flushing or by pausing the task */
1522 flush_event = gst_event_new_flush_start ();
1523 if (seqnum != GST_SEQNUM_INVALID)
1524 gst_event_set_seqnum (flush_event, seqnum);
1525 /* unlock upstream pull_range */
1526 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1527 /* make sure out loop function exits */
1528 gst_qtdemux_push_event (qtdemux, flush_event);
1530 /* non flushing seek, pause the task */
1531 gst_pad_pause_task (qtdemux->sinkpad);
1534 /* wait for streaming to finish */
1535 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1537 /* copy segment, we need this because we still need the old
1538 * segment when we close the current segment. */
1539 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1541 /* configure the segment with the seek variables */
1542 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1543 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1544 cur_type, cur, stop_type, stop, &update)) {
1546 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1548 /* now do the seek */
1549 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1552 /* prepare for streaming again */
1554 flush_event = gst_event_new_flush_stop (TRUE);
1555 if (seqnum != GST_SEQNUM_INVALID)
1556 gst_event_set_seqnum (flush_event, seqnum);
1558 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1559 gst_qtdemux_push_event (qtdemux, flush_event);
1562 /* commit the new segment */
1563 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1565 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1566 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1567 qtdemux->segment.format, qtdemux->segment.position);
1568 if (seqnum != GST_SEQNUM_INVALID)
1569 gst_message_set_seqnum (msg, seqnum);
1570 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1573 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1574 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1575 qtdemux->sinkpad, NULL);
1577 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1584 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1590 qtdemux_ensure_index (GstQTDemux * qtdemux)
1594 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1596 /* Build complete index */
1597 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1598 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1600 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1601 GST_LOG_OBJECT (qtdemux,
1602 "Building complete index of track-id %u for seeking failed!",
1612 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1615 gboolean res = TRUE;
1616 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1618 switch (GST_EVENT_TYPE (event)) {
1619 case GST_EVENT_RECONFIGURE:
1620 GST_OBJECT_LOCK (qtdemux);
1621 gst_flow_combiner_reset (qtdemux->flowcombiner);
1622 GST_OBJECT_UNLOCK (qtdemux);
1623 res = gst_pad_event_default (pad, parent, event);
1625 case GST_EVENT_SEEK:
1627 GstSeekFlags flags = 0;
1628 GstFormat seek_format;
1629 gboolean instant_rate_change;
1631 #ifndef GST_DISABLE_GST_DEBUG
1632 GstClockTime ts = gst_util_get_timestamp ();
1634 guint32 seqnum = gst_event_get_seqnum (event);
1636 qtdemux->received_seek = TRUE;
1638 gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1640 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1642 if (seqnum == qtdemux->segment_seqnum) {
1643 GST_LOG_OBJECT (pad,
1644 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1645 gst_event_unref (event);
1649 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1650 /* seek should be handled by upstream, we might need to re-download fragments */
1651 GST_DEBUG_OBJECT (qtdemux,
1652 "let upstream handle seek for fragmented playback");
1656 if (seek_format == GST_FORMAT_BYTES) {
1657 GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1658 gst_event_unref (event);
1662 gst_event_parse_seek_trickmode_interval (event,
1663 &qtdemux->trickmode_interval);
1665 /* Build complete index for seeking;
1666 * if not a fragmented file at least and we're really doing a seek,
1667 * not just an instant-rate-change */
1668 if (!qtdemux->fragmented && !instant_rate_change) {
1669 if (!qtdemux_ensure_index (qtdemux))
1672 #ifndef GST_DISABLE_GST_DEBUG
1673 ts = gst_util_get_timestamp () - ts;
1674 GST_INFO_OBJECT (qtdemux,
1675 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1677 if (qtdemux->pullbased) {
1678 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1679 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1680 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1682 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1683 && QTDEMUX_N_STREAMS (qtdemux)
1684 && !qtdemux->fragmented) {
1685 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1687 GST_DEBUG_OBJECT (qtdemux,
1688 "ignoring seek in push mode in current state");
1691 gst_event_unref (event);
1696 res = gst_pad_event_default (pad, parent, event);
1706 GST_ERROR_OBJECT (qtdemux, "Index failed");
1707 gst_event_unref (event);
1713 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1715 * If @fw is false, the coding order is explored backwards.
1717 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1718 * sample is found for that track.
1720 * The stream and sample index of the sample with the minimum offset in the direction explored
1721 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1723 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1724 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1725 * @_stream and @_index. */
1727 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1728 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1731 gint64 time, min_time;
1732 QtDemuxStream *stream;
1739 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1742 gboolean set_sample;
1744 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1751 i = str->n_samples - 1;
1755 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1756 if (str->samples[i].size == 0)
1759 if (fw && (str->samples[i].offset < byte_pos))
1762 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1765 /* move stream to first available sample */
1767 gst_qtdemux_move_stream (qtdemux, str, i);
1771 /* avoid index from sparse streams since they might be far away */
1772 if (!CUR_STREAM (str)->sparse) {
1773 /* determine min/max time */
1774 time = QTSAMPLE_PTS (str, &str->samples[i]);
1775 if (min_time == -1 || (!fw && time > min_time) ||
1776 (fw && time < min_time)) {
1780 /* determine stream with leading sample, to get its position */
1782 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1783 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1791 /* no sample for this stream, mark eos */
1793 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1804 /* Copied from mpegtsbase code */
1805 /* FIXME: replace this function when we add new util function for stream-id creation */
1807 _get_upstream_id (GstQTDemux * demux)
1809 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1812 /* Try to create one from the upstream URI, else use a randome number */
1816 /* Try to generate one from the URI query and
1817 * if it fails take a random number instead */
1818 query = gst_query_new_uri ();
1819 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1820 gst_query_parse_uri (query, &uri);
1826 /* And then generate an SHA256 sum of the URI */
1827 cs = g_checksum_new (G_CHECKSUM_SHA256);
1828 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1830 upstream_id = g_strdup (g_checksum_get_string (cs));
1831 g_checksum_free (cs);
1833 /* Just get some random number if the URI query fails */
1834 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1835 "implementing a deterministic way of creating a stream-id");
1837 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1838 g_random_int (), g_random_int ());
1841 gst_query_unref (query);
1846 static QtDemuxStream *
1847 _create_stream (GstQTDemux * demux, guint32 track_id)
1849 QtDemuxStream *stream;
1852 stream = g_new0 (QtDemuxStream, 1);
1853 stream->demux = demux;
1854 stream->track_id = track_id;
1855 upstream_id = _get_upstream_id (demux);
1856 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1857 g_free (upstream_id);
1858 /* new streams always need a discont */
1859 stream->discont = TRUE;
1860 /* we enable clipping for raw audio/video streams */
1861 stream->need_clip = FALSE;
1862 stream->process_func = NULL;
1863 stream->segment_index = -1;
1864 stream->time_position = 0;
1865 stream->sample_index = -1;
1866 stream->offset_in_sample = 0;
1867 stream->new_stream = TRUE;
1868 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1869 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1870 stream->protected = FALSE;
1871 stream->protection_scheme_type = 0;
1872 stream->protection_scheme_version = 0;
1873 stream->protection_scheme_info = NULL;
1874 stream->n_samples_moof = 0;
1875 stream->duration_moof = 0;
1876 stream->duration_last_moof = 0;
1877 stream->alignment = 1;
1878 stream->stream_tags = gst_tag_list_new_empty ();
1879 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1880 g_queue_init (&stream->protection_scheme_event_queue);
1881 stream->ref_count = 1;
1882 /* consistent default for push based mode */
1883 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1888 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1890 GstStructure *structure;
1891 const gchar *variant;
1892 const GstCaps *mediacaps = NULL;
1894 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1896 structure = gst_caps_get_structure (caps, 0);
1897 variant = gst_structure_get_string (structure, "variant");
1899 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1900 QtDemuxStream *stream;
1901 const GValue *value;
1903 demux->fragmented = TRUE;
1904 demux->mss_mode = TRUE;
1906 if (QTDEMUX_N_STREAMS (demux) > 1) {
1907 /* can't do this, we can only renegotiate for another mss format */
1911 value = gst_structure_get_value (structure, "media-caps");
1914 const GValue *timescale_v;
1916 /* TODO update when stream changes during playback */
1918 if (QTDEMUX_N_STREAMS (demux) == 0) {
1919 stream = _create_stream (demux, 1);
1920 g_ptr_array_add (demux->active_streams, stream);
1921 /* mss has no stsd/stsd entry, use id 0 as default */
1922 stream->stsd_entries_length = 1;
1923 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1924 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1926 stream = QTDEMUX_NTH_STREAM (demux, 0);
1929 timescale_v = gst_structure_get_value (structure, "timescale");
1931 stream->timescale = g_value_get_uint64 (timescale_v);
1933 /* default mss timescale */
1934 stream->timescale = 10000000;
1936 demux->timescale = stream->timescale;
1938 mediacaps = gst_value_get_caps (value);
1939 if (!CUR_STREAM (stream)->caps
1940 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1941 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1943 stream->new_caps = TRUE;
1945 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1946 structure = gst_caps_get_structure (mediacaps, 0);
1947 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1948 stream->subtype = FOURCC_vide;
1950 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1951 gst_structure_get_int (structure, "height",
1952 &CUR_STREAM (stream)->height);
1953 gst_structure_get_fraction (structure, "framerate",
1954 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1955 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1957 stream->subtype = FOURCC_soun;
1958 gst_structure_get_int (structure, "channels",
1959 &CUR_STREAM (stream)->n_channels);
1960 gst_structure_get_int (structure, "rate", &rate);
1961 CUR_STREAM (stream)->rate = rate;
1962 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1963 if (gst_structure_has_field (structure, "original-media-type")) {
1964 const gchar *media_type =
1965 gst_structure_get_string (structure, "original-media-type");
1966 if (g_str_has_prefix (media_type, "video")) {
1967 stream->subtype = FOURCC_vide;
1968 } else if (g_str_has_prefix (media_type, "audio")) {
1969 stream->subtype = FOURCC_soun;
1974 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1976 demux->mss_mode = FALSE;
1983 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1987 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1989 if (hard || qtdemux->upstream_format_is_time) {
1990 qtdemux->state = QTDEMUX_STATE_INITIAL;
1991 qtdemux->neededbytes = 16;
1992 qtdemux->todrop = 0;
1993 qtdemux->pullbased = FALSE;
1994 g_clear_pointer (&qtdemux->redirect_location, g_free);
1995 qtdemux->first_mdat = -1;
1996 qtdemux->header_size = 0;
1997 qtdemux->mdatoffset = -1;
1998 qtdemux->restoredata_offset = -1;
1999 if (qtdemux->mdatbuffer)
2000 gst_buffer_unref (qtdemux->mdatbuffer);
2001 if (qtdemux->restoredata_buffer)
2002 gst_buffer_unref (qtdemux->restoredata_buffer);
2003 qtdemux->mdatbuffer = NULL;
2004 qtdemux->restoredata_buffer = NULL;
2005 qtdemux->mdatleft = 0;
2006 qtdemux->mdatsize = 0;
2007 if (qtdemux->comp_brands)
2008 gst_buffer_unref (qtdemux->comp_brands);
2009 qtdemux->comp_brands = NULL;
2010 qtdemux->last_moov_offset = -1;
2011 if (qtdemux->moov_node_compressed) {
2012 g_node_destroy (qtdemux->moov_node_compressed);
2013 if (qtdemux->moov_node)
2014 g_free (qtdemux->moov_node->data);
2016 qtdemux->moov_node_compressed = NULL;
2017 if (qtdemux->moov_node)
2018 g_node_destroy (qtdemux->moov_node);
2019 qtdemux->moov_node = NULL;
2020 if (qtdemux->tag_list)
2021 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2022 qtdemux->tag_list = gst_tag_list_new_empty ();
2023 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2025 if (qtdemux->element_index)
2026 gst_object_unref (qtdemux->element_index);
2027 qtdemux->element_index = NULL;
2029 qtdemux->major_brand = 0;
2030 qtdemux->upstream_format_is_time = FALSE;
2031 qtdemux->upstream_seekable = FALSE;
2032 qtdemux->upstream_size = 0;
2034 qtdemux->fragment_start = -1;
2035 qtdemux->fragment_start_offset = -1;
2036 qtdemux->duration = 0;
2037 qtdemux->moof_offset = 0;
2038 qtdemux->chapters_track_id = 0;
2039 qtdemux->have_group_id = FALSE;
2040 qtdemux->group_id = G_MAXUINT;
2042 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2044 g_queue_clear (&qtdemux->protection_event_queue);
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 /* Maps the @segment to the qt edts internal segments and pushes
2104 * the corresponding segment event.
2106 * If it ends up being at a empty segment, a gap will be pushed and the next
2107 * edts segment will be activated in sequence.
2109 * To be used in push-mode only */
2111 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2115 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2116 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2118 stream->time_position = segment->start;
2120 /* in push mode we should be guaranteed that we will have empty segments
2121 * at the beginning and then one segment after, other scenarios are not
2122 * supported and are discarded when parsing the edts */
2123 for (i = 0; i < stream->n_segments; i++) {
2124 if (stream->segments[i].stop_time > segment->start) {
2125 /* push the empty segment and move to the next one */
2126 gst_qtdemux_activate_segment (qtdemux, stream, i,
2127 stream->time_position);
2128 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2129 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2130 stream->time_position);
2132 /* accumulate previous segments */
2133 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2134 stream->accumulated_base +=
2135 (stream->segment.stop -
2136 stream->segment.start) / ABS (stream->segment.rate);
2140 g_assert (i == stream->n_segments - 1);
2147 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2158 for (i = 0; i < len; i++) {
2159 QtDemuxStream *stream = g_ptr_array_index (src, i);
2161 #ifndef GST_DISABLE_GST_DEBUG
2162 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2163 stream, GST_STR_NULL (stream->stream_id), dest);
2165 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2168 g_ptr_array_set_size (src, 0);
2172 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2175 GstQTDemux *demux = GST_QTDEMUX (parent);
2176 gboolean res = TRUE;
2178 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2180 switch (GST_EVENT_TYPE (event)) {
2181 case GST_EVENT_SEGMENT:
2184 QtDemuxStream *stream;
2188 /* some debug output */
2189 gst_event_copy_segment (event, &segment);
2190 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2193 if (segment.format == GST_FORMAT_TIME) {
2194 demux->upstream_format_is_time = TRUE;
2195 demux->segment_seqnum = gst_event_get_seqnum (event);
2197 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2198 "not in time format");
2200 /* chain will send initial newsegment after pads have been added */
2201 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2202 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2207 /* check if this matches a time seek we received previously
2208 * FIXME for backwards compatibility reasons we use the
2209 * seek_offset here to compare. In the future we might want to
2210 * change this to use the seqnum as it uniquely should identify
2211 * the segment that corresponds to the seek. */
2212 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2213 ", received segment offset %" G_GINT64_FORMAT,
2214 demux->seek_offset, segment.start);
2215 if (segment.format == GST_FORMAT_BYTES
2216 && demux->seek_offset == segment.start) {
2217 GST_OBJECT_LOCK (demux);
2218 offset = segment.start;
2220 segment.format = GST_FORMAT_TIME;
2221 segment.start = demux->push_seek_start;
2222 segment.stop = demux->push_seek_stop;
2223 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2224 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2225 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2226 GST_OBJECT_UNLOCK (demux);
2229 /* we only expect a BYTE segment, e.g. following a seek */
2230 if (segment.format == GST_FORMAT_BYTES) {
2231 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2232 offset = segment.start;
2234 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2235 NULL, (gint64 *) & segment.start);
2236 if ((gint64) segment.start < 0)
2239 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2240 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2241 NULL, (gint64 *) & segment.stop);
2242 /* keyframe seeking should already arrange for start >= stop,
2243 * but make sure in other rare cases */
2244 segment.stop = MAX (segment.stop, segment.start);
2246 } else if (segment.format == GST_FORMAT_TIME) {
2247 /* push all data on the adapter before starting this
2249 gst_qtdemux_process_adapter (demux, TRUE);
2251 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2255 /* We shouldn't modify upstream driven TIME FORMAT segment */
2256 if (!demux->upstream_format_is_time) {
2257 /* accept upstream's notion of segment and distribute along */
2258 segment.format = GST_FORMAT_TIME;
2259 segment.position = segment.time = segment.start;
2260 segment.duration = demux->segment.duration;
2261 segment.base = gst_segment_to_running_time (&demux->segment,
2262 GST_FORMAT_TIME, demux->segment.position);
2265 gst_segment_copy_into (&segment, &demux->segment);
2266 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2268 /* map segment to internal qt segments and push on each stream */
2269 if (QTDEMUX_N_STREAMS (demux)) {
2270 demux->need_segment = TRUE;
2271 gst_qtdemux_check_send_pending_segment (demux);
2274 /* clear leftover in current segment, if any */
2275 gst_adapter_clear (demux->adapter);
2277 /* set up streaming thread */
2278 demux->offset = offset;
2279 if (demux->upstream_format_is_time) {
2280 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2281 "set values to restart reading from a new atom");
2282 demux->neededbytes = 16;
2285 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2288 demux->todrop = stream->samples[idx].offset - offset;
2289 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2291 /* set up for EOS */
2292 demux->neededbytes = -1;
2297 gst_event_unref (event);
2301 case GST_EVENT_FLUSH_START:
2303 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2304 gst_event_unref (event);
2307 QTDEMUX_EXPOSE_LOCK (demux);
2308 res = gst_pad_event_default (demux->sinkpad, parent, event);
2309 QTDEMUX_EXPOSE_UNLOCK (demux);
2312 case GST_EVENT_FLUSH_STOP:
2316 dur = demux->segment.duration;
2317 gst_qtdemux_reset (demux, FALSE);
2318 demux->segment.duration = dur;
2320 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2321 gst_event_unref (event);
2327 /* If we are in push mode, and get an EOS before we've seen any streams,
2328 * then error out - we have nowhere to send the EOS */
2329 if (!demux->pullbased) {
2331 gboolean has_valid_stream = FALSE;
2332 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2333 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2334 has_valid_stream = TRUE;
2338 if (!has_valid_stream)
2339 gst_qtdemux_post_no_playable_stream_error (demux);
2341 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2342 (guint) gst_adapter_available (demux->adapter));
2343 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2349 case GST_EVENT_CAPS:{
2350 GstCaps *caps = NULL;
2352 gst_event_parse_caps (event, &caps);
2353 gst_qtdemux_setcaps (demux, caps);
2355 gst_event_unref (event);
2358 case GST_EVENT_PROTECTION:
2360 const gchar *system_id = NULL;
2362 gst_event_parse_protection (event, &system_id, NULL, NULL);
2363 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2365 gst_qtdemux_append_protection_system_id (demux, system_id);
2366 /* save the event for later, for source pads that have not been created */
2367 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2368 /* send it to all pads that already exist */
2369 gst_qtdemux_push_event (demux, event);
2373 case GST_EVENT_STREAM_START:
2376 gst_event_unref (event);
2378 /* Drain all the buffers */
2379 gst_qtdemux_process_adapter (demux, TRUE);
2380 gst_qtdemux_reset (demux, FALSE);
2381 /* We expect new moov box after new stream-start event */
2382 if (demux->exposed) {
2383 gst_qtdemux_stream_concat (demux,
2384 demux->old_streams, demux->active_streams);
2393 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2400 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2403 GstQTDemux *demux = GST_QTDEMUX (parent);
2404 gboolean res = FALSE;
2406 switch (GST_QUERY_TYPE (query)) {
2407 case GST_QUERY_BITRATE:
2409 GstClockTime duration;
2411 /* populate demux->upstream_size if not done yet */
2412 gst_qtdemux_check_seekability (demux);
2414 if (demux->upstream_size != -1
2415 && gst_qtdemux_get_duration (demux, &duration)) {
2417 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2420 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2421 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2422 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2424 /* TODO: better results based on ranges/index tables */
2425 gst_query_set_bitrate (query, bitrate);
2431 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2441 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2443 GstQTDemux *demux = GST_QTDEMUX (element);
2445 GST_OBJECT_LOCK (demux);
2446 if (demux->element_index)
2447 gst_object_unref (demux->element_index);
2449 demux->element_index = gst_object_ref (index);
2451 demux->element_index = NULL;
2453 GST_OBJECT_UNLOCK (demux);
2454 /* object lock might be taken again */
2456 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2457 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2458 demux->element_index, demux->index_id);
2462 gst_qtdemux_get_index (GstElement * element)
2464 GstIndex *result = NULL;
2465 GstQTDemux *demux = GST_QTDEMUX (element);
2467 GST_OBJECT_LOCK (demux);
2468 if (demux->element_index)
2469 result = gst_object_ref (demux->element_index);
2470 GST_OBJECT_UNLOCK (demux);
2472 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2479 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2481 g_free ((gpointer) stream->stco.data);
2482 stream->stco.data = NULL;
2483 g_free ((gpointer) stream->stsz.data);
2484 stream->stsz.data = NULL;
2485 g_free ((gpointer) stream->stsc.data);
2486 stream->stsc.data = NULL;
2487 g_free ((gpointer) stream->stts.data);
2488 stream->stts.data = NULL;
2489 g_free ((gpointer) stream->stss.data);
2490 stream->stss.data = NULL;
2491 g_free ((gpointer) stream->stps.data);
2492 stream->stps.data = NULL;
2493 g_free ((gpointer) stream->ctts.data);
2494 stream->ctts.data = NULL;
2498 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2500 g_free (stream->segments);
2501 stream->segments = NULL;
2502 stream->segment_index = -1;
2503 stream->accumulated_base = 0;
2507 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2509 g_free (stream->samples);
2510 stream->samples = NULL;
2511 gst_qtdemux_stbl_free (stream);
2514 g_free (stream->ra_entries);
2515 stream->ra_entries = NULL;
2516 stream->n_ra_entries = 0;
2518 stream->sample_index = -1;
2519 stream->stbl_index = -1;
2520 stream->n_samples = 0;
2521 stream->time_position = 0;
2523 stream->n_samples_moof = 0;
2524 stream->duration_moof = 0;
2525 stream->duration_last_moof = 0;
2529 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2532 if (stream->allocator)
2533 gst_object_unref (stream->allocator);
2534 while (stream->buffers) {
2535 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2536 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2538 for (i = 0; i < stream->stsd_entries_length; i++) {
2539 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2540 if (entry->rgb8_palette) {
2541 gst_memory_unref (entry->rgb8_palette);
2542 entry->rgb8_palette = NULL;
2544 entry->sparse = FALSE;
2547 if (stream->stream_tags)
2548 gst_tag_list_unref (stream->stream_tags);
2550 stream->stream_tags = gst_tag_list_new_empty ();
2551 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2552 g_free (stream->redirect_uri);
2553 stream->redirect_uri = NULL;
2554 stream->sent_eos = FALSE;
2555 stream->protected = FALSE;
2556 if (stream->protection_scheme_info) {
2557 if (stream->protection_scheme_type == FOURCC_cenc
2558 || stream->protection_scheme_type == FOURCC_cbcs) {
2559 QtDemuxCencSampleSetInfo *info =
2560 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2561 if (info->default_properties)
2562 gst_structure_free (info->default_properties);
2563 if (info->crypto_info)
2564 g_ptr_array_free (info->crypto_info, TRUE);
2566 if (stream->protection_scheme_type == FOURCC_aavd) {
2567 QtDemuxAavdEncryptionInfo *info =
2568 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2569 if (info->default_properties)
2570 gst_structure_free (info->default_properties);
2572 g_free (stream->protection_scheme_info);
2573 stream->protection_scheme_info = NULL;
2575 stream->protection_scheme_type = 0;
2576 stream->protection_scheme_version = 0;
2577 g_queue_foreach (&stream->protection_scheme_event_queue,
2578 (GFunc) gst_event_unref, NULL);
2579 g_queue_clear (&stream->protection_scheme_event_queue);
2580 gst_qtdemux_stream_flush_segments_data (stream);
2581 gst_qtdemux_stream_flush_samples_data (stream);
2585 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2588 gst_qtdemux_stream_clear (stream);
2589 for (i = 0; i < stream->stsd_entries_length; i++) {
2590 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2592 gst_caps_unref (entry->caps);
2596 g_free (stream->stsd_entries);
2597 stream->stsd_entries = NULL;
2598 stream->stsd_entries_length = 0;
2601 static QtDemuxStream *
2602 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2604 g_atomic_int_add (&stream->ref_count, 1);
2610 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2612 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2613 gst_qtdemux_stream_reset (stream);
2614 gst_tag_list_unref (stream->stream_tags);
2616 GstQTDemux *demux = stream->demux;
2617 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2618 GST_OBJECT_LOCK (demux);
2619 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2620 GST_OBJECT_UNLOCK (demux);
2622 g_free (stream->stream_id);
2627 static GstStateChangeReturn
2628 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2630 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2631 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2633 switch (transition) {
2634 case GST_STATE_CHANGE_READY_TO_PAUSED:
2635 gst_qtdemux_reset (qtdemux, TRUE);
2641 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2643 switch (transition) {
2644 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2645 gst_qtdemux_reset (qtdemux, TRUE);
2656 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2658 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2660 g_return_if_fail (GST_IS_CONTEXT (context));
2662 if (gst_context_has_context_type (context,
2663 "drm-preferred-decryption-system-id")) {
2664 const GstStructure *s;
2666 s = gst_context_get_structure (context);
2667 g_free (qtdemux->preferred_protection_system_id);
2668 qtdemux->preferred_protection_system_id =
2669 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2670 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2671 qtdemux->preferred_protection_system_id);
2674 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2678 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2680 /* counts as header data */
2681 qtdemux->header_size += length;
2683 /* only consider at least a sufficiently complete ftyp atom */
2686 guint32 minor_version;
2689 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2690 GST_DEBUG_OBJECT (qtdemux, "ftyp major brand: %" GST_FOURCC_FORMAT,
2691 GST_FOURCC_ARGS (qtdemux->major_brand));
2692 minor_version = QT_UINT32 (buffer + 12);
2693 GST_DEBUG_OBJECT (qtdemux, "ftyp minor version: %u", minor_version);
2694 if (qtdemux->comp_brands)
2695 gst_buffer_unref (qtdemux->comp_brands);
2696 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2697 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2700 length = length - 16;
2701 while (length > 0) {
2702 GST_DEBUG_OBJECT (qtdemux, "ftyp compatible brand: %" GST_FOURCC_FORMAT,
2703 GST_FOURCC_ARGS (QT_FOURCC (p)));
2711 qtdemux_parse_styp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2713 /* only consider at least a sufficiently complete styp atom */
2716 guint32 major_brand;
2717 guint32 minor_version;
2720 major_brand = QT_FOURCC (buffer + 8);
2721 GST_DEBUG_OBJECT (qtdemux, "styp major brand: %" GST_FOURCC_FORMAT,
2722 GST_FOURCC_ARGS (major_brand));
2723 minor_version = QT_UINT32 (buffer + 12);
2724 GST_DEBUG_OBJECT (qtdemux, "styp minor version: %u", minor_version);
2725 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2726 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2729 length = length - 16;
2730 while (length > 0) {
2731 GST_DEBUG_OBJECT (qtdemux, "styp compatible brand: %" GST_FOURCC_FORMAT,
2732 GST_FOURCC_ARGS (QT_FOURCC (p)));
2740 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2741 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2742 guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2743 guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2744 const guint8 * constant_iv)
2746 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2747 gst_buffer_fill (kid_buf, 0, kid, 16);
2748 if (info->default_properties)
2749 gst_structure_free (info->default_properties);
2750 info->default_properties =
2751 gst_structure_new ("application/x-cenc",
2752 "iv_size", G_TYPE_UINT, iv_size,
2753 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2754 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2755 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2756 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2757 gst_buffer_unref (kid_buf);
2758 if (protection_scheme_type == FOURCC_cbcs) {
2759 if (crypt_byte_block != 0 || skip_byte_block != 0) {
2760 gst_structure_set (info->default_properties, "crypt_byte_block",
2761 G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2762 skip_byte_block, NULL);
2764 if (constant_iv != NULL) {
2765 GstBuffer *constant_iv_buf =
2766 gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2767 gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2768 gst_structure_set (info->default_properties, "constant_iv_size",
2769 G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2771 gst_buffer_unref (constant_iv_buf);
2773 gst_structure_set (info->default_properties, "cipher-mode",
2774 G_TYPE_STRING, "cbcs", NULL);
2776 gst_structure_set (info->default_properties, "cipher-mode",
2777 G_TYPE_STRING, "cenc", NULL);
2782 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2783 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2785 guint32 algorithm_id = 0;
2787 gboolean is_encrypted = TRUE;
2790 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2791 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2796 if (algorithm_id == 0) {
2797 is_encrypted = FALSE;
2798 } else if (algorithm_id == 1) {
2799 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2800 } else if (algorithm_id == 2) {
2801 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2804 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2807 if (!gst_byte_reader_get_data (br, 16, &kid))
2810 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2811 is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2812 gst_structure_set (info->default_properties, "piff_algorithm_id",
2813 G_TYPE_UINT, algorithm_id, NULL);
2819 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2827 QtDemuxStream *stream;
2828 GstStructure *structure;
2829 QtDemuxCencSampleSetInfo *ss_info = NULL;
2830 const gchar *system_id;
2831 gboolean uses_sub_sample_encryption = FALSE;
2832 guint32 sample_count;
2834 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2837 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2839 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2840 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2841 GST_WARNING_OBJECT (qtdemux,
2842 "Attempting PIFF box parsing on an unencrypted stream.");
2846 if (!gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2847 G_TYPE_STRING, &system_id, NULL)) {
2848 GST_WARNING_OBJECT (qtdemux, "%s field not present in caps",
2849 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD);
2853 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2855 stream->protected = TRUE;
2856 stream->protection_scheme_type = FOURCC_cenc;
2858 if (!stream->protection_scheme_info)
2859 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2861 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2862 if (!ss_info->default_properties) {
2863 ss_info->default_properties =
2864 gst_structure_new ("application/x-cenc",
2865 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2870 if (ss_info->crypto_info) {
2871 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2872 g_ptr_array_free (ss_info->crypto_info, TRUE);
2873 ss_info->crypto_info = NULL;
2877 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2879 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2880 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2884 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2885 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2889 if ((flags & 0x000001)) {
2890 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2893 } else if ((flags & 0x000002)) {
2894 uses_sub_sample_encryption = TRUE;
2897 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2899 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2903 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2904 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2908 ss_info->crypto_info =
2909 g_ptr_array_new_full (sample_count,
2910 (GDestroyNotify) qtdemux_gst_structure_free);
2912 for (i = 0; i < sample_count; ++i) {
2913 GstStructure *properties;
2917 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2918 if (properties == NULL) {
2919 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2920 qtdemux->cenc_aux_sample_count = i;
2924 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2925 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2926 gst_structure_free (properties);
2927 qtdemux->cenc_aux_sample_count = i;
2930 buf = gst_buffer_new_wrapped (data, iv_size);
2931 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2932 gst_buffer_unref (buf);
2934 if (uses_sub_sample_encryption) {
2935 guint16 n_subsamples;
2936 const GValue *kid_buf_value;
2938 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2939 || n_subsamples == 0) {
2940 GST_ERROR_OBJECT (qtdemux,
2941 "failed to get subsample count for sample %u", i);
2942 gst_structure_free (properties);
2943 qtdemux->cenc_aux_sample_count = i;
2946 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2947 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2948 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2950 gst_structure_free (properties);
2951 qtdemux->cenc_aux_sample_count = i;
2954 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2957 gst_structure_get_value (ss_info->default_properties, "kid");
2959 gst_structure_set (properties,
2960 "subsample_count", G_TYPE_UINT, n_subsamples,
2961 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2962 gst_structure_set_value (properties, "kid", kid_buf_value);
2963 gst_buffer_unref (buf);
2965 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2968 g_ptr_array_add (ss_info->crypto_info, properties);
2971 qtdemux->cenc_aux_sample_count = sample_count;
2975 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2977 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2978 0x97, 0xA9, 0x42, 0xE8,
2979 0x9C, 0x71, 0x99, 0x94,
2980 0x91, 0xE3, 0xAF, 0xAC
2982 static const guint8 playready_uuid[] = {
2983 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2984 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2987 static const guint8 piff_sample_encryption_uuid[] = {
2988 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2989 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2994 /* counts as header data */
2995 qtdemux->header_size += length;
2997 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2999 if (length <= offset + 16) {
3000 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
3004 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
3006 GstTagList *taglist;
3008 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3009 length - offset - 16, NULL);
3010 taglist = gst_tag_list_from_xmp_buffer (buf);
3011 gst_buffer_unref (buf);
3013 /* make sure we have a usable taglist */
3014 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3016 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3018 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3020 const gunichar2 *s_utf16;
3023 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3024 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3025 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3026 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3030 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3031 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3033 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3034 qtdemux_parse_piff (qtdemux, buffer, length, offset);
3036 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3037 GST_READ_UINT32_LE (buffer + offset),
3038 GST_READ_UINT32_LE (buffer + offset + 4),
3039 GST_READ_UINT32_LE (buffer + offset + 8),
3040 GST_READ_UINT32_LE (buffer + offset + 12));
3045 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3047 GstSidxParser sidx_parser;
3048 GstIsoffParserResult res;
3051 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3054 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3056 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3057 if (res == GST_ISOFF_QT_PARSER_DONE) {
3058 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3060 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3064 qtdemux_parse_cstb (GstQTDemux * qtdemux, GstByteReader * data)
3067 guint32 entry_count;
3069 GST_DEBUG_OBJECT (qtdemux, "Parsing CorrectStartTime box");
3071 qtdemux->start_utc_time = GST_CLOCK_TIME_NONE;
3073 if (gst_byte_reader_get_remaining (data) < 4) {
3074 GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box");
3078 entry_count = gst_byte_reader_get_uint32_be_unchecked (data);
3079 if (entry_count == 0)
3082 /* XXX: We assume that all start times are the same as different start times
3083 * would violate the MP4 synchronization model, so we just take the first
3084 * one here and apply it to all tracks.
3087 if (gst_byte_reader_get_remaining (data) < entry_count * 12) {
3088 GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box");
3093 gst_byte_reader_skip_unchecked (data, 4);
3095 /* In 100ns intervals */
3096 start_time = gst_byte_reader_get_uint64_be_unchecked (data);
3098 /* Convert from Jan 1 1601 to Jan 1 1970 */
3099 if (start_time < 11644473600 * G_GUINT64_CONSTANT (10000000)) {
3100 GST_WARNING_OBJECT (qtdemux, "Start UTC time before UNIX epoch");
3103 start_time -= 11644473600 * G_GUINT64_CONSTANT (10000000);
3105 /* Convert to GstClockTime */
3108 GST_DEBUG_OBJECT (qtdemux, "Start UTC time: %" GST_TIME_FORMAT,
3109 GST_TIME_ARGS (start_time));
3111 qtdemux->start_utc_time = start_time;
3114 /* caller verifies at least 8 bytes in buf */
3116 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3117 guint64 * plength, guint32 * pfourcc)
3122 length = QT_UINT32 (data);
3123 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3124 fourcc = QT_FOURCC (data + 4);
3125 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3128 length = G_MAXUINT64;
3129 } else if (length == 1 && size >= 16) {
3130 /* this means we have an extended size, which is the 64 bit value of
3131 * the next 8 bytes */
3132 length = QT_UINT64 (data + 8);
3133 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3143 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3145 guint32 version = 0;
3146 GstClockTime duration = 0;
3148 if (!gst_byte_reader_get_uint32_be (br, &version))
3153 if (!gst_byte_reader_get_uint64_be (br, &duration))
3158 if (!gst_byte_reader_get_uint32_be (br, &dur))
3163 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3164 qtdemux->duration = duration;
3170 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3176 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3177 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3179 if (!stream->parsed_trex && qtdemux->moov_node) {
3181 GstByteReader trex_data;
3183 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3185 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3188 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3190 /* skip version/flags */
3191 if (!gst_byte_reader_skip (&trex_data, 4))
3193 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3195 if (id != stream->track_id)
3197 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3199 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3201 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3203 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3206 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3207 "duration %d, size %d, flags 0x%x", stream->track_id,
3210 stream->parsed_trex = TRUE;
3211 stream->def_sample_description_index = sdi;
3212 stream->def_sample_duration = dur;
3213 stream->def_sample_size = size;
3214 stream->def_sample_flags = flags;
3217 /* iterate all siblings */
3218 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3224 *ds_duration = stream->def_sample_duration;
3225 *ds_size = stream->def_sample_size;
3226 *ds_flags = stream->def_sample_flags;
3228 /* even then, above values are better than random ... */
3229 if (G_UNLIKELY (!stream->parsed_trex)) {
3230 GST_WARNING_OBJECT (qtdemux,
3231 "failed to find fragment defaults for stream %d", stream->track_id);
3238 /* This method should be called whenever a more accurate duration might
3239 * have been found. It will update all relevant variables if/where needed
3242 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3246 GstClockTime prevdur;
3248 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3250 if (movdur > qtdemux->duration) {
3251 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3252 GST_DEBUG_OBJECT (qtdemux,
3253 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3254 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3255 qtdemux->duration = movdur;
3256 GST_DEBUG_OBJECT (qtdemux,
3257 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3258 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3259 GST_TIME_ARGS (qtdemux->segment.stop));
3260 if (qtdemux->segment.duration == prevdur) {
3261 /* If the current segment has duration/stop identical to previous duration
3262 * update them also (because they were set at that point in time with
3263 * the wrong duration */
3264 /* We convert the value *from* the timescale version to avoid rounding errors */
3265 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3266 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3267 qtdemux->segment.duration = fixeddur;
3268 qtdemux->segment.stop = fixeddur;
3272 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3273 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3275 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3276 if (movdur > stream->duration) {
3277 GST_DEBUG_OBJECT (qtdemux,
3278 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3279 GST_TIME_ARGS (duration));
3280 stream->duration = movdur;
3281 /* internal duration tracking state has been updated above, so */
3282 /* preserve an open-ended dummy segment rather than repeatedly updating
3283 * it and spamming downstream accordingly with segment events */
3284 /* also mangle the edit list end time when fragmented with a single edit
3285 * list that may only cover any non-fragmented data */
3286 if ((stream->dummy_segment ||
3287 (qtdemux->fragmented && stream->n_segments == 1)) &&
3288 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3289 /* Update all dummy values to new duration */
3290 stream->segments[0].stop_time = duration;
3291 stream->segments[0].duration = duration;
3292 stream->segments[0].media_stop = duration;
3294 /* let downstream know we possibly have a new stop time */
3295 if (stream->segment_index != -1) {
3298 if (qtdemux->segment.rate >= 0) {
3299 pos = stream->segment.start;
3301 pos = stream->segment.stop;
3304 gst_qtdemux_stream_update_segment (qtdemux, stream,
3305 stream->segment_index, pos, NULL, NULL);
3313 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3314 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3315 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3316 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3319 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3321 gint32 data_offset = 0;
3323 guint32 flags = 0, first_flags = 0, samples_count = 0;
3326 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3327 QtDemuxSample *sample;
3328 gboolean ismv = FALSE;
3329 gint64 initial_offset;
3332 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3333 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3334 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3335 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3337 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3338 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3342 /* presence of stss or not can't really tell us much,
3343 * and flags and so on tend to be marginally reliable in these files */
3344 if (stream->subtype == FOURCC_soun) {
3345 GST_DEBUG_OBJECT (qtdemux,
3346 "sound track in fragmented file; marking all keyframes");
3347 stream->all_keyframe = TRUE;
3350 if (!gst_byte_reader_get_uint8 (trun, &version) ||
3351 !gst_byte_reader_get_uint24_be (trun, &flags))
3354 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3357 if (flags & TR_DATA_OFFSET) {
3358 /* note this is really signed */
3359 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3361 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3362 /* default base offset = first byte of moof */
3363 if (*base_offset == -1) {
3364 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3365 *base_offset = moof_offset;
3367 *running_offset = *base_offset + data_offset;
3369 /* if no offset at all, that would mean data starts at moof start,
3370 * which is a bit wrong and is ismv crappy way, so compensate
3371 * assuming data is in mdat following moof */
3372 if (*base_offset == -1) {
3373 *base_offset = moof_offset + moof_length + 8;
3374 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3377 if (*running_offset == -1)
3378 *running_offset = *base_offset;
3381 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3383 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3384 data_offset, flags, samples_count);
3386 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3387 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3388 GST_DEBUG_OBJECT (qtdemux,
3389 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3390 flags ^= TR_FIRST_SAMPLE_FLAGS;
3392 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3394 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3398 /* FIXME ? spec says other bits should also be checked to determine
3399 * entry size (and prefix size for that matter) */
3401 dur_offset = size_offset = 0;
3402 if (flags & TR_SAMPLE_DURATION) {
3403 GST_LOG_OBJECT (qtdemux, "entry duration present");
3404 dur_offset = entry_size;
3407 if (flags & TR_SAMPLE_SIZE) {
3408 GST_LOG_OBJECT (qtdemux, "entry size present");
3409 size_offset = entry_size;
3412 if (flags & TR_SAMPLE_FLAGS) {
3413 GST_LOG_OBJECT (qtdemux, "entry flags present");
3414 flags_offset = entry_size;
3417 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3418 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3419 ct_offset = entry_size;
3423 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3425 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3427 if (stream->n_samples + samples_count >=
3428 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3431 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3432 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3433 (stream->n_samples + samples_count) *
3434 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3436 /* create a new array of samples if it's the first sample parsed */
3437 if (stream->n_samples == 0) {
3438 g_assert (stream->samples == NULL);
3439 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3440 /* or try to reallocate it with space enough to insert the new samples */
3442 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3443 stream->n_samples + samples_count);
3444 if (stream->samples == NULL)
3447 if (qtdemux->fragment_start != -1) {
3448 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3449 qtdemux->fragment_start = -1;
3451 if (stream->n_samples == 0) {
3452 if (decode_ts > 0) {
3453 timestamp = decode_ts;
3454 } else if (stream->pending_seek != NULL) {
3455 /* if we don't have a timestamp from a tfdt box, we'll use the one
3456 * from the mfra seek table */
3457 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3458 GST_TIME_ARGS (stream->pending_seek->ts));
3460 /* FIXME: this is not fully correct, the timestamp refers to the random
3461 * access sample refered to in the tfra entry, which may not necessarily
3462 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3463 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3468 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3469 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3470 GST_TIME_ARGS (gst_ts));
3472 /* subsequent fragments extend stream */
3474 stream->samples[stream->n_samples - 1].timestamp +
3475 stream->samples[stream->n_samples - 1].duration;
3477 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3478 * difference (1 sec.) between decode_ts and timestamp, prefer the
3480 if (has_tfdt && !qtdemux->upstream_format_is_time
3481 && ABSDIFF (decode_ts, timestamp) >
3482 MAX (stream->duration_last_moof / 2,
3483 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3484 GST_INFO_OBJECT (qtdemux,
3485 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3486 ") are significantly different (more than %" GST_TIME_FORMAT
3487 "), using decode_ts",
3488 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3489 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3490 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3491 MAX (stream->duration_last_moof / 2,
3492 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3493 timestamp = decode_ts;
3496 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3497 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3498 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3502 initial_offset = *running_offset;
3504 sample = stream->samples + stream->n_samples;
3505 for (i = 0; i < samples_count; i++) {
3506 guint32 dur, size, sflags;
3509 /* first read sample data */
3510 if (flags & TR_SAMPLE_DURATION) {
3511 dur = QT_UINT32 (data + dur_offset);
3513 dur = d_sample_duration;
3515 if (flags & TR_SAMPLE_SIZE) {
3516 size = QT_UINT32 (data + size_offset);
3518 size = d_sample_size;
3520 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3522 sflags = first_flags;
3524 sflags = d_sample_flags;
3526 } else if (flags & TR_SAMPLE_FLAGS) {
3527 sflags = QT_UINT32 (data + flags_offset);
3529 sflags = d_sample_flags;
3532 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3533 /* Read offsets as signed numbers regardless of trun version as very
3534 * high offsets are unlikely and there are files out there that use
3535 * version=0 truns with negative offsets */
3536 ct = QT_UINT32 (data + ct_offset);
3538 /* FIXME: Set offset to 0 for "no decode samples". This needs
3539 * to be handled in a codec specific manner ideally. */
3540 if (ct == G_MININT32)
3547 /* fill the sample information */
3548 sample->offset = *running_offset;
3549 sample->pts_offset = ct;
3550 sample->size = size;
3551 sample->timestamp = timestamp;
3552 sample->duration = dur;
3553 /* sample-is-difference-sample */
3554 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3555 * now idea how it relates to bitfield other than massive LE/BE confusion */
3556 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3557 *running_offset += size;
3559 stream->duration_moof += dur;
3566 /* Shift PTS/DTS to allow for negative composition offsets while keeping
3567 * A/V sync in place. This is similar to the code handling ctts/cslg in the
3568 * non-fragmented case.
3571 stream->cslg_shift = -min_ct;
3573 stream->cslg_shift = 0;
3575 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
3576 stream->cslg_shift);
3578 /* Update total duration if needed */
3579 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3581 /* Pre-emptively figure out size of mdat based on trun information.
3582 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3583 * size, else we will still be able to use this when dealing with gap'ed
3585 qtdemux->mdatleft = *running_offset - initial_offset;
3586 qtdemux->mdatoffset = initial_offset;
3587 qtdemux->mdatsize = qtdemux->mdatleft;
3589 stream->n_samples += samples_count;
3590 stream->n_samples_moof += samples_count;
3592 if (stream->pending_seek != NULL)
3593 stream->pending_seek = NULL;
3599 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3604 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3610 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3611 "be larger than %uMB (broken file?)", stream->n_samples,
3612 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3617 /* find stream with @id */
3618 static inline QtDemuxStream *
3619 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3621 QtDemuxStream *stream;
3625 if (G_UNLIKELY (!id)) {
3626 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3630 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3631 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3632 if (stream->track_id == id)
3635 if (qtdemux->mss_mode) {
3636 /* mss should have only 1 stream anyway */
3637 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3644 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3645 guint32 * fragment_number)
3647 if (!gst_byte_reader_skip (mfhd, 4))
3649 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3654 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3660 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3661 QtDemuxStream ** stream, guint32 * default_sample_duration,
3662 guint32 * default_sample_size, guint32 * default_sample_flags,
3663 gint64 * base_offset)
3666 guint32 track_id = 0;
3668 if (!gst_byte_reader_skip (tfhd, 1) ||
3669 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3672 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3675 *stream = qtdemux_find_stream (qtdemux, track_id);
3676 if (G_UNLIKELY (!*stream))
3677 goto unknown_stream;
3679 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3680 *base_offset = qtdemux->moof_offset;
3682 if (flags & TF_BASE_DATA_OFFSET)
3683 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3686 /* obtain stream defaults */
3687 if (qtdemux_parse_trex (qtdemux, *stream,
3688 default_sample_duration, default_sample_size, default_sample_flags)) {
3690 /* Default sample description index is only valid if trex parsing succeeded */
3691 (*stream)->stsd_sample_description_id =
3692 (*stream)->def_sample_description_index - 1;
3695 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3696 guint32 sample_description_index;
3697 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3699 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3702 if (qtdemux->mss_mode) {
3703 /* mss has no stsd entry */
3704 (*stream)->stsd_sample_description_id = 0;
3707 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3708 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3711 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3712 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3715 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3716 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3723 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3728 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3734 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3735 guint64 * decode_time)
3737 guint32 version = 0;
3739 if (!gst_byte_reader_get_uint32_be (br, &version))
3744 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3747 guint32 dec_time = 0;
3748 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3750 *decode_time = dec_time;
3753 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3760 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3765 /* Returns a pointer to a GstStructure containing the properties of
3766 * the stream sample identified by @sample_index. The caller must unref
3767 * the returned object after use. Returns NULL if unsuccessful. */
3768 static GstStructure *
3769 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3770 QtDemuxStream * stream, guint sample_index)
3772 QtDemuxCencSampleSetInfo *info = NULL;
3774 g_return_val_if_fail (stream != NULL, NULL);
3775 g_return_val_if_fail (stream->protected, NULL);
3776 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3778 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3780 /* Currently, cenc properties for groups of samples are not supported, so
3781 * simply return a copy of the default sample properties */
3782 return gst_structure_copy (info->default_properties);
3785 /* Parses the sizes of sample auxiliary information contained within a stream,
3786 * as given in a saiz box. Returns array of sample_count guint8 size values,
3787 * or NULL on failure */
3789 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3790 GstByteReader * br, guint32 * sample_count)
3794 guint8 default_info_size;
3796 g_return_val_if_fail (qtdemux != NULL, NULL);
3797 g_return_val_if_fail (stream != NULL, NULL);
3798 g_return_val_if_fail (br != NULL, NULL);
3799 g_return_val_if_fail (sample_count != NULL, NULL);
3801 if (!gst_byte_reader_get_uint32_be (br, &flags))
3805 /* aux_info_type and aux_info_type_parameter are ignored */
3806 if (!gst_byte_reader_skip (br, 8))
3810 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3812 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3814 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3816 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3819 if (default_info_size == 0) {
3820 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3824 info_sizes = g_new (guint8, *sample_count);
3825 memset (info_sizes, default_info_size, *sample_count);
3831 /* Parses the offset of sample auxiliary information contained within a stream,
3832 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3834 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3835 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3840 guint32 aux_info_type = 0;
3841 guint32 aux_info_type_parameter = 0;
3842 guint32 entry_count;
3845 const guint8 *aux_info_type_data = NULL;
3847 g_return_val_if_fail (qtdemux != NULL, FALSE);
3848 g_return_val_if_fail (stream != NULL, FALSE);
3849 g_return_val_if_fail (br != NULL, FALSE);
3850 g_return_val_if_fail (offset != NULL, FALSE);
3852 if (!gst_byte_reader_get_uint8 (br, &version))
3855 if (!gst_byte_reader_get_uint24_be (br, &flags))
3860 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3862 aux_info_type = QT_FOURCC (aux_info_type_data);
3864 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3866 } else if (stream->protected) {
3867 aux_info_type = stream->protection_scheme_type;
3869 aux_info_type = CUR_STREAM (stream)->fourcc;
3873 *info_type = aux_info_type;
3874 if (info_type_parameter)
3875 *info_type_parameter = aux_info_type_parameter;
3877 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3878 "aux_info_type_parameter: %#06x",
3879 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3881 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3884 if (entry_count != 1) {
3885 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3890 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3892 *offset = (guint64) off_32;
3894 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3899 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3904 qtdemux_gst_structure_free (GstStructure * gststructure)
3907 gst_structure_free (gststructure);
3911 /* Parses auxiliary information relating to samples protected using
3912 * Common Encryption (cenc); the format of this information
3913 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3916 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3917 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3919 QtDemuxCencSampleSetInfo *ss_info = NULL;
3922 GPtrArray *old_crypto_info = NULL;
3923 guint old_entries = 0;
3925 g_return_val_if_fail (qtdemux != NULL, FALSE);
3926 g_return_val_if_fail (stream != NULL, FALSE);
3927 g_return_val_if_fail (br != NULL, FALSE);
3928 g_return_val_if_fail (stream->protected, FALSE);
3929 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3931 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3933 if (ss_info->crypto_info) {
3934 old_crypto_info = ss_info->crypto_info;
3935 /* Count number of non-null entries remaining at the tail end */
3936 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3937 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3943 ss_info->crypto_info =
3944 g_ptr_array_new_full (sample_count + old_entries,
3945 (GDestroyNotify) qtdemux_gst_structure_free);
3947 /* We preserve old entries because we parse the next moof in advance
3948 * of consuming all samples from the previous moof, and otherwise
3949 * we'd discard the corresponding crypto info for the samples
3950 * from the previous fragment. */
3952 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3954 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3955 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3957 g_ptr_array_index (old_crypto_info, i) = NULL;
3961 if (old_crypto_info) {
3962 /* Everything now belongs to the new array */
3963 g_ptr_array_free (old_crypto_info, TRUE);
3966 for (i = 0; i < sample_count; ++i) {
3967 GstStructure *properties;
3968 guint16 n_subsamples = 0;
3972 gboolean could_read_iv;
3974 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3975 if (properties == NULL) {
3976 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3979 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3980 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3981 gst_structure_free (properties);
3985 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3986 if (could_read_iv) {
3987 buf = gst_buffer_new_wrapped (data, iv_size);
3988 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3989 gst_buffer_unref (buf);
3990 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3991 const GValue *constant_iv_size_value =
3992 gst_structure_get_value (properties, "constant_iv_size");
3993 const GValue *constant_iv_value =
3994 gst_structure_get_value (properties, "iv");
3995 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3996 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3997 gst_structure_free (properties);
4000 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
4001 gst_structure_remove_field (properties, "constant_iv_size");
4002 } else if (stream->protection_scheme_type == FOURCC_cenc) {
4003 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
4004 gst_structure_free (properties);
4007 size = info_sizes[i];
4008 if (size > iv_size) {
4009 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
4010 || !(n_subsamples > 0)) {
4011 gst_structure_free (properties);
4012 GST_ERROR_OBJECT (qtdemux,
4013 "failed to get subsample count for sample %u", i);
4016 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
4017 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
4018 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
4020 gst_structure_free (properties);
4023 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
4025 gst_structure_free (properties);
4028 gst_structure_set (properties,
4029 "subsample_count", G_TYPE_UINT, n_subsamples,
4030 "subsamples", GST_TYPE_BUFFER, buf, NULL);
4031 gst_buffer_unref (buf);
4033 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
4035 g_ptr_array_add (ss_info->crypto_info, properties);
4040 /* Converts a UUID in raw byte form to a string representation, as defined in
4041 * RFC 4122. The caller takes ownership of the returned string and is
4042 * responsible for freeing it after use. */
4044 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
4046 const guint8 *uuid = (const guint8 *) uuid_bytes;
4048 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
4049 "%02x%02x-%02x%02x%02x%02x%02x%02x",
4050 uuid[0], uuid[1], uuid[2], uuid[3],
4051 uuid[4], uuid[5], uuid[6], uuid[7],
4052 uuid[8], uuid[9], uuid[10], uuid[11],
4053 uuid[12], uuid[13], uuid[14], uuid[15]);
4056 /* Parses a Protection System Specific Header box (pssh), as defined in the
4057 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
4058 * information needed by a specific content protection system in order to
4059 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
4062 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4064 gchar *sysid_string;
4065 guint32 pssh_size = QT_UINT32 (node->data);
4066 GstBuffer *pssh = NULL;
4067 GstEvent *event = NULL;
4068 guint32 parent_box_type;
4071 if (G_UNLIKELY (pssh_size < 32U)) {
4072 GST_ERROR_OBJECT (qtdemux, "invalid box size");
4077 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4079 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4081 pssh = gst_buffer_new_memdup (node->data, pssh_size);
4082 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4083 gst_buffer_get_size (pssh));
4085 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4087 /* Push an event containing the pssh box onto the queues of all streams. */
4088 event = gst_event_new_protection (sysid_string, pssh,
4089 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4090 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4091 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4092 GST_TRACE_OBJECT (qtdemux,
4093 "adding protection event for stream %s and system %s",
4094 stream->stream_id, sysid_string);
4095 g_queue_push_tail (&stream->protection_scheme_event_queue,
4096 gst_event_ref (event));
4098 g_free (sysid_string);
4099 gst_event_unref (event);
4100 gst_buffer_unref (pssh);
4105 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4106 guint64 moof_offset, QtDemuxStream * stream)
4108 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4110 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4111 GNode *saiz_node, *saio_node, *pssh_node;
4112 GstByteReader saiz_data, saio_data;
4113 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4114 gint64 base_offset, running_offset;
4116 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4118 /* NOTE @stream ignored */
4120 moof_node = g_node_new ((guint8 *) buffer);
4121 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4122 qtdemux_node_dump (qtdemux, moof_node);
4124 /* Get fragment number from mfhd and check it's valid */
4126 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4127 if (mfhd_node == NULL)
4129 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4131 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4133 /* unknown base_offset to start with */
4134 base_offset = running_offset = -1;
4135 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4137 guint64 decode_time = 0;
4139 /* Fragment Header node */
4141 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4145 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4146 &ds_size, &ds_flags, &base_offset))
4149 /* The following code assumes at most a single set of sample auxiliary
4150 * data in the fragment (consisting of a saiz box and a corresponding saio
4151 * box); in theory, however, there could be multiple sets of sample
4152 * auxiliary data in a fragment. */
4154 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4157 guint32 info_type = 0;
4159 guint32 info_type_parameter = 0;
4161 g_free (qtdemux->cenc_aux_info_sizes);
4163 qtdemux->cenc_aux_info_sizes =
4164 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4165 &qtdemux->cenc_aux_sample_count);
4166 if (qtdemux->cenc_aux_info_sizes == NULL) {
4167 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4171 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4174 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4175 g_free (qtdemux->cenc_aux_info_sizes);
4176 qtdemux->cenc_aux_info_sizes = NULL;
4180 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4181 &info_type, &info_type_parameter, &offset))) {
4182 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4183 g_free (qtdemux->cenc_aux_info_sizes);
4184 qtdemux->cenc_aux_info_sizes = NULL;
4187 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4188 offset += (guint64) (base_offset - qtdemux->moof_offset);
4189 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4190 && info_type_parameter == 0U) {
4192 if (offset > length) {
4193 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4194 qtdemux->cenc_aux_info_offset = offset;
4196 gst_byte_reader_init (&br, buffer + offset, length - offset);
4197 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4198 qtdemux->cenc_aux_info_sizes,
4199 qtdemux->cenc_aux_sample_count)) {
4200 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4201 g_free (qtdemux->cenc_aux_info_sizes);
4202 qtdemux->cenc_aux_info_sizes = NULL;
4210 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4213 /* We'll use decode_time to interpolate timestamps
4214 * in case the input timestamps are missing */
4215 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4217 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4218 " (%" GST_TIME_FORMAT ")", decode_time,
4219 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4220 decode_time) : GST_CLOCK_TIME_NONE));
4222 /* Discard the fragment buffer timestamp info to avoid using it.
4223 * Rely on tfdt instead as it is more accurate than the timestamp
4224 * that is fetched from a manifest/playlist and is usually
4226 qtdemux->fragment_start = -1;
4229 if (G_UNLIKELY (!stream)) {
4230 /* we lost track of offset, we'll need to regain it,
4231 * but can delay complaining until later or avoid doing so altogether */
4235 if (G_UNLIKELY (base_offset < -1))
4238 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4240 if (!qtdemux->pullbased) {
4241 /* Sample tables can grow enough to be problematic if the system memory
4242 * is very low (e.g. embedded devices) and the videos very long
4243 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4244 * Fortunately, we can easily discard them for each new fragment when
4245 * we know qtdemux will not receive seeks outside of the current fragment.
4246 * adaptivedemux honors this assumption.
4247 * This optimization is also useful for applications that use qtdemux as
4248 * a push-based simple demuxer, like Media Source Extensions. */
4249 gst_qtdemux_stream_flush_samples_data (stream);
4252 /* initialise moof sample data */
4253 stream->n_samples_moof = 0;
4254 stream->duration_last_moof = stream->duration_moof;
4255 stream->duration_moof = 0;
4257 /* Track Run node */
4259 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4262 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4263 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4264 &running_offset, decode_time, (tfdt_node != NULL));
4265 /* iterate all siblings */
4266 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4268 /* don't use tfdt for subsequent trun as it only refers to the first */
4272 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4274 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4275 guint32 box_length = QT_UINT32 (uuid_buffer);
4277 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4280 /* if no new base_offset provided for next traf,
4281 * base is end of current traf */
4282 base_offset = running_offset;
4283 running_offset = -1;
4285 if (stream->n_samples_moof && stream->duration_moof)
4286 stream->new_caps = TRUE;
4289 /* iterate all siblings */
4290 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4293 /* parse any protection system info */
4294 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4296 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4297 qtdemux_parse_pssh (qtdemux, pssh_node);
4298 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4301 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4302 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4304 /* Unless the user has explicitly requested another seek, perform an
4305 * internal seek to the time specified in the tfdt.
4307 * This way if the user opens a file where the first tfdt is 1 hour
4308 * into the presentation, they will not have to wait 1 hour for run
4309 * time to catch up and actual playback to start. */
4312 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4313 "performing an internal seek to %" GST_TIME_FORMAT,
4314 GST_TIME_ARGS (min_dts));
4316 qtdemux->segment.start = min_dts;
4317 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4319 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4320 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4321 stream->time_position = min_dts;
4324 /* Before this code was run a segment was already sent when the moov was
4325 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4326 * be emitted after a moov, and we can emit a second segment anyway for
4327 * special cases like this. */
4328 qtdemux->need_segment = TRUE;
4331 qtdemux->first_moof_already_parsed = TRUE;
4333 g_node_destroy (moof_node);
4338 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4343 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4348 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4353 g_node_destroy (moof_node);
4354 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4355 (_("This file is corrupt and cannot be played.")), (NULL));
4361 /* might be used if some day we actually use mfra & co
4362 * for random access to fragments,
4363 * but that will require quite some modifications and much less relying
4364 * on a sample array */
4368 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4370 QtDemuxStream *stream;
4371 guint32 ver_flags, track_id, len, num_entries, i;
4372 guint value_size, traf_size, trun_size, sample_size;
4373 guint64 time = 0, moof_offset = 0;
4375 GstBuffer *buf = NULL;
4380 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4382 if (!gst_byte_reader_skip (&tfra, 8))
4385 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4388 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4389 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4390 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4393 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4395 stream = qtdemux_find_stream (qtdemux, track_id);
4397 goto unknown_trackid;
4399 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4400 sample_size = (len & 3) + 1;
4401 trun_size = ((len & 12) >> 2) + 1;
4402 traf_size = ((len & 48) >> 4) + 1;
4404 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4405 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4407 if (num_entries == 0)
4410 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4411 value_size + value_size + traf_size + trun_size + sample_size))
4414 g_free (stream->ra_entries);
4415 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4416 stream->n_ra_entries = num_entries;
4418 for (i = 0; i < num_entries; i++) {
4419 qt_atom_parser_get_offset (&tfra, value_size, &time);
4420 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4421 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4422 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4423 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4425 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4427 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4428 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4430 stream->ra_entries[i].ts = time;
4431 stream->ra_entries[i].moof_offset = moof_offset;
4433 /* don't want to go through the entire file and read all moofs at startup */
4435 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4436 if (ret != GST_FLOW_OK)
4438 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4439 moof_offset, stream);
4440 gst_buffer_unref (buf);
4444 check_update_duration (qtdemux, time);
4451 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4456 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4461 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4467 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4469 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4470 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4471 GstBuffer *mfro = NULL, *mfra = NULL;
4473 gboolean ret = FALSE;
4474 GNode *mfra_node, *tfra_node;
4475 guint64 mfra_offset = 0;
4476 guint32 fourcc, mfra_size;
4479 /* query upstream size in bytes */
4480 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4481 goto size_query_failed;
4483 /* mfro box should be at the very end of the file */
4484 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4485 if (flow != GST_FLOW_OK)
4488 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4490 fourcc = QT_FOURCC (mfro_map.data + 4);
4491 if (fourcc != FOURCC_mfro)
4494 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4495 if (mfro_map.size < 16)
4496 goto invalid_mfro_size;
4498 mfra_size = QT_UINT32 (mfro_map.data + 12);
4499 if (mfra_size >= len)
4500 goto invalid_mfra_size;
4502 mfra_offset = len - mfra_size;
4504 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4505 mfra_offset, mfra_size);
4507 /* now get and parse mfra box */
4508 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4509 if (flow != GST_FLOW_OK)
4512 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4514 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4515 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4517 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4520 qtdemux_parse_tfra (qtdemux, tfra_node);
4521 /* iterate all siblings */
4522 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4524 g_node_destroy (mfra_node);
4526 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4532 if (mfro_map.memory != NULL)
4533 gst_buffer_unmap (mfro, &mfro_map);
4534 gst_buffer_unref (mfro);
4537 if (mfra_map.memory != NULL)
4538 gst_buffer_unmap (mfra, &mfra_map);
4539 gst_buffer_unref (mfra);
4546 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4551 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4556 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4561 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4567 add_offset (guint64 offset, guint64 advance)
4569 /* Avoid 64-bit overflow by clamping */
4570 if (offset > G_MAXUINT64 - advance)
4572 return offset + advance;
4575 static GstFlowReturn
4576 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4580 GstBuffer *buf = NULL;
4581 GstFlowReturn ret = GST_FLOW_OK;
4582 guint64 cur_offset = qtdemux->offset;
4585 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4586 if (G_UNLIKELY (ret != GST_FLOW_OK))
4588 gst_buffer_map (buf, &map, GST_MAP_READ);
4589 if (G_LIKELY (map.size >= 8))
4590 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4591 gst_buffer_unmap (buf, &map);
4592 gst_buffer_unref (buf);
4594 /* maybe we already got most we needed, so only consider this eof */
4595 if (G_UNLIKELY (length == 0)) {
4596 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4597 (_("Invalid atom size.")),
4598 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4599 GST_FOURCC_ARGS (fourcc)));
4606 /* record for later parsing when needed */
4607 if (!qtdemux->moof_offset) {
4608 qtdemux->moof_offset = qtdemux->offset;
4610 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4613 qtdemux->offset += length; /* skip moof and keep going */
4615 if (qtdemux->got_moov) {
4616 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4628 GST_LOG_OBJECT (qtdemux,
4629 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4630 GST_FOURCC_ARGS (fourcc), cur_offset);
4631 qtdemux->offset = add_offset (qtdemux->offset, length);
4636 GstBuffer *moov = NULL;
4638 if (qtdemux->got_moov) {
4639 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4640 qtdemux->offset = add_offset (qtdemux->offset, length);
4644 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4645 if (ret != GST_FLOW_OK)
4647 gst_buffer_map (moov, &map, GST_MAP_READ);
4649 if (length != map.size) {
4650 /* Some files have a 'moov' atom at the end of the file which contains
4651 * a terminal 'free' atom where the body of the atom is missing.
4652 * Check for, and permit, this special case.
4654 if (map.size >= 8) {
4655 guint8 *final_data = map.data + (map.size - 8);
4656 guint32 final_length = QT_UINT32 (final_data);
4657 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4659 if (final_fourcc == FOURCC_free
4660 && map.size + final_length - 8 == length) {
4661 /* Ok, we've found that special case. Allocate a new buffer with
4662 * that free atom actually present. */
4663 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4664 gst_buffer_fill (newmoov, 0, map.data, map.size);
4665 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4666 gst_buffer_unmap (moov, &map);
4667 gst_buffer_unref (moov);
4669 gst_buffer_map (moov, &map, GST_MAP_READ);
4674 if (length != map.size) {
4675 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4676 (_("This file is incomplete and cannot be played.")),
4677 ("We got less than expected (received %" G_GSIZE_FORMAT
4678 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4679 (guint) length, cur_offset));
4680 gst_buffer_unmap (moov, &map);
4681 gst_buffer_unref (moov);
4682 ret = GST_FLOW_ERROR;
4685 qtdemux->offset += length;
4687 qtdemux_parse_moov (qtdemux, map.data, length);
4688 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4690 qtdemux_parse_tree (qtdemux);
4691 if (qtdemux->moov_node_compressed) {
4692 g_node_destroy (qtdemux->moov_node_compressed);
4693 g_free (qtdemux->moov_node->data);
4695 qtdemux->moov_node_compressed = NULL;
4696 g_node_destroy (qtdemux->moov_node);
4697 qtdemux->moov_node = NULL;
4698 gst_buffer_unmap (moov, &map);
4699 gst_buffer_unref (moov);
4700 qtdemux->got_moov = TRUE;
4706 GstBuffer *ftyp = NULL;
4708 /* extract major brand; might come in handy for ISO vs QT issues */
4709 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4710 if (ret != GST_FLOW_OK)
4712 qtdemux->offset += length;
4713 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4714 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4715 gst_buffer_unmap (ftyp, &map);
4716 gst_buffer_unref (ftyp);
4721 GstBuffer *styp = NULL;
4723 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &styp);
4724 if (ret != GST_FLOW_OK)
4726 qtdemux->offset += length;
4727 gst_buffer_map (styp, &map, GST_MAP_READ);
4728 qtdemux_parse_styp (qtdemux, map.data, map.size);
4729 gst_buffer_unmap (styp, &map);
4730 gst_buffer_unref (styp);
4735 GstBuffer *uuid = NULL;
4737 /* uuid are extension atoms */
4738 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4739 if (ret != GST_FLOW_OK)
4741 qtdemux->offset += length;
4742 gst_buffer_map (uuid, &map, GST_MAP_READ);
4743 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4744 gst_buffer_unmap (uuid, &map);
4745 gst_buffer_unref (uuid);
4750 GstBuffer *sidx = NULL;
4751 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4752 if (ret != GST_FLOW_OK)
4754 qtdemux->offset += length;
4755 gst_buffer_map (sidx, &map, GST_MAP_READ);
4756 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4757 gst_buffer_unmap (sidx, &map);
4758 gst_buffer_unref (sidx);
4763 GstBuffer *meta = NULL;
4764 GNode *node, *child;
4765 GstByteReader child_data;
4766 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &meta);
4767 if (ret != GST_FLOW_OK)
4769 qtdemux->offset += length;
4770 gst_buffer_map (meta, &map, GST_MAP_READ);
4772 node = g_node_new (map.data);
4774 qtdemux_parse_node (qtdemux, node, map.data, map.size);
4776 /* Parse ONVIF Export File Format CorrectStartTime box if available */
4778 qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb,
4780 qtdemux_parse_cstb (qtdemux, &child_data);
4783 g_node_destroy (node);
4785 gst_buffer_unmap (meta, &map);
4786 gst_buffer_unref (meta);
4791 GstBuffer *unknown = NULL;
4793 GST_LOG_OBJECT (qtdemux,
4794 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4795 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4797 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4798 if (ret != GST_FLOW_OK)
4800 gst_buffer_map (unknown, &map, GST_MAP_READ);
4801 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4802 gst_buffer_unmap (unknown, &map);
4803 gst_buffer_unref (unknown);
4804 qtdemux->offset += length;
4810 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4811 /* digested all data, show what we have */
4812 qtdemux_prepare_streams (qtdemux);
4813 QTDEMUX_EXPOSE_LOCK (qtdemux);
4814 ret = qtdemux_expose_streams (qtdemux);
4815 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4817 qtdemux->state = QTDEMUX_STATE_MOVIE;
4818 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4825 /* Seeks to the previous keyframe of the indexed stream and
4826 * aligns other streams with respect to the keyframe timestamp
4827 * of indexed stream. Only called in case of Reverse Playback
4829 static GstFlowReturn
4830 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4832 guint32 seg_idx = 0, k_index = 0;
4833 guint32 ref_seg_idx, ref_k_index;
4834 GstClockTime k_pos = 0, last_stop = 0;
4835 QtDemuxSegment *seg = NULL;
4836 QtDemuxStream *ref_str = NULL;
4837 guint64 seg_media_start_mov; /* segment media start time in mov format */
4841 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4842 * and finally align all the other streams on that timestamp with their
4843 * respective keyframes */
4844 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4845 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4847 /* No candidate yet, take the first stream */
4853 /* So that stream has a segment, we prefer video streams */
4854 if (str->subtype == FOURCC_vide) {
4860 if (G_UNLIKELY (!ref_str)) {
4861 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4865 if (G_UNLIKELY (!ref_str->from_sample)) {
4866 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4870 /* So that stream has been playing from from_sample to to_sample. We will
4871 * get the timestamp of the previous sample and search for a keyframe before
4872 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4873 if (ref_str->subtype == FOURCC_vide) {
4874 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4875 ref_str->from_sample - 1, FALSE);
4877 if (ref_str->from_sample >= 10)
4878 k_index = ref_str->from_sample - 10;
4884 ref_str->samples[k_index].timestamp +
4885 ref_str->samples[k_index].pts_offset;
4887 /* get current segment for that stream */
4888 seg = &ref_str->segments[ref_str->segment_index];
4889 /* Use segment start in original timescale for comparisons */
4890 seg_media_start_mov = seg->trak_media_start;
4892 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4893 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4894 k_index, target_ts, seg_media_start_mov,
4895 GST_TIME_ARGS (seg->media_start));
4897 /* Crawl back through segments to find the one containing this I frame */
4898 while (target_ts < seg_media_start_mov) {
4899 GST_DEBUG_OBJECT (qtdemux,
4900 "keyframe position (sample %u) is out of segment %u " " target %"
4901 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4902 ref_str->segment_index, target_ts, seg_media_start_mov);
4904 if (G_UNLIKELY (!ref_str->segment_index)) {
4905 /* Reached first segment, let's consider it's EOS */
4908 ref_str->segment_index--;
4909 seg = &ref_str->segments[ref_str->segment_index];
4910 /* Use segment start in original timescale for comparisons */
4911 seg_media_start_mov = seg->trak_media_start;
4913 /* Calculate time position of the keyframe and where we should stop */
4915 QTSTREAMTIME_TO_GSTTIME (ref_str,
4916 target_ts - seg->trak_media_start) + seg->time;
4918 QTSTREAMTIME_TO_GSTTIME (ref_str,
4919 ref_str->samples[ref_str->from_sample].timestamp -
4920 seg->trak_media_start) + seg->time;
4922 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4923 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4924 k_index, GST_TIME_ARGS (k_pos));
4926 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4927 qtdemux->segment.position = last_stop;
4928 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4929 GST_TIME_ARGS (last_stop));
4931 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4932 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4936 ref_seg_idx = ref_str->segment_index;
4937 ref_k_index = k_index;
4939 /* Align them all on this */
4940 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4942 GstClockTime seg_time = 0;
4943 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4945 /* aligning reference stream again might lead to backing up to yet another
4946 * keyframe (due to timestamp rounding issues),
4947 * potentially putting more load on downstream; so let's try to avoid */
4948 if (str == ref_str) {
4949 seg_idx = ref_seg_idx;
4950 seg = &str->segments[seg_idx];
4951 k_index = ref_k_index;
4952 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4953 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4955 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4956 GST_DEBUG_OBJECT (qtdemux,
4957 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4958 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4960 /* get segment and time in the segment */
4961 seg = &str->segments[seg_idx];
4962 seg_time = k_pos - seg->time;
4964 /* get the media time in the segment.
4965 * No adjustment for empty "filler" segments */
4966 if (seg->media_start != GST_CLOCK_TIME_NONE)
4967 seg_time += seg->media_start;
4969 /* get the index of the sample with media time */
4970 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4971 GST_DEBUG_OBJECT (qtdemux,
4972 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4973 GST_TIME_ARGS (seg_time), index);
4975 /* find previous keyframe */
4976 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4979 /* Remember until where we want to go */
4980 str->to_sample = str->from_sample - 1;
4981 /* Define our time position */
4983 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4984 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4985 if (seg->media_start != GST_CLOCK_TIME_NONE)
4986 str->time_position -= seg->media_start;
4988 /* Now seek back in time */
4989 gst_qtdemux_move_stream (qtdemux, str, k_index);
4990 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4991 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4992 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4998 return GST_FLOW_EOS;
5002 * Gets the current qt segment start, stop and position for the
5003 * given time offset. This is used in update_segment()
5006 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
5007 QtDemuxStream * stream, GstClockTime offset,
5008 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
5010 GstClockTime seg_time;
5011 GstClockTime start, stop, time;
5012 QtDemuxSegment *segment;
5014 segment = &stream->segments[stream->segment_index];
5016 /* get time in this segment */
5017 seg_time = (offset - segment->time) * segment->rate;
5019 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
5020 GST_TIME_ARGS (seg_time));
5022 if (G_UNLIKELY (seg_time > segment->duration)) {
5023 GST_LOG_OBJECT (stream->pad,
5024 "seg_time > segment->duration %" GST_TIME_FORMAT,
5025 GST_TIME_ARGS (segment->duration));
5026 seg_time = segment->duration;
5029 /* qtdemux->segment.stop is in outside-time-realm, whereas
5030 * segment->media_stop is in track-time-realm.
5032 * In order to compare the two, we need to bring segment.stop
5033 * into the track-time-realm
5035 * FIXME - does this comment still hold? Don't see any conversion here */
5037 stop = qtdemux->segment.stop;
5038 if (stop == GST_CLOCK_TIME_NONE)
5039 stop = qtdemux->segment.duration;
5040 if (stop == GST_CLOCK_TIME_NONE)
5041 stop = segment->media_stop;
5044 MIN (segment->media_stop, stop - segment->time + segment->media_start);
5046 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5047 start = segment->time + seg_time;
5049 stop = start - seg_time + segment->duration;
5050 } else if (qtdemux->segment.rate >= 0) {
5051 start = MIN (segment->media_start + seg_time, stop);
5054 if (segment->media_start >= qtdemux->segment.start) {
5055 time = segment->time;
5057 time = segment->time + (qtdemux->segment.start - segment->media_start);
5060 start = MAX (segment->media_start, qtdemux->segment.start);
5061 stop = MIN (segment->media_start + seg_time, stop);
5070 * Updates the qt segment used for the stream and pushes a new segment event
5071 * downstream on this stream's pad.
5074 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5075 gint seg_idx, GstClockTime offset, GstClockTime * _start,
5076 GstClockTime * _stop)
5078 QtDemuxSegment *segment;
5079 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
5083 /* update the current segment */
5084 stream->segment_index = seg_idx;
5086 /* get the segment */
5087 segment = &stream->segments[seg_idx];
5089 if (G_UNLIKELY (offset < segment->time)) {
5090 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
5091 GST_TIME_ARGS (segment->time));
5095 /* segment lies beyond total indicated duration */
5096 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5097 segment->time > qtdemux->segment.duration)) {
5098 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5099 " < segment->time %" GST_TIME_FORMAT,
5100 GST_TIME_ARGS (qtdemux->segment.duration),
5101 GST_TIME_ARGS (segment->time));
5105 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5106 &start, &stop, &time);
5108 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5109 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5110 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5112 /* combine global rate with that of the segment */
5113 rate = segment->rate * qtdemux->segment.rate;
5115 /* Copy flags from main segment */
5116 stream->segment.flags = qtdemux->segment.flags;
5118 /* update the segment values used for clipping */
5119 stream->segment.offset = qtdemux->segment.offset;
5120 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5121 stream->segment.applied_rate = qtdemux->segment.applied_rate;
5122 stream->segment.rate = rate;
5123 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5124 stream->cslg_shift);
5126 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5127 stream->cslg_shift);
5129 stream->segment.stop = stop;
5130 stream->segment.time = time;
5131 stream->segment.position = stream->segment.start;
5133 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5136 /* now prepare and send the segment */
5138 event = gst_event_new_segment (&stream->segment);
5139 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5140 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5142 gst_pad_push_event (stream->pad, event);
5143 /* assume we can send more data now */
5144 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5145 /* clear to send tags on this pad now */
5146 gst_qtdemux_push_tags (qtdemux, stream);
5157 /* activate the given segment number @seg_idx of @stream at time @offset.
5158 * @offset is an absolute global position over all the segments.
5160 * This will push out a NEWSEGMENT event with the right values and
5161 * position the stream index to the first decodable sample before
5165 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5166 guint32 seg_idx, GstClockTime offset)
5168 QtDemuxSegment *segment;
5169 guint32 index, kf_index;
5170 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5172 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5173 seg_idx, GST_TIME_ARGS (offset));
5175 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5179 segment = &stream->segments[stream->segment_index];
5181 /* in the fragmented case, we pick a fragment that starts before our
5182 * desired position and rely on downstream to wait for a keyframe
5183 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5184 * tfra entries tells us which trun/sample the key unit is in, but we don't
5185 * make use of this additional information at the moment) */
5186 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5187 stream->to_sample = G_MAXUINT32;
5190 /* well, it will be taken care of below */
5191 qtdemux->fragmented_seek_pending = FALSE;
5192 /* FIXME ideally the do_fragmented_seek can be done right here,
5193 * rather than at loop level
5194 * (which might even allow handling edit lists in a fragmented file) */
5197 /* We don't need to look for a sample in push-based */
5198 if (!qtdemux->pullbased)
5201 /* and move to the keyframe before the indicated media time of the
5203 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5204 if (qtdemux->segment.rate >= 0) {
5205 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5206 stream->to_sample = G_MAXUINT32;
5207 GST_DEBUG_OBJECT (stream->pad,
5208 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5209 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5210 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5212 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5213 stream->to_sample = index;
5214 GST_DEBUG_OBJECT (stream->pad,
5215 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5216 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5217 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5220 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5221 "this is an empty segment");
5225 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5226 * encountered an error and printed a message so we return appropriately */
5230 /* we're at the right spot */
5231 if (index == stream->sample_index) {
5232 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5236 /* find keyframe of the target index */
5237 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5239 /* go back two frames to provide lead-in for non-raw audio decoders */
5240 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5241 guint32 lead_in = 2;
5242 guint32 old_index = kf_index;
5243 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5245 if (gst_structure_has_name (s, "audio/mpeg")) {
5247 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5248 && mpegversion == 1) {
5249 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5254 kf_index = MAX (kf_index, lead_in) - lead_in;
5255 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5256 GST_DEBUG_OBJECT (stream->pad,
5257 "Moving backwards %u frames to ensure sufficient sound lead-in",
5258 old_index - kf_index);
5260 kf_index = old_index;
5264 /* if we move forwards, we don't have to go back to the previous
5265 * keyframe since we already sent that. We can also just jump to
5266 * the keyframe right before the target index if there is one. */
5267 if (index > stream->sample_index) {
5268 /* moving forwards check if we move past a keyframe */
5269 if (kf_index > stream->sample_index) {
5270 GST_DEBUG_OBJECT (stream->pad,
5271 "moving forwards to keyframe at %u "
5272 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5274 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5275 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5276 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5278 GST_DEBUG_OBJECT (stream->pad,
5279 "moving forwards, keyframe at %u "
5280 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5282 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5283 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5286 GST_DEBUG_OBJECT (stream->pad,
5287 "moving backwards to %sframe at %u "
5288 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5289 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5290 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5291 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5292 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5298 /* prepare to get the current sample of @stream, getting essential values.
5300 * This function will also prepare and send the segment when needed.
5302 * Return FALSE if the stream is EOS.
5307 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5308 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5309 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5310 gboolean * keyframe)
5312 QtDemuxSample *sample;
5313 GstClockTime time_position;
5316 g_return_val_if_fail (stream != NULL, FALSE);
5318 time_position = stream->time_position;
5319 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5322 seg_idx = stream->segment_index;
5323 if (G_UNLIKELY (seg_idx == -1)) {
5324 /* find segment corresponding to time_position if we are looking
5326 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5329 /* different segment, activate it, sample_index will be set. */
5330 if (G_UNLIKELY (stream->segment_index != seg_idx))
5331 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5333 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5334 segments[stream->segment_index]))) {
5335 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5337 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5338 " prepare empty sample");
5341 *pts = *dts = time_position;
5342 *duration = seg->duration - (time_position - seg->time);
5349 if (stream->sample_index == -1)
5350 stream->sample_index = 0;
5352 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5353 stream->sample_index, stream->n_samples);
5355 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5356 if (!qtdemux->fragmented)
5359 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5363 GST_OBJECT_LOCK (qtdemux);
5364 flow = qtdemux_add_fragmented_samples (qtdemux);
5365 GST_OBJECT_UNLOCK (qtdemux);
5367 if (flow != GST_FLOW_OK)
5370 while (stream->sample_index >= stream->n_samples);
5373 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5374 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5375 stream->sample_index);
5379 /* now get the info for the sample we're at */
5380 sample = &stream->samples[stream->sample_index];
5382 *dts = QTSAMPLE_DTS (stream, sample);
5383 *pts = QTSAMPLE_PTS (stream, sample);
5384 *offset = sample->offset;
5385 *size = sample->size;
5386 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5387 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5394 stream->time_position = GST_CLOCK_TIME_NONE;
5399 /* move to the next sample in @stream.
5401 * Moves to the next segment when needed.
5404 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5406 QtDemuxSample *sample;
5407 QtDemuxSegment *segment;
5409 /* get current segment */
5410 segment = &stream->segments[stream->segment_index];
5412 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5413 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5417 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5418 /* Mark the stream as EOS */
5419 GST_DEBUG_OBJECT (qtdemux,
5420 "reached max allowed sample %u, mark EOS", stream->to_sample);
5421 stream->time_position = GST_CLOCK_TIME_NONE;
5425 /* move to next sample */
5426 stream->sample_index++;
5427 stream->offset_in_sample = 0;
5429 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5432 /* reached the last sample, we need the next segment */
5433 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5436 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5437 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5438 stream->sample_index);
5442 /* get next sample */
5443 sample = &stream->samples[stream->sample_index];
5445 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5446 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5447 GST_TIME_ARGS (segment->media_stop));
5449 /* see if we are past the segment */
5450 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5453 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5454 /* inside the segment, update time_position, looks very familiar to
5455 * GStreamer segments, doesn't it? */
5456 stream->time_position =
5457 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5459 /* not yet in segment, time does not yet increment. This means
5460 * that we are still prerolling keyframes to the decoder so it can
5461 * decode the first sample of the segment. */
5462 stream->time_position = segment->time;
5466 /* move to the next segment */
5469 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5471 if (stream->segment_index == stream->n_segments - 1) {
5472 /* are we at the end of the last segment, we're EOS */
5473 stream->time_position = GST_CLOCK_TIME_NONE;
5475 /* else we're only at the end of the current segment */
5476 stream->time_position = segment->stop_time;
5478 /* make sure we select a new segment */
5480 /* accumulate previous segments */
5481 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5482 stream->accumulated_base +=
5483 (stream->segment.stop -
5484 stream->segment.start) / ABS (stream->segment.rate);
5486 stream->segment_index = -1;
5491 gst_qtdemux_sync_streams (GstQTDemux * demux)
5495 if (QTDEMUX_N_STREAMS (demux) <= 1)
5498 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5499 QtDemuxStream *stream;
5500 GstClockTime end_time;
5502 stream = QTDEMUX_NTH_STREAM (demux, i);
5507 /* TODO advance time on subtitle streams here, if any some day */
5509 /* some clips/trailers may have unbalanced streams at the end,
5510 * so send EOS on shorter stream to prevent stalling others */
5512 /* do not mess with EOS if SEGMENT seeking */
5513 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5516 if (demux->pullbased) {
5517 /* loop mode is sample time based */
5518 if (!STREAM_IS_EOS (stream))
5521 /* push mode is byte position based */
5522 if (stream->n_samples &&
5523 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5527 if (stream->sent_eos)
5530 /* only act if some gap */
5531 end_time = stream->segments[stream->n_segments - 1].stop_time;
5532 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5533 ", stream end: %" GST_TIME_FORMAT,
5534 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5535 if (GST_CLOCK_TIME_IS_VALID (end_time)
5536 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5539 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5540 GST_PAD_NAME (stream->pad));
5541 stream->sent_eos = TRUE;
5542 event = gst_event_new_eos ();
5543 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5544 gst_event_set_seqnum (event, demux->segment_seqnum);
5545 gst_pad_push_event (stream->pad, event);
5550 /* EOS and NOT_LINKED need to be combined. This means that we return:
5552 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5553 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5555 static GstFlowReturn
5556 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5559 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5562 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5565 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5567 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5571 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5572 * completely clipped
5574 * Should be used only with raw buffers */
5576 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5579 guint64 start, stop, cstart, cstop, diff;
5580 GstClockTime pts, duration;
5582 gint num_rate, denom_rate;
5587 osize = size = gst_buffer_get_size (buf);
5590 /* depending on the type, setup the clip parameters */
5591 if (stream->subtype == FOURCC_soun) {
5592 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5593 num_rate = GST_SECOND;
5594 denom_rate = (gint) CUR_STREAM (stream)->rate;
5596 } else if (stream->subtype == FOURCC_vide) {
5598 num_rate = CUR_STREAM (stream)->fps_n;
5599 denom_rate = CUR_STREAM (stream)->fps_d;
5604 if (frame_size <= 0)
5605 goto bad_frame_size;
5607 /* we can only clip if we have a valid pts */
5608 pts = GST_BUFFER_PTS (buf);
5609 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5612 duration = GST_BUFFER_DURATION (buf);
5614 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5616 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5620 stop = start + duration;
5622 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5623 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5626 /* see if some clipping happened */
5627 diff = cstart - start;
5633 /* bring clipped time to samples and to bytes */
5634 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5637 GST_DEBUG_OBJECT (qtdemux,
5638 "clipping start to %" GST_TIME_FORMAT " %"
5639 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5645 diff = stop - cstop;
5650 /* bring clipped time to samples and then to bytes */
5651 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5653 GST_DEBUG_OBJECT (qtdemux,
5654 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5655 " bytes", GST_TIME_ARGS (cstop), diff);
5660 if (offset != 0 || size != osize)
5661 gst_buffer_resize (buf, offset, size);
5663 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5664 GST_BUFFER_PTS (buf) = pts;
5665 GST_BUFFER_DURATION (buf) = duration;
5669 /* dropped buffer */
5672 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5677 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5682 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5687 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5688 gst_buffer_unref (buf);
5694 gst_qtdemux_align_buffer (GstQTDemux * demux,
5695 GstBuffer * buffer, gsize alignment)
5699 gst_buffer_map (buffer, &map, GST_MAP_READ);
5701 if (map.size < sizeof (guintptr)) {
5702 gst_buffer_unmap (buffer, &map);
5706 if (((guintptr) map.data) & (alignment - 1)) {
5707 GstBuffer *new_buffer;
5708 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5710 new_buffer = gst_buffer_new_allocate (NULL,
5711 gst_buffer_get_size (buffer), ¶ms);
5713 /* Copy data "by hand", so ensure alignment is kept: */
5714 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5716 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5717 GST_DEBUG_OBJECT (demux,
5718 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5721 gst_buffer_unmap (buffer, &map);
5722 gst_buffer_unref (buffer);
5727 gst_buffer_unmap (buffer, &map);
5732 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5738 /* We are converting from pairs to triplets */
5739 *res = ccpair_size / 2 * 3;
5740 storage = g_malloc (*res);
5741 for (i = 0; i * 2 < ccpair_size; i += 1) {
5742 /* FIXME: Use line offset 0 as we simply can't know here */
5744 storage[i * 3] = 0x80 | 0x00;
5746 storage[i * 3] = 0x00 | 0x00;
5747 storage[i * 3 + 1] = ccpair[i * 2];
5748 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5755 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5759 guint32 atom_length, fourcc;
5760 QtDemuxStreamStsdEntry *stsd_entry;
5762 GST_MEMDUMP ("caption atom", data, size);
5764 /* There might be multiple atoms */
5769 atom_length = QT_UINT32 (data);
5770 fourcc = QT_FOURCC (data + 4);
5771 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5774 GST_DEBUG_OBJECT (stream->pad, "here");
5776 /* Check if we have something compatible */
5777 stsd_entry = CUR_STREAM (stream);
5778 switch (stsd_entry->fourcc) {
5780 guint8 *cdat = NULL, *cdt2 = NULL;
5781 gsize cdat_size = 0, cdt2_size = 0;
5782 /* Should be cdat or cdt2 */
5783 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5784 GST_WARNING_OBJECT (stream->pad,
5785 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5786 GST_FOURCC_ARGS (fourcc));
5790 /* Convert to S334-1 Annex A byte triplet */
5791 if (fourcc == FOURCC_cdat)
5792 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5794 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5795 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5798 /* Check for another atom ? */
5799 if (size > atom_length + 8) {
5800 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5801 if (size >= atom_length + new_atom_length) {
5802 fourcc = QT_FOURCC (data + atom_length + 4);
5803 if (fourcc == FOURCC_cdat) {
5806 convert_to_s334_1a (data + atom_length + 8,
5807 new_atom_length - 8, 1, &cdat_size);
5809 GST_WARNING_OBJECT (stream->pad,
5810 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5814 convert_to_s334_1a (data + atom_length + 8,
5815 new_atom_length - 8, 2, &cdt2_size);
5817 GST_WARNING_OBJECT (stream->pad,
5818 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5823 *cclen = cdat_size + cdt2_size;
5824 res = g_malloc (*cclen);
5826 memcpy (res, cdat, cdat_size);
5828 memcpy (res + cdat_size, cdt2, cdt2_size);
5834 if (fourcc != FOURCC_ccdp) {
5835 GST_WARNING_OBJECT (stream->pad,
5836 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5837 GST_FOURCC_ARGS (fourcc));
5840 *cclen = atom_length - 8;
5841 res = g_memdup2 (data + 8, *cclen);
5844 /* Keep this here in case other closed caption formats are added */
5845 g_assert_not_reached ();
5849 GST_MEMDUMP ("Output", res, *cclen);
5854 GST_WARNING ("[cdat] atom is too small or invalid");
5858 /* Handle Closed Caption sample buffers.
5859 * The input buffer metadata must be writable,
5860 * but time/duration etc not yet set and need not be preserved */
5862 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5865 GstBuffer *outbuf = NULL;
5870 gst_buffer_map (buf, &map, GST_MAP_READ);
5872 /* empty buffer is sent to terminate previous subtitle */
5873 if (map.size <= 2) {
5874 gst_buffer_unmap (buf, &map);
5875 gst_buffer_unref (buf);
5879 /* For closed caption, we need to extract the information from the
5880 * [cdat],[cdt2] or [ccdp] atom */
5881 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5882 gst_buffer_unmap (buf, &map);
5884 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5885 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5887 /* Conversion failed or there's nothing */
5889 gst_buffer_unref (buf);
5894 /* DVD subpicture specific sample handling.
5895 * the input buffer metadata must be writable,
5896 * but time/duration etc not yet set and need not be preserved */
5898 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5901 /* send a one time dvd clut event */
5902 if (stream->pending_event && stream->pad)
5903 gst_pad_push_event (stream->pad, stream->pending_event);
5904 stream->pending_event = NULL;
5906 /* empty buffer is sent to terminate previous subtitle */
5907 if (gst_buffer_get_size (buf) <= 2) {
5908 gst_buffer_unref (buf);
5912 /* That's all the processing needed for subpictures */
5916 /* Timed text formats
5917 * the input buffer metadata must be writable,
5918 * but time/duration etc not yet set and need not be preserved */
5920 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5923 GstBuffer *outbuf = NULL;
5928 /* not many cases for now */
5929 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5930 stream->subtype != FOURCC_sbtl)) {
5934 gst_buffer_map (buf, &map, GST_MAP_READ);
5936 /* empty buffer is sent to terminate previous subtitle */
5937 if (map.size <= 2) {
5938 gst_buffer_unmap (buf, &map);
5939 gst_buffer_unref (buf);
5943 nsize = GST_READ_UINT16_BE (map.data);
5944 nsize = MIN (nsize, map.size - 2);
5946 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5949 /* takes care of UTF-8 validation or UTF-16 recognition,
5950 * no other encoding expected */
5951 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5952 gst_buffer_unmap (buf, &map);
5955 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5956 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5958 /* this should not really happen unless the subtitle is corrupted */
5960 gst_buffer_unref (buf);
5962 /* FIXME ? convert optional subsequent style info to markup */
5967 /* WebVTT sample handling according to 14496-30 */
5969 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5972 GstBuffer *outbuf = NULL;
5975 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5976 g_assert_not_reached (); /* The buffer must be mappable */
5979 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5980 GstEvent *gap = NULL;
5981 /* Push a gap event */
5982 stream->segment.position = GST_BUFFER_PTS (buf);
5984 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5985 gst_pad_push_event (stream->pad, gap);
5987 if (GST_BUFFER_DURATION_IS_VALID (buf))
5988 stream->segment.position += GST_BUFFER_DURATION (buf);
5991 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5992 GST_BUFFER_DURATION (buf), map.data, map.size);
5993 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5996 gst_buffer_unmap (buf, &map);
5997 gst_buffer_unref (buf);
6002 static GstFlowReturn
6003 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6006 GstFlowReturn ret = GST_FLOW_OK;
6007 GstClockTime pts, duration;
6009 if (stream->need_clip)
6010 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
6012 if (G_UNLIKELY (buf == NULL))
6015 if (G_UNLIKELY (stream->discont)) {
6016 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6017 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
6018 stream->discont = FALSE;
6020 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6023 GST_LOG_OBJECT (qtdemux,
6024 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
6025 ", duration %" GST_TIME_FORMAT " on pad %s",
6026 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
6027 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
6028 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
6030 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
6031 GstStructure *crypto_info;
6032 QtDemuxAavdEncryptionInfo *info =
6033 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
6035 crypto_info = gst_structure_copy (info->default_properties);
6036 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6037 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
6040 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
6041 || stream->protection_scheme_type == FOURCC_cbcs)) {
6042 GstStructure *crypto_info;
6043 QtDemuxCencSampleSetInfo *info =
6044 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6048 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
6049 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
6050 GST_PTR_FORMAT, event);
6051 gst_pad_push_event (stream->pad, event);
6054 if (info->crypto_info == NULL) {
6055 if (stream->protection_scheme_type == FOURCC_cbcs) {
6056 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
6057 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
6058 GST_ERROR_OBJECT (qtdemux,
6059 "failed to attach cbcs metadata to buffer");
6060 qtdemux_gst_structure_free (crypto_info);
6062 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
6065 GST_DEBUG_OBJECT (qtdemux,
6066 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
6069 /* The end of the crypto_info array matches our n_samples position,
6070 * so count backward from there */
6071 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
6072 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
6073 /* steal structure from array */
6074 crypto_info = g_ptr_array_index (info->crypto_info, index);
6075 g_ptr_array_index (info->crypto_info, index) = NULL;
6076 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
6077 info->crypto_info->len);
6078 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6079 GST_ERROR_OBJECT (qtdemux,
6080 "failed to attach cenc metadata to buffer");
6082 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
6083 index, stream->sample_index);
6088 if (stream->alignment > 1)
6089 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6091 pts = GST_BUFFER_PTS (buf);
6092 duration = GST_BUFFER_DURATION (buf);
6094 ret = gst_pad_push (stream->pad, buf);
6096 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6097 /* mark position in stream, we'll need this to know when to send GAP event */
6098 stream->segment.position = pts + duration;
6106 static GstFlowReturn
6107 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6110 GstFlowReturn ret = GST_FLOW_OK;
6112 if (stream->subtype == FOURCC_clcp
6113 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6115 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6116 guint n_triplets, i;
6117 guint field1_off = 0, field2_off = 0;
6119 /* We have to split CEA608 buffers so that each outgoing buffer contains
6120 * one byte pair per field according to the framerate of the video track.
6122 * If there is only a single byte pair per field we don't have to do
6126 gst_buffer_map (buf, &map, GST_MAP_READ);
6128 n_triplets = map.size / 3;
6129 for (i = 0; i < n_triplets; i++) {
6130 if (map.data[3 * i] & 0x80)
6136 g_assert (n_field1 || n_field2);
6138 /* If there's more than 1 frame we have to split, otherwise we can just
6140 if (n_field1 > 1 || n_field2 > 1) {
6142 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6143 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6145 for (i = 0; i < n_output_buffers; i++) {
6147 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6151 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6152 outptr = outmap.data;
6155 gboolean found = FALSE;
6157 while (map.data + field1_off < map.data + map.size) {
6158 if (map.data[field1_off] & 0x80) {
6159 memcpy (outptr, &map.data[field1_off], 3);
6168 const guint8 empty[] = { 0x80, 0x80, 0x80 };
6170 memcpy (outptr, empty, 3);
6177 gboolean found = FALSE;
6179 while (map.data + field2_off < map.data + map.size) {
6180 if ((map.data[field2_off] & 0x80) == 0) {
6181 memcpy (outptr, &map.data[field2_off], 3);
6190 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6192 memcpy (outptr, empty, 3);
6198 gst_buffer_unmap (outbuf, &outmap);
6200 GST_BUFFER_PTS (outbuf) =
6201 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6202 GST_SECOND * CUR_STREAM (stream)->fps_d,
6203 CUR_STREAM (stream)->fps_n);
6204 GST_BUFFER_DURATION (outbuf) =
6205 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6206 CUR_STREAM (stream)->fps_n);
6207 GST_BUFFER_OFFSET (outbuf) = -1;
6208 GST_BUFFER_OFFSET_END (outbuf) = -1;
6210 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6212 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6215 gst_buffer_unmap (buf, &map);
6216 gst_buffer_unref (buf);
6218 gst_buffer_unmap (buf, &map);
6219 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6222 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6228 /* Sets a buffer's attributes properly and pushes it downstream.
6229 * Also checks for additional actions and custom processing that may
6230 * need to be done first.
6232 static GstFlowReturn
6233 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6234 QtDemuxStream * stream, GstBuffer * buf,
6235 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6236 gboolean keyframe, GstClockTime position, guint64 byte_position)
6238 GstFlowReturn ret = GST_FLOW_OK;
6240 /* offset the timestamps according to the edit list */
6242 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6246 gst_buffer_map (buf, &map, GST_MAP_READ);
6247 url = g_strndup ((gchar *) map.data, map.size);
6248 gst_buffer_unmap (buf, &map);
6249 if (url != NULL && strlen (url) != 0) {
6250 /* we have RTSP redirect now */
6251 g_free (qtdemux->redirect_location);
6252 qtdemux->redirect_location = g_strdup (url);
6253 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6254 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6255 gst_structure_new ("redirect",
6256 "new-location", G_TYPE_STRING, url, NULL)));
6258 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6264 /* position reporting */
6265 if (qtdemux->segment.rate >= 0) {
6266 qtdemux->segment.position = position;
6267 gst_qtdemux_sync_streams (qtdemux);
6270 if (G_UNLIKELY (!stream->pad)) {
6271 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6272 gst_buffer_unref (buf);
6276 /* send out pending buffers */
6277 while (stream->buffers) {
6278 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6280 if (G_UNLIKELY (stream->discont)) {
6281 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6282 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6283 stream->discont = FALSE;
6285 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6288 if (stream->alignment > 1)
6289 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6290 gst_pad_push (stream->pad, buffer);
6292 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6295 /* we're going to modify the metadata */
6296 buf = gst_buffer_make_writable (buf);
6298 if (qtdemux->start_utc_time != GST_CLOCK_TIME_NONE) {
6299 static GstStaticCaps unix_caps = GST_STATIC_CAPS ("timestamp/x-unix");
6300 GstCaps *caps = gst_static_caps_get (&unix_caps);
6301 gst_buffer_add_reference_timestamp_meta (buf, caps,
6302 pts + qtdemux->start_utc_time - stream->cslg_shift,
6303 GST_CLOCK_TIME_NONE);
6304 gst_caps_unref (caps);
6307 GST_BUFFER_DTS (buf) = dts;
6308 GST_BUFFER_PTS (buf) = pts;
6309 GST_BUFFER_DURATION (buf) = duration;
6310 GST_BUFFER_OFFSET (buf) = -1;
6311 GST_BUFFER_OFFSET_END (buf) = -1;
6313 if (G_UNLIKELY (stream->process_func))
6314 buf = stream->process_func (qtdemux, stream, buf);
6321 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6322 stream->on_keyframe = FALSE;
6324 stream->on_keyframe = TRUE;
6327 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6328 gst_buffer_append_memory (buf,
6329 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6331 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6332 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6335 if (G_UNLIKELY (qtdemux->element_index)) {
6336 GstClockTime stream_time;
6339 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6341 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6342 GST_LOG_OBJECT (qtdemux,
6343 "adding association %" GST_TIME_FORMAT "-> %"
6344 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6345 gst_index_add_association (qtdemux->element_index,
6347 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6348 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6349 GST_FORMAT_BYTES, byte_position, NULL);
6354 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6360 static const QtDemuxRandomAccessEntry *
6361 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6362 GstClockTime pos, gboolean after)
6364 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6365 guint n_entries = stream->n_ra_entries;
6368 /* we assume the table is sorted */
6369 for (i = 0; i < n_entries; ++i) {
6370 if (entries[i].ts > pos)
6374 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6375 * probably okay to assume that the index lists the very first fragment */
6382 return &entries[i - 1];
6386 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6388 const QtDemuxRandomAccessEntry *best_entry = NULL;
6391 GST_OBJECT_LOCK (qtdemux);
6393 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6395 /* first see if we can determine where to go to using mfra,
6396 * before we start clearing things */
6397 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6398 const QtDemuxRandomAccessEntry *entry;
6399 QtDemuxStream *stream;
6400 gboolean is_audio_or_video;
6402 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6404 if (stream->ra_entries == NULL)
6407 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6408 is_audio_or_video = TRUE;
6410 is_audio_or_video = FALSE;
6413 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6414 stream->time_position, !is_audio_or_video);
6416 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6417 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6419 stream->pending_seek = entry;
6421 /* decide position to jump to just based on audio/video tracks, not subs */
6422 if (!is_audio_or_video)
6425 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6429 /* no luck, will handle seek otherwise */
6430 if (best_entry == NULL) {
6431 GST_OBJECT_UNLOCK (qtdemux);
6435 /* ok, now we can prepare for processing as of located moof */
6436 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6437 QtDemuxStream *stream;
6439 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6441 g_free (stream->samples);
6442 stream->samples = NULL;
6443 stream->n_samples = 0;
6444 stream->stbl_index = -1; /* no samples have yet been parsed */
6445 stream->sample_index = -1;
6447 if (stream->protection_scheme_info) {
6448 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6449 if (stream->protection_scheme_type == FOURCC_cenc
6450 || stream->protection_scheme_type == FOURCC_cbcs) {
6451 QtDemuxCencSampleSetInfo *info =
6452 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6453 if (info->crypto_info) {
6454 g_ptr_array_free (info->crypto_info, TRUE);
6455 info->crypto_info = NULL;
6461 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6462 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6463 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6464 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6466 qtdemux->moof_offset = best_entry->moof_offset;
6468 qtdemux_add_fragmented_samples (qtdemux);
6470 GST_OBJECT_UNLOCK (qtdemux);
6474 static GstFlowReturn
6475 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6477 GstFlowReturn ret = GST_FLOW_OK;
6478 GstBuffer *buf = NULL;
6479 QtDemuxStream *stream, *target_stream = NULL;
6480 GstClockTime min_time;
6482 GstClockTime dts = GST_CLOCK_TIME_NONE;
6483 GstClockTime pts = GST_CLOCK_TIME_NONE;
6484 GstClockTime duration = 0;
6485 gboolean keyframe = FALSE;
6486 guint sample_size = 0;
6487 guint num_samples = 1;
6492 if (qtdemux->fragmented_seek_pending) {
6493 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6494 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6495 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6496 qtdemux->fragmented_seek_pending = FALSE;
6498 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6502 /* Figure out the next stream sample to output, min_time is expressed in
6503 * global time and runs over the edit list segments. */
6504 min_time = G_MAXUINT64;
6505 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6506 GstClockTime position;
6508 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6509 position = stream->time_position;
6511 if (!GST_CLOCK_TIME_IS_VALID (position))
6514 if (stream->segment_index != -1) {
6515 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6516 position += segment->media_start;
6519 /* position of -1 is EOS */
6520 if (position < min_time) {
6521 min_time = position;
6522 target_stream = stream;
6526 if (G_UNLIKELY (target_stream == NULL)) {
6527 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6531 /* check for segment end */
6532 if (G_UNLIKELY (qtdemux->segment.stop != -1
6533 && qtdemux->segment.rate >= 0
6534 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6535 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6536 target_stream->time_position = GST_CLOCK_TIME_NONE;
6540 /* fetch info for the current sample of this stream */
6541 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, target_stream,
6542 &empty, &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6545 /* Send catche-up GAP event for each other stream if required.
6546 * This logic will be applied only for positive rate */
6547 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux) &&
6548 qtdemux->segment.rate >= 0; i++) {
6549 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6551 if (stream == target_stream ||
6552 !GST_CLOCK_TIME_IS_VALID (stream->segment.stop) ||
6553 !GST_CLOCK_TIME_IS_VALID (stream->segment.position))
6557 GstClockTime gap_threshold;
6558 /* kind of running time with offset segment.base and segment.start */
6559 GstClockTime pseudo_target_time = target_stream->segment.base;
6560 GstClockTime pseudo_cur_time = stream->segment.base;
6562 /* make sure positive offset, segment.position can be smallr than
6563 * segment.start for some reasons */
6564 if (target_stream->segment.position >= target_stream->segment.start) {
6565 pseudo_target_time +=
6566 (target_stream->segment.position - target_stream->segment.start);
6569 if (stream->segment.position >= stream->segment.start)
6570 pseudo_cur_time += (stream->segment.position - stream->segment.start);
6572 /* Only send gap events on non-subtitle streams if lagging way behind. */
6573 if (stream->subtype == FOURCC_subp
6574 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6575 stream->subtype == FOURCC_wvtt)
6576 gap_threshold = 1 * GST_SECOND;
6578 gap_threshold = 3 * GST_SECOND;
6580 /* send gap events until the stream catches up */
6581 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6582 while (GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6583 pseudo_cur_time < (G_MAXUINT64 - gap_threshold) &&
6584 pseudo_cur_time + gap_threshold < pseudo_target_time) {
6586 gst_event_new_gap (stream->segment.position, gap_threshold);
6587 GST_LOG_OBJECT (stream->pad, "Sending %" GST_PTR_FORMAT, gap);
6589 gst_pad_push_event (stream->pad, gap);
6590 stream->segment.position += gap_threshold;
6591 pseudo_cur_time += gap_threshold;
6596 stream = target_stream;
6598 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6599 if (stream->new_caps) {
6600 gst_qtdemux_configure_stream (qtdemux, stream);
6601 qtdemux_do_allocation (stream, qtdemux);
6604 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6605 if (G_UNLIKELY (qtdemux->segment.
6606 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6607 if (stream->subtype == FOURCC_vide) {
6609 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6612 } else if (qtdemux->trickmode_interval > 0) {
6613 GstClockTimeDiff interval;
6615 if (qtdemux->segment.rate > 0)
6616 interval = stream->time_position - stream->last_keyframe_dts;
6618 interval = stream->last_keyframe_dts - stream->time_position;
6620 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6621 && interval < qtdemux->trickmode_interval) {
6622 GST_LOG_OBJECT (qtdemux,
6623 "Skipping keyframe within interval on track-id %u",
6627 stream->last_keyframe_dts = stream->time_position;
6633 GST_DEBUG_OBJECT (qtdemux,
6634 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6635 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6636 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6637 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6638 GST_TIME_ARGS (duration));
6640 if (G_UNLIKELY (empty)) {
6641 /* empty segment, push a gap if there's a second or more
6642 * difference and move to the next one */
6643 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6644 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6645 stream->segment.position = pts + duration;
6649 /* hmm, empty sample, skip and move to next sample */
6650 if (G_UNLIKELY (sample_size <= 0))
6653 /* last pushed sample was out of boundary, goto next sample */
6654 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6657 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6658 GST_DEBUG_OBJECT (qtdemux,
6659 "size %d larger than stream max_buffer_size %d, trimming",
6660 sample_size, stream->max_buffer_size);
6662 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6663 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6664 && sample_size < stream->min_buffer_size) {
6665 guint start_sample_index = stream->sample_index;
6666 guint accumulated_size = sample_size;
6667 guint64 expected_next_offset = offset + sample_size;
6669 GST_DEBUG_OBJECT (qtdemux,
6670 "size %d smaller than stream min_buffer_size %d, combining with the next",
6671 sample_size, stream->min_buffer_size);
6673 while (stream->sample_index < stream->to_sample
6674 && stream->sample_index + 1 < stream->n_samples) {
6675 const QtDemuxSample *next_sample;
6677 /* Increment temporarily */
6678 stream->sample_index++;
6680 /* Failed to parse sample so let's go back to the previous one that was
6681 * still successful */
6682 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6683 stream->sample_index--;
6687 next_sample = &stream->samples[stream->sample_index];
6689 /* Not contiguous with the previous sample so let's go back to the
6690 * previous one that was still successful */
6691 if (next_sample->offset != expected_next_offset) {
6692 stream->sample_index--;
6696 accumulated_size += next_sample->size;
6697 expected_next_offset += next_sample->size;
6698 if (accumulated_size >= stream->min_buffer_size)
6702 num_samples = stream->sample_index + 1 - start_sample_index;
6703 stream->sample_index = start_sample_index;
6704 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6705 num_samples, accumulated_size);
6706 size = accumulated_size;
6711 if (qtdemux->cenc_aux_info_offset > 0) {
6714 GstBuffer *aux_info = NULL;
6716 /* pull the data stored before the sample */
6718 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6719 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6720 if (G_UNLIKELY (ret != GST_FLOW_OK))
6722 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6723 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6724 gst_byte_reader_init (&br, map.data + 8, map.size);
6725 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6726 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6727 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6728 gst_buffer_unmap (aux_info, &map);
6729 gst_buffer_unref (aux_info);
6730 ret = GST_FLOW_ERROR;
6733 gst_buffer_unmap (aux_info, &map);
6734 gst_buffer_unref (aux_info);
6737 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6740 if (stream->use_allocator) {
6741 /* if we have a per-stream allocator, use it */
6742 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6745 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6747 if (G_UNLIKELY (ret != GST_FLOW_OK))
6750 /* Update for both splitting and combining of samples */
6751 if (size != sample_size) {
6752 pts += gst_util_uint64_scale_int (GST_SECOND,
6753 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6756 gst_util_uint64_scale_int (GST_SECOND,
6757 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6760 gst_util_uint64_scale_int (GST_SECOND,
6761 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6764 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6765 dts, pts, duration, keyframe, min_time, offset);
6767 if (size < sample_size) {
6768 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6769 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6771 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6773 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6774 if (time_position >= segment->media_start) {
6775 /* inside the segment, update time_position, looks very familiar to
6776 * GStreamer segments, doesn't it? */
6777 stream->time_position = (time_position - segment->media_start) +
6780 /* not yet in segment, time does not yet increment. This means
6781 * that we are still prerolling keyframes to the decoder so it can
6782 * decode the first sample of the segment. */
6783 stream->time_position = segment->time;
6785 } else if (size > sample_size) {
6786 /* Increase to the last sample we already pulled so that advancing
6787 * below brings us to the next sample we need to pull */
6788 stream->sample_index += num_samples - 1;
6792 GST_OBJECT_LOCK (qtdemux);
6793 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6794 GST_OBJECT_UNLOCK (qtdemux);
6795 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6796 * we have no more data for the pad to push */
6797 if (ret == GST_FLOW_EOS)
6800 stream->offset_in_sample += size;
6801 if (stream->offset_in_sample >= sample_size) {
6802 gst_qtdemux_advance_sample (qtdemux, stream);
6807 gst_qtdemux_advance_sample (qtdemux, stream);
6815 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6821 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6822 /* EOS will be raised if all are EOS */
6829 gst_qtdemux_loop (GstPad * pad)
6831 GstQTDemux *qtdemux;
6835 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6837 cur_offset = qtdemux->offset;
6838 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6839 cur_offset, qt_demux_state_string (qtdemux->state));
6841 switch (qtdemux->state) {
6842 case QTDEMUX_STATE_INITIAL:
6843 case QTDEMUX_STATE_HEADER:
6844 ret = gst_qtdemux_loop_state_header (qtdemux);
6846 case QTDEMUX_STATE_MOVIE:
6847 ret = gst_qtdemux_loop_state_movie (qtdemux);
6848 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6849 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6857 /* if something went wrong, pause */
6858 if (ret != GST_FLOW_OK)
6862 gst_object_unref (qtdemux);
6868 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6869 (NULL), ("streaming stopped, invalid state"));
6870 gst_pad_pause_task (pad);
6871 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6876 const gchar *reason = gst_flow_get_name (ret);
6878 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6880 gst_pad_pause_task (pad);
6882 /* fatal errors need special actions */
6884 if (ret == GST_FLOW_EOS) {
6885 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6886 /* we have no streams, post an error */
6887 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6889 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6892 if ((stop = qtdemux->segment.stop) == -1)
6893 stop = qtdemux->segment.duration;
6895 if (qtdemux->segment.rate >= 0) {
6896 GstMessage *message;
6899 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6900 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6901 GST_FORMAT_TIME, stop);
6902 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6903 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6904 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6905 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6907 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6908 gst_qtdemux_push_event (qtdemux, event);
6910 GstMessage *message;
6913 /* For Reverse Playback */
6914 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6915 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6916 GST_FORMAT_TIME, qtdemux->segment.start);
6917 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6918 qtdemux->segment.start);
6919 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6920 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6921 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6923 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6924 gst_qtdemux_push_event (qtdemux, event);
6929 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6930 event = gst_event_new_eos ();
6931 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6932 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6933 gst_qtdemux_push_event (qtdemux, event);
6935 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6936 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6937 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6946 * Returns if there are samples to be played.
6949 has_next_entry (GstQTDemux * demux)
6951 QtDemuxStream *stream;
6954 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6956 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6957 stream = QTDEMUX_NTH_STREAM (demux, i);
6959 if (stream->sample_index == -1) {
6960 stream->sample_index = 0;
6961 stream->offset_in_sample = 0;
6964 if (stream->sample_index >= stream->n_samples) {
6965 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6968 GST_DEBUG_OBJECT (demux, "Found a sample");
6972 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6979 * Returns the size of the first entry at the current offset.
6980 * If -1, there are none (which means EOS or empty file).
6983 next_entry_size (GstQTDemux * demux)
6985 QtDemuxStream *stream, *target_stream = NULL;
6986 guint64 smalloffs = (guint64) - 1;
6987 QtDemuxSample *sample;
6990 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6993 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6994 stream = QTDEMUX_NTH_STREAM (demux, i);
6996 if (stream->sample_index == -1) {
6997 stream->sample_index = 0;
6998 stream->offset_in_sample = 0;
7001 if (stream->sample_index >= stream->n_samples) {
7002 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
7006 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
7007 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
7008 stream->sample_index);
7012 sample = &stream->samples[stream->sample_index];
7014 GST_LOG_OBJECT (demux,
7015 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
7016 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
7017 stream->sample_index, sample->offset, sample->size);
7019 if (((smalloffs == -1)
7020 || (sample->offset < smalloffs)) && (sample->size)) {
7021 smalloffs = sample->offset;
7022 target_stream = stream;
7029 GST_LOG_OBJECT (demux,
7030 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
7031 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
7033 stream = target_stream;
7034 sample = &stream->samples[stream->sample_index];
7036 if (sample->offset >= demux->offset) {
7037 demux->todrop = sample->offset - demux->offset;
7038 return sample->size + demux->todrop;
7041 GST_DEBUG_OBJECT (demux,
7042 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
7047 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
7049 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
7051 gst_element_post_message (GST_ELEMENT_CAST (demux),
7052 gst_message_new_element (GST_OBJECT_CAST (demux),
7053 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
7057 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
7062 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
7065 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
7066 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
7067 GST_SEEK_TYPE_NONE, -1);
7069 /* store seqnum to drop flush events, they don't need to reach downstream */
7070 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
7071 res = gst_pad_push_event (demux->sinkpad, event);
7072 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
7077 /* check for seekable upstream, above and beyond a mere query */
7079 gst_qtdemux_check_seekability (GstQTDemux * demux)
7082 gboolean seekable = FALSE;
7083 gint64 start = -1, stop = -1;
7085 if (demux->upstream_size)
7088 if (demux->upstream_format_is_time)
7091 query = gst_query_new_seeking (GST_FORMAT_BYTES);
7092 if (!gst_pad_peer_query (demux->sinkpad, query)) {
7093 GST_DEBUG_OBJECT (demux, "seeking query failed");
7097 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
7099 /* try harder to query upstream size if we didn't get it the first time */
7100 if (seekable && stop == -1) {
7101 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
7102 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
7105 /* if upstream doesn't know the size, it's likely that it's not seekable in
7106 * practice even if it technically may be seekable */
7107 if (seekable && (start != 0 || stop <= start)) {
7108 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
7113 gst_query_unref (query);
7115 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
7116 G_GUINT64_FORMAT ")", seekable, start, stop);
7117 demux->upstream_seekable = seekable;
7118 demux->upstream_size = seekable ? stop : -1;
7122 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
7124 g_return_if_fail (bytes <= demux->todrop);
7126 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
7127 gst_adapter_flush (demux->adapter, bytes);
7128 demux->neededbytes -= bytes;
7129 demux->offset += bytes;
7130 demux->todrop -= bytes;
7133 /* PUSH-MODE only: Send a segment, if not done already. */
7135 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
7137 if (G_UNLIKELY (demux->need_segment)) {
7140 if (!demux->upstream_format_is_time) {
7141 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
7143 GstEvent *segment_event;
7144 segment_event = gst_event_new_segment (&demux->segment);
7145 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
7146 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
7147 gst_qtdemux_push_event (demux, segment_event);
7150 demux->need_segment = FALSE;
7152 /* clear to send tags on all streams */
7153 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7154 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7155 gst_qtdemux_push_tags (demux, stream);
7156 if (CUR_STREAM (stream)->sparse) {
7157 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
7158 gst_pad_push_event (stream->pad,
7159 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7165 /* Used for push mode only. */
7167 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7168 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7170 GstClockTime ts, dur;
7174 stream->segments[segment_index].duration - (pos -
7175 stream->segments[segment_index].time);
7176 stream->time_position += dur;
7178 /* Only gaps with a duration of at least one second are propagated.
7179 * Same workaround as in pull mode.
7180 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7181 if (dur >= GST_SECOND) {
7183 gap = gst_event_new_gap (ts, dur);
7185 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7186 "segment: %" GST_PTR_FORMAT, gap);
7187 gst_pad_push_event (stream->pad, gap);
7191 static GstFlowReturn
7192 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7196 demux = GST_QTDEMUX (parent);
7198 GST_DEBUG_OBJECT (demux,
7199 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7200 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7201 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7202 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7203 gst_buffer_get_size (inbuf), demux->offset);
7205 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7206 gboolean is_gap_input = FALSE;
7209 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7211 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7212 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7215 /* Check if we can land back on our feet in the case where upstream is
7216 * handling the seeking/pushing of samples with gaps in between (like
7217 * in the case of trick-mode DASH for example) */
7218 if (demux->upstream_format_is_time
7219 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7220 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7222 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7223 GST_LOG_OBJECT (demux,
7224 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7225 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7227 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7228 stream, GST_BUFFER_OFFSET (inbuf));
7230 QtDemuxSample *sample = &stream->samples[res];
7231 GST_LOG_OBJECT (demux,
7232 "Checking if sample %d from track-id %u is valid (offset:%"
7233 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7234 stream->track_id, sample->offset, sample->size);
7235 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7236 GST_LOG_OBJECT (demux,
7237 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7239 is_gap_input = TRUE;
7240 /* We can go back to standard playback mode */
7241 demux->state = QTDEMUX_STATE_MOVIE;
7242 /* Remember which sample this stream is at */
7243 stream->sample_index = res;
7244 /* Finally update all push-based values to the expected values */
7245 demux->neededbytes = stream->samples[res].size;
7246 demux->offset = GST_BUFFER_OFFSET (inbuf);
7248 demux->mdatsize - demux->offset + demux->mdatoffset;
7253 if (!is_gap_input) {
7254 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7255 /* Reset state if it's a real discont */
7256 demux->neededbytes = 16;
7257 demux->state = QTDEMUX_STATE_INITIAL;
7258 demux->offset = GST_BUFFER_OFFSET (inbuf);
7259 gst_adapter_clear (demux->adapter);
7262 /* Reverse fragmented playback, need to flush all we have before
7263 * consuming a new fragment.
7264 * The samples array have the timestamps calculated by accumulating the
7265 * durations but this won't work for reverse playback of fragments as
7266 * the timestamps of a subsequent fragment should be smaller than the
7267 * previously received one. */
7268 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7269 gst_qtdemux_process_adapter (demux, TRUE);
7270 g_ptr_array_foreach (demux->active_streams,
7271 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7275 gst_adapter_push (demux->adapter, inbuf);
7277 GST_DEBUG_OBJECT (demux,
7278 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7279 demux->neededbytes, gst_adapter_available (demux->adapter));
7281 return gst_qtdemux_process_adapter (demux, FALSE);
7284 static GstFlowReturn
7285 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7287 GstFlowReturn ret = GST_FLOW_OK;
7289 /* we never really mean to buffer that much */
7290 if (demux->neededbytes == -1) {
7294 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7295 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7297 #ifndef GST_DISABLE_GST_DEBUG
7299 guint64 discont_offset, distance_from_discont;
7301 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7302 distance_from_discont =
7303 gst_adapter_distance_from_discont (demux->adapter);
7305 GST_DEBUG_OBJECT (demux,
7306 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7307 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7308 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7309 demux->offset, discont_offset, distance_from_discont);
7313 switch (demux->state) {
7314 case QTDEMUX_STATE_INITIAL:{
7319 gst_qtdemux_check_seekability (demux);
7321 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7323 /* get fourcc/length, set neededbytes */
7324 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7326 gst_adapter_unmap (demux->adapter);
7328 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7329 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7331 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7332 (_("This file is invalid and cannot be played.")),
7333 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7334 GST_FOURCC_ARGS (fourcc)));
7335 ret = GST_FLOW_ERROR;
7338 if (fourcc == FOURCC_mdat) {
7339 gint next_entry = next_entry_size (demux);
7340 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7341 || !demux->fragmented)) {
7342 /* we have the headers, start playback */
7343 demux->state = QTDEMUX_STATE_MOVIE;
7344 demux->neededbytes = next_entry;
7345 demux->mdatleft = size;
7346 demux->mdatsize = demux->mdatleft;
7348 /* no headers yet, try to get them */
7351 guint64 old, target;
7354 old = demux->offset;
7355 target = old + size;
7357 /* try to jump over the atom with a seek */
7358 /* only bother if it seems worth doing so,
7359 * and avoids possible upstream/server problems */
7360 if (demux->upstream_seekable &&
7361 demux->upstream_size > 4 * (1 << 20)) {
7362 res = qtdemux_seek_offset (demux, target);
7364 GST_DEBUG_OBJECT (demux, "skipping seek");
7369 GST_DEBUG_OBJECT (demux, "seek success");
7370 /* remember the offset fo the first mdat so we can seek back to it
7371 * after we have the headers */
7372 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7373 demux->first_mdat = old;
7374 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7377 /* seek worked, continue reading */
7378 demux->offset = target;
7379 demux->neededbytes = 16;
7380 demux->state = QTDEMUX_STATE_INITIAL;
7382 /* seek failed, need to buffer */
7383 demux->offset = old;
7384 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7385 /* there may be multiple mdat (or alike) buffers */
7387 if (demux->mdatbuffer)
7388 bs = gst_buffer_get_size (demux->mdatbuffer);
7391 if (size + bs > 10 * (1 << 20))
7393 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7394 demux->neededbytes = size;
7395 if (!demux->mdatbuffer)
7396 demux->mdatoffset = demux->offset;
7399 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7400 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7401 (_("This file is invalid and cannot be played.")),
7402 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7403 GST_FOURCC_ARGS (fourcc), size));
7404 ret = GST_FLOW_ERROR;
7407 /* this means we already started buffering and still no moov header,
7408 * let's continue buffering everything till we get moov */
7409 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7410 || fourcc == FOURCC_moof))
7412 demux->neededbytes = size;
7413 demux->state = QTDEMUX_STATE_HEADER;
7417 case QTDEMUX_STATE_HEADER:{
7421 GST_DEBUG_OBJECT (demux, "In header");
7423 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7425 /* parse the header */
7426 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7428 if (fourcc == FOURCC_moov) {
7429 /* in usual fragmented setup we could try to scan for more
7430 * and end up at the the moov (after mdat) again */
7431 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7433 || demux->last_moov_offset == demux->offset)) {
7434 GST_DEBUG_OBJECT (demux,
7435 "Skipping moov atom as we have (this) one already");
7437 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7439 if (demux->got_moov && demux->fragmented) {
7440 GST_DEBUG_OBJECT (demux,
7441 "Got a second moov, clean up data from old one");
7442 if (demux->moov_node_compressed) {
7443 g_node_destroy (demux->moov_node_compressed);
7444 if (demux->moov_node)
7445 g_free (demux->moov_node->data);
7447 demux->moov_node_compressed = NULL;
7448 if (demux->moov_node)
7449 g_node_destroy (demux->moov_node);
7450 demux->moov_node = NULL;
7451 demux->start_utc_time = GST_CLOCK_TIME_NONE;
7454 demux->last_moov_offset = demux->offset;
7456 /* Update streams with new moov */
7457 gst_qtdemux_stream_concat (demux,
7458 demux->old_streams, demux->active_streams);
7460 qtdemux_parse_moov (demux, data, demux->neededbytes);
7461 qtdemux_node_dump (demux, demux->moov_node);
7462 qtdemux_parse_tree (demux);
7463 qtdemux_prepare_streams (demux);
7464 QTDEMUX_EXPOSE_LOCK (demux);
7465 qtdemux_expose_streams (demux);
7466 QTDEMUX_EXPOSE_UNLOCK (demux);
7468 demux->got_moov = TRUE;
7470 gst_qtdemux_check_send_pending_segment (demux);
7472 if (demux->moov_node_compressed) {
7473 g_node_destroy (demux->moov_node_compressed);
7474 g_free (demux->moov_node->data);
7476 demux->moov_node_compressed = NULL;
7477 g_node_destroy (demux->moov_node);
7478 demux->moov_node = NULL;
7479 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7481 } else if (fourcc == FOURCC_moof) {
7482 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7484 GstClockTime prev_pts;
7485 guint64 prev_offset;
7486 guint64 adapter_discont_offset, adapter_discont_dist;
7488 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7491 * The timestamp of the moof buffer is relevant as some scenarios
7492 * won't have the initial timestamp in the atoms. Whenever a new
7493 * buffer has started, we get that buffer's PTS and use it as a base
7494 * timestamp for the trun entries.
7496 * To keep track of the current buffer timestamp and starting point
7497 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7498 * from the beginning of the buffer, with the distance and demux->offset
7499 * we know if it is still the same buffer or not.
7501 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7502 prev_offset = demux->offset - dist;
7503 if (demux->fragment_start_offset == -1
7504 || prev_offset > demux->fragment_start_offset) {
7505 demux->fragment_start_offset = prev_offset;
7506 demux->fragment_start = prev_pts;
7507 GST_DEBUG_OBJECT (demux,
7508 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7509 GST_TIME_FORMAT, demux->fragment_start_offset,
7510 GST_TIME_ARGS (demux->fragment_start));
7513 /* We can't use prev_offset() here because this would require
7514 * upstream to set consistent and correct offsets on all buffers
7515 * since the discont. Nothing ever did that in the past and we
7516 * would break backwards compatibility here then.
7517 * Instead take the offset we had at the last discont and count
7518 * the bytes from there. This works with old code as there would
7519 * be no discont between moov and moof, and also works with
7520 * adaptivedemux which correctly sets offset and will set the
7521 * DISCONT flag accordingly when needed.
7523 * We also only do this for upstream TIME segments as otherwise
7524 * there are potential backwards compatibility problems with
7525 * seeking in PUSH mode and upstream providing inconsistent
7527 adapter_discont_offset =
7528 gst_adapter_offset_at_discont (demux->adapter);
7529 adapter_discont_dist =
7530 gst_adapter_distance_from_discont (demux->adapter);
7532 GST_DEBUG_OBJECT (demux,
7533 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7534 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7535 demux->offset, adapter_discont_offset, adapter_discont_dist);
7537 if (demux->upstream_format_is_time) {
7538 demux->moof_offset = adapter_discont_offset;
7539 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7540 demux->moof_offset += adapter_discont_dist;
7541 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7542 demux->moof_offset = demux->offset;
7544 demux->moof_offset = demux->offset;
7547 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7548 demux->moof_offset, NULL)) {
7549 gst_adapter_unmap (demux->adapter);
7550 ret = GST_FLOW_ERROR;
7554 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7555 if (demux->mss_mode && !demux->exposed) {
7556 QTDEMUX_EXPOSE_LOCK (demux);
7557 qtdemux_expose_streams (demux);
7558 QTDEMUX_EXPOSE_UNLOCK (demux);
7561 gst_qtdemux_check_send_pending_segment (demux);
7563 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7565 } else if (fourcc == FOURCC_ftyp) {
7566 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7567 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7568 } else if (fourcc == FOURCC_uuid) {
7569 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7570 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7571 } else if (fourcc == FOURCC_sidx) {
7572 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7573 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7574 } else if (fourcc == FOURCC_meta) {
7575 GNode *node, *child;
7576 GstByteReader child_data;
7578 node = g_node_new ((gpointer) data);
7579 qtdemux_parse_node (demux, node, data, demux->neededbytes);
7581 /* Parse ONVIF Export File Format CorrectStartTime box if available */
7583 qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb,
7585 qtdemux_parse_cstb (demux, &child_data);
7588 g_node_destroy (node);
7592 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7596 /* [free] and [skip] are padding atoms */
7597 GST_DEBUG_OBJECT (demux,
7598 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7599 GST_FOURCC_ARGS (fourcc));
7602 GST_WARNING_OBJECT (demux,
7603 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7604 GST_FOURCC_ARGS (fourcc));
7605 /* Let's jump that one and go back to initial state */
7609 gst_adapter_unmap (demux->adapter);
7612 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7613 gsize remaining_data_size = 0;
7615 /* the mdat was before the header */
7616 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7617 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7618 /* restore our adapter/offset view of things with upstream;
7619 * put preceding buffered data ahead of current moov data.
7620 * This should also handle evil mdat, moov, mdat cases and alike */
7621 gst_adapter_flush (demux->adapter, demux->neededbytes);
7623 /* Store any remaining data after the mdat for later usage */
7624 remaining_data_size = gst_adapter_available (demux->adapter);
7625 if (remaining_data_size > 0) {
7626 g_assert (demux->restoredata_buffer == NULL);
7627 demux->restoredata_buffer =
7628 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7629 demux->restoredata_offset = demux->offset + demux->neededbytes;
7630 GST_DEBUG_OBJECT (demux,
7631 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7632 G_GUINT64_FORMAT, remaining_data_size,
7633 demux->restoredata_offset);
7636 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7637 demux->mdatbuffer = NULL;
7638 demux->offset = demux->mdatoffset;
7639 demux->neededbytes = next_entry_size (demux);
7640 demux->state = QTDEMUX_STATE_MOVIE;
7641 demux->mdatleft = gst_adapter_available (demux->adapter);
7642 demux->mdatsize = demux->mdatleft;
7644 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7645 gst_adapter_flush (demux->adapter, demux->neededbytes);
7647 /* only go back to the mdat if there are samples to play */
7648 if (demux->got_moov && demux->first_mdat != -1
7649 && has_next_entry (demux)) {
7652 /* we need to seek back */
7653 res = qtdemux_seek_offset (demux, demux->first_mdat);
7655 demux->offset = demux->first_mdat;
7657 GST_DEBUG_OBJECT (demux, "Seek back failed");
7660 demux->offset += demux->neededbytes;
7662 demux->neededbytes = 16;
7663 demux->state = QTDEMUX_STATE_INITIAL;
7668 case QTDEMUX_STATE_BUFFER_MDAT:{
7672 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7674 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7675 gst_buffer_extract (buf, 0, fourcc, 4);
7676 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7677 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7678 if (demux->mdatbuffer)
7679 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7681 demux->mdatbuffer = buf;
7682 demux->offset += demux->neededbytes;
7683 demux->neededbytes = 16;
7684 demux->state = QTDEMUX_STATE_INITIAL;
7685 gst_qtdemux_post_progress (demux, 1, 1);
7689 case QTDEMUX_STATE_MOVIE:{
7690 QtDemuxStream *stream = NULL;
7691 QtDemuxSample *sample;
7692 GstClockTime dts, pts, duration;
7696 GST_DEBUG_OBJECT (demux,
7697 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7699 if (demux->fragmented) {
7700 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7702 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7703 /* if needed data starts within this atom,
7704 * then it should not exceed this atom */
7705 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7706 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7707 (_("This file is invalid and cannot be played.")),
7708 ("sample data crosses atom boundary"));
7709 ret = GST_FLOW_ERROR;
7712 demux->mdatleft -= demux->neededbytes;
7714 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7715 /* so we are dropping more than left in this atom */
7716 gst_qtdemux_drop_data (demux, demux->mdatleft);
7717 demux->mdatleft = 0;
7719 /* need to resume atom parsing so we do not miss any other pieces */
7720 demux->state = QTDEMUX_STATE_INITIAL;
7721 demux->neededbytes = 16;
7723 /* check if there was any stored post mdat data from previous buffers */
7724 if (demux->restoredata_buffer) {
7725 g_assert (gst_adapter_available (demux->adapter) == 0);
7727 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7728 demux->restoredata_buffer = NULL;
7729 demux->offset = demux->restoredata_offset;
7736 if (demux->todrop) {
7737 if (demux->cenc_aux_info_offset > 0) {
7741 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7742 data = gst_adapter_map (demux->adapter, demux->todrop);
7743 gst_byte_reader_init (&br, data + 8, demux->todrop);
7744 if (!qtdemux_parse_cenc_aux_info (demux,
7745 QTDEMUX_NTH_STREAM (demux, 0), &br,
7746 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7747 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7748 ret = GST_FLOW_ERROR;
7749 gst_adapter_unmap (demux->adapter);
7750 g_free (demux->cenc_aux_info_sizes);
7751 demux->cenc_aux_info_sizes = NULL;
7754 demux->cenc_aux_info_offset = 0;
7755 g_free (demux->cenc_aux_info_sizes);
7756 demux->cenc_aux_info_sizes = NULL;
7757 gst_adapter_unmap (demux->adapter);
7759 gst_qtdemux_drop_data (demux, demux->todrop);
7763 /* initial newsegment sent here after having added pads,
7764 * possible others in sink_event */
7765 gst_qtdemux_check_send_pending_segment (demux);
7767 /* Figure out which stream this packet belongs to */
7768 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7769 stream = QTDEMUX_NTH_STREAM (demux, i);
7770 if (stream->sample_index >= stream->n_samples) {
7771 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7775 GST_LOG_OBJECT (demux,
7776 "Checking track-id %u (sample_index:%d / offset:%"
7777 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7778 stream->sample_index,
7779 stream->samples[stream->sample_index].offset,
7780 stream->samples[stream->sample_index].size);
7782 if (stream->samples[stream->sample_index].offset == demux->offset)
7786 if (G_UNLIKELY (stream == NULL))
7787 goto unknown_stream;
7789 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7791 if (stream->new_caps) {
7792 gst_qtdemux_configure_stream (demux, stream);
7795 /* Put data in a buffer, set timestamps, caps, ... */
7796 sample = &stream->samples[stream->sample_index];
7798 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7799 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7800 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7802 dts = QTSAMPLE_DTS (stream, sample);
7803 pts = QTSAMPLE_PTS (stream, sample);
7804 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7805 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7807 /* check for segment end */
7808 if (G_UNLIKELY (demux->segment.stop != -1
7809 && demux->segment.stop <= pts && stream->on_keyframe)
7810 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7811 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7812 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7814 /* skip this data, stream is EOS */
7815 gst_adapter_flush (demux->adapter, demux->neededbytes);
7816 demux->offset += demux->neededbytes;
7818 /* check if all streams are eos */
7820 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7821 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7830 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7832 /* FIXME: should either be an assert or a plain check */
7833 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7835 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7836 dts, pts, duration, keyframe, dts, demux->offset);
7840 GST_OBJECT_LOCK (demux);
7841 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7842 GST_OBJECT_UNLOCK (demux);
7844 /* skip this data, stream is EOS */
7845 gst_adapter_flush (demux->adapter, demux->neededbytes);
7848 stream->sample_index++;
7849 stream->offset_in_sample = 0;
7851 /* update current offset and figure out size of next buffer */
7852 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7853 demux->offset, demux->neededbytes);
7854 demux->offset += demux->neededbytes;
7855 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7859 if (ret == GST_FLOW_EOS) {
7860 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7861 demux->neededbytes = -1;
7865 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7866 if (demux->fragmented) {
7867 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7868 /* there may be more to follow, only finish this atom */
7869 demux->todrop = demux->mdatleft;
7870 demux->neededbytes = demux->todrop;
7875 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7876 goto non_ok_unlinked_flow;
7885 /* when buffering movie data, at least show user something is happening */
7886 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7887 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7888 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7889 demux->neededbytes);
7896 non_ok_unlinked_flow:
7898 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7899 gst_flow_get_name (ret));
7904 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7905 ret = GST_FLOW_ERROR;
7910 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7916 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7917 (NULL), ("qtdemuxer invalid state %d", demux->state));
7918 ret = GST_FLOW_ERROR;
7923 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7924 (NULL), ("no 'moov' atom within the first 10 MB"));
7925 ret = GST_FLOW_ERROR;
7931 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7936 query = gst_query_new_scheduling ();
7938 if (!gst_pad_peer_query (sinkpad, query)) {
7939 gst_query_unref (query);
7943 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7944 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7945 gst_query_unref (query);
7950 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7951 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7955 GST_DEBUG_OBJECT (sinkpad, "activating push");
7956 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7961 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7962 GstPadMode mode, gboolean active)
7965 GstQTDemux *demux = GST_QTDEMUX (parent);
7968 case GST_PAD_MODE_PUSH:
7969 demux->pullbased = FALSE;
7972 case GST_PAD_MODE_PULL:
7974 demux->pullbased = TRUE;
7975 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7978 res = gst_pad_stop_task (sinkpad);
7990 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7996 memset (&z, 0, sizeof (z));
8001 if ((ret = inflateInit (&z)) != Z_OK) {
8002 GST_ERROR ("inflateInit() returned %d", ret);
8006 z.next_in = z_buffer;
8007 z.avail_in = z_length;
8009 buffer = (guint8 *) g_malloc (*length);
8010 z.avail_out = *length;
8011 z.next_out = (Bytef *) buffer;
8013 ret = inflate (&z, Z_NO_FLUSH);
8014 if (ret == Z_STREAM_END) {
8016 } else if (ret != Z_OK) {
8017 GST_WARNING ("inflate() returned %d", ret);
8021 if (*length > G_MAXUINT - 4096 || *length > QTDEMUX_MAX_SAMPLE_INDEX_SIZE) {
8022 GST_WARNING ("too big decompressed data");
8028 buffer = (guint8 *) g_realloc (buffer, *length);
8029 z.next_out = (Bytef *) (buffer + z.total_out);
8030 z.avail_out += *length - z.total_out;
8031 } while (z.avail_in > 0);
8033 if (ret != Z_STREAM_END) {
8038 *length = z.total_out;
8045 #endif /* HAVE_ZLIB */
8048 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
8052 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
8054 /* counts as header data */
8055 qtdemux->header_size += length;
8057 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
8058 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
8060 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
8067 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
8068 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
8069 if (dcom == NULL || cmvd == NULL)
8070 goto invalid_compression;
8072 dcom_len = QT_UINT32 (dcom->data);
8074 goto invalid_compression;
8076 method = QT_FOURCC ((guint8 *) dcom->data + 8);
8080 guint uncompressed_length;
8081 guint compressed_length;
8085 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
8087 goto invalid_compression;
8089 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
8090 compressed_length = cmvd_len - 12;
8091 GST_LOG ("length = %u", uncompressed_length);
8094 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
8095 compressed_length, &uncompressed_length);
8098 qtdemux->moov_node_compressed = qtdemux->moov_node;
8099 qtdemux->moov_node = g_node_new (buf);
8101 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
8102 uncompressed_length);
8106 #endif /* HAVE_ZLIB */
8108 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
8109 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
8116 invalid_compression:
8118 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
8124 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
8127 while (G_UNLIKELY (buf < end)) {
8131 if (G_UNLIKELY (buf + 4 > end)) {
8132 GST_LOG_OBJECT (qtdemux, "buffer overrun");
8135 len = QT_UINT32 (buf);
8136 if (G_UNLIKELY (len == 0)) {
8137 GST_LOG_OBJECT (qtdemux, "empty container");
8140 if (G_UNLIKELY (len < 8)) {
8141 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
8144 if (G_UNLIKELY (len > (end - buf))) {
8145 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
8146 (gint) (end - buf));
8150 child = g_node_new ((guint8 *) buf);
8151 g_node_append (node, child);
8152 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
8153 qtdemux_parse_node (qtdemux, child, buf, len);
8161 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
8164 int len = QT_UINT32 (xdxt->data);
8165 guint8 *buf = xdxt->data;
8166 guint8 *end = buf + len;
8169 /* skip size and type */
8177 size = QT_UINT32 (buf);
8178 type = QT_FOURCC (buf + 4);
8180 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
8182 if (buf + size > end || size <= 0)
8188 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8189 GST_FOURCC_ARGS (type));
8193 buffer = gst_buffer_new_and_alloc (size);
8194 gst_buffer_fill (buffer, 0, buf, size);
8195 stream->buffers = g_slist_append (stream->buffers, buffer);
8196 GST_LOG_OBJECT (qtdemux, "parsing theora header");
8199 buffer = gst_buffer_new_and_alloc (size);
8200 gst_buffer_fill (buffer, 0, buf, size);
8201 stream->buffers = g_slist_append (stream->buffers, buffer);
8202 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
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 codebook");
8211 GST_WARNING_OBJECT (qtdemux,
8212 "unknown theora cookie %" GST_FOURCC_FORMAT,
8213 GST_FOURCC_ARGS (type));
8222 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8226 guint32 node_length = 0;
8227 const QtNodeType *type;
8230 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8232 if (G_UNLIKELY (length < 8))
8233 goto not_enough_data;
8235 node_length = QT_UINT32 (buffer);
8236 fourcc = QT_FOURCC (buffer + 4);
8238 /* ignore empty nodes */
8239 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8242 type = qtdemux_type_get (fourcc);
8244 end = buffer + length;
8246 GST_LOG_OBJECT (qtdemux,
8247 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8248 GST_FOURCC_ARGS (fourcc), node_length, type->name);
8250 if (node_length > length)
8251 goto broken_atom_size;
8253 if (type->flags & QT_FLAG_CONTAINER) {
8254 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8259 if (node_length < 20) {
8260 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8263 GST_DEBUG_OBJECT (qtdemux,
8264 "parsing stsd (sample table, sample description) atom");
8265 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8266 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8278 /* also read alac (or whatever) in stead of mp4a in the following,
8279 * since a similar layout is used in other cases as well */
8280 if (fourcc == FOURCC_mp4a)
8282 else if (fourcc == FOURCC_fLaC)
8287 /* There are two things we might encounter here: a true mp4a atom, and
8288 an mp4a entry in an stsd atom. The latter is what we're interested
8289 in, and it looks like an atom, but isn't really one. The true mp4a
8290 atom is short, so we detect it based on length here. */
8291 if (length < min_size) {
8292 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8293 GST_FOURCC_ARGS (fourcc));
8297 /* 'version' here is the sound sample description version. Types 0 and
8298 1 are documented in the QTFF reference, but type 2 is not: it's
8299 described in Apple header files instead (struct SoundDescriptionV2
8301 version = QT_UINT16 (buffer + 16);
8303 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8304 GST_FOURCC_ARGS (fourcc), version);
8306 /* parse any esds descriptors */
8318 GST_WARNING_OBJECT (qtdemux,
8319 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8320 GST_FOURCC_ARGS (fourcc), version);
8325 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8353 /* codec_data is contained inside these atoms, which all have
8354 * the same format. */
8355 /* video sample description size is 86 bytes without extension.
8356 * node_length have to be bigger than 86 bytes because video sample
8357 * description can include extensions such as esds, fiel, glbl, etc. */
8358 if (node_length < 86) {
8359 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8360 " sample description length too short (%u < 86)",
8361 GST_FOURCC_ARGS (fourcc), node_length);
8365 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8366 GST_FOURCC_ARGS (fourcc));
8368 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8370 * revision level (2 bytes) : must be set to 0. */
8371 version = QT_UINT32 (buffer + 16);
8372 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8374 /* compressor name : PASCAL string and informative purposes
8375 * first byte : the number of bytes to be displayed.
8376 * it has to be less than 32 because it is reserved
8377 * space of 32 bytes total including itself. */
8378 str_len = QT_UINT8 (buffer + 50);
8380 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8381 (char *) buffer + 51);
8383 GST_WARNING_OBJECT (qtdemux,
8384 "compressorname length too big (%u > 31)", str_len);
8386 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8388 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8393 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8395 /* You are reading this correctly. QTFF specifies that the
8396 * metadata atom is a short atom, whereas ISO BMFF specifies
8397 * it's a full atom. But since so many people are doing things
8398 * differently, we actually peek into the atom to see which
8401 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8402 GST_FOURCC_ARGS (fourcc));
8405 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8406 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8407 * starts with a 'hdlr' atom */
8408 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8409 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8410 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8411 * with version/flags both set to zero */
8412 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8414 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8419 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8420 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8421 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8430 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8431 GST_FOURCC_ARGS (fourcc));
8435 version = QT_UINT32 (buffer + 12);
8436 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8443 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8448 if (length < offset) {
8449 GST_WARNING_OBJECT (qtdemux,
8450 "skipping too small %" GST_FOURCC_FORMAT " box",
8451 GST_FOURCC_ARGS (fourcc));
8454 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8460 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8465 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8470 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8474 if (!strcmp (type->name, "unknown"))
8475 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8479 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8480 GST_FOURCC_ARGS (fourcc));
8486 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8487 (_("This file is corrupt and cannot be played.")),
8488 ("Not enough data for an atom header, got only %u bytes", length));
8493 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8494 (_("This file is corrupt and cannot be played.")),
8495 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8496 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8503 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8505 /* FIXME: This can only reliably work if demuxers have a
8506 * separate streaming thread per srcpad. This should be
8507 * done in a demuxer base class, which integrates parts
8510 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8515 query = gst_query_new_allocation (stream->caps, FALSE);
8517 if (!gst_pad_peer_query (stream->pad, query)) {
8518 /* not a problem, just debug a little */
8519 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8522 if (stream->allocator)
8523 gst_object_unref (stream->allocator);
8525 if (gst_query_get_n_allocation_params (query) > 0) {
8526 /* try the allocator */
8527 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8529 stream->use_allocator = TRUE;
8531 stream->allocator = NULL;
8532 gst_allocation_params_init (&stream->params);
8533 stream->use_allocator = FALSE;
8535 gst_query_unref (query);
8540 pad_query (const GValue * item, GValue * value, gpointer user_data)
8542 GstPad *pad = g_value_get_object (item);
8543 GstQuery *query = user_data;
8546 res = gst_pad_peer_query (pad, query);
8549 g_value_set_boolean (value, TRUE);
8553 GST_INFO_OBJECT (pad, "pad peer query failed");
8558 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8559 GstPadDirection direction)
8562 GstIteratorFoldFunction func = pad_query;
8563 GValue res = { 0, };
8565 g_value_init (&res, G_TYPE_BOOLEAN);
8566 g_value_set_boolean (&res, FALSE);
8569 if (direction == GST_PAD_SRC)
8570 it = gst_element_iterate_src_pads (element);
8572 it = gst_element_iterate_sink_pads (element);
8574 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8575 gst_iterator_resync (it);
8577 gst_iterator_free (it);
8579 return g_value_get_boolean (&res);
8583 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8584 QtDemuxStream * stream)
8588 GstElement *element = GST_ELEMENT (qtdemux);
8590 gchar **filtered_sys_ids;
8591 GValue event_list = G_VALUE_INIT;
8594 /* 1. Check if we already have the context. */
8595 if (qtdemux->preferred_protection_system_id != NULL) {
8596 GST_LOG_OBJECT (element,
8597 "already have the protection context, no need to request it again");
8601 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8602 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8603 (const gchar **) qtdemux->protection_system_ids->pdata);
8605 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8606 qtdemux->protection_system_ids->len - 1);
8607 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8608 "decryptors for %u of them, running context request",
8609 qtdemux->protection_system_ids->len,
8610 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8613 if (stream->protection_scheme_event_queue.length) {
8614 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8615 stream->protection_scheme_event_queue.length);
8616 walk = stream->protection_scheme_event_queue.tail;
8618 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8619 qtdemux->protection_event_queue.length);
8620 walk = qtdemux->protection_event_queue.tail;
8623 g_value_init (&event_list, GST_TYPE_LIST);
8624 for (; walk; walk = g_list_previous (walk)) {
8625 GValue event_value = G_VALUE_INIT;
8626 g_value_init (&event_value, GST_TYPE_EVENT);
8627 g_value_set_boxed (&event_value, walk->data);
8628 gst_value_list_append_and_take_value (&event_list, &event_value);
8631 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8632 * check if downstream already has a context of the specific type
8633 * 2b) Query upstream as above.
8635 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8636 st = gst_query_writable_structure (query);
8637 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8638 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8640 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8641 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8642 gst_query_parse_context (query, &ctxt);
8643 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8644 gst_element_set_context (element, ctxt);
8645 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8646 gst_query_parse_context (query, &ctxt);
8647 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8648 gst_element_set_context (element, ctxt);
8650 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8651 * the required context type and afterwards check if a
8652 * usable context was set now as in 1). The message could
8653 * be handled by the parent bins of the element and the
8658 GST_INFO_OBJECT (element, "posting need context message");
8659 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8660 "drm-preferred-decryption-system-id");
8661 st = (GstStructure *) gst_message_get_structure (msg);
8662 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8663 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8666 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8667 gst_element_post_message (element, msg);
8670 g_strfreev (filtered_sys_ids);
8671 g_value_unset (&event_list);
8672 gst_query_unref (query);
8676 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8677 QtDemuxStream * stream)
8680 const gchar *selected_system = NULL;
8682 g_return_val_if_fail (qtdemux != NULL, FALSE);
8683 g_return_val_if_fail (stream != NULL, FALSE);
8684 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8687 if (stream->protection_scheme_type == FOURCC_aavd) {
8688 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8689 if (!gst_structure_has_name (s, "application/x-aavd")) {
8690 gst_structure_set (s,
8691 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8693 gst_structure_set_name (s, "application/x-aavd");
8698 if (stream->protection_scheme_type != FOURCC_cenc
8699 && stream->protection_scheme_type != FOURCC_cbcs) {
8700 GST_ERROR_OBJECT (qtdemux,
8701 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8702 GST_FOURCC_ARGS (stream->protection_scheme_type));
8706 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8707 if (!gst_structure_has_name (s, "application/x-cenc")) {
8708 gst_structure_set (s,
8709 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8710 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8711 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8713 gst_structure_set_name (s, "application/x-cenc");
8716 if (qtdemux->protection_system_ids == NULL) {
8717 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8718 "cenc protection system information has been found, not setting a "
8719 "protection system UUID");
8723 gst_qtdemux_request_protection_context (qtdemux, stream);
8724 if (qtdemux->preferred_protection_system_id != NULL) {
8725 const gchar *preferred_system_array[] =
8726 { qtdemux->preferred_protection_system_id, NULL };
8728 selected_system = gst_protection_select_system (preferred_system_array);
8730 if (selected_system) {
8731 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8732 qtdemux->preferred_protection_system_id);
8734 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8735 "because there is no available decryptor",
8736 qtdemux->preferred_protection_system_id);
8740 if (!selected_system) {
8741 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8742 selected_system = gst_protection_select_system ((const gchar **)
8743 qtdemux->protection_system_ids->pdata);
8744 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8745 qtdemux->protection_system_ids->len - 1);
8748 if (!selected_system) {
8749 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8750 "suitable decryptor element has been found");
8754 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8757 gst_structure_set (s,
8758 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8765 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8767 /* fps is calculated base on the duration of the average framerate since
8768 * qt does not have a fixed framerate. */
8769 gboolean fps_available = TRUE;
8770 guint32 first_duration = 0;
8772 if (stream->n_samples > 0)
8773 first_duration = stream->samples[0].duration;
8775 if ((stream->n_samples == 1 && first_duration == 0)
8776 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8778 CUR_STREAM (stream)->fps_n = 0;
8779 CUR_STREAM (stream)->fps_d = 1;
8781 if (stream->duration == 0 || stream->n_samples < 2) {
8782 CUR_STREAM (stream)->fps_n = stream->timescale;
8783 CUR_STREAM (stream)->fps_d = 1;
8784 fps_available = FALSE;
8786 GstClockTime avg_duration;
8790 /* duration and n_samples can be updated for fragmented format
8791 * so, framerate of fragmented format is calculated using data in a moof */
8792 if (qtdemux->fragmented && stream->n_samples_moof > 0
8793 && stream->duration_moof > 0) {
8794 n_samples = stream->n_samples_moof;
8795 duration = stream->duration_moof;
8797 n_samples = stream->n_samples;
8798 duration = stream->duration;
8801 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8802 /* stream->duration is guint64, timescale, n_samples are guint32 */
8804 gst_util_uint64_scale_round (duration -
8805 first_duration, GST_SECOND,
8806 (guint64) (stream->timescale) * (n_samples - 1));
8808 GST_LOG_OBJECT (qtdemux,
8809 "Calculating avg sample duration based on stream (or moof) duration %"
8811 " minus first sample %u, leaving %d samples gives %"
8812 GST_TIME_FORMAT, duration, first_duration,
8813 n_samples - 1, GST_TIME_ARGS (avg_duration));
8816 gst_video_guess_framerate (avg_duration,
8817 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8819 GST_DEBUG_OBJECT (qtdemux,
8820 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8821 stream->timescale, CUR_STREAM (stream)->fps_n,
8822 CUR_STREAM (stream)->fps_d);
8826 return fps_available;
8830 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8832 if (stream->subtype == FOURCC_vide) {
8833 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8835 if (CUR_STREAM (stream)->caps) {
8836 CUR_STREAM (stream)->caps =
8837 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8839 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8840 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8841 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8842 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8844 /* set framerate if calculated framerate is reliable */
8845 if (fps_available) {
8846 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8847 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8848 CUR_STREAM (stream)->fps_d, NULL);
8851 /* calculate pixel-aspect-ratio using display width and height */
8852 GST_DEBUG_OBJECT (qtdemux,
8853 "video size %dx%d, target display size %dx%d",
8854 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8855 stream->display_width, stream->display_height);
8856 /* qt file might have pasp atom */
8857 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8858 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8859 CUR_STREAM (stream)->par_h);
8860 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8861 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8862 CUR_STREAM (stream)->par_h, NULL);
8863 } else if (stream->display_width > 0 && stream->display_height > 0
8864 && CUR_STREAM (stream)->width > 0
8865 && CUR_STREAM (stream)->height > 0) {
8868 /* calculate the pixel aspect ratio using the display and pixel w/h */
8869 n = stream->display_width * CUR_STREAM (stream)->height;
8870 d = stream->display_height * CUR_STREAM (stream)->width;
8873 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8874 CUR_STREAM (stream)->par_w = n;
8875 CUR_STREAM (stream)->par_h = d;
8876 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8877 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8878 CUR_STREAM (stream)->par_h, NULL);
8881 if (CUR_STREAM (stream)->interlace_mode > 0) {
8882 if (CUR_STREAM (stream)->interlace_mode == 1) {
8883 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8884 G_TYPE_STRING, "progressive", NULL);
8885 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8886 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8887 G_TYPE_STRING, "interleaved", NULL);
8888 if (CUR_STREAM (stream)->field_order == 9) {
8889 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8890 G_TYPE_STRING, "top-field-first", NULL);
8891 } else if (CUR_STREAM (stream)->field_order == 14) {
8892 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8893 G_TYPE_STRING, "bottom-field-first", NULL);
8898 /* Create incomplete colorimetry here if needed */
8899 if (CUR_STREAM (stream)->colorimetry.range ||
8900 CUR_STREAM (stream)->colorimetry.matrix ||
8901 CUR_STREAM (stream)->colorimetry.transfer
8902 || CUR_STREAM (stream)->colorimetry.primaries) {
8903 gchar *colorimetry =
8904 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8905 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8906 G_TYPE_STRING, colorimetry, NULL);
8907 g_free (colorimetry);
8910 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8911 guint par_w = 1, par_h = 1;
8913 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8914 par_w = CUR_STREAM (stream)->par_w;
8915 par_h = CUR_STREAM (stream)->par_h;
8918 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8919 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8921 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8924 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8925 "multiview-mode", G_TYPE_STRING,
8926 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8927 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8928 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8933 else if (stream->subtype == FOURCC_soun) {
8934 if (CUR_STREAM (stream)->caps) {
8935 CUR_STREAM (stream)->caps =
8936 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8937 if (CUR_STREAM (stream)->rate > 0)
8938 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8939 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8940 if (CUR_STREAM (stream)->n_channels > 0)
8941 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8942 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8943 if (CUR_STREAM (stream)->n_channels > 2) {
8944 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8945 * correctly; this is just the minimum we can do - assume
8946 * we don't actually have any channel positions. */
8947 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8948 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8953 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8954 const GstStructure *s;
8955 QtDemuxStream *fps_stream = NULL;
8956 gboolean fps_available = FALSE;
8958 /* CEA608 closed caption tracks are a bit special in that each sample
8959 * can contain CCs for multiple frames, and CCs can be omitted and have to
8960 * be inferred from the duration of the sample then.
8962 * As such we take the framerate from the (first) video track here for
8963 * CEA608 as there must be one CC byte pair for every video frame
8964 * according to the spec.
8966 * For CEA708 all is fine and there is one sample per frame.
8969 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8970 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8973 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8974 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8976 if (tmp->subtype == FOURCC_vide) {
8983 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8984 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8985 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8988 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8989 fps_stream = stream;
8992 CUR_STREAM (stream)->caps =
8993 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8995 /* set framerate if calculated framerate is reliable */
8996 if (fps_available) {
8997 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8998 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8999 CUR_STREAM (stream)->fps_d, NULL);
9004 gboolean forward_collection = FALSE;
9005 GstCaps *prev_caps = NULL;
9007 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
9008 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
9009 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
9010 gst_pad_set_active (stream->pad, TRUE);
9012 gst_pad_use_fixed_caps (stream->pad);
9014 if (stream->protected) {
9015 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
9016 GST_ERROR_OBJECT (qtdemux,
9017 "Failed to configure protected stream caps.");
9022 if (stream->new_stream) {
9024 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
9027 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
9030 gst_event_parse_stream_flags (event, &stream_flags);
9031 if (gst_event_parse_group_id (event, &qtdemux->group_id))
9032 qtdemux->have_group_id = TRUE;
9034 qtdemux->have_group_id = FALSE;
9035 gst_event_unref (event);
9036 } else if (!qtdemux->have_group_id) {
9037 qtdemux->have_group_id = TRUE;
9038 qtdemux->group_id = gst_util_group_id_next ();
9041 stream->new_stream = FALSE;
9042 event = gst_event_new_stream_start (stream->stream_id);
9043 if (qtdemux->have_group_id)
9044 gst_event_set_group_id (event, qtdemux->group_id);
9045 if (stream->disabled)
9046 stream_flags |= GST_STREAM_FLAG_UNSELECT;
9047 if (CUR_STREAM (stream)->sparse) {
9048 stream_flags |= GST_STREAM_FLAG_SPARSE;
9050 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
9052 gst_event_set_stream_flags (event, stream_flags);
9053 gst_pad_push_event (stream->pad, event);
9055 forward_collection = TRUE;
9058 prev_caps = gst_pad_get_current_caps (stream->pad);
9060 if (CUR_STREAM (stream)->caps) {
9062 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
9063 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
9064 CUR_STREAM (stream)->caps);
9065 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
9067 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
9070 GST_WARNING_OBJECT (qtdemux, "stream without caps");
9074 gst_caps_unref (prev_caps);
9075 stream->new_caps = FALSE;
9077 if (forward_collection) {
9078 /* Forward upstream collection and selection if any */
9079 GstEvent *upstream_event = gst_pad_get_sticky_event (qtdemux->sinkpad,
9080 GST_EVENT_STREAM_COLLECTION, 0);
9082 gst_pad_push_event (stream->pad, upstream_event);
9089 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
9090 QtDemuxStream * stream)
9092 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
9095 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
9096 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
9097 if (G_UNLIKELY (stream->stsd_sample_description_id >=
9098 stream->stsd_entries_length)) {
9099 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
9100 (_("This file is invalid and cannot be played.")),
9101 ("New sample description id is out of bounds (%d >= %d)",
9102 stream->stsd_sample_description_id, stream->stsd_entries_length));
9104 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
9105 stream->new_caps = TRUE;
9110 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
9111 QtDemuxStream * stream, GstTagList * list)
9113 gboolean ret = TRUE;
9115 if (stream->subtype == FOURCC_vide) {
9116 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9119 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9122 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9123 gst_object_unref (stream->pad);
9129 qtdemux->n_video_streams++;
9130 } else if (stream->subtype == FOURCC_soun) {
9131 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
9134 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9136 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9137 gst_object_unref (stream->pad);
9142 qtdemux->n_audio_streams++;
9143 } else if (stream->subtype == FOURCC_strm) {
9144 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9145 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9146 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9147 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
9148 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9151 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9153 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9154 gst_object_unref (stream->pad);
9159 qtdemux->n_sub_streams++;
9160 } else if (stream->subtype == FOURCC_meta) {
9161 gchar *name = g_strdup_printf ("meta_%u", qtdemux->n_meta_streams);
9164 gst_pad_new_from_static_template (&gst_qtdemux_metasrc_template, name);
9166 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9167 gst_object_unref (stream->pad);
9172 qtdemux->n_meta_streams++;
9173 } else if (CUR_STREAM (stream)->caps) {
9174 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9177 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9179 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9180 gst_object_unref (stream->pad);
9185 qtdemux->n_video_streams++;
9187 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9194 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9195 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9196 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9197 GST_OBJECT_LOCK (qtdemux);
9198 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9199 GST_OBJECT_UNLOCK (qtdemux);
9201 if (stream->stream_tags)
9202 gst_tag_list_unref (stream->stream_tags);
9203 stream->stream_tags = list;
9205 /* global tags go on each pad anyway */
9206 stream->send_global_tags = TRUE;
9207 /* send upstream GST_EVENT_PROTECTION events that were received before
9208 this source pad was created */
9209 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9210 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9214 gst_tag_list_unref (list);
9218 /* find next atom with @fourcc starting at @offset */
9219 static GstFlowReturn
9220 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9221 guint64 * length, guint32 fourcc)
9227 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9228 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9234 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9235 if (G_UNLIKELY (ret != GST_FLOW_OK))
9237 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9240 gst_buffer_unref (buf);
9243 gst_buffer_map (buf, &map, GST_MAP_READ);
9244 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9245 gst_buffer_unmap (buf, &map);
9246 gst_buffer_unref (buf);
9248 if (G_UNLIKELY (*length == 0)) {
9249 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9250 ret = GST_FLOW_ERROR;
9254 if (lfourcc == fourcc) {
9255 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9256 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9259 GST_LOG_OBJECT (qtdemux,
9260 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9261 GST_FOURCC_ARGS (lfourcc), *offset);
9262 if (*offset == G_MAXUINT64)
9272 /* might simply have had last one */
9273 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9278 /* should only do something in pull mode */
9279 /* call with OBJECT lock */
9280 static GstFlowReturn
9281 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9283 guint64 length, offset;
9284 GstBuffer *buf = NULL;
9285 GstFlowReturn ret = GST_FLOW_OK;
9286 GstFlowReturn res = GST_FLOW_OK;
9289 offset = qtdemux->moof_offset;
9290 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9293 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9294 return GST_FLOW_EOS;
9297 /* best not do pull etc with lock held */
9298 GST_OBJECT_UNLOCK (qtdemux);
9300 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9301 if (ret != GST_FLOW_OK)
9304 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9305 if (G_UNLIKELY (ret != GST_FLOW_OK))
9307 gst_buffer_map (buf, &map, GST_MAP_READ);
9308 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9309 gst_buffer_unmap (buf, &map);
9310 gst_buffer_unref (buf);
9315 gst_buffer_unmap (buf, &map);
9316 gst_buffer_unref (buf);
9320 /* look for next moof */
9321 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9322 if (G_UNLIKELY (ret != GST_FLOW_OK))
9326 GST_OBJECT_LOCK (qtdemux);
9328 qtdemux->moof_offset = offset;
9334 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9336 res = GST_FLOW_ERROR;
9341 /* maybe upstream temporarily flushing */
9342 if (ret != GST_FLOW_FLUSHING) {
9343 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9346 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9347 /* resume at current position next time */
9355 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9359 gint32 stts_duration;
9360 GstByteWriter stsc, stts, stsz;
9362 /* Each sample has a different size, which we don't support for merging */
9363 if (stream->sample_size == 0) {
9364 GST_DEBUG_OBJECT (qtdemux,
9365 "Not all samples have the same size, not merging");
9369 /* The stream has a ctts table, we don't support that */
9370 if (stream->ctts_present) {
9371 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9375 /* If there's a sync sample table also ignore this stream */
9376 if (stream->stps_present || stream->stss_present) {
9377 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9381 /* If chunks are considered samples already ignore this stream */
9382 if (stream->chunks_are_samples) {
9383 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9387 /* Require that all samples have the same duration */
9388 if (stream->n_sample_times > 1) {
9389 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9393 /* Parse the stts to get the sample duration and number of samples */
9394 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9395 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9397 /* Parse the number of chunks from the stco manually because the
9398 * reader is already behind that */
9399 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9401 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9404 /* Now parse stsc, convert chunks into single samples and generate a
9405 * new stsc, stts and stsz from this information */
9406 gst_byte_writer_init (&stsc);
9407 gst_byte_writer_init (&stts);
9408 gst_byte_writer_init (&stsz);
9410 /* Note: we skip fourccs, size, version, flags and other fields of the new
9411 * atoms as the byte readers with them are already behind that position
9412 * anyway and only update the values of those inside the stream directly.
9414 stream->n_sample_times = 0;
9415 stream->n_samples = 0;
9416 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9418 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9420 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9421 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9422 sample_description_id =
9423 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9425 if (i == stream->n_samples_per_chunk - 1) {
9426 /* +1 because first_chunk is 1-based */
9427 last_chunk = num_chunks + 1;
9429 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9432 GST_DEBUG_OBJECT (qtdemux,
9433 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9434 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9436 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9437 /* One sample in this chunk */
9438 gst_byte_writer_put_uint32_be (&stsc, 1);
9439 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9441 /* For each chunk write a stts and stsz entry now */
9442 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9443 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9444 for (j = first_chunk; j < last_chunk; j++) {
9445 gst_byte_writer_put_uint32_be (&stsz,
9446 stream->sample_size * samples_per_chunk);
9449 stream->n_sample_times += 1;
9450 stream->n_samples += last_chunk - first_chunk;
9453 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9455 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9456 stream->n_samples, stream->n_sample_times);
9458 /* We don't have a fixed sample size anymore */
9459 stream->sample_size = 0;
9461 /* Free old data for the atoms */
9462 g_free ((gpointer) stream->stsz.data);
9463 stream->stsz.data = NULL;
9464 g_free ((gpointer) stream->stsc.data);
9465 stream->stsc.data = NULL;
9466 g_free ((gpointer) stream->stts.data);
9467 stream->stts.data = NULL;
9469 /* Store new data and replace byte readers */
9470 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9471 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9472 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9473 stream->stts.size = gst_byte_writer_get_size (&stts);
9474 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9475 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9476 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9477 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9478 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9481 /* initialise bytereaders for stbl sub-atoms */
9483 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9485 stream->stbl_index = -1; /* no samples have yet been parsed */
9486 stream->sample_index = -1;
9488 /* time-to-sample atom */
9489 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9492 /* copy atom data into a new buffer for later use */
9493 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9495 /* skip version + flags */
9496 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9497 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9499 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9501 /* make sure there's enough data */
9502 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9503 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9504 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9505 stream->n_sample_times);
9506 if (!stream->n_sample_times)
9510 /* sync sample atom */
9511 stream->stps_present = FALSE;
9512 if ((stream->stss_present =
9513 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9514 &stream->stss) ? TRUE : FALSE) == TRUE) {
9515 /* copy atom data into a new buffer for later use */
9516 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9518 /* skip version + flags */
9519 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9520 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9523 if (stream->n_sample_syncs) {
9524 /* make sure there's enough data */
9525 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9529 /* partial sync sample atom */
9530 if ((stream->stps_present =
9531 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9532 &stream->stps) ? TRUE : FALSE) == TRUE) {
9533 /* copy atom data into a new buffer for later use */
9534 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9536 /* skip version + flags */
9537 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9538 !gst_byte_reader_get_uint32_be (&stream->stps,
9539 &stream->n_sample_partial_syncs))
9542 /* if there are no entries, the stss table contains the real
9544 if (stream->n_sample_partial_syncs) {
9545 /* make sure there's enough data */
9546 if (!qt_atom_parser_has_chunks (&stream->stps,
9547 stream->n_sample_partial_syncs, 4))
9554 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9557 /* copy atom data into a new buffer for later use */
9558 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9560 /* skip version + flags */
9561 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9562 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9565 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9568 if (!stream->n_samples)
9571 /* sample-to-chunk atom */
9572 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9575 /* copy atom data into a new buffer for later use */
9576 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9578 /* skip version + flags */
9579 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9580 !gst_byte_reader_get_uint32_be (&stream->stsc,
9581 &stream->n_samples_per_chunk))
9584 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9585 stream->n_samples_per_chunk);
9587 /* make sure there's enough data */
9588 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9594 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9595 stream->co_size = sizeof (guint32);
9596 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9598 stream->co_size = sizeof (guint64);
9602 /* copy atom data into a new buffer for later use */
9603 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9605 /* skip version + flags */
9606 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9609 /* chunks_are_samples == TRUE means treat chunks as samples */
9610 stream->chunks_are_samples = stream->sample_size
9611 && !CUR_STREAM (stream)->sampled;
9612 if (stream->chunks_are_samples) {
9613 /* treat chunks as samples */
9614 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9617 /* skip number of entries */
9618 if (!gst_byte_reader_skip (&stream->stco, 4))
9621 /* make sure there are enough data in the stsz atom */
9622 if (!stream->sample_size) {
9623 /* different sizes for each sample */
9624 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9629 /* composition time-to-sample */
9630 if ((stream->ctts_present =
9631 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9632 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9633 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9634 guint8 ctts_version;
9635 gboolean checked_ctts = FALSE;
9637 /* copy atom data into a new buffer for later use */
9638 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9640 /* version 1 has signed offsets */
9641 if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9645 if (!gst_byte_reader_skip (&stream->ctts, 3)
9646 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9647 &stream->n_composition_times))
9650 /* make sure there's enough data */
9651 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9655 /* This is optional, if missing we iterate the ctts */
9656 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9657 guint8 cslg_version;
9659 /* cslg version 1 has 64 bit fields */
9660 if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9664 if (!gst_byte_reader_skip (&cslg, 3))
9667 if (cslg_version == 0) {
9668 gint32 composition_to_dts_shift;
9670 if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9673 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9675 gint64 composition_to_dts_shift;
9677 if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9680 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9683 gint32 cslg_least = 0;
9684 guint num_entries, pos;
9687 pos = gst_byte_reader_get_pos (&stream->ctts);
9688 num_entries = stream->n_composition_times;
9690 checked_ctts = TRUE;
9692 stream->cslg_shift = 0;
9694 for (i = 0; i < num_entries; i++) {
9697 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9698 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9699 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9700 * slightly inaccurate PTS could be more usable than corrupted one */
9701 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9702 && ABS (offset) / 2 > stream->duration)) {
9703 GST_WARNING_OBJECT (qtdemux,
9704 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9705 " larger than duration %" G_GUINT64_FORMAT, offset,
9708 stream->cslg_shift = 0;
9709 stream->ctts_present = FALSE;
9713 /* Don't consider "no decode samples" with offset G_MININT32
9714 * for the DTS/PTS shift */
9715 if (offset != G_MININT32 && offset < cslg_least)
9716 cslg_least = offset;
9720 stream->cslg_shift = -cslg_least;
9722 stream->cslg_shift = 0;
9724 /* reset the reader so we can generate sample table */
9725 gst_byte_reader_set_pos (&stream->ctts, pos);
9728 /* Check if ctts values are looking reasonable if that didn't happen above */
9729 if (!checked_ctts) {
9730 guint num_entries, pos;
9733 pos = gst_byte_reader_get_pos (&stream->ctts);
9734 num_entries = stream->n_composition_times;
9736 for (i = 0; i < num_entries; i++) {
9739 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9740 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9741 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9742 * slightly inaccurate PTS could be more usable than corrupted one */
9743 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9744 && ABS (offset) / 2 > stream->duration)) {
9745 GST_WARNING_OBJECT (qtdemux,
9746 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9747 " larger than duration %" G_GUINT64_FORMAT, offset,
9750 stream->cslg_shift = 0;
9751 stream->ctts_present = FALSE;
9756 /* reset the reader so we can generate sample table */
9757 gst_byte_reader_set_pos (&stream->ctts, pos);
9760 /* Ensure the cslg_shift value is consistent so we can use it
9761 * unconditionally to produce TS and Segment */
9762 stream->cslg_shift = 0;
9765 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
9766 stream->cslg_shift);
9768 /* For raw audio streams especially we might want to merge the samples
9769 * to not output one audio sample per buffer. We're doing this here
9770 * before allocating the sample tables so that from this point onwards
9771 * the number of container samples are static */
9772 if (stream->min_buffer_size > 0) {
9773 qtdemux_merge_sample_table (qtdemux, stream);
9777 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9778 stream->n_samples, (guint) sizeof (QtDemuxSample),
9779 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9781 if (stream->n_samples >=
9782 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9783 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9784 "be larger than %uMB (broken file?)", stream->n_samples,
9785 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9789 g_assert (stream->samples == NULL);
9790 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9791 if (!stream->samples) {
9792 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9801 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9802 (_("This file is corrupt and cannot be played.")), (NULL));
9807 gst_qtdemux_stbl_free (stream);
9808 if (!qtdemux->fragmented) {
9809 /* not quite good */
9810 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9813 /* may pick up samples elsewhere */
9819 /* collect samples from the next sample to be parsed up to sample @n for @stream
9820 * by reading the info from @stbl
9822 * This code can be executed from both the streaming thread and the seeking
9823 * thread so it takes the object lock to protect itself
9826 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9829 QtDemuxSample *samples, *first, *cur, *last;
9830 guint32 n_samples_per_chunk;
9833 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9834 GST_FOURCC_FORMAT ", pad %s",
9835 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9836 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9838 n_samples = stream->n_samples;
9841 goto out_of_samples;
9843 GST_OBJECT_LOCK (qtdemux);
9844 if (n <= stream->stbl_index)
9845 goto already_parsed;
9847 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9849 if (!stream->stsz.data) {
9850 /* so we already parsed and passed all the moov samples;
9851 * onto fragmented ones */
9852 g_assert (qtdemux->fragmented);
9856 /* pointer to the sample table */
9857 samples = stream->samples;
9859 /* starts from -1, moves to the next sample index to parse */
9860 stream->stbl_index++;
9862 /* keep track of the first and last sample to fill */
9863 first = &samples[stream->stbl_index];
9866 if (!stream->chunks_are_samples) {
9867 /* set the sample sizes */
9868 if (stream->sample_size == 0) {
9869 /* different sizes for each sample */
9870 for (cur = first; cur <= last; cur++) {
9871 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9872 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9873 (guint) (cur - samples), cur->size);
9876 /* samples have the same size */
9877 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9878 for (cur = first; cur <= last; cur++)
9879 cur->size = stream->sample_size;
9883 n_samples_per_chunk = stream->n_samples_per_chunk;
9886 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9889 if (stream->stsc_chunk_index >= stream->last_chunk
9890 || stream->stsc_chunk_index < stream->first_chunk) {
9891 stream->first_chunk =
9892 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9893 stream->samples_per_chunk =
9894 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9896 stream->stsd_sample_description_id =
9897 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9899 /* chunk numbers are counted from 1 it seems */
9900 if (G_UNLIKELY (stream->first_chunk == 0))
9903 --stream->first_chunk;
9905 /* the last chunk of each entry is calculated by taking the first chunk
9906 * of the next entry; except if there is no next, where we fake it with
9908 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9909 stream->last_chunk = G_MAXUINT32;
9911 stream->last_chunk =
9912 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9913 if (G_UNLIKELY (stream->last_chunk == 0))
9916 --stream->last_chunk;
9919 GST_LOG_OBJECT (qtdemux,
9920 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9921 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9922 stream->samples_per_chunk, stream->stsd_sample_description_id);
9924 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9927 if (stream->last_chunk != G_MAXUINT32) {
9928 if (!qt_atom_parser_peek_sub (&stream->stco,
9929 stream->first_chunk * stream->co_size,
9930 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9935 stream->co_chunk = stream->stco;
9936 if (!gst_byte_reader_skip (&stream->co_chunk,
9937 stream->first_chunk * stream->co_size))
9941 stream->stsc_chunk_index = stream->first_chunk;
9944 last_chunk = stream->last_chunk;
9946 if (stream->chunks_are_samples) {
9947 cur = &samples[stream->stsc_chunk_index];
9949 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9952 stream->stsc_chunk_index = j;
9957 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9960 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9961 "%" G_GUINT64_FORMAT, j, cur->offset);
9963 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9964 CUR_STREAM (stream)->bytes_per_frame > 0) {
9966 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9967 CUR_STREAM (stream)->samples_per_frame *
9968 CUR_STREAM (stream)->bytes_per_frame;
9970 cur->size = stream->samples_per_chunk;
9973 GST_DEBUG_OBJECT (qtdemux,
9974 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9975 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9976 stream->stco_sample_index)), cur->size);
9978 cur->timestamp = stream->stco_sample_index;
9979 cur->duration = stream->samples_per_chunk;
9980 cur->keyframe = TRUE;
9983 stream->stco_sample_index += stream->samples_per_chunk;
9985 stream->stsc_chunk_index = j;
9987 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9988 guint32 samples_per_chunk;
9989 guint64 chunk_offset;
9991 if (!stream->stsc_sample_index
9992 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9993 &stream->chunk_offset))
9996 samples_per_chunk = stream->samples_per_chunk;
9997 chunk_offset = stream->chunk_offset;
9999 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
10000 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
10001 G_GUINT64_FORMAT " and size %d",
10002 (guint) (cur - samples), chunk_offset, cur->size);
10004 cur->offset = chunk_offset;
10005 chunk_offset += cur->size;
10008 if (G_UNLIKELY (cur > last)) {
10010 stream->stsc_sample_index = k + 1;
10011 stream->chunk_offset = chunk_offset;
10012 stream->stsc_chunk_index = j;
10016 stream->stsc_sample_index = 0;
10018 stream->stsc_chunk_index = j;
10020 stream->stsc_index++;
10023 if (stream->chunks_are_samples)
10027 guint32 n_sample_times;
10029 n_sample_times = stream->n_sample_times;
10032 for (i = stream->stts_index; i < n_sample_times; i++) {
10033 guint32 stts_samples;
10034 gint32 stts_duration;
10037 if (stream->stts_sample_index >= stream->stts_samples
10038 || !stream->stts_sample_index) {
10040 stream->stts_samples =
10041 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10042 stream->stts_duration =
10043 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10045 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
10046 i, stream->stts_samples, stream->stts_duration);
10048 stream->stts_sample_index = 0;
10051 stts_samples = stream->stts_samples;
10052 stts_duration = stream->stts_duration;
10053 stts_time = stream->stts_time;
10055 for (j = stream->stts_sample_index; j < stts_samples; j++) {
10056 GST_DEBUG_OBJECT (qtdemux,
10057 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
10058 (guint) (cur - samples), j,
10059 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
10061 cur->timestamp = stts_time;
10062 cur->duration = stts_duration;
10064 /* avoid 32-bit wrap-around,
10065 * but still mind possible 'negative' duration */
10066 stts_time += (gint64) stts_duration;
10069 if (G_UNLIKELY (cur > last)) {
10071 stream->stts_time = stts_time;
10072 stream->stts_sample_index = j + 1;
10073 if (stream->stts_sample_index >= stream->stts_samples)
10074 stream->stts_index++;
10078 stream->stts_sample_index = 0;
10079 stream->stts_time = stts_time;
10080 stream->stts_index++;
10082 /* fill up empty timestamps with the last timestamp, this can happen when
10083 * the last samples do not decode and so we don't have timestamps for them.
10084 * We however look at the last timestamp to estimate the track length so we
10085 * need something in here. */
10086 for (; cur < last; cur++) {
10087 GST_DEBUG_OBJECT (qtdemux,
10088 "fill sample %d: timestamp %" GST_TIME_FORMAT,
10089 (guint) (cur - samples),
10090 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
10091 cur->timestamp = stream->stts_time;
10092 cur->duration = -1;
10097 /* sample sync, can be NULL */
10098 if (stream->stss_present == TRUE) {
10099 guint32 n_sample_syncs;
10101 n_sample_syncs = stream->n_sample_syncs;
10103 if (!n_sample_syncs) {
10104 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
10105 stream->all_keyframe = TRUE;
10107 for (i = stream->stss_index; i < n_sample_syncs; i++) {
10108 /* note that the first sample is index 1, not 0 */
10111 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
10113 if (G_LIKELY (index > 0 && index <= n_samples)) {
10115 samples[index].keyframe = TRUE;
10116 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10117 /* and exit if we have enough samples */
10118 if (G_UNLIKELY (index >= n)) {
10125 stream->stss_index = i;
10128 /* stps marks partial sync frames like open GOP I-Frames */
10129 if (stream->stps_present == TRUE) {
10130 guint32 n_sample_partial_syncs;
10132 n_sample_partial_syncs = stream->n_sample_partial_syncs;
10134 /* if there are no entries, the stss table contains the real
10136 if (n_sample_partial_syncs) {
10137 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
10138 /* note that the first sample is index 1, not 0 */
10141 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
10143 if (G_LIKELY (index > 0 && index <= n_samples)) {
10145 samples[index].keyframe = TRUE;
10146 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10147 /* and exit if we have enough samples */
10148 if (G_UNLIKELY (index >= n)) {
10155 stream->stps_index = i;
10159 /* no stss, all samples are keyframes */
10160 stream->all_keyframe = TRUE;
10161 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10166 /* composition time to sample */
10167 if (stream->ctts_present == TRUE) {
10168 guint32 n_composition_times;
10169 guint32 ctts_count;
10170 gint32 ctts_soffset;
10172 /* Fill in the pts_offsets */
10174 n_composition_times = stream->n_composition_times;
10176 for (i = stream->ctts_index; i < n_composition_times; i++) {
10177 if (stream->ctts_sample_index >= stream->ctts_count
10178 || !stream->ctts_sample_index) {
10179 stream->ctts_count =
10180 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10181 stream->ctts_soffset =
10182 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10183 stream->ctts_sample_index = 0;
10186 ctts_count = stream->ctts_count;
10187 ctts_soffset = stream->ctts_soffset;
10189 /* FIXME: Set offset to 0 for "no decode samples". This needs
10190 * to be handled in a codec specific manner ideally. */
10191 if (ctts_soffset == G_MININT32)
10194 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10195 cur->pts_offset = ctts_soffset;
10198 if (G_UNLIKELY (cur > last)) {
10200 stream->ctts_sample_index = j + 1;
10204 stream->ctts_sample_index = 0;
10205 stream->ctts_index++;
10209 stream->stbl_index = n;
10210 /* if index has been completely parsed, free data that is no-longer needed */
10211 if (n + 1 == stream->n_samples) {
10212 gst_qtdemux_stbl_free (stream);
10213 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10214 if (qtdemux->pullbased) {
10215 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10216 while (n + 1 == stream->n_samples)
10217 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10221 GST_OBJECT_UNLOCK (qtdemux);
10228 GST_LOG_OBJECT (qtdemux,
10229 "Tried to parse up to sample %u but this sample has already been parsed",
10231 /* if fragmented, there may be more */
10232 if (qtdemux->fragmented && n == stream->stbl_index)
10234 GST_OBJECT_UNLOCK (qtdemux);
10240 GST_LOG_OBJECT (qtdemux,
10241 "Tried to parse up to sample %u but there are only %u samples", n + 1,
10242 stream->n_samples);
10243 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10244 (_("This file is corrupt and cannot be played.")), (NULL));
10249 GST_OBJECT_UNLOCK (qtdemux);
10250 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10251 (_("This file is corrupt and cannot be played.")), (NULL));
10256 /* collect all segment info for @stream.
10259 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10263 /* accept edts if they contain gaps at start and there is only
10264 * one media segment */
10265 gboolean allow_pushbased_edts = TRUE;
10266 gint media_segments_count = 0;
10268 /* parse and prepare segment info from the edit list */
10269 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10270 stream->n_segments = 0;
10271 stream->segments = NULL;
10272 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10275 guint segment_number, entry_size;
10277 GstClockTime stime;
10278 const guint8 *buffer;
10282 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10283 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10286 buffer = elst->data;
10288 size = QT_UINT32 (buffer);
10289 /* version, flags, n_segments */
10291 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10294 version = QT_UINT8 (buffer + 8);
10295 entry_size = (version == 1) ? 20 : 12;
10297 n_segments = QT_UINT32 (buffer + 12);
10299 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10300 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10304 /* we might allocate a bit too much, at least allocate 1 segment */
10305 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10307 /* segments always start from 0 */
10311 for (segment_number = 0; segment_number < n_segments; segment_number++) {
10313 guint64 media_time;
10314 gboolean empty_edit = FALSE;
10315 QtDemuxSegment *segment;
10317 GstClockTime media_start = GST_CLOCK_TIME_NONE;
10319 if (version == 1) {
10320 media_time = QT_UINT64 (buffer + 8);
10321 duration = QT_UINT64 (buffer);
10322 if (media_time == G_MAXUINT64)
10325 media_time = QT_UINT32 (buffer + 4);
10326 duration = QT_UINT32 (buffer);
10327 if (media_time == G_MAXUINT32)
10332 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10334 segment = &stream->segments[segment_number];
10336 /* time and duration expressed in global timescale */
10337 segment->time = stime;
10338 if (duration != 0 || empty_edit) {
10339 /* edge case: empty edits with duration=zero are treated here.
10340 * (files should not have these anyway). */
10342 /* add non scaled values so we don't cause roundoff errors */
10344 stime = QTTIME_TO_GSTTIME (qtdemux, time);
10345 segment->duration = stime - segment->time;
10347 /* zero duration does not imply media_start == media_stop
10348 * but, only specify media_start. The edit ends with the track. */
10349 stime = segment->duration = GST_CLOCK_TIME_NONE;
10350 /* Don't allow more edits after this one. */
10351 n_segments = segment_number + 1;
10353 segment->stop_time = stime;
10355 segment->trak_media_start = media_time;
10356 /* media_time expressed in stream timescale */
10358 segment->media_start = media_start;
10359 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10360 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10361 media_segments_count++;
10363 segment->media_start = GST_CLOCK_TIME_NONE;
10364 segment->media_stop = GST_CLOCK_TIME_NONE;
10366 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10368 if (rate_int <= 1) {
10369 /* 0 is not allowed, some programs write 1 instead of the floating point
10371 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10375 segment->rate = rate_int / 65536.0;
10378 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10379 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10380 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10381 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10382 segment_number, GST_TIME_ARGS (segment->time),
10383 GST_TIME_ARGS (segment->duration),
10384 GST_TIME_ARGS (segment->media_start), media_time,
10385 GST_TIME_ARGS (segment->media_stop),
10386 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10387 stream->timescale);
10388 if (segment->stop_time > qtdemux->segment.stop &&
10389 !qtdemux->upstream_format_is_time) {
10390 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10391 " extends to %" GST_TIME_FORMAT
10392 " past the end of the declared movie duration %" GST_TIME_FORMAT
10393 " movie segment will be extended", segment_number,
10394 GST_TIME_ARGS (segment->stop_time),
10395 GST_TIME_ARGS (qtdemux->segment.stop));
10396 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10399 buffer += entry_size;
10401 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10402 stream->n_segments = n_segments;
10403 if (media_segments_count != 1)
10404 allow_pushbased_edts = FALSE;
10408 /* push based does not handle segments, so act accordingly here,
10409 * and warn if applicable */
10410 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10411 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10412 /* remove and use default one below, we stream like it anyway */
10413 g_free (stream->segments);
10414 stream->segments = NULL;
10415 stream->n_segments = 0;
10418 /* no segments, create one to play the complete trak */
10419 if (stream->n_segments == 0) {
10420 GstClockTime stream_duration =
10421 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10423 if (stream->segments == NULL)
10424 stream->segments = g_new (QtDemuxSegment, 1);
10426 /* represent unknown our way */
10427 if (stream_duration == 0)
10428 stream_duration = GST_CLOCK_TIME_NONE;
10430 stream->segments[0].time = 0;
10431 stream->segments[0].stop_time = stream_duration;
10432 stream->segments[0].duration = stream_duration;
10433 stream->segments[0].media_start = 0;
10434 stream->segments[0].media_stop = stream_duration;
10435 stream->segments[0].rate = 1.0;
10436 stream->segments[0].trak_media_start = 0;
10438 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10439 GST_TIME_ARGS (stream_duration));
10440 stream->n_segments = 1;
10441 stream->dummy_segment = TRUE;
10443 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10449 * Parses the stsd atom of a svq3 trak looking for
10450 * the SMI and gama atoms.
10453 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10454 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10456 const guint8 *_gamma = NULL;
10457 GstBuffer *_seqh = NULL;
10458 const guint8 *stsd_data = stsd_entry_data;
10459 guint32 length = QT_UINT32 (stsd_data);
10463 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10469 version = QT_UINT16 (stsd_data);
10470 if (version == 3) {
10471 if (length >= 70) {
10474 while (length > 8) {
10475 guint32 fourcc, size;
10476 const guint8 *data;
10477 size = QT_UINT32 (stsd_data);
10478 fourcc = QT_FOURCC (stsd_data + 4);
10479 data = stsd_data + 8;
10482 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10483 "svq3 atom parsing");
10492 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10493 " for gama atom, expected 12", size);
10498 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10500 if (_seqh != NULL) {
10501 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10502 " found, ignoring");
10504 seqh_size = QT_UINT32 (data + 4);
10505 if (seqh_size > 0) {
10506 _seqh = gst_buffer_new_and_alloc (seqh_size);
10507 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10514 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10515 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10519 if (size <= length) {
10525 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10528 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10529 G_GUINT16_FORMAT, version);
10539 } else if (_seqh) {
10540 gst_buffer_unref (_seqh);
10545 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10548 GstByteReader dref;
10552 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10553 * atom that might contain a 'data' atom with the rtsp uri.
10554 * This case was reported in bug #597497, some info about
10555 * the hndl atom can be found in TN1195
10557 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10558 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10561 guint32 dref_num_entries = 0;
10562 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10563 gst_byte_reader_skip (&dref, 4) &&
10564 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10567 /* search dref entries for hndl atom */
10568 for (i = 0; i < dref_num_entries; i++) {
10569 guint32 size = 0, type;
10570 guint8 string_len = 0;
10571 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10572 qt_atom_parser_get_fourcc (&dref, &type)) {
10573 if (type == FOURCC_hndl) {
10574 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10576 /* skip data reference handle bytes and the
10577 * following pascal string and some extra 4
10578 * bytes I have no idea what are */
10579 if (!gst_byte_reader_skip (&dref, 4) ||
10580 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10581 !gst_byte_reader_skip (&dref, string_len + 4)) {
10582 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10586 /* iterate over the atoms to find the data atom */
10587 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10591 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10592 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10593 if (atom_type == FOURCC_data) {
10594 const guint8 *uri_aux = NULL;
10596 /* found the data atom that might contain the rtsp uri */
10597 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10598 "hndl atom, interpreting it as an URI");
10599 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10601 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10602 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10604 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10605 "didn't contain a rtsp address");
10607 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10612 /* skipping to the next entry */
10613 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10616 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10623 /* skip to the next entry */
10624 if (!gst_byte_reader_skip (&dref, size - 8))
10627 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10630 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10636 #define AMR_NB_ALL_MODES 0x81ff
10637 #define AMR_WB_ALL_MODES 0x83ff
10639 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10641 /* The 'damr' atom is of the form:
10643 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10644 * 32 b 8 b 16 b 8 b 8 b
10646 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10647 * represents the highest mode used in the stream (and thus the maximum
10648 * bitrate), with a couple of special cases as seen below.
10651 /* Map of frame type ID -> bitrate */
10652 static const guint nb_bitrates[] = {
10653 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10655 static const guint wb_bitrates[] = {
10656 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10662 gst_buffer_map (buf, &map, GST_MAP_READ);
10664 if (map.size != 0x11) {
10665 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10669 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10670 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10671 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10675 mode_set = QT_UINT16 (map.data + 13);
10677 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10678 max_mode = 7 + (wb ? 1 : 0);
10680 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10681 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10683 if (max_mode == -1) {
10684 GST_DEBUG ("No mode indication was found (mode set) = %x",
10689 gst_buffer_unmap (buf, &map);
10690 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10693 gst_buffer_unmap (buf, &map);
10698 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10699 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10702 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10708 if (gst_byte_reader_get_remaining (reader) < 36)
10711 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10712 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10713 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10714 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10715 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10716 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10717 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10718 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10719 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10721 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10722 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10723 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10725 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10726 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10728 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10729 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10736 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10737 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10744 * This macro will only compare value abdegh, it expects cfi to have already
10747 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10748 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10750 /* only handle the cases where the last column has standard values */
10751 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10752 const gchar *rotation_tag = NULL;
10754 /* no rotation needed */
10755 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10757 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10758 rotation_tag = "rotate-90";
10759 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10760 rotation_tag = "rotate-180";
10761 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10762 rotation_tag = "rotate-270";
10764 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10767 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10768 GST_STR_NULL (rotation_tag));
10769 if (rotation_tag != NULL) {
10770 if (*taglist == NULL)
10771 *taglist = gst_tag_list_new_empty ();
10772 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10773 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10776 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10781 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10782 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10786 GstBuffer *adrm_buf = NULL;
10787 QtDemuxAavdEncryptionInfo *info;
10789 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10790 if (G_UNLIKELY (!adrm)) {
10791 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10794 adrm_size = QT_UINT32 (adrm->data);
10795 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10797 stream->protection_scheme_type = FOURCC_aavd;
10799 if (!stream->protection_scheme_info)
10800 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10802 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10804 if (info->default_properties)
10805 gst_structure_free (info->default_properties);
10806 info->default_properties = gst_structure_new ("application/x-aavd",
10807 "encrypted", G_TYPE_BOOLEAN, TRUE,
10808 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10809 gst_buffer_unref (adrm_buf);
10811 *original_fmt = FOURCC_mp4a;
10815 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10816 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10817 * Common Encryption (cenc), the function will also parse the tenc box (defined
10818 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10819 * (typically an enc[v|a|t|s] sample entry); the function will set
10820 * @original_fmt to the fourcc of the original unencrypted stream format.
10821 * Returns TRUE if successful; FALSE otherwise. */
10823 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10824 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10830 QtDemuxCencSampleSetInfo *info;
10832 const guint8 *tenc_data;
10834 g_return_val_if_fail (qtdemux != NULL, FALSE);
10835 g_return_val_if_fail (stream != NULL, FALSE);
10836 g_return_val_if_fail (container != NULL, FALSE);
10837 g_return_val_if_fail (original_fmt != NULL, FALSE);
10839 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10840 if (G_UNLIKELY (!sinf)) {
10841 if (stream->protection_scheme_type == FOURCC_cenc
10842 || stream->protection_scheme_type == FOURCC_cbcs) {
10843 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10844 "mandatory for Common Encryption");
10850 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10851 if (G_UNLIKELY (!frma)) {
10852 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10856 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10857 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10858 GST_FOURCC_ARGS (*original_fmt));
10860 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10862 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10865 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10866 stream->protection_scheme_version =
10867 QT_UINT32 ((const guint8 *) schm->data + 16);
10869 GST_DEBUG_OBJECT (qtdemux,
10870 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10871 "protection_scheme_version: %#010x",
10872 GST_FOURCC_ARGS (stream->protection_scheme_type),
10873 stream->protection_scheme_version);
10875 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10877 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10880 if (stream->protection_scheme_type != FOURCC_cenc &&
10881 stream->protection_scheme_type != FOURCC_piff &&
10882 stream->protection_scheme_type != FOURCC_cbcs) {
10883 GST_ERROR_OBJECT (qtdemux,
10884 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10885 GST_FOURCC_ARGS (stream->protection_scheme_type));
10889 if (G_UNLIKELY (!stream->protection_scheme_info))
10890 stream->protection_scheme_info =
10891 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10893 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10895 if (stream->protection_scheme_type == FOURCC_cenc
10896 || stream->protection_scheme_type == FOURCC_cbcs) {
10897 guint8 is_encrypted;
10899 guint8 constant_iv_size = 0;
10900 const guint8 *default_kid;
10901 guint8 crypt_byte_block = 0;
10902 guint8 skip_byte_block = 0;
10903 const guint8 *constant_iv = NULL;
10905 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10907 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10908 "which is mandatory for Common Encryption");
10911 tenc_data = (const guint8 *) tenc->data + 12;
10912 is_encrypted = QT_UINT8 (tenc_data + 2);
10913 iv_size = QT_UINT8 (tenc_data + 3);
10914 default_kid = (tenc_data + 4);
10915 if (stream->protection_scheme_type == FOURCC_cbcs) {
10916 guint8 possible_pattern_info;
10917 if (iv_size == 0) {
10918 constant_iv_size = QT_UINT8 (tenc_data + 20);
10919 if (constant_iv_size != 8 && constant_iv_size != 16) {
10920 GST_ERROR_OBJECT (qtdemux,
10921 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10924 constant_iv = (tenc_data + 21);
10926 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10927 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10928 skip_byte_block = possible_pattern_info & 0x0f;
10930 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10931 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10932 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10933 } else if (stream->protection_scheme_type == FOURCC_piff) {
10935 static const guint8 piff_track_encryption_uuid[] = {
10936 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10937 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10940 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10942 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10943 "which is mandatory for Common Encryption");
10947 tenc_data = (const guint8 *) tenc->data + 8;
10948 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10949 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10950 GST_ERROR_OBJECT (qtdemux,
10951 "Unsupported track encryption box with uuid: %s", box_uuid);
10955 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10956 gst_byte_reader_init (&br, tenc_data, 20);
10957 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10958 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10961 stream->protection_scheme_type = FOURCC_cenc;
10968 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10969 QtDemuxStream ** stream2)
10971 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10975 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10980 /*parse svmi header if existing */
10981 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10983 guint32 len = QT_UINT32 ((guint8 *) svmi->data);
10984 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10986 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10987 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10988 guint8 frame_type, frame_layout;
10989 guint32 stereo_mono_change_count;
10994 /* MPEG-A stereo video */
10995 if (qtdemux->major_brand == FOURCC_ss02)
10996 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10998 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10999 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
11000 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
11002 switch (frame_type) {
11004 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
11007 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
11010 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
11013 /* mode 3 is primary/secondary view sequence, ie
11014 * left/right views in separate tracks. See section 7.2
11015 * of ISO/IEC 23000-11:2009 */
11016 /* In the future this might be supported using related
11017 * streams, like an enhancement track - if files like this
11019 GST_FIXME_OBJECT (qtdemux,
11020 "Implement stereo video in separate streams");
11023 if ((frame_layout & 0x1) == 0)
11024 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
11026 GST_LOG_OBJECT (qtdemux,
11027 "StereoVideo: composition type: %u, is_left_first: %u",
11028 frame_type, frame_layout);
11030 if (stereo_mono_change_count > 1) {
11031 GST_FIXME_OBJECT (qtdemux,
11032 "Mixed-mono flags are not yet supported in qtdemux.");
11035 stream->multiview_mode = mode;
11036 stream->multiview_flags = flags;
11043 /* parse the traks.
11044 * With each track we associate a new QtDemuxStream that contains all the info
11046 * traks that do not decode to something (like strm traks) will not have a pad.
11049 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
11051 GstByteReader tkhd;
11065 QtDemuxStream *stream = NULL;
11066 const guint8 *stsd_data;
11067 const guint8 *stsd_entry_data;
11068 guint remaining_stsd_len;
11069 guint stsd_entry_count;
11071 guint16 lang_code; /* quicktime lang code or packed iso code */
11073 guint32 tkhd_flags = 0;
11074 guint8 tkhd_version = 0;
11075 guint32 w = 0, h = 0;
11076 guint value_size, stsd_len, len;
11080 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
11082 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
11083 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
11084 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
11087 /* pick between 64 or 32 bits */
11088 value_size = tkhd_version == 1 ? 8 : 4;
11089 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
11090 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
11093 /* Check if current moov has duplicated track_id */
11094 if (qtdemux_find_stream (qtdemux, track_id))
11095 goto existing_stream;
11097 stream = _create_stream (qtdemux, track_id);
11098 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11100 /* need defaults for fragments */
11101 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
11103 if ((tkhd_flags & 1) == 0)
11104 stream->disabled = TRUE;
11106 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
11107 tkhd_version, tkhd_flags, stream->track_id);
11109 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
11112 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
11113 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
11114 if (qtdemux->major_brand != FOURCC_mjp2 ||
11115 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
11119 len = QT_UINT32 ((guint8 *) mdhd->data);
11120 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
11121 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
11122 if (version == 0x01000000) {
11125 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
11126 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
11127 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
11131 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
11132 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
11133 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
11136 if (lang_code < 0x400) {
11137 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
11138 } else if (lang_code == 0x7fff) {
11139 stream->lang_id[0] = 0; /* unspecified */
11141 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11142 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11143 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11144 stream->lang_id[3] = 0;
11147 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11148 stream->timescale);
11149 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11151 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11152 lang_code, stream->lang_id);
11154 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11157 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11158 /* chapters track reference */
11159 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11161 gsize length = GST_READ_UINT32_BE (chap->data);
11162 if (qtdemux->chapters_track_id)
11163 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11165 if (length >= 12) {
11166 qtdemux->chapters_track_id =
11167 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11172 /* fragmented files may have bogus duration in moov */
11173 if (!qtdemux->fragmented &&
11174 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11175 guint64 tdur1, tdur2;
11177 /* don't overflow */
11178 tdur1 = stream->timescale * (guint64) qtdemux->duration;
11179 tdur2 = qtdemux->timescale * (guint64) stream->duration;
11182 * some of those trailers, nowadays, have prologue images that are
11183 * themselves video tracks as well. I haven't really found a way to
11184 * identify those yet, except for just looking at their duration. */
11185 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11186 GST_WARNING_OBJECT (qtdemux,
11187 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11188 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11189 "found, assuming preview image or something; skipping track",
11190 stream->duration, stream->timescale, qtdemux->duration,
11191 qtdemux->timescale);
11192 gst_qtdemux_stream_unref (stream);
11197 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11200 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11201 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11203 len = QT_UINT32 ((guint8 *) hdlr->data);
11205 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11206 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11207 GST_FOURCC_ARGS (stream->subtype));
11209 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11212 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11215 /* Parse out svmi (and later st3d/sv3d) atoms */
11216 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
11219 /* parse rest of tkhd */
11220 if (stream->subtype == FOURCC_vide) {
11223 /* version 1 uses some 64-bit ints */
11224 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11227 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11230 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11231 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11234 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11235 &stream->stream_tags);
11239 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11241 stsd_data = (const guint8 *) stsd->data;
11243 /* stsd should at least have one entry */
11244 stsd_len = QT_UINT32 (stsd_data);
11245 if (stsd_len < 24) {
11246 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11247 if (stream->subtype == FOURCC_vivo) {
11248 gst_qtdemux_stream_unref (stream);
11255 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11256 /* each stsd entry must contain at least 8 bytes */
11257 if (stream->stsd_entries_length == 0
11258 || stream->stsd_entries_length > stsd_len / 8) {
11259 stream->stsd_entries_length = 0;
11262 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11263 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
11264 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
11266 stsd_entry_data = stsd_data + 16;
11267 remaining_stsd_len = stsd_len - 16;
11268 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11270 gchar *codec = NULL;
11271 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11273 /* and that entry should fit within stsd */
11274 len = QT_UINT32 (stsd_entry_data);
11275 if (len > remaining_stsd_len)
11278 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11279 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
11280 GST_FOURCC_ARGS (entry->fourcc));
11281 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
11283 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11284 goto error_encrypted;
11286 if (fourcc == FOURCC_aavd) {
11287 if (stream->subtype != FOURCC_soun) {
11288 GST_ERROR_OBJECT (qtdemux,
11289 "Unexpeced stsd type 'aavd' outside 'soun' track");
11291 /* encrypted audio with sound sample description v0 */
11292 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11293 stream->protected = TRUE;
11294 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11295 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11299 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11300 /* FIXME this looks wrong, there might be multiple children
11301 * with the same type */
11302 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11303 stream->protected = TRUE;
11304 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11305 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11308 if (stream->subtype == FOURCC_vide) {
11313 gint depth, palette_size, palette_count;
11314 guint32 *palette_data = NULL;
11316 entry->sampled = TRUE;
11318 stream->display_width = w >> 16;
11319 stream->display_height = h >> 16;
11322 if (len < 86) /* TODO verify */
11325 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11326 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11327 entry->fps_n = 0; /* this is filled in later */
11328 entry->fps_d = 0; /* this is filled in later */
11329 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11330 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11332 /* if color_table_id is 0, ctab atom must follow; however some files
11333 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11334 * if color table is not present we'll correct the value */
11335 if (entry->color_table_id == 0 &&
11337 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11338 entry->color_table_id = -1;
11341 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11342 entry->width, entry->height, entry->bits_per_sample,
11343 entry->color_table_id);
11345 depth = entry->bits_per_sample;
11347 /* more than 32 bits means grayscale */
11348 gray = (depth > 32);
11349 /* low 32 bits specify the depth */
11352 /* different number of palette entries is determined by depth. */
11354 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11355 palette_count = (1 << depth);
11356 palette_size = palette_count * 4;
11358 if (entry->color_table_id) {
11359 switch (palette_count) {
11363 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11366 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11371 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11373 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11378 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11381 g_memdup2 (ff_qt_default_palette_256, palette_size);
11384 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11385 (_("The video in this file might not play correctly.")),
11386 ("unsupported palette depth %d", depth));
11390 guint i, j, start, end;
11396 start = QT_UINT32 (stsd_entry_data + offset + 70);
11397 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11398 end = QT_UINT16 (stsd_entry_data + offset + 76);
11400 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11401 start, end, palette_count);
11408 if (len < 94 + (end - start) * 8)
11411 /* palette is always the same size */
11412 palette_data = g_malloc0 (256 * 4);
11413 palette_size = 256 * 4;
11415 for (j = 0, i = start; i <= end; j++, i++) {
11416 guint32 a, r, g, b;
11418 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11419 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11420 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11421 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11423 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11424 (g & 0xff00) | (b >> 8);
11429 gst_caps_unref (entry->caps);
11432 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11434 if (G_UNLIKELY (!entry->caps)) {
11435 g_free (palette_data);
11436 goto unknown_stream;
11440 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11441 GST_TAG_VIDEO_CODEC, codec, NULL);
11446 if (palette_data) {
11449 if (entry->rgb8_palette)
11450 gst_memory_unref (entry->rgb8_palette);
11451 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11452 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11454 s = gst_caps_get_structure (entry->caps, 0);
11456 /* non-raw video has a palette_data property. raw video has the palette as
11457 * an extra plane that we append to the output buffers before we push
11459 if (!gst_structure_has_name (s, "video/x-raw")) {
11460 GstBuffer *palette;
11462 palette = gst_buffer_new ();
11463 gst_buffer_append_memory (palette, entry->rgb8_palette);
11464 entry->rgb8_palette = NULL;
11466 gst_caps_set_simple (entry->caps, "palette_data",
11467 GST_TYPE_BUFFER, palette, NULL);
11468 gst_buffer_unref (palette);
11470 } else if (palette_count != 0) {
11471 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11472 (NULL), ("Unsupported palette depth %d", depth));
11475 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11476 QT_UINT16 (stsd_entry_data + offset + 32));
11482 /* pick 'the' stsd child */
11483 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11484 // We should skip parsing the stsd for non-protected streams if
11485 // the entry doesn't match the fourcc, since they don't change
11486 // format. However, for protected streams we can have partial
11487 // encryption, where parts of the stream are encrypted and parts
11488 // not. For both parts of such streams, we should ensure the
11489 // esds overrides are parsed for both from the stsd.
11490 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11491 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11493 else if (!stream->protected)
11498 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11499 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11500 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11501 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11505 const guint8 *pasp_data = (const guint8 *) pasp->data;
11506 guint len = QT_UINT32 (pasp_data);
11509 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11510 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11512 CUR_STREAM (stream)->par_w = 0;
11513 CUR_STREAM (stream)->par_h = 0;
11516 CUR_STREAM (stream)->par_w = 0;
11517 CUR_STREAM (stream)->par_h = 0;
11521 const guint8 *fiel_data = (const guint8 *) fiel->data;
11522 guint len = QT_UINT32 (fiel_data);
11525 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11526 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11531 const guint8 *colr_data = (const guint8 *) colr->data;
11532 guint len = QT_UINT32 (colr_data);
11534 if (len == 19 || len == 18) {
11535 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11537 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11538 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11539 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11540 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11541 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11543 CUR_STREAM (stream)->colorimetry.primaries =
11544 gst_video_color_primaries_from_iso (primaries);
11545 CUR_STREAM (stream)->colorimetry.transfer =
11546 gst_video_transfer_function_from_iso (transfer_function);
11547 CUR_STREAM (stream)->colorimetry.matrix =
11548 gst_video_color_matrix_from_iso (matrix);
11549 CUR_STREAM (stream)->colorimetry.range =
11550 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11551 GST_VIDEO_COLOR_RANGE_16_235;
11553 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11556 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11561 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11562 stream->stream_tags);
11569 guint len = QT_UINT32 (stsd_entry_data);
11570 len = len <= 0x56 ? 0 : len - 0x56;
11571 const guint8 *avc_data = stsd_entry_data + 0x56;
11574 while (len >= 0x8) {
11577 if (QT_UINT32 (avc_data) <= 0x8)
11579 else if (QT_UINT32 (avc_data) <= len)
11580 size = QT_UINT32 (avc_data) - 0x8;
11585 /* No real data, so break out */
11588 switch (QT_FOURCC (avc_data + 0x4)) {
11591 /* parse, if found */
11594 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11596 /* First 4 bytes are the length of the atom, the next 4 bytes
11597 * are the fourcc, the next 1 byte is the version, and the
11598 * subsequent bytes are profile_tier_level structure like data. */
11599 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11600 avc_data + 8 + 1, size - 1);
11601 buf = gst_buffer_new_and_alloc (size);
11602 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11603 gst_caps_set_simple (entry->caps,
11604 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11605 gst_buffer_unref (buf);
11613 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11615 /* First 4 bytes are the length of the atom, the next 4 bytes
11616 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11617 * next 1 byte is the version, and the
11618 * subsequent bytes are sequence parameter set like data. */
11620 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11622 gst_codec_utils_h264_caps_set_level_and_profile
11623 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11625 buf = gst_buffer_new_and_alloc (size);
11626 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11627 gst_caps_set_simple (entry->caps,
11628 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11629 gst_buffer_unref (buf);
11635 guint avg_bitrate, max_bitrate;
11637 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11641 max_bitrate = QT_UINT32 (avc_data + 0xc);
11642 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11644 if (!max_bitrate && !avg_bitrate)
11647 /* Some muxers seem to swap the average and maximum bitrates
11648 * (I'm looking at you, YouTube), so we swap for sanity. */
11649 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11650 guint temp = avg_bitrate;
11652 avg_bitrate = max_bitrate;
11653 max_bitrate = temp;
11656 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11657 gst_tag_list_add (stream->stream_tags,
11658 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11659 max_bitrate, NULL);
11661 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11662 gst_tag_list_add (stream->stream_tags,
11663 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11675 avc_data += size + 8;
11686 guint len = QT_UINT32 (stsd_entry_data);
11687 len = len <= 0x56 ? 0 : len - 0x56;
11688 const guint8 *hevc_data = stsd_entry_data + 0x56;
11691 while (len >= 0x8) {
11694 if (QT_UINT32 (hevc_data) <= 0x8)
11696 else if (QT_UINT32 (hevc_data) <= len)
11697 size = QT_UINT32 (hevc_data) - 0x8;
11702 /* No real data, so break out */
11705 switch (QT_FOURCC (hevc_data + 0x4)) {
11708 /* parse, if found */
11711 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11713 /* First 4 bytes are the length of the atom, the next 4 bytes
11714 * are the fourcc, the next 1 byte is the version, and the
11715 * subsequent bytes are sequence parameter set like data. */
11716 gst_codec_utils_h265_caps_set_level_tier_and_profile
11717 (entry->caps, hevc_data + 8 + 1, size - 1);
11719 buf = gst_buffer_new_and_alloc (size);
11720 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11721 gst_caps_set_simple (entry->caps,
11722 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11723 gst_buffer_unref (buf);
11730 hevc_data += size + 8;
11743 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11744 GST_FOURCC_ARGS (fourcc));
11746 /* codec data might be in glbl extension atom */
11748 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11754 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11756 len = QT_UINT32 (data);
11759 buf = gst_buffer_new_and_alloc (len);
11760 gst_buffer_fill (buf, 0, data + 8, len);
11761 gst_caps_set_simple (entry->caps,
11762 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11763 gst_buffer_unref (buf);
11770 /* see annex I of the jpeg2000 spec */
11771 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11772 const guint8 *data;
11773 const gchar *colorspace = NULL;
11775 guint32 ncomp_map = 0;
11776 gint32 *comp_map = NULL;
11777 guint32 nchan_def = 0;
11778 gint32 *chan_def = NULL;
11780 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11781 /* some required atoms */
11782 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11785 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11789 /* number of components; redundant with info in codestream, but useful
11791 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11792 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11794 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11796 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11799 GST_DEBUG_OBJECT (qtdemux, "found colr");
11800 /* extract colour space info */
11801 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11802 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11804 colorspace = "sRGB";
11807 colorspace = "GRAY";
11810 colorspace = "sYUV";
11818 /* colr is required, and only values 16, 17, and 18 are specified,
11819 so error if we have no colorspace */
11822 /* extract component mapping */
11823 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11825 guint32 cmap_len = 0;
11827 cmap_len = QT_UINT32 (cmap->data);
11828 if (cmap_len >= 8) {
11829 /* normal box, subtract off header */
11831 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11832 if (cmap_len % 4 == 0) {
11833 ncomp_map = (cmap_len / 4);
11834 comp_map = g_new0 (gint32, ncomp_map);
11835 for (i = 0; i < ncomp_map; i++) {
11838 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11839 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11840 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11841 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11846 /* extract channel definitions */
11847 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11849 guint32 cdef_len = 0;
11851 cdef_len = QT_UINT32 (cdef->data);
11852 if (cdef_len >= 10) {
11853 /* normal box, subtract off header and len */
11855 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11856 if (cdef_len % 6 == 0) {
11857 nchan_def = (cdef_len / 6);
11858 chan_def = g_new0 (gint32, nchan_def);
11859 for (i = 0; i < nchan_def; i++)
11861 for (i = 0; i < nchan_def; i++) {
11862 guint16 cn, typ, asoc;
11863 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11864 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11865 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11866 if (cn < nchan_def) {
11869 chan_def[cn] = asoc;
11872 chan_def[cn] = 0; /* alpha */
11875 chan_def[cn] = -typ;
11883 gst_caps_set_simple (entry->caps,
11884 "num-components", G_TYPE_INT, ncomp, NULL);
11885 gst_caps_set_simple (entry->caps,
11886 "colorspace", G_TYPE_STRING, colorspace, NULL);
11889 GValue arr = { 0, };
11890 GValue elt = { 0, };
11892 g_value_init (&arr, GST_TYPE_ARRAY);
11893 g_value_init (&elt, G_TYPE_INT);
11894 for (i = 0; i < ncomp_map; i++) {
11895 g_value_set_int (&elt, comp_map[i]);
11896 gst_value_array_append_value (&arr, &elt);
11898 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11899 "component-map", &arr);
11900 g_value_unset (&elt);
11901 g_value_unset (&arr);
11906 GValue arr = { 0, };
11907 GValue elt = { 0, };
11909 g_value_init (&arr, GST_TYPE_ARRAY);
11910 g_value_init (&elt, G_TYPE_INT);
11911 for (i = 0; i < nchan_def; i++) {
11912 g_value_set_int (&elt, chan_def[i]);
11913 gst_value_array_append_value (&arr, &elt);
11915 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11916 "channel-definitions", &arr);
11917 g_value_unset (&elt);
11918 g_value_unset (&arr);
11922 /* some optional atoms */
11923 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11924 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11926 /* indicate possible fields in caps */
11928 data = (guint8 *) field->data + 8;
11930 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11931 (gint) * data, NULL);
11933 /* add codec_data if provided */
11938 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11939 data = prefix->data;
11940 len = QT_UINT32 (data);
11943 buf = gst_buffer_new_and_alloc (len);
11944 gst_buffer_fill (buf, 0, data + 8, len);
11945 gst_caps_set_simple (entry->caps,
11946 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11947 gst_buffer_unref (buf);
11956 GstBuffer *seqh = NULL;
11957 const guint8 *gamma_data = NULL;
11958 guint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11960 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11963 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11964 QT_FP32 (gamma_data), NULL);
11967 /* sorry for the bad name, but we don't know what this is, other
11968 * than its own fourcc */
11969 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11971 gst_buffer_unref (seqh);
11974 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11975 buf = gst_buffer_new_and_alloc (len);
11976 gst_buffer_fill (buf, 0, stsd_data, len);
11977 gst_caps_set_simple (entry->caps,
11978 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11979 gst_buffer_unref (buf);
11984 /* https://developer.apple.com/standards/qtff-2001.pdf,
11985 * page 92, "Video Sample Description", under table 3.1 */
11988 const gint compressor_offset =
11989 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11990 const gint min_size = compressor_offset + 32 + 2 + 2;
11993 guint16 color_table_id = 0;
11996 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11998 /* recover information on interlaced/progressive */
11999 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
12003 len = QT_UINT32 (jpeg->data);
12004 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
12006 if (len >= min_size) {
12007 gst_byte_reader_init (&br, jpeg->data, len);
12009 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
12010 gst_byte_reader_get_uint16_le (&br, &color_table_id);
12011 if (color_table_id != 0) {
12012 /* the spec says there can be concatenated chunks in the data, and we want
12013 * to find one called field. Walk through them. */
12014 gint offset = min_size;
12015 while (offset + 8 < len) {
12016 guint32 size = 0, tag;
12017 ok = gst_byte_reader_get_uint32_le (&br, &size);
12018 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
12019 if (!ok || size < 8) {
12020 GST_WARNING_OBJECT (qtdemux,
12021 "Failed to walk optional chunk list");
12024 GST_DEBUG_OBJECT (qtdemux,
12025 "Found optional %4.4s chunk, size %u",
12026 (const char *) &tag, size);
12027 if (tag == FOURCC_fiel) {
12028 guint8 n_fields = 0, ordering = 0;
12029 gst_byte_reader_get_uint8 (&br, &n_fields);
12030 gst_byte_reader_get_uint8 (&br, &ordering);
12031 if (n_fields == 1 || n_fields == 2) {
12032 GST_DEBUG_OBJECT (qtdemux,
12033 "Found fiel tag with %u fields, ordering %u",
12034 n_fields, ordering);
12036 gst_caps_set_simple (CUR_STREAM (stream)->caps,
12037 "interlace-mode", G_TYPE_STRING, "interleaved",
12040 GST_WARNING_OBJECT (qtdemux,
12041 "Found fiel tag with invalid fields (%u)", n_fields);
12047 GST_DEBUG_OBJECT (qtdemux,
12048 "Color table ID is 0, not trying to get interlacedness");
12051 GST_WARNING_OBJECT (qtdemux,
12052 "Length of jpeg chunk is too small, not trying to get interlacedness");
12060 gst_caps_set_simple (entry->caps,
12061 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
12067 GNode *xith, *xdxt;
12069 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
12070 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12074 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
12078 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
12079 /* collect the headers and store them in a stream list so that we can
12080 * send them out first */
12081 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
12091 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
12092 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12095 ovc1_data = ovc1->data;
12096 ovc1_len = QT_UINT32 (ovc1_data);
12097 if (ovc1_len <= 198) {
12098 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
12101 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
12102 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
12103 gst_caps_set_simple (entry->caps,
12104 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12105 gst_buffer_unref (buf);
12110 guint len = QT_UINT32 (stsd_entry_data);
12111 len = len <= 0x56 ? 0 : len - 0x56;
12112 const guint8 *vc1_data = stsd_entry_data + 0x56;
12118 if (QT_UINT32 (vc1_data) <= 8)
12120 else if (QT_UINT32 (vc1_data) <= len)
12121 size = QT_UINT32 (vc1_data) - 8;
12126 /* No real data, so break out */
12129 switch (QT_FOURCC (vc1_data + 0x4)) {
12130 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
12134 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
12135 buf = gst_buffer_new_and_alloc (size);
12136 gst_buffer_fill (buf, 0, vc1_data + 8, size);
12137 gst_caps_set_simple (entry->caps,
12138 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12139 gst_buffer_unref (buf);
12146 vc1_data += size + 8;
12152 guint len = QT_UINT32 (stsd_entry_data);
12153 len = len <= 0x56 ? 0 : len - 0x56;
12154 const guint8 *av1_data = stsd_entry_data + 0x56;
12157 while (len >= 0x8) {
12160 if (QT_UINT32 (av1_data) <= 0x8)
12162 else if (QT_UINT32 (av1_data) <= len)
12163 size = QT_UINT32 (av1_data) - 0x8;
12168 /* No real data, so break out */
12171 switch (QT_FOURCC (av1_data + 0x4)) {
12174 /* parse, if found */
12176 guint8 pres_delay_field;
12178 GST_DEBUG_OBJECT (qtdemux,
12179 "found av1C codec_data in stsd of size %d", size);
12181 /* not enough data, just ignore and hope for the best */
12186 * 4 bytes: atom length
12191 * 1 bits: initial_presentation_delay_present
12192 * 4 bits: initial_presentation_delay (if present else reserved
12196 if (av1_data[9] != 0) {
12197 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
12201 /* We skip initial_presentation_delay* for now */
12202 pres_delay_field = *(av1_data + 12);
12203 if (pres_delay_field & (1 << 5)) {
12204 gst_caps_set_simple (entry->caps,
12205 "presentation-delay", G_TYPE_INT,
12206 (gint) (pres_delay_field & 0x0F) + 1, NULL);
12209 buf = gst_buffer_new_and_alloc (size - 5);
12210 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12211 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12212 gst_caps_set_simple (entry->caps,
12213 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12214 gst_buffer_unref (buf);
12223 av1_data += size + 8;
12229 /* TODO: Need to parse vpcC for VP8 codec too.
12230 * Note that VPCodecConfigurationBox (vpcC) is defined for
12231 * vp08, vp09, and vp10 fourcc. */
12234 guint len = QT_UINT32 (stsd_entry_data);
12235 len = len <= 0x56 ? 0 : len - 0x56;
12236 const guint8 *vpcc_data = stsd_entry_data + 0x56;
12239 while (len >= 0x8) {
12242 if (QT_UINT32 (vpcc_data) <= 0x8)
12244 else if (QT_UINT32 (vpcc_data) <= len)
12245 size = QT_UINT32 (vpcc_data) - 0x8;
12250 /* No real data, so break out */
12253 switch (QT_FOURCC (vpcc_data + 0x4)) {
12256 const gchar *profile_str = NULL;
12257 const gchar *chroma_format_str = NULL;
12260 guint8 chroma_format;
12261 GstVideoColorimetry cinfo;
12263 /* parse, if found */
12264 GST_DEBUG_OBJECT (qtdemux,
12265 "found vp codec_data in stsd of size %d", size);
12267 /* the meaning of "size" is length of the atom body, excluding
12268 * atom length and fourcc fields */
12273 * 4 bytes: atom length
12280 * 3 bits: chromaSubsampling
12281 * 1 bit: videoFullRangeFlag
12282 * 1 byte: colourPrimaries
12283 * 1 byte: transferCharacteristics
12284 * 1 byte: matrixCoefficients
12285 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
12286 * rest: codecIntializationData (not used for vp8 and vp9)
12289 if (vpcc_data[8] != 1) {
12290 GST_WARNING_OBJECT (qtdemux,
12291 "unknown vpcC version %d", vpcc_data[8]);
12295 profile = vpcc_data[12];
12314 gst_caps_set_simple (entry->caps,
12315 "profile", G_TYPE_STRING, profile_str, NULL);
12318 /* skip level, the VP9 spec v0.6 defines only one level atm,
12319 * but webm spec define various ones. Add level to caps
12320 * if we really need it then */
12322 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12323 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12324 gst_caps_set_simple (entry->caps,
12325 "bit-depth-luma", G_TYPE_UINT, bitdepth,
12326 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12329 chroma_format = (vpcc_data[14] & 0xe) >> 1;
12330 switch (chroma_format) {
12333 chroma_format_str = "4:2:0";
12336 chroma_format_str = "4:2:2";
12339 chroma_format_str = "4:4:4";
12345 if (chroma_format_str) {
12346 gst_caps_set_simple (entry->caps,
12347 "chroma-format", G_TYPE_STRING, chroma_format_str,
12351 if ((vpcc_data[14] & 0x1) != 0)
12352 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12354 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12356 gst_video_color_primaries_from_iso (vpcc_data[15]);
12358 gst_video_transfer_function_from_iso (vpcc_data[16]);
12360 gst_video_color_matrix_from_iso (vpcc_data[17]);
12362 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12363 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12364 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12365 /* set this only if all values are known, otherwise this
12366 * might overwrite valid ones parsed from other color box */
12367 CUR_STREAM (stream)->colorimetry = cinfo;
12376 vpcc_data += size + 8;
12386 GST_INFO_OBJECT (qtdemux,
12387 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12388 GST_FOURCC_ARGS (fourcc), entry->caps);
12390 } else if (stream->subtype == FOURCC_soun) {
12392 guint version, samplesize;
12393 guint16 compression_id;
12394 gboolean amrwb = FALSE;
12397 /* sample description entry (16) + sound sample description v0 (20) */
12401 version = QT_UINT32 (stsd_entry_data + offset);
12402 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12403 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12404 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12405 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12407 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12408 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12409 QT_UINT32 (stsd_entry_data + offset + 4));
12410 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12411 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12412 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12413 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12414 QT_UINT16 (stsd_entry_data + offset + 14));
12415 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12417 if (compression_id == 0xfffe)
12418 entry->sampled = TRUE;
12420 /* first assume uncompressed audio */
12421 entry->bytes_per_sample = samplesize / 8;
12422 entry->samples_per_frame = entry->n_channels;
12423 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12424 entry->samples_per_packet = entry->samples_per_frame;
12425 entry->bytes_per_packet = entry->bytes_per_sample;
12429 if (version == 0x00010000) {
12430 /* sample description entry (16) + sound sample description v1 (20+16) */
12434 /* take information from here over the normal sample description */
12435 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12436 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12437 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12438 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12440 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12441 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12442 entry->samples_per_packet);
12443 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12444 entry->bytes_per_packet);
12445 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12446 entry->bytes_per_frame);
12447 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12448 entry->bytes_per_sample);
12450 if (!entry->sampled && entry->bytes_per_packet) {
12451 entry->samples_per_frame = (entry->bytes_per_frame /
12452 entry->bytes_per_packet) * entry->samples_per_packet;
12453 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12454 entry->samples_per_frame);
12456 } else if (version == 0x00020000) {
12457 /* sample description entry (16) + sound sample description v2 (56) */
12461 /* take information from here over the normal sample description */
12462 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12463 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12464 entry->samples_per_frame = entry->n_channels;
12465 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12466 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12467 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12468 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12470 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12471 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12472 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12473 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12474 entry->bytes_per_sample * 8);
12475 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12476 QT_UINT32 (stsd_entry_data + offset + 24));
12477 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12478 entry->bytes_per_packet);
12479 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12480 entry->samples_per_packet);
12481 } else if (version != 0x00000) {
12482 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12487 /* Yes, these have to be hard-coded */
12490 entry->samples_per_packet = 6;
12491 entry->bytes_per_packet = 1;
12492 entry->bytes_per_frame = 1 * entry->n_channels;
12493 entry->bytes_per_sample = 1;
12494 entry->samples_per_frame = 6 * entry->n_channels;
12499 entry->samples_per_packet = 3;
12500 entry->bytes_per_packet = 1;
12501 entry->bytes_per_frame = 1 * entry->n_channels;
12502 entry->bytes_per_sample = 1;
12503 entry->samples_per_frame = 3 * entry->n_channels;
12508 entry->samples_per_packet = 64;
12509 entry->bytes_per_packet = 34;
12510 entry->bytes_per_frame = 34 * entry->n_channels;
12511 entry->bytes_per_sample = 2;
12512 entry->samples_per_frame = 64 * entry->n_channels;
12518 entry->samples_per_packet = 1;
12519 entry->bytes_per_packet = 1;
12520 entry->bytes_per_frame = 1 * entry->n_channels;
12521 entry->bytes_per_sample = 1;
12522 entry->samples_per_frame = 1 * entry->n_channels;
12527 entry->samples_per_packet = 160;
12528 entry->bytes_per_packet = 33;
12529 entry->bytes_per_frame = 33 * entry->n_channels;
12530 entry->bytes_per_sample = 2;
12531 entry->samples_per_frame = 160 * entry->n_channels;
12534 /* fix up any invalid header information from above */
12539 /* Sometimes these are set to 0 in the sound sample descriptions so
12540 * let's try to infer useful values from the other information we
12541 * have available */
12542 if (entry->bytes_per_sample == 0)
12543 entry->bytes_per_sample =
12544 entry->bytes_per_frame / entry->n_channels;
12545 if (entry->bytes_per_sample == 0)
12546 entry->bytes_per_sample = samplesize / 8;
12548 if (entry->bytes_per_frame == 0)
12549 entry->bytes_per_frame =
12550 entry->bytes_per_sample * entry->n_channels;
12552 if (entry->bytes_per_packet == 0)
12553 entry->bytes_per_packet = entry->bytes_per_sample;
12555 if (entry->samples_per_frame == 0)
12556 entry->samples_per_frame = entry->n_channels;
12558 if (entry->samples_per_packet == 0)
12559 entry->samples_per_packet = entry->samples_per_frame;
12569 entry->bytes_per_sample = 3;
12573 entry->bytes_per_sample = 4;
12576 entry->bytes_per_sample = 8;
12579 entry->bytes_per_sample = 2;
12582 g_assert_not_reached ();
12585 entry->samples_per_frame = entry->n_channels;
12586 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12587 entry->samples_per_packet = entry->samples_per_frame;
12588 entry->bytes_per_packet = entry->bytes_per_sample;
12596 gst_caps_unref (entry->caps);
12598 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12599 stsd_entry_data + 32, len - 16, &codec);
12610 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12612 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12614 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12616 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12619 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12620 const gchar *format_str;
12624 format_str = (enda_value) ? "S24LE" : "S24BE";
12627 format_str = (enda_value) ? "S32LE" : "S32BE";
12630 format_str = (enda_value) ? "F32LE" : "F32BE";
12633 format_str = (enda_value) ? "F64LE" : "F64BE";
12636 g_assert_not_reached ();
12639 gst_caps_set_simple (entry->caps,
12640 "format", G_TYPE_STRING, format_str, NULL);
12646 const guint8 *owma_data;
12647 const gchar *codec_name = NULL;
12651 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12652 /* FIXME this should also be gst_riff_strf_auds,
12653 * but the latter one is actually missing bits-per-sample :( */
12658 gint32 nSamplesPerSec;
12659 gint32 nAvgBytesPerSec;
12660 gint16 nBlockAlign;
12661 gint16 wBitsPerSample;
12664 WAVEFORMATEX *wfex;
12666 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12667 owma_data = stsd_entry_data;
12668 owma_len = QT_UINT32 (owma_data);
12669 if (owma_len <= 54) {
12670 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12673 wfex = (WAVEFORMATEX *) (owma_data + 36);
12674 buf = gst_buffer_new_and_alloc (owma_len - 54);
12675 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12676 if (wfex->wFormatTag == 0x0161) {
12677 codec_name = "Windows Media Audio";
12679 } else if (wfex->wFormatTag == 0x0162) {
12680 codec_name = "Windows Media Audio 9 Pro";
12682 } else if (wfex->wFormatTag == 0x0163) {
12683 codec_name = "Windows Media Audio 9 Lossless";
12684 /* is that correct? gstffmpegcodecmap.c is missing it, but
12685 * fluendo codec seems to support it */
12689 gst_caps_set_simple (entry->caps,
12690 "codec_data", GST_TYPE_BUFFER, buf,
12691 "wmaversion", G_TYPE_INT, version,
12692 "block_align", G_TYPE_INT,
12693 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12694 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12695 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12696 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12697 gst_buffer_unref (buf);
12701 codec = g_strdup (codec_name);
12707 guint len = QT_UINT32 (stsd_entry_data);
12708 len = len <= offset ? 0 : len - offset;
12709 const guint8 *wfex_data = stsd_entry_data + offset;
12710 const gchar *codec_name = NULL;
12712 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12713 /* FIXME this should also be gst_riff_strf_auds,
12714 * but the latter one is actually missing bits-per-sample :( */
12719 gint32 nSamplesPerSec;
12720 gint32 nAvgBytesPerSec;
12721 gint16 nBlockAlign;
12722 gint16 wBitsPerSample;
12727 /* FIXME: unify with similar wavformatex parsing code above */
12728 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12734 if (QT_UINT32 (wfex_data) <= 0x8)
12736 else if (QT_UINT32 (wfex_data) <= len)
12737 size = QT_UINT32 (wfex_data) - 8;
12742 /* No real data, so break out */
12745 switch (QT_FOURCC (wfex_data + 4)) {
12746 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12748 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12753 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12754 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12755 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12756 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12757 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12758 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12759 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12761 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12762 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12763 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12764 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12765 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12766 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12768 if (wfex.wFormatTag == 0x0161) {
12769 codec_name = "Windows Media Audio";
12771 } else if (wfex.wFormatTag == 0x0162) {
12772 codec_name = "Windows Media Audio 9 Pro";
12774 } else if (wfex.wFormatTag == 0x0163) {
12775 codec_name = "Windows Media Audio 9 Lossless";
12776 /* is that correct? gstffmpegcodecmap.c is missing it, but
12777 * fluendo codec seems to support it */
12781 gst_caps_set_simple (entry->caps,
12782 "wmaversion", G_TYPE_INT, version,
12783 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12784 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12785 "width", G_TYPE_INT, wfex.wBitsPerSample,
12786 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12788 if (size > wfex.cbSize) {
12791 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12792 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12793 size - wfex.cbSize);
12794 gst_caps_set_simple (entry->caps,
12795 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12796 gst_buffer_unref (buf);
12798 GST_WARNING_OBJECT (qtdemux, "no codec data");
12803 codec = g_strdup (codec_name);
12811 wfex_data += size + 8;
12817 const guint8 *dops_data;
12818 guint8 *channel_mapping = NULL;
12821 guint8 channel_mapping_family;
12822 guint8 stream_count;
12823 guint8 coupled_count;
12826 version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12828 dops_data = stsd_entry_data + 51;
12830 dops_data = stsd_entry_data + 35;
12832 channels = GST_READ_UINT8 (dops_data + 10);
12833 rate = GST_READ_UINT32_LE (dops_data + 13);
12834 channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12835 stream_count = GST_READ_UINT8 (dops_data + 20);
12836 coupled_count = GST_READ_UINT8 (dops_data + 21);
12838 if (channels > 0) {
12839 channel_mapping = g_malloc (channels * sizeof (guint8));
12840 for (i = 0; i < channels; i++)
12841 channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12844 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12845 channel_mapping_family, stream_count, coupled_count,
12847 g_free (channel_mapping);
12858 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12859 GST_TAG_AUDIO_CODEC, codec, NULL);
12863 /* some bitrate info may have ended up in caps */
12864 s = gst_caps_get_structure (entry->caps, 0);
12865 gst_structure_get_int (s, "bitrate", &bitrate);
12867 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12868 GST_TAG_BITRATE, bitrate, NULL);
12872 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12873 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12874 if (stream->protected) {
12875 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12876 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12878 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12888 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12890 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12892 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12896 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12897 16 bits is a byte-swapped wave-style codec identifier,
12898 and we can find a WAVE header internally to a 'wave' atom here.
12899 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12900 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12903 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12904 if (len < offset + 20) {
12905 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12907 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12908 const guint8 *data = stsd_entry_data + offset + 16;
12910 GNode *waveheadernode;
12912 wavenode = g_node_new ((guint8 *) data);
12913 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12914 const guint8 *waveheader;
12917 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12918 if (waveheadernode) {
12919 waveheader = (const guint8 *) waveheadernode->data;
12920 headerlen = QT_UINT32 (waveheader);
12922 if (headerlen > 8) {
12923 gst_riff_strf_auds *header = NULL;
12924 GstBuffer *headerbuf;
12930 headerbuf = gst_buffer_new_and_alloc (headerlen);
12931 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12933 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12934 headerbuf, &header, &extra)) {
12935 gst_caps_unref (entry->caps);
12936 /* FIXME: Need to do something with the channel reorder map */
12938 gst_riff_create_audio_caps (header->format, NULL, header,
12939 extra, NULL, NULL, NULL);
12942 gst_buffer_unref (extra);
12947 GST_DEBUG ("Didn't find waveheadernode for this codec");
12949 g_node_destroy (wavenode);
12952 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12953 stream->stream_tags);
12957 /* FIXME: what is in the chunk? */
12960 gint len = QT_UINT32 (stsd_data);
12962 /* seems to be always = 116 = 0x74 */
12968 gint len = QT_UINT32 (stsd_entry_data);
12971 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12973 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12974 gst_caps_set_simple (entry->caps,
12975 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12976 gst_buffer_unref (buf);
12978 gst_caps_set_simple (entry->caps,
12979 "samplesize", G_TYPE_INT, samplesize, NULL);
12984 GNode *alac, *wave = NULL;
12986 /* apparently, m4a has this atom appended directly in the stsd entry,
12987 * while mov has it in a wave atom */
12988 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12990 /* alac now refers to stsd entry atom */
12991 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12993 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12995 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12998 const guint8 *alac_data = alac->data;
12999 gint len = QT_UINT32 (alac->data);
13003 GST_DEBUG_OBJECT (qtdemux,
13004 "discarding alac atom with unexpected len %d", len);
13006 /* codec-data contains alac atom size and prefix,
13007 * ffmpeg likes it that way, not quite gst-ish though ...*/
13008 buf = gst_buffer_new_and_alloc (len);
13009 gst_buffer_fill (buf, 0, alac->data, len);
13010 gst_caps_set_simple (entry->caps,
13011 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13012 gst_buffer_unref (buf);
13014 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
13015 entry->n_channels = QT_UINT8 (alac_data + 21);
13016 entry->rate = QT_UINT32 (alac_data + 32);
13017 samplesize = QT_UINT8 (alac_data + 16 + 1);
13020 gst_caps_set_simple (entry->caps,
13021 "samplesize", G_TYPE_INT, samplesize, NULL);
13026 /* The codingname of the sample entry is 'fLaC' */
13027 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
13030 /* The 'dfLa' box is added to the sample entry to convey
13031 initializing information for the decoder. */
13032 const GNode *dfla =
13033 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
13036 const guint32 len = QT_UINT32 (dfla->data);
13038 /* Must contain at least dfLa box header (12),
13039 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
13041 GST_DEBUG_OBJECT (qtdemux,
13042 "discarding dfla atom with unexpected len %d", len);
13044 /* skip dfLa header to get the METADATA_BLOCKs */
13045 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
13046 const guint32 metadata_blocks_len = len - 12;
13048 gchar *stream_marker = g_strdup ("fLaC");
13049 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
13050 strlen (stream_marker));
13053 guint32 remainder = 0;
13054 guint32 block_size = 0;
13055 gboolean is_last = FALSE;
13057 GValue array = G_VALUE_INIT;
13058 GValue value = G_VALUE_INIT;
13060 g_value_init (&array, GST_TYPE_ARRAY);
13061 g_value_init (&value, GST_TYPE_BUFFER);
13063 gst_value_set_buffer (&value, block);
13064 gst_value_array_append_value (&array, &value);
13065 g_value_reset (&value);
13067 gst_buffer_unref (block);
13069 /* check there's at least one METADATA_BLOCK_HEADER's worth
13070 * of data, and we haven't already finished parsing */
13071 while (!is_last && ((index + 3) < metadata_blocks_len)) {
13072 remainder = metadata_blocks_len - index;
13074 /* add the METADATA_BLOCK_HEADER size to the signalled size */
13076 (metadata_blocks[index + 1] << 16) +
13077 (metadata_blocks[index + 2] << 8) +
13078 metadata_blocks[index + 3];
13080 /* be careful not to read off end of box */
13081 if (block_size > remainder) {
13085 is_last = metadata_blocks[index] >> 7;
13087 block = gst_buffer_new_and_alloc (block_size);
13089 gst_buffer_fill (block, 0, &metadata_blocks[index],
13092 gst_value_set_buffer (&value, block);
13093 gst_value_array_append_value (&array, &value);
13094 g_value_reset (&value);
13096 gst_buffer_unref (block);
13098 index += block_size;
13101 /* only append the metadata if we successfully read all of it */
13103 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
13104 (stream)->caps, 0), "streamheader", &array);
13106 GST_WARNING_OBJECT (qtdemux,
13107 "discarding all METADATA_BLOCKs due to invalid "
13108 "block_size %d at idx %d, rem %d", block_size, index,
13112 g_value_unset (&value);
13113 g_value_unset (&array);
13115 /* The sample rate obtained from the stsd may not be accurate
13116 * since it cannot represent rates greater than 65535Hz, so
13117 * override that value with the sample rate from the
13118 * METADATA_BLOCK_STREAMINFO block */
13119 CUR_STREAM (stream)->rate =
13120 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
13131 gint len = QT_UINT32 (stsd_entry_data);
13134 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
13137 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
13139 /* If we have enough data, let's try to get the 'damr' atom. See
13140 * the 3GPP container spec (26.244) for more details. */
13141 if ((len - 0x34) > 8 &&
13142 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
13143 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13144 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
13147 gst_caps_set_simple (entry->caps,
13148 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13149 gst_buffer_unref (buf);
13155 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
13156 gint len = QT_UINT32 (stsd_entry_data);
13157 guint16 sound_version = 0;
13158 /* FIXME: Can this be determined somehow? There doesn't seem to be
13159 * anything in mp4a atom that specifis compression */
13161 guint16 channels = entry->n_channels;
13162 guint32 time_scale = (guint32) entry->rate;
13163 gint sample_rate_index = -1;
13166 sound_version = QT_UINT16 (stsd_entry_data + 16);
13168 if (sound_version == 1) {
13169 channels = QT_UINT16 (stsd_entry_data + 24);
13170 time_scale = QT_UINT32 (stsd_entry_data + 30);
13172 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
13176 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
13180 sample_rate_index =
13181 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
13182 if (sample_rate_index >= 0 && channels > 0) {
13183 guint8 codec_data[2];
13186 /* build AAC codec data */
13187 codec_data[0] = profile << 3;
13188 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
13189 codec_data[1] = (sample_rate_index & 0x01) << 7;
13190 codec_data[1] |= (channels & 0xF) << 3;
13192 buf = gst_buffer_new_and_alloc (2);
13193 gst_buffer_fill (buf, 0, codec_data, 2);
13194 gst_caps_set_simple (entry->caps,
13195 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13196 gst_buffer_unref (buf);
13206 /* Fully handled elsewhere */
13209 GST_INFO_OBJECT (qtdemux,
13210 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13214 GST_INFO_OBJECT (qtdemux,
13215 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13216 GST_FOURCC_ARGS (fourcc), entry->caps);
13218 } else if (stream->subtype == FOURCC_strm) {
13219 if (fourcc == FOURCC_rtsp) {
13220 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
13222 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
13223 GST_FOURCC_ARGS (fourcc));
13224 goto unknown_stream;
13226 entry->sampled = TRUE;
13227 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
13228 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
13229 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
13231 entry->sampled = TRUE;
13232 entry->sparse = TRUE;
13235 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13238 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13239 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13244 /* hunt for sort-of codec data */
13248 GNode *mp4s = NULL;
13249 GNode *esds = NULL;
13251 /* look for palette in a stsd->mp4s->esds sub-atom */
13252 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
13254 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
13255 if (esds == NULL) {
13257 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13261 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13262 stream->stream_tags);
13266 GST_INFO_OBJECT (qtdemux,
13267 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13270 GST_INFO_OBJECT (qtdemux,
13271 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13272 GST_FOURCC_ARGS (fourcc), entry->caps);
13273 } else if (stream->subtype == FOURCC_meta) {
13274 entry->sampled = TRUE;
13275 entry->sparse = TRUE;
13278 qtdemux_meta_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13281 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13282 GST_TAG_CODEC, codec, NULL);
13287 GST_INFO_OBJECT (qtdemux,
13288 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13289 GST_FOURCC_ARGS (fourcc), entry->caps);
13291 /* everything in 1 sample */
13292 entry->sampled = TRUE;
13295 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13298 if (entry->caps == NULL)
13299 goto unknown_stream;
13302 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13303 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13309 /* promote to sampled format */
13310 if (entry->fourcc == FOURCC_samr) {
13311 /* force mono 8000 Hz for AMR */
13312 entry->sampled = TRUE;
13313 entry->n_channels = 1;
13314 entry->rate = 8000;
13315 } else if (entry->fourcc == FOURCC_sawb) {
13316 /* force mono 16000 Hz for AMR-WB */
13317 entry->sampled = TRUE;
13318 entry->n_channels = 1;
13319 entry->rate = 16000;
13320 } else if (entry->fourcc == FOURCC_mp4a) {
13321 entry->sampled = TRUE;
13325 stsd_entry_data += len;
13326 remaining_stsd_len -= len;
13330 /* collect sample information */
13331 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13332 goto samples_failed;
13334 if (qtdemux->fragmented) {
13337 /* need all moov samples as basis; probably not many if any at all */
13338 /* prevent moof parsing taking of at this time */
13339 offset = qtdemux->moof_offset;
13340 qtdemux->moof_offset = 0;
13341 if (stream->n_samples &&
13342 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13343 qtdemux->moof_offset = offset;
13344 goto samples_failed;
13346 qtdemux->moof_offset = offset;
13347 /* movie duration more reliable in this case (e.g. mehd) */
13348 if (qtdemux->segment.duration &&
13349 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13351 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13354 /* configure segments */
13355 if (!qtdemux_parse_segments (qtdemux, stream, trak))
13356 goto segments_failed;
13358 /* add some language tag, if useful */
13359 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13360 strcmp (stream->lang_id, "und")) {
13361 const gchar *lang_code;
13363 /* convert ISO 639-2 code to ISO 639-1 */
13364 lang_code = gst_tag_get_language_code (stream->lang_id);
13365 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13366 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13369 /* Check for UDTA tags */
13370 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13371 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13374 /* Insert and sort new stream in track-id order.
13375 * This will help in comparing old/new streams during stream update check */
13376 g_ptr_array_add (qtdemux->active_streams, stream);
13377 g_ptr_array_sort (qtdemux->active_streams,
13378 (GCompareFunc) qtdemux_track_id_compare_func);
13379 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13380 QTDEMUX_N_STREAMS (qtdemux));
13387 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13388 (_("This file is corrupt and cannot be played.")), (NULL));
13390 gst_qtdemux_stream_unref (stream);
13395 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13396 gst_qtdemux_stream_unref (stream);
13402 /* we posted an error already */
13403 /* free stbl sub-atoms */
13404 gst_qtdemux_stbl_free (stream);
13405 gst_qtdemux_stream_unref (stream);
13410 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13416 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13417 GST_FOURCC_ARGS (stream->subtype));
13418 gst_qtdemux_stream_unref (stream);
13423 /* If we can estimate the overall bitrate, and don't have information about the
13424 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13425 * the overall bitrate minus the sum of the bitrates of all other streams. This
13426 * should be useful for the common case where we have one audio and one video
13427 * stream and can estimate the bitrate of one, but not the other. */
13429 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13431 QtDemuxStream *stream = NULL;
13432 gint64 size, sys_bitrate, sum_bitrate = 0;
13433 GstClockTime duration;
13437 if (qtdemux->fragmented)
13440 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13442 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13444 GST_DEBUG_OBJECT (qtdemux,
13445 "Size in bytes of the stream not known - bailing");
13449 /* Subtract the header size */
13450 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13451 size, qtdemux->header_size);
13453 if (size < qtdemux->header_size)
13456 size = size - qtdemux->header_size;
13458 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13459 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13463 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13464 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13465 switch (str->subtype) {
13468 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13469 CUR_STREAM (str)->caps);
13470 /* retrieve bitrate, prefer avg then max */
13472 if (str->stream_tags) {
13473 if (gst_tag_list_get_uint (str->stream_tags,
13474 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13475 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13476 if (gst_tag_list_get_uint (str->stream_tags,
13477 GST_TAG_NOMINAL_BITRATE, &bitrate))
13478 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13479 if (gst_tag_list_get_uint (str->stream_tags,
13480 GST_TAG_BITRATE, &bitrate))
13481 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13484 sum_bitrate += bitrate;
13487 GST_DEBUG_OBJECT (qtdemux,
13488 ">1 stream with unknown bitrate - bailing");
13495 /* For other subtypes, we assume no significant impact on bitrate */
13501 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13505 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13507 if (sys_bitrate < sum_bitrate) {
13508 /* This can happen, since sum_bitrate might be derived from maximum
13509 * bitrates and not average bitrates */
13510 GST_DEBUG_OBJECT (qtdemux,
13511 "System bitrate less than sum bitrate - bailing");
13515 bitrate = sys_bitrate - sum_bitrate;
13516 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13517 ", Stream bitrate = %u", sys_bitrate, bitrate);
13519 if (!stream->stream_tags)
13520 stream->stream_tags = gst_tag_list_new_empty ();
13522 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13524 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13525 GST_TAG_BITRATE, bitrate, NULL);
13528 static GstFlowReturn
13529 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13531 GstFlowReturn ret = GST_FLOW_OK;
13534 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13536 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13537 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13538 guint32 sample_num = 0;
13540 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13541 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13543 if (qtdemux->fragmented && qtdemux->pullbased) {
13544 /* need all moov samples first */
13545 GST_OBJECT_LOCK (qtdemux);
13546 while (stream->n_samples == 0)
13547 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13549 GST_OBJECT_UNLOCK (qtdemux);
13551 /* discard any stray moof */
13552 qtdemux->moof_offset = 0;
13555 /* prepare braking */
13556 if (ret != GST_FLOW_ERROR)
13559 /* in pull mode, we should have parsed some sample info by now;
13560 * and quite some code will not handle no samples.
13561 * in push mode, we'll just have to deal with it */
13562 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13563 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13564 g_ptr_array_remove_index (qtdemux->active_streams, i);
13567 } else if (stream->track_id == qtdemux->chapters_track_id &&
13568 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13569 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13570 so that it doesn't look like a subtitle track */
13571 g_ptr_array_remove_index (qtdemux->active_streams, i);
13576 /* parse the initial sample for use in setting the frame rate cap */
13577 while (sample_num == 0 && sample_num < stream->n_samples) {
13578 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13588 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13590 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13594 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13598 /* Different length, updated */
13599 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13602 /* streams in list are sorted in track-id order */
13603 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13604 /* Different stream-id, updated */
13605 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13606 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13614 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13615 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13617 /* Connect old stream's srcpad to new stream */
13618 newstream->pad = oldstream->pad;
13619 oldstream->pad = NULL;
13621 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13622 * case we need to force one through */
13623 newstream->new_stream = newstream->pad != NULL
13624 && GST_PAD_IS_EOS (newstream->pad);
13626 return gst_qtdemux_configure_stream (qtdemux, newstream);
13630 qtdemux_update_streams (GstQTDemux * qtdemux)
13633 g_assert (qtdemux->streams_aware);
13635 /* At below, figure out which stream in active_streams has identical stream-id
13636 * with that of in old_streams. If there is matching stream-id,
13637 * corresponding newstream will not be exposed again,
13638 * but demux will reuse srcpad of matched old stream
13640 * active_streams : newly created streams from the latest moov
13641 * old_streams : existing streams (belong to previous moov)
13644 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13645 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13646 QtDemuxStream *oldstream = NULL;
13649 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13650 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13652 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13653 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13654 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13656 /* null pad stream cannot be reused */
13657 if (oldstream->pad == NULL)
13662 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13664 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13667 /* we don't need to preserve order of old streams */
13668 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13672 /* now we have all info and can expose */
13673 list = stream->stream_tags;
13674 stream->stream_tags = NULL;
13675 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13683 /* Must be called with expose lock */
13684 static GstFlowReturn
13685 qtdemux_expose_streams (GstQTDemux * qtdemux)
13689 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13691 if (!qtdemux_is_streams_update (qtdemux)) {
13692 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13693 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13694 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13695 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13696 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13697 return GST_FLOW_ERROR;
13700 g_ptr_array_set_size (qtdemux->old_streams, 0);
13701 qtdemux->need_segment = TRUE;
13703 return GST_FLOW_OK;
13706 if (qtdemux->streams_aware) {
13707 if (!qtdemux_update_streams (qtdemux))
13708 return GST_FLOW_ERROR;
13710 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13711 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13714 /* now we have all info and can expose */
13715 list = stream->stream_tags;
13716 stream->stream_tags = NULL;
13717 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13718 return GST_FLOW_ERROR;
13723 gst_qtdemux_guess_bitrate (qtdemux);
13725 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13727 /* If we have still old_streams, it's no more used stream */
13728 for (i = 0; i < qtdemux->old_streams->len; i++) {
13729 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13734 event = gst_event_new_eos ();
13735 if (qtdemux->segment_seqnum)
13736 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13738 gst_pad_push_event (stream->pad, event);
13742 g_ptr_array_set_size (qtdemux->old_streams, 0);
13744 /* check if we should post a redirect in case there is a single trak
13745 * and it is a redirecting trak */
13746 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13747 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13750 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13751 "an external content");
13752 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13753 gst_structure_new ("redirect",
13754 "new-location", G_TYPE_STRING,
13755 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13756 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13757 g_free (qtdemux->redirect_location);
13758 qtdemux->redirect_location =
13759 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13762 g_ptr_array_foreach (qtdemux->active_streams,
13763 (GFunc) qtdemux_do_allocation, qtdemux);
13765 qtdemux->need_segment = TRUE;
13767 qtdemux->exposed = TRUE;
13768 return GST_FLOW_OK;
13773 GstStructure *structure; /* helper for sort function */
13775 guint min_req_bitrate;
13776 guint min_req_qt_version;
13780 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13782 GstQtReference *ref_a = (GstQtReference *) a;
13783 GstQtReference *ref_b = (GstQtReference *) b;
13785 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13786 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13788 /* known bitrates go before unknown; higher bitrates go first */
13789 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13792 /* sort the redirects and post a message for the application.
13795 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13797 GstQtReference *best;
13800 GValue list_val = { 0, };
13803 g_assert (references != NULL);
13805 references = g_list_sort (references, qtdemux_redirects_sort_func);
13807 best = (GstQtReference *) references->data;
13809 g_value_init (&list_val, GST_TYPE_LIST);
13811 for (l = references; l != NULL; l = l->next) {
13812 GstQtReference *ref = (GstQtReference *) l->data;
13813 GValue struct_val = { 0, };
13815 ref->structure = gst_structure_new ("redirect",
13816 "new-location", G_TYPE_STRING, ref->location, NULL);
13818 if (ref->min_req_bitrate > 0) {
13819 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13820 ref->min_req_bitrate, NULL);
13823 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13824 g_value_set_boxed (&struct_val, ref->structure);
13825 gst_value_list_append_value (&list_val, &struct_val);
13826 g_value_unset (&struct_val);
13827 /* don't free anything here yet, since we need best->structure below */
13830 g_assert (best != NULL);
13831 s = gst_structure_copy (best->structure);
13833 if (g_list_length (references) > 1) {
13834 gst_structure_set_value (s, "locations", &list_val);
13837 g_value_unset (&list_val);
13839 for (l = references; l != NULL; l = l->next) {
13840 GstQtReference *ref = (GstQtReference *) l->data;
13842 gst_structure_free (ref->structure);
13843 g_free (ref->location);
13846 g_list_free (references);
13848 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13849 g_free (qtdemux->redirect_location);
13850 qtdemux->redirect_location =
13851 g_strdup (gst_structure_get_string (s, "new-location"));
13852 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13853 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13856 /* look for redirect nodes, collect all redirect information and
13860 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13862 GNode *rmra, *rmda, *rdrf;
13864 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13866 GList *redirects = NULL;
13868 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13870 GstQtReference ref = { NULL, NULL, 0, 0 };
13871 GNode *rmdr, *rmvc;
13873 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13874 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13875 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13876 ref.min_req_bitrate);
13879 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13880 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13881 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13883 #ifndef GST_DISABLE_GST_DEBUG
13884 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13886 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13888 GST_LOG_OBJECT (qtdemux,
13889 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13890 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13891 bitmask, check_type);
13892 if (package == FOURCC_qtim && check_type == 0) {
13893 ref.min_req_qt_version = version;
13897 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13903 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13904 if (ref_len > 20) {
13905 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13906 ref_data = (guint8 *) rdrf->data + 20;
13907 if (ref_type == FOURCC_alis) {
13908 guint record_len, record_version, fn_len;
13910 if (ref_len > 70) {
13911 /* MacOSX alias record, google for alias-layout.txt */
13912 record_len = QT_UINT16 (ref_data + 4);
13913 record_version = QT_UINT16 (ref_data + 4 + 2);
13914 fn_len = QT_UINT8 (ref_data + 50);
13915 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13916 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13919 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13922 } else if (ref_type == FOURCC_url_) {
13923 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13925 GST_DEBUG_OBJECT (qtdemux,
13926 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13927 GST_FOURCC_ARGS (ref_type));
13929 if (ref.location != NULL) {
13930 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13932 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13934 GST_WARNING_OBJECT (qtdemux,
13935 "Failed to extract redirect location from rdrf atom");
13938 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13942 /* look for others */
13943 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13946 if (redirects != NULL) {
13947 qtdemux_process_redirects (qtdemux, redirects);
13953 static GstTagList *
13954 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13958 if (tags == NULL) {
13959 tags = gst_tag_list_new_empty ();
13960 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13963 if (qtdemux->major_brand == FOURCC_mjp2)
13964 fmt = "Motion JPEG 2000";
13965 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13967 else if (qtdemux->major_brand == FOURCC_qt__)
13969 else if (qtdemux->fragmented)
13972 fmt = "ISO MP4/M4A";
13974 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13975 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13977 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13983 /* we have read the complete moov node now.
13984 * This function parses all of the relevant info, creates the traks and
13985 * prepares all data structures for playback
13988 qtdemux_parse_tree (GstQTDemux * qtdemux)
13995 guint64 creation_time;
13996 GstDateTime *datetime = NULL;
13999 /* make sure we have a usable taglist */
14000 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14002 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
14003 if (mvhd == NULL) {
14004 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
14005 return qtdemux_parse_redirects (qtdemux);
14008 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
14009 if (version == 1) {
14010 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
14011 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
14012 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
14013 } else if (version == 0) {
14014 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
14015 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
14016 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
14018 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
14022 /* Moving qt creation time (secs since 1904) to unix time */
14023 if (creation_time != 0) {
14024 /* Try to use epoch first as it should be faster and more commonly found */
14025 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
14028 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
14029 /* some data cleansing sanity */
14030 now_s = g_get_real_time () / G_USEC_PER_SEC;
14031 if (now_s + 24 * 3600 < creation_time) {
14032 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
14034 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
14037 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
14038 GDateTime *dt, *dt_local;
14040 dt = g_date_time_add_seconds (base_dt, creation_time);
14041 dt_local = g_date_time_to_local (dt);
14042 datetime = gst_date_time_new_from_g_date_time (dt_local);
14044 g_date_time_unref (base_dt);
14045 g_date_time_unref (dt);
14049 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
14050 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
14052 gst_date_time_unref (datetime);
14055 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
14056 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
14058 /* check for fragmented file and get some (default) data */
14059 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
14062 GstByteReader mehd_data;
14064 /* let track parsing or anyone know weird stuff might happen ... */
14065 qtdemux->fragmented = TRUE;
14067 /* compensate for total duration */
14068 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
14070 qtdemux_parse_mehd (qtdemux, &mehd_data);
14073 /* Update the movie segment duration, unless it was directly given to us
14074 * by upstream. Otherwise let it as is, as we don't want to mangle the
14075 * duration provided by upstream that may come e.g. from a MPD file. */
14076 if (!qtdemux->upstream_format_is_time) {
14077 GstClockTime duration;
14078 /* set duration in the segment info */
14079 gst_qtdemux_get_duration (qtdemux, &duration);
14080 qtdemux->segment.duration = duration;
14081 /* also do not exceed duration; stop is set that way post seek anyway,
14082 * and segment activation falls back to duration,
14083 * whereas loop only checks stop, so let's align this here as well */
14084 qtdemux->segment.stop = duration;
14087 /* parse all traks */
14088 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
14090 qtdemux_parse_trak (qtdemux, trak);
14091 /* iterate all siblings */
14092 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
14095 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14098 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
14100 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14102 GST_LOG_OBJECT (qtdemux, "No udta node found.");
14105 /* maybe also some tags in meta box */
14106 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
14108 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
14109 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14111 GST_LOG_OBJECT (qtdemux, "No meta node found.");
14114 /* parse any protection system info */
14115 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
14117 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
14118 qtdemux_parse_pssh (qtdemux, pssh);
14119 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
14122 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
14127 /* taken from ffmpeg */
14129 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14141 len = (len << 7) | (c & 0x7f);
14150 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14151 gsize codec_data_size)
14153 GList *list = NULL;
14154 guint8 *p = codec_data;
14155 gint i, offset, num_packets;
14156 guint *length, last;
14158 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14160 if (codec_data == NULL || codec_data_size == 0)
14163 /* start of the stream and vorbis audio or theora video, need to
14164 * send the codec_priv data as first three packets */
14165 num_packets = p[0] + 1;
14166 GST_DEBUG_OBJECT (qtdemux,
14167 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14168 (guint) num_packets, codec_data_size);
14170 /* Let's put some limits, Don't think there even is a xiph codec
14171 * with more than 3-4 headers */
14172 if (G_UNLIKELY (num_packets > 16)) {
14173 GST_WARNING_OBJECT (qtdemux,
14174 "Unlikely number of xiph headers, most likely not valid");
14178 length = g_alloca (num_packets * sizeof (guint));
14182 /* first packets, read length values */
14183 for (i = 0; i < num_packets - 1; i++) {
14185 while (offset < codec_data_size) {
14186 length[i] += p[offset];
14187 if (p[offset++] != 0xff)
14192 if (offset + last > codec_data_size)
14195 /* last packet is the remaining size */
14196 length[i] = codec_data_size - offset - last;
14198 for (i = 0; i < num_packets; i++) {
14201 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14203 if (offset + length[i] > codec_data_size)
14206 hdr = gst_buffer_new_memdup (p + offset, length[i]);
14207 list = g_list_append (list, hdr);
14209 offset += length[i];
14218 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14224 /* this can change the codec originally present in @list */
14226 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14227 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14229 int len = QT_UINT32 (esds->data);
14230 guint8 *ptr = esds->data;
14231 guint8 *end = ptr + len;
14233 guint8 *data_ptr = NULL;
14235 guint8 object_type_id = 0;
14236 guint8 stream_type = 0;
14237 const char *codec_name = NULL;
14238 GstCaps *caps = NULL;
14240 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14242 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14244 while (ptr + 1 < end) {
14245 tag = QT_UINT8 (ptr);
14246 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14248 len = read_descr_size (ptr, end, &ptr);
14249 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14251 /* Check the stated amount of data is available for reading */
14252 if (len < 0 || ptr + len > end)
14256 case ES_DESCRIPTOR_TAG:
14257 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14258 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14261 case DECODER_CONFIG_DESC_TAG:{
14262 guint max_bitrate, avg_bitrate;
14264 object_type_id = QT_UINT8 (ptr);
14265 stream_type = QT_UINT8 (ptr + 1) >> 2;
14266 max_bitrate = QT_UINT32 (ptr + 5);
14267 avg_bitrate = QT_UINT32 (ptr + 9);
14268 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14269 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14270 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14271 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14272 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14273 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14274 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14275 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14277 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14278 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14279 avg_bitrate, NULL);
14284 case DECODER_SPECIFIC_INFO_TAG:
14285 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14286 if (object_type_id == 0xe0 && len == 0x40) {
14292 GST_DEBUG_OBJECT (qtdemux,
14293 "Have VOBSUB palette. Creating palette event");
14294 /* move to decConfigDescr data and read palette */
14296 for (i = 0; i < 16; i++) {
14297 clut[i] = QT_UINT32 (data);
14301 s = gst_structure_new ("application/x-gst-dvd", "event",
14302 G_TYPE_STRING, "dvd-spu-clut-change",
14303 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14304 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14305 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14306 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14307 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14308 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14309 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14310 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14313 /* store event and trigger custom processing */
14314 stream->pending_event =
14315 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14317 /* Generic codec_data handler puts it on the caps */
14324 case SL_CONFIG_DESC_TAG:
14325 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14329 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14331 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14337 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14338 * in use, and should also be used to override some other parameters for some
14340 switch (object_type_id) {
14341 case 0x20: /* MPEG-4 */
14342 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14343 * profile_and_level_indication */
14344 if (data_ptr != NULL && data_len >= 5 &&
14345 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14346 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14347 data_ptr + 4, data_len - 4);
14349 break; /* Nothing special needed here */
14350 case 0x21: /* H.264 */
14351 codec_name = "H.264 / AVC";
14352 caps = gst_caps_new_simple ("video/x-h264",
14353 "stream-format", G_TYPE_STRING, "avc",
14354 "alignment", G_TYPE_STRING, "au", NULL);
14356 case 0x40: /* AAC (any) */
14357 case 0x66: /* AAC Main */
14358 case 0x67: /* AAC LC */
14359 case 0x68: /* AAC SSR */
14360 /* Override channels and rate based on the codec_data, as it's often
14362 /* Only do so for basic setup without HE-AAC extension */
14363 if (data_ptr && data_len == 2) {
14364 guint channels, rate;
14366 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14368 entry->n_channels = channels;
14370 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14372 entry->rate = rate;
14375 /* Set level and profile if possible */
14376 if (data_ptr != NULL && data_len >= 2) {
14377 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14378 data_ptr, data_len);
14380 const gchar *profile_str = NULL;
14383 guint8 *codec_data;
14384 gint rate_idx, profile;
14386 /* No codec_data, let's invent something.
14387 * FIXME: This is wrong for SBR! */
14389 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14391 buffer = gst_buffer_new_and_alloc (2);
14392 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14393 codec_data = map.data;
14396 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14399 switch (object_type_id) {
14401 profile_str = "main";
14405 profile_str = "lc";
14409 profile_str = "ssr";
14417 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14419 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14421 gst_buffer_unmap (buffer, &map);
14422 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14423 GST_TYPE_BUFFER, buffer, NULL);
14424 gst_buffer_unref (buffer);
14427 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14428 G_TYPE_STRING, profile_str, NULL);
14432 case 0x60: /* MPEG-2, various profiles */
14438 codec_name = "MPEG-2 video";
14439 caps = gst_caps_new_simple ("video/mpeg",
14440 "mpegversion", G_TYPE_INT, 2,
14441 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14443 case 0x69: /* MPEG-2 BC audio */
14444 case 0x6B: /* MPEG-1 audio */
14445 caps = gst_caps_new_simple ("audio/mpeg",
14446 "mpegversion", G_TYPE_INT, 1, NULL);
14447 codec_name = "MPEG-1 audio";
14449 case 0x6A: /* MPEG-1 */
14450 codec_name = "MPEG-1 video";
14451 caps = gst_caps_new_simple ("video/mpeg",
14452 "mpegversion", G_TYPE_INT, 1,
14453 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14455 case 0x6C: /* MJPEG */
14457 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14459 codec_name = "Motion-JPEG";
14461 case 0x6D: /* PNG */
14463 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14465 codec_name = "PNG still images";
14467 case 0x6E: /* JPEG2000 */
14468 codec_name = "JPEG-2000";
14469 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14471 case 0xA4: /* Dirac */
14472 codec_name = "Dirac";
14473 caps = gst_caps_new_empty_simple ("video/x-dirac");
14475 case 0xA5: /* AC3 */
14476 codec_name = "AC-3 audio";
14477 caps = gst_caps_new_simple ("audio/x-ac3",
14478 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14480 case 0xA9: /* AC3 */
14481 codec_name = "DTS audio";
14482 caps = gst_caps_new_simple ("audio/x-dts",
14483 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14486 if (stream_type == 0x05 && data_ptr) {
14488 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14491 GValue arr_val = G_VALUE_INIT;
14492 GValue buf_val = G_VALUE_INIT;
14495 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14496 codec_name = "Vorbis";
14497 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14498 g_value_init (&arr_val, GST_TYPE_ARRAY);
14499 g_value_init (&buf_val, GST_TYPE_BUFFER);
14500 for (tmp = headers; tmp; tmp = tmp->next) {
14501 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14502 gst_value_array_append_value (&arr_val, &buf_val);
14504 s = gst_caps_get_structure (caps, 0);
14505 gst_structure_take_value (s, "streamheader", &arr_val);
14506 g_value_unset (&buf_val);
14507 g_list_free (headers);
14514 case 0xE1: /* QCELP */
14515 /* QCELP, the codec_data is a riff tag (little endian) with
14516 * 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). */
14517 caps = gst_caps_new_empty_simple ("audio/qcelp");
14518 codec_name = "QCELP";
14524 /* If we have a replacement caps, then change our caps for this stream */
14526 gst_caps_unref (entry->caps);
14527 entry->caps = caps;
14530 if (codec_name && list)
14531 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14532 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14534 /* Add the codec_data attribute to caps, if we have it */
14538 buffer = gst_buffer_new_and_alloc (data_len);
14539 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14541 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14542 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14544 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14546 gst_buffer_unref (buffer);
14551 static inline GstCaps *
14552 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14556 char *s, fourstr[5];
14558 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14559 for (i = 0; i < 4; i++) {
14560 if (!g_ascii_isalnum (fourstr[i]))
14563 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14564 caps = gst_caps_new_empty_simple (s);
14569 #define _codec(name) \
14571 if (codec_name) { \
14572 *codec_name = g_strdup (name); \
14577 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14578 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14579 const guint8 * stsd_entry_data, gchar ** codec_name)
14581 GstCaps *caps = NULL;
14582 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14586 _codec ("PNG still images");
14587 caps = gst_caps_new_empty_simple ("image/png");
14590 _codec ("JPEG still images");
14592 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14595 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14596 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14597 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14598 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14599 _codec ("Motion-JPEG");
14601 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14604 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14605 _codec ("Motion-JPEG format B");
14606 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14609 _codec ("JPEG-2000");
14610 /* override to what it should be according to spec, avoid palette_data */
14611 entry->bits_per_sample = 24;
14612 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14615 _codec ("Sorensen video v.3");
14616 caps = gst_caps_new_simple ("video/x-svq",
14617 "svqversion", G_TYPE_INT, 3, NULL);
14619 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14620 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14621 _codec ("Sorensen video v.1");
14622 caps = gst_caps_new_simple ("video/x-svq",
14623 "svqversion", G_TYPE_INT, 1, NULL);
14625 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14626 caps = gst_caps_new_empty_simple ("video/x-raw");
14627 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14628 _codec ("Windows Raw RGB");
14629 stream->alignment = 32;
14635 bps = QT_UINT16 (stsd_entry_data + 82);
14638 format = GST_VIDEO_FORMAT_RGB15;
14641 format = GST_VIDEO_FORMAT_RGB16;
14644 format = GST_VIDEO_FORMAT_RGB;
14647 format = GST_VIDEO_FORMAT_ARGB;
14655 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14656 format = GST_VIDEO_FORMAT_I420;
14658 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14659 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14660 format = GST_VIDEO_FORMAT_I420;
14663 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14664 format = GST_VIDEO_FORMAT_UYVY;
14666 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14667 format = GST_VIDEO_FORMAT_v308;
14669 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14670 format = GST_VIDEO_FORMAT_v216;
14673 format = GST_VIDEO_FORMAT_v210;
14675 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14676 format = GST_VIDEO_FORMAT_r210;
14678 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14679 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14680 format = GST_VIDEO_FORMAT_v410;
14683 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14684 * but different order than AYUV
14685 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14686 format = GST_VIDEO_FORMAT_v408;
14689 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14690 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14691 _codec ("MPEG-1 video");
14692 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14693 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14695 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14696 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14697 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14698 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14699 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14700 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14701 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14702 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14703 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14704 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14705 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14706 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14707 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14708 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14709 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14710 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14711 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14712 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14713 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14714 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14715 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14716 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14717 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14718 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14719 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14720 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14721 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14722 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14723 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14724 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14725 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14726 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14727 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14728 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14729 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14730 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14731 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14732 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14733 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14734 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14735 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14736 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14737 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14738 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14739 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14740 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14741 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14742 _codec ("MPEG-2 video");
14743 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14744 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14746 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14747 _codec ("GIF still images");
14748 caps = gst_caps_new_empty_simple ("image/gif");
14751 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14753 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14755 /* ffmpeg uses the height/width props, don't know why */
14756 caps = gst_caps_new_simple ("video/x-h263",
14757 "variant", G_TYPE_STRING, "itu", NULL);
14761 _codec ("MPEG-4 video");
14762 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14763 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14765 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14766 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14767 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14768 caps = gst_caps_new_simple ("video/x-msmpeg",
14769 "msmpegversion", G_TYPE_INT, 43, NULL);
14771 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14773 caps = gst_caps_new_simple ("video/x-divx",
14774 "divxversion", G_TYPE_INT, 3, NULL);
14776 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14777 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14779 caps = gst_caps_new_simple ("video/x-divx",
14780 "divxversion", G_TYPE_INT, 4, NULL);
14782 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14784 caps = gst_caps_new_simple ("video/x-divx",
14785 "divxversion", G_TYPE_INT, 5, NULL);
14788 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14790 caps = gst_caps_new_simple ("video/x-ffv",
14791 "ffvversion", G_TYPE_INT, 1, NULL);
14794 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14795 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14800 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14801 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14802 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14806 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14807 _codec ("Cinepak");
14808 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14810 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14811 _codec ("Apple QuickDraw");
14812 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14814 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14815 _codec ("Apple video");
14816 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14821 _codec ("H.264 / AVC");
14822 caps = gst_caps_new_simple ("video/x-h264",
14823 "stream-format", G_TYPE_STRING, "avc",
14824 "alignment", G_TYPE_STRING, "au", NULL);
14828 _codec ("H.264 / AVC");
14829 caps = gst_caps_new_simple ("video/x-h264",
14830 "stream-format", G_TYPE_STRING, "avc3",
14831 "alignment", G_TYPE_STRING, "au", NULL);
14836 _codec ("H.265 / HEVC");
14837 caps = gst_caps_new_simple ("video/x-h265",
14838 "stream-format", G_TYPE_STRING, "hvc1",
14839 "alignment", G_TYPE_STRING, "au", NULL);
14843 _codec ("H.265 / HEVC");
14844 caps = gst_caps_new_simple ("video/x-h265",
14845 "stream-format", G_TYPE_STRING, "hev1",
14846 "alignment", G_TYPE_STRING, "au", NULL);
14849 _codec ("Run-length encoding");
14850 caps = gst_caps_new_simple ("video/x-rle",
14851 "layout", G_TYPE_STRING, "quicktime", NULL);
14854 _codec ("Run-length encoding");
14855 caps = gst_caps_new_simple ("video/x-rle",
14856 "layout", G_TYPE_STRING, "microsoft", NULL);
14858 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14859 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14860 _codec ("Indeo Video 3");
14861 caps = gst_caps_new_simple ("video/x-indeo",
14862 "indeoversion", G_TYPE_INT, 3, NULL);
14864 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14865 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14866 _codec ("Intel Video 4");
14867 caps = gst_caps_new_simple ("video/x-indeo",
14868 "indeoversion", G_TYPE_INT, 4, NULL);
14872 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14873 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14874 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14875 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14876 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14877 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14878 _codec ("DV Video");
14879 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14880 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14882 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14883 case FOURCC_dv5p: /* DVCPRO50 PAL */
14884 _codec ("DVCPro50 Video");
14885 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14886 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14888 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14889 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14890 _codec ("DVCProHD Video");
14891 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14892 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14894 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14895 _codec ("Apple Graphics (SMC)");
14896 caps = gst_caps_new_empty_simple ("video/x-smc");
14898 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14900 caps = gst_caps_new_empty_simple ("video/x-vp3");
14902 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14903 _codec ("VP6 Flash");
14904 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14908 caps = gst_caps_new_empty_simple ("video/x-theora");
14909 /* theora uses one byte of padding in the data stream because it does not
14910 * allow 0 sized packets while theora does */
14911 entry->padding = 1;
14915 caps = gst_caps_new_empty_simple ("video/x-dirac");
14917 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14918 _codec ("TIFF still images");
14919 caps = gst_caps_new_empty_simple ("image/tiff");
14921 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14922 _codec ("Apple Intermediate Codec");
14923 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14925 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14926 _codec ("AVID DNxHD");
14927 caps = gst_caps_from_string ("video/x-dnxhd");
14931 _codec ("On2 VP8");
14932 caps = gst_caps_from_string ("video/x-vp8");
14935 _codec ("Google VP9");
14936 caps = gst_caps_from_string ("video/x-vp9");
14939 _codec ("Apple ProRes LT");
14941 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14945 _codec ("Apple ProRes HQ");
14947 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14951 _codec ("Apple ProRes");
14953 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14957 _codec ("Apple ProRes Proxy");
14959 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14963 _codec ("Apple ProRes 4444");
14965 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14968 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14969 if (entry->bits_per_sample > 0) {
14970 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14975 _codec ("Apple ProRes 4444 XQ");
14977 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14980 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14981 if (entry->bits_per_sample > 0) {
14982 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14987 _codec ("GoPro CineForm");
14988 caps = gst_caps_from_string ("video/x-cineform");
14993 caps = gst_caps_new_simple ("video/x-wmv",
14994 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14998 caps = gst_caps_new_simple ("video/x-av1",
14999 "alignment", G_TYPE_STRING, "tu", NULL);
15001 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
15004 caps = _get_unknown_codec_name ("video", fourcc);
15009 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
15012 gst_video_info_init (&info);
15013 gst_video_info_set_format (&info, format, entry->width, entry->height);
15015 caps = gst_video_info_to_caps (&info);
15016 *codec_name = gst_pb_utils_get_codec_description (caps);
15018 /* enable clipping for raw video streams */
15019 stream->need_clip = TRUE;
15020 stream->alignment = 32;
15027 round_up_pow2 (guint n)
15039 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15040 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
15041 int len, gchar ** codec_name)
15044 const GstStructure *s;
15047 GstAudioFormat format = 0;
15050 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15052 depth = entry->bytes_per_packet * 8;
15055 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
15057 /* 8-bit audio is unsigned */
15059 format = GST_AUDIO_FORMAT_U8;
15060 /* otherwise it's signed and big-endian just like 'twos' */
15062 endian = G_BIG_ENDIAN;
15069 endian = G_LITTLE_ENDIAN;
15072 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
15074 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
15078 caps = gst_caps_new_simple ("audio/x-raw",
15079 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15080 "layout", G_TYPE_STRING, "interleaved", NULL);
15081 stream->alignment = GST_ROUND_UP_8 (depth);
15082 stream->alignment = round_up_pow2 (stream->alignment);
15086 _codec ("Raw 64-bit floating-point audio");
15087 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15089 caps = gst_caps_new_simple ("audio/x-raw",
15090 "format", G_TYPE_STRING, "F64BE",
15091 "layout", G_TYPE_STRING, "interleaved", NULL);
15092 stream->alignment = 8;
15095 _codec ("Raw 32-bit floating-point audio");
15096 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15098 caps = gst_caps_new_simple ("audio/x-raw",
15099 "format", G_TYPE_STRING, "F32BE",
15100 "layout", G_TYPE_STRING, "interleaved", NULL);
15101 stream->alignment = 4;
15104 _codec ("Raw 24-bit PCM audio");
15105 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15107 caps = gst_caps_new_simple ("audio/x-raw",
15108 "format", G_TYPE_STRING, "S24BE",
15109 "layout", G_TYPE_STRING, "interleaved", NULL);
15110 stream->alignment = 4;
15113 _codec ("Raw 32-bit PCM audio");
15114 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15116 caps = gst_caps_new_simple ("audio/x-raw",
15117 "format", G_TYPE_STRING, "S32BE",
15118 "layout", G_TYPE_STRING, "interleaved", NULL);
15119 stream->alignment = 4;
15122 _codec ("Raw 16-bit PCM audio");
15123 caps = gst_caps_new_simple ("audio/x-raw",
15124 "format", G_TYPE_STRING, "S16LE",
15125 "layout", G_TYPE_STRING, "interleaved", NULL);
15126 stream->alignment = 2;
15129 _codec ("Mu-law audio");
15130 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
15133 _codec ("A-law audio");
15134 caps = gst_caps_new_empty_simple ("audio/x-alaw");
15138 _codec ("Microsoft ADPCM");
15139 /* Microsoft ADPCM-ACM code 2 */
15140 caps = gst_caps_new_simple ("audio/x-adpcm",
15141 "layout", G_TYPE_STRING, "microsoft", NULL);
15145 _codec ("DVI/IMA ADPCM");
15146 caps = gst_caps_new_simple ("audio/x-adpcm",
15147 "layout", G_TYPE_STRING, "dvi", NULL);
15151 _codec ("DVI/Intel IMA ADPCM");
15152 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15153 caps = gst_caps_new_simple ("audio/x-adpcm",
15154 "layout", G_TYPE_STRING, "quicktime", NULL);
15158 /* MPEG layer 3, CBR only (pre QT4.1) */
15161 _codec ("MPEG-1 layer 3");
15162 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15163 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15164 "mpegversion", G_TYPE_INT, 1, NULL);
15166 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15167 _codec ("MPEG-1 layer 2");
15169 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15170 "mpegversion", G_TYPE_INT, 1, NULL);
15173 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15174 _codec ("EAC-3 audio");
15175 caps = gst_caps_new_simple ("audio/x-eac3",
15176 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15177 entry->sampled = TRUE;
15179 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15181 _codec ("AC-3 audio");
15182 caps = gst_caps_new_simple ("audio/x-ac3",
15183 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15184 entry->sampled = TRUE;
15186 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15187 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15188 _codec ("DTS audio");
15189 caps = gst_caps_new_simple ("audio/x-dts",
15190 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15191 entry->sampled = TRUE;
15193 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15194 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15195 _codec ("DTS-HD audio");
15196 caps = gst_caps_new_simple ("audio/x-dts",
15197 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15198 entry->sampled = TRUE;
15202 caps = gst_caps_new_simple ("audio/x-mace",
15203 "maceversion", G_TYPE_INT, 3, NULL);
15207 caps = gst_caps_new_simple ("audio/x-mace",
15208 "maceversion", G_TYPE_INT, 6, NULL);
15210 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15212 caps = gst_caps_new_empty_simple ("application/ogg");
15214 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15215 _codec ("DV audio");
15216 caps = gst_caps_new_empty_simple ("audio/x-dv");
15219 _codec ("MPEG-4 AAC audio");
15220 caps = gst_caps_new_simple ("audio/mpeg",
15221 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15222 "stream-format", G_TYPE_STRING, "raw", NULL);
15224 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15225 _codec ("QDesign Music");
15226 caps = gst_caps_new_empty_simple ("audio/x-qdm");
15229 _codec ("QDesign Music v.2");
15230 /* FIXME: QDesign music version 2 (no constant) */
15231 if (FALSE && data) {
15232 caps = gst_caps_new_simple ("audio/x-qdm2",
15233 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15234 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15235 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15237 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15241 _codec ("GSM audio");
15242 caps = gst_caps_new_empty_simple ("audio/x-gsm");
15245 _codec ("AMR audio");
15246 caps = gst_caps_new_empty_simple ("audio/AMR");
15249 _codec ("AMR-WB audio");
15250 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15253 _codec ("Quicktime IMA ADPCM");
15254 caps = gst_caps_new_simple ("audio/x-adpcm",
15255 "layout", G_TYPE_STRING, "quicktime", NULL);
15258 _codec ("Apple lossless audio");
15259 caps = gst_caps_new_empty_simple ("audio/x-alac");
15262 _codec ("Free Lossless Audio Codec");
15263 caps = gst_caps_new_simple ("audio/x-flac",
15264 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15266 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15267 _codec ("QualComm PureVoice");
15268 caps = gst_caps_from_string ("audio/qcelp");
15273 caps = gst_caps_new_empty_simple ("audio/x-wma");
15277 caps = gst_caps_new_empty_simple ("audio/x-opus");
15284 GstAudioFormat format;
15287 FLAG_IS_FLOAT = 0x1,
15288 FLAG_IS_BIG_ENDIAN = 0x2,
15289 FLAG_IS_SIGNED = 0x4,
15290 FLAG_IS_PACKED = 0x8,
15291 FLAG_IS_ALIGNED_HIGH = 0x10,
15292 FLAG_IS_NON_INTERLEAVED = 0x20
15294 _codec ("Raw LPCM audio");
15296 if (data && len >= 36) {
15297 depth = QT_UINT32 (data + 24);
15298 flags = QT_UINT32 (data + 28);
15299 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15301 if ((flags & FLAG_IS_FLOAT) == 0) {
15306 if ((flags & FLAG_IS_ALIGNED_HIGH))
15309 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15310 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15311 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15312 caps = gst_caps_new_simple ("audio/x-raw",
15313 "format", G_TYPE_STRING,
15315 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15316 "UNKNOWN", "layout", G_TYPE_STRING,
15317 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15318 "interleaved", NULL);
15319 stream->alignment = GST_ROUND_UP_8 (depth);
15320 stream->alignment = round_up_pow2 (stream->alignment);
15325 if (flags & FLAG_IS_BIG_ENDIAN)
15326 format = GST_AUDIO_FORMAT_F64BE;
15328 format = GST_AUDIO_FORMAT_F64LE;
15330 if (flags & FLAG_IS_BIG_ENDIAN)
15331 format = GST_AUDIO_FORMAT_F32BE;
15333 format = GST_AUDIO_FORMAT_F32LE;
15335 caps = gst_caps_new_simple ("audio/x-raw",
15336 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15337 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15338 "non-interleaved" : "interleaved", NULL);
15339 stream->alignment = width / 8;
15343 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15346 caps = gst_caps_new_empty_simple ("audio/x-ac4");
15349 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15353 caps = _get_unknown_codec_name ("audio", fourcc);
15359 GstCaps *templ_caps =
15360 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15361 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15362 gst_caps_unref (caps);
15363 gst_caps_unref (templ_caps);
15364 caps = intersection;
15367 /* enable clipping for raw audio streams */
15368 s = gst_caps_get_structure (caps, 0);
15369 name = gst_structure_get_name (s);
15370 if (g_str_has_prefix (name, "audio/x-raw")) {
15371 stream->need_clip = TRUE;
15372 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15373 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15374 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15375 stream->max_buffer_size);
15381 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15382 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15383 const guint8 * stsd_entry_data, gchar ** codec_name)
15387 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15391 _codec ("DVD subtitle");
15392 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15393 stream->process_func = gst_qtdemux_process_buffer_dvd;
15396 _codec ("Quicktime timed text");
15399 _codec ("3GPP timed text");
15401 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15403 /* actual text piece needs to be extracted */
15404 stream->process_func = gst_qtdemux_process_buffer_text;
15407 _codec ("XML subtitles");
15408 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15413 const gchar *buf = "WEBVTT\n\n";
15415 _codec ("WebVTT subtitles");
15416 caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15417 stream->process_func = gst_qtdemux_process_buffer_wvtt;
15419 /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15420 buffer = gst_buffer_new_and_alloc (8);
15421 gst_buffer_fill (buffer, 0, buf, 8);
15422 stream->buffers = g_slist_append (stream->buffers, buffer);
15427 _codec ("CEA 608 Closed Caption");
15429 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15430 G_TYPE_STRING, "s334-1a", NULL);
15431 stream->process_func = gst_qtdemux_process_buffer_clcp;
15432 stream->need_split = TRUE;
15435 _codec ("CEA 708 Closed Caption");
15437 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15438 G_TYPE_STRING, "cdp", NULL);
15439 stream->process_func = gst_qtdemux_process_buffer_clcp;
15444 caps = _get_unknown_codec_name ("text", fourcc);
15452 qtdemux_meta_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15453 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15454 const guint8 * stsd_entry_data, gchar ** codec_name)
15456 GstCaps *caps = NULL;
15458 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15462 gsize size = QT_UINT32 (stsd_entry_data);
15463 GstByteReader reader = GST_BYTE_READER_INIT (stsd_entry_data, size);
15464 const gchar *content_encoding;
15465 const gchar *namespaces;
15466 const gchar *schema_locations;
15468 if (!gst_byte_reader_skip (&reader, 8 + 6 + 2)) {
15469 GST_WARNING_OBJECT (qtdemux, "Too short metx sample entry");
15473 if (!gst_byte_reader_get_string (&reader, &content_encoding) ||
15474 !gst_byte_reader_get_string (&reader, &namespaces) ||
15475 !gst_byte_reader_get_string (&reader, &schema_locations)) {
15476 GST_WARNING_OBJECT (qtdemux, "Too short metx sample entry");
15480 if (strstr (namespaces, "http://www.onvif.org/ver10/schema") != 0) {
15481 if (content_encoding == NULL || *content_encoding == '\0'
15482 || g_ascii_strcasecmp (content_encoding, "xml") == 0) {
15483 _codec ("ONVIF Timed XML MetaData");
15485 gst_caps_new_simple ("application/x-onvif-metadata", "parsed",
15486 G_TYPE_BOOLEAN, TRUE, NULL);
15488 GST_DEBUG_OBJECT (qtdemux, "Unknown content encoding: %s",
15492 GST_DEBUG_OBJECT (qtdemux, "Unknown metadata namespaces: %s",
15503 caps = _get_unknown_codec_name ("meta", fourcc);
15509 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15510 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15511 const guint8 * stsd_entry_data, gchar ** codec_name)
15517 _codec ("MPEG 1 video");
15518 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15519 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15529 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15530 const gchar * system_id)
15534 if (!qtdemux->protection_system_ids)
15535 qtdemux->protection_system_ids =
15536 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15537 /* Check whether we already have an entry for this system ID. */
15538 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15539 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15540 if (g_ascii_strcasecmp (system_id, id) == 0) {
15544 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15545 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,