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");
1988 gst_pad_stop_task (qtdemux->sinkpad);
1990 if (hard || qtdemux->upstream_format_is_time) {
1991 qtdemux->state = QTDEMUX_STATE_INITIAL;
1992 qtdemux->neededbytes = 16;
1993 qtdemux->todrop = 0;
1994 qtdemux->pullbased = FALSE;
1995 g_clear_pointer (&qtdemux->redirect_location, g_free);
1996 qtdemux->first_mdat = -1;
1997 qtdemux->header_size = 0;
1998 qtdemux->mdatoffset = -1;
1999 qtdemux->restoredata_offset = -1;
2000 if (qtdemux->mdatbuffer)
2001 gst_buffer_unref (qtdemux->mdatbuffer);
2002 if (qtdemux->restoredata_buffer)
2003 gst_buffer_unref (qtdemux->restoredata_buffer);
2004 qtdemux->mdatbuffer = NULL;
2005 qtdemux->restoredata_buffer = NULL;
2006 qtdemux->mdatleft = 0;
2007 qtdemux->mdatsize = 0;
2008 if (qtdemux->comp_brands)
2009 gst_buffer_unref (qtdemux->comp_brands);
2010 qtdemux->comp_brands = NULL;
2011 qtdemux->last_moov_offset = -1;
2012 if (qtdemux->moov_node_compressed) {
2013 g_node_destroy (qtdemux->moov_node_compressed);
2014 if (qtdemux->moov_node)
2015 g_free (qtdemux->moov_node->data);
2017 qtdemux->moov_node_compressed = NULL;
2018 if (qtdemux->moov_node)
2019 g_node_destroy (qtdemux->moov_node);
2020 qtdemux->moov_node = NULL;
2021 if (qtdemux->tag_list)
2022 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2023 qtdemux->tag_list = gst_tag_list_new_empty ();
2024 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2026 if (qtdemux->element_index)
2027 gst_object_unref (qtdemux->element_index);
2028 qtdemux->element_index = NULL;
2030 qtdemux->major_brand = 0;
2031 qtdemux->upstream_format_is_time = FALSE;
2032 qtdemux->upstream_seekable = FALSE;
2033 qtdemux->upstream_size = 0;
2035 qtdemux->fragment_start = -1;
2036 qtdemux->fragment_start_offset = -1;
2037 qtdemux->duration = 0;
2038 qtdemux->moof_offset = 0;
2039 qtdemux->chapters_track_id = 0;
2040 qtdemux->have_group_id = FALSE;
2041 qtdemux->group_id = G_MAXUINT;
2043 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2045 g_queue_clear (&qtdemux->protection_event_queue);
2047 qtdemux->received_seek = FALSE;
2048 qtdemux->first_moof_already_parsed = FALSE;
2050 qtdemux->offset = 0;
2051 gst_adapter_clear (qtdemux->adapter);
2052 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2053 qtdemux->need_segment = TRUE;
2056 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2057 qtdemux->trickmode_interval = 0;
2058 g_ptr_array_set_size (qtdemux->active_streams, 0);
2059 g_ptr_array_set_size (qtdemux->old_streams, 0);
2060 qtdemux->n_video_streams = 0;
2061 qtdemux->n_audio_streams = 0;
2062 qtdemux->n_sub_streams = 0;
2063 qtdemux->n_meta_streams = 0;
2064 qtdemux->exposed = FALSE;
2065 qtdemux->fragmented = FALSE;
2066 qtdemux->mss_mode = FALSE;
2067 gst_caps_replace (&qtdemux->media_caps, NULL);
2068 qtdemux->timescale = 0;
2069 qtdemux->got_moov = FALSE;
2070 qtdemux->start_utc_time = GST_CLOCK_TIME_NONE;
2071 qtdemux->cenc_aux_info_offset = 0;
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 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2847 G_TYPE_STRING, &system_id, NULL);
2848 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2850 stream->protected = TRUE;
2851 stream->protection_scheme_type = FOURCC_cenc;
2853 if (!stream->protection_scheme_info)
2854 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2856 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2857 if (!ss_info->default_properties) {
2858 ss_info->default_properties =
2859 gst_structure_new ("application/x-cenc",
2860 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2865 if (ss_info->crypto_info) {
2866 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2867 g_ptr_array_free (ss_info->crypto_info, TRUE);
2868 ss_info->crypto_info = NULL;
2872 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2874 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2875 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2879 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2880 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2884 if ((flags & 0x000001)) {
2885 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2888 } else if ((flags & 0x000002)) {
2889 uses_sub_sample_encryption = TRUE;
2892 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2894 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2898 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2899 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2903 ss_info->crypto_info =
2904 g_ptr_array_new_full (sample_count,
2905 (GDestroyNotify) qtdemux_gst_structure_free);
2907 for (i = 0; i < sample_count; ++i) {
2908 GstStructure *properties;
2912 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2913 if (properties == NULL) {
2914 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2915 qtdemux->cenc_aux_sample_count = i;
2919 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2920 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2921 gst_structure_free (properties);
2922 qtdemux->cenc_aux_sample_count = i;
2925 buf = gst_buffer_new_wrapped (data, iv_size);
2926 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2927 gst_buffer_unref (buf);
2929 if (uses_sub_sample_encryption) {
2930 guint16 n_subsamples;
2931 const GValue *kid_buf_value;
2933 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2934 || n_subsamples == 0) {
2935 GST_ERROR_OBJECT (qtdemux,
2936 "failed to get subsample count for sample %u", i);
2937 gst_structure_free (properties);
2938 qtdemux->cenc_aux_sample_count = i;
2941 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2942 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2943 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2945 gst_structure_free (properties);
2946 qtdemux->cenc_aux_sample_count = i;
2949 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2952 gst_structure_get_value (ss_info->default_properties, "kid");
2954 gst_structure_set (properties,
2955 "subsample_count", G_TYPE_UINT, n_subsamples,
2956 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2957 gst_structure_set_value (properties, "kid", kid_buf_value);
2958 gst_buffer_unref (buf);
2960 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2963 g_ptr_array_add (ss_info->crypto_info, properties);
2966 qtdemux->cenc_aux_sample_count = sample_count;
2970 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2972 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2973 0x97, 0xA9, 0x42, 0xE8,
2974 0x9C, 0x71, 0x99, 0x94,
2975 0x91, 0xE3, 0xAF, 0xAC
2977 static const guint8 playready_uuid[] = {
2978 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2979 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2982 static const guint8 piff_sample_encryption_uuid[] = {
2983 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2984 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2989 /* counts as header data */
2990 qtdemux->header_size += length;
2992 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2994 if (length <= offset + 16) {
2995 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2999 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
3001 GstTagList *taglist;
3003 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3004 length - offset - 16, NULL);
3005 taglist = gst_tag_list_from_xmp_buffer (buf);
3006 gst_buffer_unref (buf);
3008 /* make sure we have a usable taglist */
3009 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3011 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3013 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3015 const gunichar2 *s_utf16;
3018 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3019 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3020 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3021 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3025 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3026 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3028 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3029 qtdemux_parse_piff (qtdemux, buffer, length, offset);
3031 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3032 GST_READ_UINT32_LE (buffer + offset),
3033 GST_READ_UINT32_LE (buffer + offset + 4),
3034 GST_READ_UINT32_LE (buffer + offset + 8),
3035 GST_READ_UINT32_LE (buffer + offset + 12));
3040 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3042 GstSidxParser sidx_parser;
3043 GstIsoffParserResult res;
3046 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3049 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3051 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3052 if (res == GST_ISOFF_QT_PARSER_DONE) {
3053 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3055 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3059 qtdemux_parse_cstb (GstQTDemux * qtdemux, GstByteReader * data)
3062 guint32 entry_count;
3064 GST_DEBUG_OBJECT (qtdemux, "Parsing CorrectStartTime box");
3066 qtdemux->start_utc_time = GST_CLOCK_TIME_NONE;
3068 if (gst_byte_reader_get_remaining (data) < 4) {
3069 GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box");
3073 entry_count = gst_byte_reader_get_uint32_be_unchecked (data);
3074 if (entry_count == 0)
3077 /* XXX: We assume that all start times are the same as different start times
3078 * would violate the MP4 synchronization model, so we just take the first
3079 * one here and apply it to all tracks.
3082 if (gst_byte_reader_get_remaining (data) < entry_count * 12) {
3083 GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box");
3088 gst_byte_reader_skip_unchecked (data, 4);
3090 /* In 100ns intervals */
3091 start_time = gst_byte_reader_get_uint64_be_unchecked (data);
3093 /* Convert from Jan 1 1601 to Jan 1 1970 */
3094 if (start_time < 11644473600 * G_GUINT64_CONSTANT (10000000)) {
3095 GST_WARNING_OBJECT (qtdemux, "Start UTC time before UNIX epoch");
3098 start_time -= 11644473600 * G_GUINT64_CONSTANT (10000000);
3100 /* Convert to GstClockTime */
3103 GST_DEBUG_OBJECT (qtdemux, "Start UTC time: %" GST_TIME_FORMAT,
3104 GST_TIME_ARGS (start_time));
3106 qtdemux->start_utc_time = start_time;
3109 /* caller verifies at least 8 bytes in buf */
3111 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3112 guint64 * plength, guint32 * pfourcc)
3117 length = QT_UINT32 (data);
3118 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3119 fourcc = QT_FOURCC (data + 4);
3120 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3123 length = G_MAXUINT64;
3124 } else if (length == 1 && size >= 16) {
3125 /* this means we have an extended size, which is the 64 bit value of
3126 * the next 8 bytes */
3127 length = QT_UINT64 (data + 8);
3128 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3138 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3140 guint32 version = 0;
3141 GstClockTime duration = 0;
3143 if (!gst_byte_reader_get_uint32_be (br, &version))
3148 if (!gst_byte_reader_get_uint64_be (br, &duration))
3153 if (!gst_byte_reader_get_uint32_be (br, &dur))
3158 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3159 qtdemux->duration = duration;
3165 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3171 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3172 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3174 if (!stream->parsed_trex && qtdemux->moov_node) {
3176 GstByteReader trex_data;
3178 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3180 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3183 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3185 /* skip version/flags */
3186 if (!gst_byte_reader_skip (&trex_data, 4))
3188 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3190 if (id != stream->track_id)
3192 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3194 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3196 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3198 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3201 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3202 "duration %d, size %d, flags 0x%x", stream->track_id,
3205 stream->parsed_trex = TRUE;
3206 stream->def_sample_description_index = sdi;
3207 stream->def_sample_duration = dur;
3208 stream->def_sample_size = size;
3209 stream->def_sample_flags = flags;
3212 /* iterate all siblings */
3213 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3219 *ds_duration = stream->def_sample_duration;
3220 *ds_size = stream->def_sample_size;
3221 *ds_flags = stream->def_sample_flags;
3223 /* even then, above values are better than random ... */
3224 if (G_UNLIKELY (!stream->parsed_trex)) {
3225 GST_WARNING_OBJECT (qtdemux,
3226 "failed to find fragment defaults for stream %d", stream->track_id);
3233 /* This method should be called whenever a more accurate duration might
3234 * have been found. It will update all relevant variables if/where needed
3237 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3241 GstClockTime prevdur;
3243 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3245 if (movdur > qtdemux->duration) {
3246 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3247 GST_DEBUG_OBJECT (qtdemux,
3248 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3249 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3250 qtdemux->duration = movdur;
3251 GST_DEBUG_OBJECT (qtdemux,
3252 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3253 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3254 GST_TIME_ARGS (qtdemux->segment.stop));
3255 if (qtdemux->segment.duration == prevdur) {
3256 /* If the current segment has duration/stop identical to previous duration
3257 * update them also (because they were set at that point in time with
3258 * the wrong duration */
3259 /* We convert the value *from* the timescale version to avoid rounding errors */
3260 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3261 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3262 qtdemux->segment.duration = fixeddur;
3263 qtdemux->segment.stop = fixeddur;
3267 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3268 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3270 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3271 if (movdur > stream->duration) {
3272 GST_DEBUG_OBJECT (qtdemux,
3273 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3274 GST_TIME_ARGS (duration));
3275 stream->duration = movdur;
3276 /* internal duration tracking state has been updated above, so */
3277 /* preserve an open-ended dummy segment rather than repeatedly updating
3278 * it and spamming downstream accordingly with segment events */
3279 /* also mangle the edit list end time when fragmented with a single edit
3280 * list that may only cover any non-fragmented data */
3281 if ((stream->dummy_segment ||
3282 (qtdemux->fragmented && stream->n_segments == 1)) &&
3283 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3284 /* Update all dummy values to new duration */
3285 stream->segments[0].stop_time = duration;
3286 stream->segments[0].duration = duration;
3287 stream->segments[0].media_stop = duration;
3289 /* let downstream know we possibly have a new stop time */
3290 if (stream->segment_index != -1) {
3293 if (qtdemux->segment.rate >= 0) {
3294 pos = stream->segment.start;
3296 pos = stream->segment.stop;
3299 gst_qtdemux_stream_update_segment (qtdemux, stream,
3300 stream->segment_index, pos, NULL, NULL);
3308 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3309 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3310 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3311 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3314 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3316 gint32 data_offset = 0;
3318 guint32 flags = 0, first_flags = 0, samples_count = 0;
3321 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3322 QtDemuxSample *sample;
3323 gboolean ismv = FALSE;
3324 gint64 initial_offset;
3327 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3328 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3329 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3330 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3332 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3333 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3337 /* presence of stss or not can't really tell us much,
3338 * and flags and so on tend to be marginally reliable in these files */
3339 if (stream->subtype == FOURCC_soun) {
3340 GST_DEBUG_OBJECT (qtdemux,
3341 "sound track in fragmented file; marking all keyframes");
3342 stream->all_keyframe = TRUE;
3345 if (!gst_byte_reader_get_uint8 (trun, &version) ||
3346 !gst_byte_reader_get_uint24_be (trun, &flags))
3349 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3352 if (flags & TR_DATA_OFFSET) {
3353 /* note this is really signed */
3354 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3356 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3357 /* default base offset = first byte of moof */
3358 if (*base_offset == -1) {
3359 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3360 *base_offset = moof_offset;
3362 *running_offset = *base_offset + data_offset;
3364 /* if no offset at all, that would mean data starts at moof start,
3365 * which is a bit wrong and is ismv crappy way, so compensate
3366 * assuming data is in mdat following moof */
3367 if (*base_offset == -1) {
3368 *base_offset = moof_offset + moof_length + 8;
3369 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3372 if (*running_offset == -1)
3373 *running_offset = *base_offset;
3376 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3378 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3379 data_offset, flags, samples_count);
3381 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3382 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3383 GST_DEBUG_OBJECT (qtdemux,
3384 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3385 flags ^= TR_FIRST_SAMPLE_FLAGS;
3387 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3389 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3393 /* FIXME ? spec says other bits should also be checked to determine
3394 * entry size (and prefix size for that matter) */
3396 dur_offset = size_offset = 0;
3397 if (flags & TR_SAMPLE_DURATION) {
3398 GST_LOG_OBJECT (qtdemux, "entry duration present");
3399 dur_offset = entry_size;
3402 if (flags & TR_SAMPLE_SIZE) {
3403 GST_LOG_OBJECT (qtdemux, "entry size present");
3404 size_offset = entry_size;
3407 if (flags & TR_SAMPLE_FLAGS) {
3408 GST_LOG_OBJECT (qtdemux, "entry flags present");
3409 flags_offset = entry_size;
3412 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3413 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3414 ct_offset = entry_size;
3418 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3420 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3422 if (stream->n_samples + samples_count >=
3423 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3426 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3427 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3428 (stream->n_samples + samples_count) *
3429 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3431 /* create a new array of samples if it's the first sample parsed */
3432 if (stream->n_samples == 0) {
3433 g_assert (stream->samples == NULL);
3434 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3435 /* or try to reallocate it with space enough to insert the new samples */
3437 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3438 stream->n_samples + samples_count);
3439 if (stream->samples == NULL)
3442 if (qtdemux->fragment_start != -1) {
3443 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3444 qtdemux->fragment_start = -1;
3446 if (stream->n_samples == 0) {
3447 if (decode_ts > 0) {
3448 timestamp = decode_ts;
3449 } else if (stream->pending_seek != NULL) {
3450 /* if we don't have a timestamp from a tfdt box, we'll use the one
3451 * from the mfra seek table */
3452 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3453 GST_TIME_ARGS (stream->pending_seek->ts));
3455 /* FIXME: this is not fully correct, the timestamp refers to the random
3456 * access sample refered to in the tfra entry, which may not necessarily
3457 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3458 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3463 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3464 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3465 GST_TIME_ARGS (gst_ts));
3467 /* subsequent fragments extend stream */
3469 stream->samples[stream->n_samples - 1].timestamp +
3470 stream->samples[stream->n_samples - 1].duration;
3472 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3473 * difference (1 sec.) between decode_ts and timestamp, prefer the
3475 if (has_tfdt && !qtdemux->upstream_format_is_time
3476 && ABSDIFF (decode_ts, timestamp) >
3477 MAX (stream->duration_last_moof / 2,
3478 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3479 GST_INFO_OBJECT (qtdemux,
3480 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3481 ") are significantly different (more than %" GST_TIME_FORMAT
3482 "), using decode_ts",
3483 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3484 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3485 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3486 MAX (stream->duration_last_moof / 2,
3487 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3488 timestamp = decode_ts;
3491 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3492 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3493 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3497 initial_offset = *running_offset;
3499 sample = stream->samples + stream->n_samples;
3500 for (i = 0; i < samples_count; i++) {
3501 guint32 dur, size, sflags;
3504 /* first read sample data */
3505 if (flags & TR_SAMPLE_DURATION) {
3506 dur = QT_UINT32 (data + dur_offset);
3508 dur = d_sample_duration;
3510 if (flags & TR_SAMPLE_SIZE) {
3511 size = QT_UINT32 (data + size_offset);
3513 size = d_sample_size;
3515 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3517 sflags = first_flags;
3519 sflags = d_sample_flags;
3521 } else if (flags & TR_SAMPLE_FLAGS) {
3522 sflags = QT_UINT32 (data + flags_offset);
3524 sflags = d_sample_flags;
3527 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3528 /* Read offsets as signed numbers regardless of trun version as very
3529 * high offsets are unlikely and there are files out there that use
3530 * version=0 truns with negative offsets */
3531 ct = QT_UINT32 (data + ct_offset);
3533 /* FIXME: Set offset to 0 for "no decode samples". This needs
3534 * to be handled in a codec specific manner ideally. */
3535 if (ct == G_MININT32)
3542 /* fill the sample information */
3543 sample->offset = *running_offset;
3544 sample->pts_offset = ct;
3545 sample->size = size;
3546 sample->timestamp = timestamp;
3547 sample->duration = dur;
3548 /* sample-is-difference-sample */
3549 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3550 * now idea how it relates to bitfield other than massive LE/BE confusion */
3551 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3552 *running_offset += size;
3554 stream->duration_moof += dur;
3561 /* Shift PTS/DTS to allow for negative composition offsets while keeping
3562 * A/V sync in place. This is similar to the code handling ctts/cslg in the
3563 * non-fragmented case.
3566 stream->cslg_shift = -min_ct;
3568 stream->cslg_shift = 0;
3570 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
3571 stream->cslg_shift);
3573 /* Update total duration if needed */
3574 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3576 /* Pre-emptively figure out size of mdat based on trun information.
3577 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3578 * size, else we will still be able to use this when dealing with gap'ed
3580 qtdemux->mdatleft = *running_offset - initial_offset;
3581 qtdemux->mdatoffset = initial_offset;
3582 qtdemux->mdatsize = qtdemux->mdatleft;
3584 stream->n_samples += samples_count;
3585 stream->n_samples_moof += samples_count;
3587 if (stream->pending_seek != NULL)
3588 stream->pending_seek = NULL;
3594 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3599 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3605 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3606 "be larger than %uMB (broken file?)", stream->n_samples,
3607 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3612 /* find stream with @id */
3613 static inline QtDemuxStream *
3614 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3616 QtDemuxStream *stream;
3620 if (G_UNLIKELY (!id)) {
3621 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3625 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3626 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3627 if (stream->track_id == id)
3630 if (qtdemux->mss_mode) {
3631 /* mss should have only 1 stream anyway */
3632 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3639 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3640 guint32 * fragment_number)
3642 if (!gst_byte_reader_skip (mfhd, 4))
3644 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3649 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3655 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3656 QtDemuxStream ** stream, guint32 * default_sample_duration,
3657 guint32 * default_sample_size, guint32 * default_sample_flags,
3658 gint64 * base_offset)
3661 guint32 track_id = 0;
3663 if (!gst_byte_reader_skip (tfhd, 1) ||
3664 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3667 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3670 *stream = qtdemux_find_stream (qtdemux, track_id);
3671 if (G_UNLIKELY (!*stream))
3672 goto unknown_stream;
3674 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3675 *base_offset = qtdemux->moof_offset;
3677 if (flags & TF_BASE_DATA_OFFSET)
3678 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3681 /* obtain stream defaults */
3682 if (qtdemux_parse_trex (qtdemux, *stream,
3683 default_sample_duration, default_sample_size, default_sample_flags)) {
3685 /* Default sample description index is only valid if trex parsing succeeded */
3686 (*stream)->stsd_sample_description_id =
3687 (*stream)->def_sample_description_index - 1;
3690 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3691 guint32 sample_description_index;
3692 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3694 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3697 if (qtdemux->mss_mode) {
3698 /* mss has no stsd entry */
3699 (*stream)->stsd_sample_description_id = 0;
3702 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3703 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3706 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3707 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3710 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3711 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3718 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3723 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3729 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3730 guint64 * decode_time)
3732 guint32 version = 0;
3734 if (!gst_byte_reader_get_uint32_be (br, &version))
3739 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3742 guint32 dec_time = 0;
3743 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3745 *decode_time = dec_time;
3748 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3755 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3760 /* Returns a pointer to a GstStructure containing the properties of
3761 * the stream sample identified by @sample_index. The caller must unref
3762 * the returned object after use. Returns NULL if unsuccessful. */
3763 static GstStructure *
3764 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3765 QtDemuxStream * stream, guint sample_index)
3767 QtDemuxCencSampleSetInfo *info = NULL;
3769 g_return_val_if_fail (stream != NULL, NULL);
3770 g_return_val_if_fail (stream->protected, NULL);
3771 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3773 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3775 /* Currently, cenc properties for groups of samples are not supported, so
3776 * simply return a copy of the default sample properties */
3777 return gst_structure_copy (info->default_properties);
3780 /* Parses the sizes of sample auxiliary information contained within a stream,
3781 * as given in a saiz box. Returns array of sample_count guint8 size values,
3782 * or NULL on failure */
3784 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3785 GstByteReader * br, guint32 * sample_count)
3789 guint8 default_info_size;
3791 g_return_val_if_fail (qtdemux != NULL, NULL);
3792 g_return_val_if_fail (stream != NULL, NULL);
3793 g_return_val_if_fail (br != NULL, NULL);
3794 g_return_val_if_fail (sample_count != NULL, NULL);
3796 if (!gst_byte_reader_get_uint32_be (br, &flags))
3800 /* aux_info_type and aux_info_type_parameter are ignored */
3801 if (!gst_byte_reader_skip (br, 8))
3805 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3807 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3809 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3811 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3814 if (default_info_size == 0) {
3815 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3819 info_sizes = g_new (guint8, *sample_count);
3820 memset (info_sizes, default_info_size, *sample_count);
3826 /* Parses the offset of sample auxiliary information contained within a stream,
3827 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3829 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3830 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3835 guint32 aux_info_type = 0;
3836 guint32 aux_info_type_parameter = 0;
3837 guint32 entry_count;
3840 const guint8 *aux_info_type_data = NULL;
3842 g_return_val_if_fail (qtdemux != NULL, FALSE);
3843 g_return_val_if_fail (stream != NULL, FALSE);
3844 g_return_val_if_fail (br != NULL, FALSE);
3845 g_return_val_if_fail (offset != NULL, FALSE);
3847 if (!gst_byte_reader_get_uint8 (br, &version))
3850 if (!gst_byte_reader_get_uint24_be (br, &flags))
3855 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3857 aux_info_type = QT_FOURCC (aux_info_type_data);
3859 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3861 } else if (stream->protected) {
3862 aux_info_type = stream->protection_scheme_type;
3864 aux_info_type = CUR_STREAM (stream)->fourcc;
3868 *info_type = aux_info_type;
3869 if (info_type_parameter)
3870 *info_type_parameter = aux_info_type_parameter;
3872 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3873 "aux_info_type_parameter: %#06x",
3874 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3876 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3879 if (entry_count != 1) {
3880 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3885 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3887 *offset = (guint64) off_32;
3889 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3894 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3899 qtdemux_gst_structure_free (GstStructure * gststructure)
3902 gst_structure_free (gststructure);
3906 /* Parses auxiliary information relating to samples protected using
3907 * Common Encryption (cenc); the format of this information
3908 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3911 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3912 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3914 QtDemuxCencSampleSetInfo *ss_info = NULL;
3917 GPtrArray *old_crypto_info = NULL;
3918 guint old_entries = 0;
3920 g_return_val_if_fail (qtdemux != NULL, FALSE);
3921 g_return_val_if_fail (stream != NULL, FALSE);
3922 g_return_val_if_fail (br != NULL, FALSE);
3923 g_return_val_if_fail (stream->protected, FALSE);
3924 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3926 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3928 if (ss_info->crypto_info) {
3929 old_crypto_info = ss_info->crypto_info;
3930 /* Count number of non-null entries remaining at the tail end */
3931 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3932 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3938 ss_info->crypto_info =
3939 g_ptr_array_new_full (sample_count + old_entries,
3940 (GDestroyNotify) qtdemux_gst_structure_free);
3942 /* We preserve old entries because we parse the next moof in advance
3943 * of consuming all samples from the previous moof, and otherwise
3944 * we'd discard the corresponding crypto info for the samples
3945 * from the previous fragment. */
3947 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3949 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3950 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3952 g_ptr_array_index (old_crypto_info, i) = NULL;
3956 if (old_crypto_info) {
3957 /* Everything now belongs to the new array */
3958 g_ptr_array_free (old_crypto_info, TRUE);
3961 for (i = 0; i < sample_count; ++i) {
3962 GstStructure *properties;
3963 guint16 n_subsamples = 0;
3967 gboolean could_read_iv;
3969 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3970 if (properties == NULL) {
3971 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3974 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3975 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3976 gst_structure_free (properties);
3980 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3981 if (could_read_iv) {
3982 buf = gst_buffer_new_wrapped (data, iv_size);
3983 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3984 gst_buffer_unref (buf);
3985 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3986 const GValue *constant_iv_size_value =
3987 gst_structure_get_value (properties, "constant_iv_size");
3988 const GValue *constant_iv_value =
3989 gst_structure_get_value (properties, "iv");
3990 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3991 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3992 gst_structure_free (properties);
3995 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3996 gst_structure_remove_field (properties, "constant_iv_size");
3997 } else if (stream->protection_scheme_type == FOURCC_cenc) {
3998 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3999 gst_structure_free (properties);
4002 size = info_sizes[i];
4003 if (size > iv_size) {
4004 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
4005 || !(n_subsamples > 0)) {
4006 gst_structure_free (properties);
4007 GST_ERROR_OBJECT (qtdemux,
4008 "failed to get subsample count for sample %u", i);
4011 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
4012 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
4013 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
4015 gst_structure_free (properties);
4018 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
4020 gst_structure_free (properties);
4023 gst_structure_set (properties,
4024 "subsample_count", G_TYPE_UINT, n_subsamples,
4025 "subsamples", GST_TYPE_BUFFER, buf, NULL);
4026 gst_buffer_unref (buf);
4028 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
4030 g_ptr_array_add (ss_info->crypto_info, properties);
4035 /* Converts a UUID in raw byte form to a string representation, as defined in
4036 * RFC 4122. The caller takes ownership of the returned string and is
4037 * responsible for freeing it after use. */
4039 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
4041 const guint8 *uuid = (const guint8 *) uuid_bytes;
4043 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
4044 "%02x%02x-%02x%02x%02x%02x%02x%02x",
4045 uuid[0], uuid[1], uuid[2], uuid[3],
4046 uuid[4], uuid[5], uuid[6], uuid[7],
4047 uuid[8], uuid[9], uuid[10], uuid[11],
4048 uuid[12], uuid[13], uuid[14], uuid[15]);
4051 /* Parses a Protection System Specific Header box (pssh), as defined in the
4052 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
4053 * information needed by a specific content protection system in order to
4054 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
4057 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4059 gchar *sysid_string;
4060 guint32 pssh_size = QT_UINT32 (node->data);
4061 GstBuffer *pssh = NULL;
4062 GstEvent *event = NULL;
4063 guint32 parent_box_type;
4066 if (G_UNLIKELY (pssh_size < 32U)) {
4067 GST_ERROR_OBJECT (qtdemux, "invalid box size");
4072 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4074 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4076 pssh = gst_buffer_new_memdup (node->data, pssh_size);
4077 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4078 gst_buffer_get_size (pssh));
4080 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4082 /* Push an event containing the pssh box onto the queues of all streams. */
4083 event = gst_event_new_protection (sysid_string, pssh,
4084 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4085 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4086 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4087 GST_TRACE_OBJECT (qtdemux,
4088 "adding protection event for stream %s and system %s",
4089 stream->stream_id, sysid_string);
4090 g_queue_push_tail (&stream->protection_scheme_event_queue,
4091 gst_event_ref (event));
4093 g_free (sysid_string);
4094 gst_event_unref (event);
4095 gst_buffer_unref (pssh);
4100 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4101 guint64 moof_offset, QtDemuxStream * stream)
4103 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4105 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4106 GNode *saiz_node, *saio_node, *pssh_node;
4107 GstByteReader saiz_data, saio_data;
4108 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4109 gint64 base_offset, running_offset;
4111 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4113 /* NOTE @stream ignored */
4115 moof_node = g_node_new ((guint8 *) buffer);
4116 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4117 qtdemux_node_dump (qtdemux, moof_node);
4119 /* Get fragment number from mfhd and check it's valid */
4121 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4122 if (mfhd_node == NULL)
4124 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4126 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4128 /* unknown base_offset to start with */
4129 base_offset = running_offset = -1;
4130 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4132 guint64 decode_time = 0;
4134 /* Fragment Header node */
4136 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4140 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4141 &ds_size, &ds_flags, &base_offset))
4144 /* The following code assumes at most a single set of sample auxiliary
4145 * data in the fragment (consisting of a saiz box and a corresponding saio
4146 * box); in theory, however, there could be multiple sets of sample
4147 * auxiliary data in a fragment. */
4149 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4152 guint32 info_type = 0;
4154 guint32 info_type_parameter = 0;
4156 g_free (qtdemux->cenc_aux_info_sizes);
4158 qtdemux->cenc_aux_info_sizes =
4159 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4160 &qtdemux->cenc_aux_sample_count);
4161 if (qtdemux->cenc_aux_info_sizes == NULL) {
4162 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4166 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4169 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4170 g_free (qtdemux->cenc_aux_info_sizes);
4171 qtdemux->cenc_aux_info_sizes = NULL;
4175 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4176 &info_type, &info_type_parameter, &offset))) {
4177 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4178 g_free (qtdemux->cenc_aux_info_sizes);
4179 qtdemux->cenc_aux_info_sizes = NULL;
4182 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4183 offset += (guint64) (base_offset - qtdemux->moof_offset);
4184 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4185 && info_type_parameter == 0U) {
4187 if (offset > length) {
4188 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4189 qtdemux->cenc_aux_info_offset = offset;
4191 gst_byte_reader_init (&br, buffer + offset, length - offset);
4192 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4193 qtdemux->cenc_aux_info_sizes,
4194 qtdemux->cenc_aux_sample_count)) {
4195 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4196 g_free (qtdemux->cenc_aux_info_sizes);
4197 qtdemux->cenc_aux_info_sizes = NULL;
4205 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4208 /* We'll use decode_time to interpolate timestamps
4209 * in case the input timestamps are missing */
4210 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4212 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4213 " (%" GST_TIME_FORMAT ")", decode_time,
4214 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4215 decode_time) : GST_CLOCK_TIME_NONE));
4217 /* Discard the fragment buffer timestamp info to avoid using it.
4218 * Rely on tfdt instead as it is more accurate than the timestamp
4219 * that is fetched from a manifest/playlist and is usually
4221 qtdemux->fragment_start = -1;
4224 if (G_UNLIKELY (!stream)) {
4225 /* we lost track of offset, we'll need to regain it,
4226 * but can delay complaining until later or avoid doing so altogether */
4230 if (G_UNLIKELY (base_offset < -1))
4233 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4235 if (!qtdemux->pullbased) {
4236 /* Sample tables can grow enough to be problematic if the system memory
4237 * is very low (e.g. embedded devices) and the videos very long
4238 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4239 * Fortunately, we can easily discard them for each new fragment when
4240 * we know qtdemux will not receive seeks outside of the current fragment.
4241 * adaptivedemux honors this assumption.
4242 * This optimization is also useful for applications that use qtdemux as
4243 * a push-based simple demuxer, like Media Source Extensions. */
4244 gst_qtdemux_stream_flush_samples_data (stream);
4247 /* initialise moof sample data */
4248 stream->n_samples_moof = 0;
4249 stream->duration_last_moof = stream->duration_moof;
4250 stream->duration_moof = 0;
4252 /* Track Run node */
4254 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4257 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4258 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4259 &running_offset, decode_time, (tfdt_node != NULL));
4260 /* iterate all siblings */
4261 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4263 /* don't use tfdt for subsequent trun as it only refers to the first */
4267 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4269 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4270 guint32 box_length = QT_UINT32 (uuid_buffer);
4272 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4275 /* if no new base_offset provided for next traf,
4276 * base is end of current traf */
4277 base_offset = running_offset;
4278 running_offset = -1;
4280 if (stream->n_samples_moof && stream->duration_moof)
4281 stream->new_caps = TRUE;
4284 /* iterate all siblings */
4285 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4288 /* parse any protection system info */
4289 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4291 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4292 qtdemux_parse_pssh (qtdemux, pssh_node);
4293 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4296 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4297 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4299 /* Unless the user has explicitly requested another seek, perform an
4300 * internal seek to the time specified in the tfdt.
4302 * This way if the user opens a file where the first tfdt is 1 hour
4303 * into the presentation, they will not have to wait 1 hour for run
4304 * time to catch up and actual playback to start. */
4307 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4308 "performing an internal seek to %" GST_TIME_FORMAT,
4309 GST_TIME_ARGS (min_dts));
4311 qtdemux->segment.start = min_dts;
4312 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4314 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4315 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4316 stream->time_position = min_dts;
4319 /* Before this code was run a segment was already sent when the moov was
4320 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4321 * be emitted after a moov, and we can emit a second segment anyway for
4322 * special cases like this. */
4323 qtdemux->need_segment = TRUE;
4326 qtdemux->first_moof_already_parsed = TRUE;
4328 g_node_destroy (moof_node);
4333 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4338 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4343 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4348 g_node_destroy (moof_node);
4349 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4350 (_("This file is corrupt and cannot be played.")), (NULL));
4356 /* might be used if some day we actually use mfra & co
4357 * for random access to fragments,
4358 * but that will require quite some modifications and much less relying
4359 * on a sample array */
4363 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4365 QtDemuxStream *stream;
4366 guint32 ver_flags, track_id, len, num_entries, i;
4367 guint value_size, traf_size, trun_size, sample_size;
4368 guint64 time = 0, moof_offset = 0;
4370 GstBuffer *buf = NULL;
4375 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4377 if (!gst_byte_reader_skip (&tfra, 8))
4380 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4383 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4384 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4385 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4388 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4390 stream = qtdemux_find_stream (qtdemux, track_id);
4392 goto unknown_trackid;
4394 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4395 sample_size = (len & 3) + 1;
4396 trun_size = ((len & 12) >> 2) + 1;
4397 traf_size = ((len & 48) >> 4) + 1;
4399 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4400 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4402 if (num_entries == 0)
4405 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4406 value_size + value_size + traf_size + trun_size + sample_size))
4409 g_free (stream->ra_entries);
4410 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4411 stream->n_ra_entries = num_entries;
4413 for (i = 0; i < num_entries; i++) {
4414 qt_atom_parser_get_offset (&tfra, value_size, &time);
4415 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4416 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4417 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4418 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4420 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4422 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4423 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4425 stream->ra_entries[i].ts = time;
4426 stream->ra_entries[i].moof_offset = moof_offset;
4428 /* don't want to go through the entire file and read all moofs at startup */
4430 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4431 if (ret != GST_FLOW_OK)
4433 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4434 moof_offset, stream);
4435 gst_buffer_unref (buf);
4439 check_update_duration (qtdemux, time);
4446 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4451 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4456 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4462 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4464 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4465 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4466 GstBuffer *mfro = NULL, *mfra = NULL;
4468 gboolean ret = FALSE;
4469 GNode *mfra_node, *tfra_node;
4470 guint64 mfra_offset = 0;
4471 guint32 fourcc, mfra_size;
4474 /* query upstream size in bytes */
4475 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4476 goto size_query_failed;
4478 /* mfro box should be at the very end of the file */
4479 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4480 if (flow != GST_FLOW_OK)
4483 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4485 fourcc = QT_FOURCC (mfro_map.data + 4);
4486 if (fourcc != FOURCC_mfro)
4489 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4490 if (mfro_map.size < 16)
4491 goto invalid_mfro_size;
4493 mfra_size = QT_UINT32 (mfro_map.data + 12);
4494 if (mfra_size >= len)
4495 goto invalid_mfra_size;
4497 mfra_offset = len - mfra_size;
4499 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4500 mfra_offset, mfra_size);
4502 /* now get and parse mfra box */
4503 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4504 if (flow != GST_FLOW_OK)
4507 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4509 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4510 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4512 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4515 qtdemux_parse_tfra (qtdemux, tfra_node);
4516 /* iterate all siblings */
4517 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4519 g_node_destroy (mfra_node);
4521 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4527 if (mfro_map.memory != NULL)
4528 gst_buffer_unmap (mfro, &mfro_map);
4529 gst_buffer_unref (mfro);
4532 if (mfra_map.memory != NULL)
4533 gst_buffer_unmap (mfra, &mfra_map);
4534 gst_buffer_unref (mfra);
4541 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4546 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4551 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4556 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4562 add_offset (guint64 offset, guint64 advance)
4564 /* Avoid 64-bit overflow by clamping */
4565 if (offset > G_MAXUINT64 - advance)
4567 return offset + advance;
4570 static GstFlowReturn
4571 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4575 GstBuffer *buf = NULL;
4576 GstFlowReturn ret = GST_FLOW_OK;
4577 guint64 cur_offset = qtdemux->offset;
4580 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4581 if (G_UNLIKELY (ret != GST_FLOW_OK))
4583 gst_buffer_map (buf, &map, GST_MAP_READ);
4584 if (G_LIKELY (map.size >= 8))
4585 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4586 gst_buffer_unmap (buf, &map);
4587 gst_buffer_unref (buf);
4589 /* maybe we already got most we needed, so only consider this eof */
4590 if (G_UNLIKELY (length == 0)) {
4591 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4592 (_("Invalid atom size.")),
4593 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4594 GST_FOURCC_ARGS (fourcc)));
4601 /* record for later parsing when needed */
4602 if (!qtdemux->moof_offset) {
4603 qtdemux->moof_offset = qtdemux->offset;
4605 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4608 qtdemux->offset += length; /* skip moof and keep going */
4610 if (qtdemux->got_moov) {
4611 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4623 GST_LOG_OBJECT (qtdemux,
4624 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4625 GST_FOURCC_ARGS (fourcc), cur_offset);
4626 qtdemux->offset = add_offset (qtdemux->offset, length);
4631 GstBuffer *moov = NULL;
4633 if (qtdemux->got_moov) {
4634 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4635 qtdemux->offset = add_offset (qtdemux->offset, length);
4639 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4640 if (ret != GST_FLOW_OK)
4642 gst_buffer_map (moov, &map, GST_MAP_READ);
4644 if (length != map.size) {
4645 /* Some files have a 'moov' atom at the end of the file which contains
4646 * a terminal 'free' atom where the body of the atom is missing.
4647 * Check for, and permit, this special case.
4649 if (map.size >= 8) {
4650 guint8 *final_data = map.data + (map.size - 8);
4651 guint32 final_length = QT_UINT32 (final_data);
4652 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4654 if (final_fourcc == FOURCC_free
4655 && map.size + final_length - 8 == length) {
4656 /* Ok, we've found that special case. Allocate a new buffer with
4657 * that free atom actually present. */
4658 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4659 gst_buffer_fill (newmoov, 0, map.data, map.size);
4660 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4661 gst_buffer_unmap (moov, &map);
4662 gst_buffer_unref (moov);
4664 gst_buffer_map (moov, &map, GST_MAP_READ);
4669 if (length != map.size) {
4670 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4671 (_("This file is incomplete and cannot be played.")),
4672 ("We got less than expected (received %" G_GSIZE_FORMAT
4673 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4674 (guint) length, cur_offset));
4675 gst_buffer_unmap (moov, &map);
4676 gst_buffer_unref (moov);
4677 ret = GST_FLOW_ERROR;
4680 qtdemux->offset += length;
4682 qtdemux_parse_moov (qtdemux, map.data, length);
4683 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4685 qtdemux_parse_tree (qtdemux);
4686 if (qtdemux->moov_node_compressed) {
4687 g_node_destroy (qtdemux->moov_node_compressed);
4688 g_free (qtdemux->moov_node->data);
4690 qtdemux->moov_node_compressed = NULL;
4691 g_node_destroy (qtdemux->moov_node);
4692 qtdemux->moov_node = NULL;
4693 gst_buffer_unmap (moov, &map);
4694 gst_buffer_unref (moov);
4695 qtdemux->got_moov = TRUE;
4701 GstBuffer *ftyp = NULL;
4703 /* extract major brand; might come in handy for ISO vs QT issues */
4704 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4705 if (ret != GST_FLOW_OK)
4707 qtdemux->offset += length;
4708 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4709 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4710 gst_buffer_unmap (ftyp, &map);
4711 gst_buffer_unref (ftyp);
4716 GstBuffer *styp = NULL;
4718 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &styp);
4719 if (ret != GST_FLOW_OK)
4721 qtdemux->offset += length;
4722 gst_buffer_map (styp, &map, GST_MAP_READ);
4723 qtdemux_parse_styp (qtdemux, map.data, map.size);
4724 gst_buffer_unmap (styp, &map);
4725 gst_buffer_unref (styp);
4730 GstBuffer *uuid = NULL;
4732 /* uuid are extension atoms */
4733 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4734 if (ret != GST_FLOW_OK)
4736 qtdemux->offset += length;
4737 gst_buffer_map (uuid, &map, GST_MAP_READ);
4738 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4739 gst_buffer_unmap (uuid, &map);
4740 gst_buffer_unref (uuid);
4745 GstBuffer *sidx = NULL;
4746 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4747 if (ret != GST_FLOW_OK)
4749 qtdemux->offset += length;
4750 gst_buffer_map (sidx, &map, GST_MAP_READ);
4751 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4752 gst_buffer_unmap (sidx, &map);
4753 gst_buffer_unref (sidx);
4758 GstBuffer *meta = NULL;
4759 GNode *node, *child;
4760 GstByteReader child_data;
4761 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &meta);
4762 if (ret != GST_FLOW_OK)
4764 qtdemux->offset += length;
4765 gst_buffer_map (meta, &map, GST_MAP_READ);
4767 node = g_node_new (map.data);
4769 qtdemux_parse_node (qtdemux, node, map.data, map.size);
4771 /* Parse ONVIF Export File Format CorrectStartTime box if available */
4773 qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb,
4775 qtdemux_parse_cstb (qtdemux, &child_data);
4778 g_node_destroy (node);
4780 gst_buffer_unmap (meta, &map);
4781 gst_buffer_unref (meta);
4786 GstBuffer *unknown = NULL;
4788 GST_LOG_OBJECT (qtdemux,
4789 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4790 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4792 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4793 if (ret != GST_FLOW_OK)
4795 gst_buffer_map (unknown, &map, GST_MAP_READ);
4796 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4797 gst_buffer_unmap (unknown, &map);
4798 gst_buffer_unref (unknown);
4799 qtdemux->offset += length;
4805 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4806 /* digested all data, show what we have */
4807 qtdemux_prepare_streams (qtdemux);
4808 QTDEMUX_EXPOSE_LOCK (qtdemux);
4809 ret = qtdemux_expose_streams (qtdemux);
4810 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4812 qtdemux->state = QTDEMUX_STATE_MOVIE;
4813 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4820 /* Seeks to the previous keyframe of the indexed stream and
4821 * aligns other streams with respect to the keyframe timestamp
4822 * of indexed stream. Only called in case of Reverse Playback
4824 static GstFlowReturn
4825 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4827 guint32 seg_idx = 0, k_index = 0;
4828 guint32 ref_seg_idx, ref_k_index;
4829 GstClockTime k_pos = 0, last_stop = 0;
4830 QtDemuxSegment *seg = NULL;
4831 QtDemuxStream *ref_str = NULL;
4832 guint64 seg_media_start_mov; /* segment media start time in mov format */
4836 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4837 * and finally align all the other streams on that timestamp with their
4838 * respective keyframes */
4839 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4840 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4842 /* No candidate yet, take the first stream */
4848 /* So that stream has a segment, we prefer video streams */
4849 if (str->subtype == FOURCC_vide) {
4855 if (G_UNLIKELY (!ref_str)) {
4856 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4860 if (G_UNLIKELY (!ref_str->from_sample)) {
4861 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4865 /* So that stream has been playing from from_sample to to_sample. We will
4866 * get the timestamp of the previous sample and search for a keyframe before
4867 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4868 if (ref_str->subtype == FOURCC_vide) {
4869 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4870 ref_str->from_sample - 1, FALSE);
4872 if (ref_str->from_sample >= 10)
4873 k_index = ref_str->from_sample - 10;
4879 ref_str->samples[k_index].timestamp +
4880 ref_str->samples[k_index].pts_offset;
4882 /* get current segment for that stream */
4883 seg = &ref_str->segments[ref_str->segment_index];
4884 /* Use segment start in original timescale for comparisons */
4885 seg_media_start_mov = seg->trak_media_start;
4887 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4888 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4889 k_index, target_ts, seg_media_start_mov,
4890 GST_TIME_ARGS (seg->media_start));
4892 /* Crawl back through segments to find the one containing this I frame */
4893 while (target_ts < seg_media_start_mov) {
4894 GST_DEBUG_OBJECT (qtdemux,
4895 "keyframe position (sample %u) is out of segment %u " " target %"
4896 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4897 ref_str->segment_index, target_ts, seg_media_start_mov);
4899 if (G_UNLIKELY (!ref_str->segment_index)) {
4900 /* Reached first segment, let's consider it's EOS */
4903 ref_str->segment_index--;
4904 seg = &ref_str->segments[ref_str->segment_index];
4905 /* Use segment start in original timescale for comparisons */
4906 seg_media_start_mov = seg->trak_media_start;
4908 /* Calculate time position of the keyframe and where we should stop */
4910 QTSTREAMTIME_TO_GSTTIME (ref_str,
4911 target_ts - seg->trak_media_start) + seg->time;
4913 QTSTREAMTIME_TO_GSTTIME (ref_str,
4914 ref_str->samples[ref_str->from_sample].timestamp -
4915 seg->trak_media_start) + seg->time;
4917 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4918 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4919 k_index, GST_TIME_ARGS (k_pos));
4921 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4922 qtdemux->segment.position = last_stop;
4923 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4924 GST_TIME_ARGS (last_stop));
4926 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4927 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4931 ref_seg_idx = ref_str->segment_index;
4932 ref_k_index = k_index;
4934 /* Align them all on this */
4935 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4937 GstClockTime seg_time = 0;
4938 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4940 /* aligning reference stream again might lead to backing up to yet another
4941 * keyframe (due to timestamp rounding issues),
4942 * potentially putting more load on downstream; so let's try to avoid */
4943 if (str == ref_str) {
4944 seg_idx = ref_seg_idx;
4945 seg = &str->segments[seg_idx];
4946 k_index = ref_k_index;
4947 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4948 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4950 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4951 GST_DEBUG_OBJECT (qtdemux,
4952 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4953 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4955 /* get segment and time in the segment */
4956 seg = &str->segments[seg_idx];
4957 seg_time = k_pos - seg->time;
4959 /* get the media time in the segment.
4960 * No adjustment for empty "filler" segments */
4961 if (seg->media_start != GST_CLOCK_TIME_NONE)
4962 seg_time += seg->media_start;
4964 /* get the index of the sample with media time */
4965 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4966 GST_DEBUG_OBJECT (qtdemux,
4967 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4968 GST_TIME_ARGS (seg_time), index);
4970 /* find previous keyframe */
4971 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4974 /* Remember until where we want to go */
4975 str->to_sample = str->from_sample - 1;
4976 /* Define our time position */
4978 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4979 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4980 if (seg->media_start != GST_CLOCK_TIME_NONE)
4981 str->time_position -= seg->media_start;
4983 /* Now seek back in time */
4984 gst_qtdemux_move_stream (qtdemux, str, k_index);
4985 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4986 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4987 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4993 return GST_FLOW_EOS;
4997 * Gets the current qt segment start, stop and position for the
4998 * given time offset. This is used in update_segment()
5001 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
5002 QtDemuxStream * stream, GstClockTime offset,
5003 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
5005 GstClockTime seg_time;
5006 GstClockTime start, stop, time;
5007 QtDemuxSegment *segment;
5009 segment = &stream->segments[stream->segment_index];
5011 /* get time in this segment */
5012 seg_time = (offset - segment->time) * segment->rate;
5014 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
5015 GST_TIME_ARGS (seg_time));
5017 if (G_UNLIKELY (seg_time > segment->duration)) {
5018 GST_LOG_OBJECT (stream->pad,
5019 "seg_time > segment->duration %" GST_TIME_FORMAT,
5020 GST_TIME_ARGS (segment->duration));
5021 seg_time = segment->duration;
5024 /* qtdemux->segment.stop is in outside-time-realm, whereas
5025 * segment->media_stop is in track-time-realm.
5027 * In order to compare the two, we need to bring segment.stop
5028 * into the track-time-realm
5030 * FIXME - does this comment still hold? Don't see any conversion here */
5032 stop = qtdemux->segment.stop;
5033 if (stop == GST_CLOCK_TIME_NONE)
5034 stop = qtdemux->segment.duration;
5035 if (stop == GST_CLOCK_TIME_NONE)
5036 stop = segment->media_stop;
5039 MIN (segment->media_stop, stop - segment->time + segment->media_start);
5041 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5042 start = segment->time + seg_time;
5044 stop = start - seg_time + segment->duration;
5045 } else if (qtdemux->segment.rate >= 0) {
5046 start = MIN (segment->media_start + seg_time, stop);
5049 if (segment->media_start >= qtdemux->segment.start) {
5050 time = segment->time;
5052 time = segment->time + (qtdemux->segment.start - segment->media_start);
5055 start = MAX (segment->media_start, qtdemux->segment.start);
5056 stop = MIN (segment->media_start + seg_time, stop);
5065 * Updates the qt segment used for the stream and pushes a new segment event
5066 * downstream on this stream's pad.
5069 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5070 gint seg_idx, GstClockTime offset, GstClockTime * _start,
5071 GstClockTime * _stop)
5073 QtDemuxSegment *segment;
5074 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
5078 /* update the current segment */
5079 stream->segment_index = seg_idx;
5081 /* get the segment */
5082 segment = &stream->segments[seg_idx];
5084 if (G_UNLIKELY (offset < segment->time)) {
5085 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
5086 GST_TIME_ARGS (segment->time));
5090 /* segment lies beyond total indicated duration */
5091 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5092 segment->time > qtdemux->segment.duration)) {
5093 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5094 " < segment->time %" GST_TIME_FORMAT,
5095 GST_TIME_ARGS (qtdemux->segment.duration),
5096 GST_TIME_ARGS (segment->time));
5100 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5101 &start, &stop, &time);
5103 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5104 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5105 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5107 /* combine global rate with that of the segment */
5108 rate = segment->rate * qtdemux->segment.rate;
5110 /* Copy flags from main segment */
5111 stream->segment.flags = qtdemux->segment.flags;
5113 /* update the segment values used for clipping */
5114 stream->segment.offset = qtdemux->segment.offset;
5115 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5116 stream->segment.applied_rate = qtdemux->segment.applied_rate;
5117 stream->segment.rate = rate;
5118 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5119 stream->cslg_shift);
5121 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5122 stream->cslg_shift);
5124 stream->segment.stop = stop;
5125 stream->segment.time = time;
5126 stream->segment.position = stream->segment.start;
5128 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5131 /* now prepare and send the segment */
5133 event = gst_event_new_segment (&stream->segment);
5134 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5135 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5137 gst_pad_push_event (stream->pad, event);
5138 /* assume we can send more data now */
5139 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5140 /* clear to send tags on this pad now */
5141 gst_qtdemux_push_tags (qtdemux, stream);
5152 /* activate the given segment number @seg_idx of @stream at time @offset.
5153 * @offset is an absolute global position over all the segments.
5155 * This will push out a NEWSEGMENT event with the right values and
5156 * position the stream index to the first decodable sample before
5160 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5161 guint32 seg_idx, GstClockTime offset)
5163 QtDemuxSegment *segment;
5164 guint32 index, kf_index;
5165 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5167 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5168 seg_idx, GST_TIME_ARGS (offset));
5170 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5174 segment = &stream->segments[stream->segment_index];
5176 /* in the fragmented case, we pick a fragment that starts before our
5177 * desired position and rely on downstream to wait for a keyframe
5178 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5179 * tfra entries tells us which trun/sample the key unit is in, but we don't
5180 * make use of this additional information at the moment) */
5181 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5182 stream->to_sample = G_MAXUINT32;
5185 /* well, it will be taken care of below */
5186 qtdemux->fragmented_seek_pending = FALSE;
5187 /* FIXME ideally the do_fragmented_seek can be done right here,
5188 * rather than at loop level
5189 * (which might even allow handling edit lists in a fragmented file) */
5192 /* We don't need to look for a sample in push-based */
5193 if (!qtdemux->pullbased)
5196 /* and move to the keyframe before the indicated media time of the
5198 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5199 if (qtdemux->segment.rate >= 0) {
5200 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5201 stream->to_sample = G_MAXUINT32;
5202 GST_DEBUG_OBJECT (stream->pad,
5203 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5204 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5205 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5207 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5208 stream->to_sample = index;
5209 GST_DEBUG_OBJECT (stream->pad,
5210 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5211 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5212 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5215 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5216 "this is an empty segment");
5220 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5221 * encountered an error and printed a message so we return appropriately */
5225 /* we're at the right spot */
5226 if (index == stream->sample_index) {
5227 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5231 /* find keyframe of the target index */
5232 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5234 /* go back two frames to provide lead-in for non-raw audio decoders */
5235 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5236 guint32 lead_in = 2;
5237 guint32 old_index = kf_index;
5238 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5240 if (gst_structure_has_name (s, "audio/mpeg")) {
5242 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5243 && mpegversion == 1) {
5244 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5249 kf_index = MAX (kf_index, lead_in) - lead_in;
5250 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5251 GST_DEBUG_OBJECT (stream->pad,
5252 "Moving backwards %u frames to ensure sufficient sound lead-in",
5253 old_index - kf_index);
5255 kf_index = old_index;
5259 /* if we move forwards, we don't have to go back to the previous
5260 * keyframe since we already sent that. We can also just jump to
5261 * the keyframe right before the target index if there is one. */
5262 if (index > stream->sample_index) {
5263 /* moving forwards check if we move past a keyframe */
5264 if (kf_index > stream->sample_index) {
5265 GST_DEBUG_OBJECT (stream->pad,
5266 "moving forwards to keyframe at %u "
5267 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5269 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5270 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5271 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5273 GST_DEBUG_OBJECT (stream->pad,
5274 "moving forwards, keyframe at %u "
5275 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5277 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5278 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5281 GST_DEBUG_OBJECT (stream->pad,
5282 "moving backwards to %sframe at %u "
5283 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5284 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5285 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5286 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5287 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5293 /* prepare to get the current sample of @stream, getting essential values.
5295 * This function will also prepare and send the segment when needed.
5297 * Return FALSE if the stream is EOS.
5302 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5303 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5304 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5305 gboolean * keyframe)
5307 QtDemuxSample *sample;
5308 GstClockTime time_position;
5311 g_return_val_if_fail (stream != NULL, FALSE);
5313 time_position = stream->time_position;
5314 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5317 seg_idx = stream->segment_index;
5318 if (G_UNLIKELY (seg_idx == -1)) {
5319 /* find segment corresponding to time_position if we are looking
5321 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5324 /* different segment, activate it, sample_index will be set. */
5325 if (G_UNLIKELY (stream->segment_index != seg_idx))
5326 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5328 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5329 segments[stream->segment_index]))) {
5330 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5332 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5333 " prepare empty sample");
5336 *pts = *dts = time_position;
5337 *duration = seg->duration - (time_position - seg->time);
5344 if (stream->sample_index == -1)
5345 stream->sample_index = 0;
5347 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5348 stream->sample_index, stream->n_samples);
5350 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5351 if (!qtdemux->fragmented)
5354 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5358 GST_OBJECT_LOCK (qtdemux);
5359 flow = qtdemux_add_fragmented_samples (qtdemux);
5360 GST_OBJECT_UNLOCK (qtdemux);
5362 if (flow != GST_FLOW_OK)
5365 while (stream->sample_index >= stream->n_samples);
5368 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5369 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5370 stream->sample_index);
5374 /* now get the info for the sample we're at */
5375 sample = &stream->samples[stream->sample_index];
5377 *dts = QTSAMPLE_DTS (stream, sample);
5378 *pts = QTSAMPLE_PTS (stream, sample);
5379 *offset = sample->offset;
5380 *size = sample->size;
5381 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5382 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5389 stream->time_position = GST_CLOCK_TIME_NONE;
5394 /* move to the next sample in @stream.
5396 * Moves to the next segment when needed.
5399 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5401 QtDemuxSample *sample;
5402 QtDemuxSegment *segment;
5404 /* get current segment */
5405 segment = &stream->segments[stream->segment_index];
5407 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5408 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5412 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5413 /* Mark the stream as EOS */
5414 GST_DEBUG_OBJECT (qtdemux,
5415 "reached max allowed sample %u, mark EOS", stream->to_sample);
5416 stream->time_position = GST_CLOCK_TIME_NONE;
5420 /* move to next sample */
5421 stream->sample_index++;
5422 stream->offset_in_sample = 0;
5424 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5427 /* reached the last sample, we need the next segment */
5428 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5431 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5432 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5433 stream->sample_index);
5437 /* get next sample */
5438 sample = &stream->samples[stream->sample_index];
5440 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5441 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5442 GST_TIME_ARGS (segment->media_stop));
5444 /* see if we are past the segment */
5445 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5448 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5449 /* inside the segment, update time_position, looks very familiar to
5450 * GStreamer segments, doesn't it? */
5451 stream->time_position =
5452 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5454 /* not yet in segment, time does not yet increment. This means
5455 * that we are still prerolling keyframes to the decoder so it can
5456 * decode the first sample of the segment. */
5457 stream->time_position = segment->time;
5461 /* move to the next segment */
5464 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5466 if (stream->segment_index == stream->n_segments - 1) {
5467 /* are we at the end of the last segment, we're EOS */
5468 stream->time_position = GST_CLOCK_TIME_NONE;
5470 /* else we're only at the end of the current segment */
5471 stream->time_position = segment->stop_time;
5473 /* make sure we select a new segment */
5475 /* accumulate previous segments */
5476 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5477 stream->accumulated_base +=
5478 (stream->segment.stop -
5479 stream->segment.start) / ABS (stream->segment.rate);
5481 stream->segment_index = -1;
5486 gst_qtdemux_sync_streams (GstQTDemux * demux)
5490 if (QTDEMUX_N_STREAMS (demux) <= 1)
5493 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5494 QtDemuxStream *stream;
5495 GstClockTime end_time;
5497 stream = QTDEMUX_NTH_STREAM (demux, i);
5502 /* TODO advance time on subtitle streams here, if any some day */
5504 /* some clips/trailers may have unbalanced streams at the end,
5505 * so send EOS on shorter stream to prevent stalling others */
5507 /* do not mess with EOS if SEGMENT seeking */
5508 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5511 if (demux->pullbased) {
5512 /* loop mode is sample time based */
5513 if (!STREAM_IS_EOS (stream))
5516 /* push mode is byte position based */
5517 if (stream->n_samples &&
5518 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5522 if (stream->sent_eos)
5525 /* only act if some gap */
5526 end_time = stream->segments[stream->n_segments - 1].stop_time;
5527 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5528 ", stream end: %" GST_TIME_FORMAT,
5529 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5530 if (GST_CLOCK_TIME_IS_VALID (end_time)
5531 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5534 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5535 GST_PAD_NAME (stream->pad));
5536 stream->sent_eos = TRUE;
5537 event = gst_event_new_eos ();
5538 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5539 gst_event_set_seqnum (event, demux->segment_seqnum);
5540 gst_pad_push_event (stream->pad, event);
5545 /* EOS and NOT_LINKED need to be combined. This means that we return:
5547 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5548 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5550 static GstFlowReturn
5551 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5554 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5557 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5560 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5562 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5566 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5567 * completely clipped
5569 * Should be used only with raw buffers */
5571 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5574 guint64 start, stop, cstart, cstop, diff;
5575 GstClockTime pts, duration;
5577 gint num_rate, denom_rate;
5582 osize = size = gst_buffer_get_size (buf);
5585 /* depending on the type, setup the clip parameters */
5586 if (stream->subtype == FOURCC_soun) {
5587 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5588 num_rate = GST_SECOND;
5589 denom_rate = (gint) CUR_STREAM (stream)->rate;
5591 } else if (stream->subtype == FOURCC_vide) {
5593 num_rate = CUR_STREAM (stream)->fps_n;
5594 denom_rate = CUR_STREAM (stream)->fps_d;
5599 if (frame_size <= 0)
5600 goto bad_frame_size;
5602 /* we can only clip if we have a valid pts */
5603 pts = GST_BUFFER_PTS (buf);
5604 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5607 duration = GST_BUFFER_DURATION (buf);
5609 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5611 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5615 stop = start + duration;
5617 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5618 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5621 /* see if some clipping happened */
5622 diff = cstart - start;
5628 /* bring clipped time to samples and to bytes */
5629 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5632 GST_DEBUG_OBJECT (qtdemux,
5633 "clipping start to %" GST_TIME_FORMAT " %"
5634 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5640 diff = stop - cstop;
5645 /* bring clipped time to samples and then to bytes */
5646 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5648 GST_DEBUG_OBJECT (qtdemux,
5649 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5650 " bytes", GST_TIME_ARGS (cstop), diff);
5655 if (offset != 0 || size != osize)
5656 gst_buffer_resize (buf, offset, size);
5658 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5659 GST_BUFFER_PTS (buf) = pts;
5660 GST_BUFFER_DURATION (buf) = duration;
5664 /* dropped buffer */
5667 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5672 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5677 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5682 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5683 gst_buffer_unref (buf);
5689 gst_qtdemux_align_buffer (GstQTDemux * demux,
5690 GstBuffer * buffer, gsize alignment)
5694 gst_buffer_map (buffer, &map, GST_MAP_READ);
5696 if (map.size < sizeof (guintptr)) {
5697 gst_buffer_unmap (buffer, &map);
5701 if (((guintptr) map.data) & (alignment - 1)) {
5702 GstBuffer *new_buffer;
5703 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5705 new_buffer = gst_buffer_new_allocate (NULL,
5706 gst_buffer_get_size (buffer), ¶ms);
5708 /* Copy data "by hand", so ensure alignment is kept: */
5709 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5711 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5712 GST_DEBUG_OBJECT (demux,
5713 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5716 gst_buffer_unmap (buffer, &map);
5717 gst_buffer_unref (buffer);
5722 gst_buffer_unmap (buffer, &map);
5727 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5733 /* We are converting from pairs to triplets */
5734 *res = ccpair_size / 2 * 3;
5735 storage = g_malloc (*res);
5736 for (i = 0; i * 2 < ccpair_size; i += 1) {
5737 /* FIXME: Use line offset 0 as we simply can't know here */
5739 storage[i * 3] = 0x80 | 0x00;
5741 storage[i * 3] = 0x00 | 0x00;
5742 storage[i * 3 + 1] = ccpair[i * 2];
5743 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5750 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5754 guint32 atom_length, fourcc;
5755 QtDemuxStreamStsdEntry *stsd_entry;
5757 GST_MEMDUMP ("caption atom", data, size);
5759 /* There might be multiple atoms */
5764 atom_length = QT_UINT32 (data);
5765 fourcc = QT_FOURCC (data + 4);
5766 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5769 GST_DEBUG_OBJECT (stream->pad, "here");
5771 /* Check if we have something compatible */
5772 stsd_entry = CUR_STREAM (stream);
5773 switch (stsd_entry->fourcc) {
5775 guint8 *cdat = NULL, *cdt2 = NULL;
5776 gsize cdat_size = 0, cdt2_size = 0;
5777 /* Should be cdat or cdt2 */
5778 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5779 GST_WARNING_OBJECT (stream->pad,
5780 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5781 GST_FOURCC_ARGS (fourcc));
5785 /* Convert to S334-1 Annex A byte triplet */
5786 if (fourcc == FOURCC_cdat)
5787 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5789 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5790 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5793 /* Check for another atom ? */
5794 if (size > atom_length + 8) {
5795 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5796 if (size >= atom_length + new_atom_length) {
5797 fourcc = QT_FOURCC (data + atom_length + 4);
5798 if (fourcc == FOURCC_cdat) {
5801 convert_to_s334_1a (data + atom_length + 8,
5802 new_atom_length - 8, 1, &cdat_size);
5804 GST_WARNING_OBJECT (stream->pad,
5805 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5809 convert_to_s334_1a (data + atom_length + 8,
5810 new_atom_length - 8, 2, &cdt2_size);
5812 GST_WARNING_OBJECT (stream->pad,
5813 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5818 *cclen = cdat_size + cdt2_size;
5819 res = g_malloc (*cclen);
5821 memcpy (res, cdat, cdat_size);
5823 memcpy (res + cdat_size, cdt2, cdt2_size);
5829 if (fourcc != FOURCC_ccdp) {
5830 GST_WARNING_OBJECT (stream->pad,
5831 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5832 GST_FOURCC_ARGS (fourcc));
5835 *cclen = atom_length - 8;
5836 res = g_memdup2 (data + 8, *cclen);
5839 /* Keep this here in case other closed caption formats are added */
5840 g_assert_not_reached ();
5844 GST_MEMDUMP ("Output", res, *cclen);
5849 GST_WARNING ("[cdat] atom is too small or invalid");
5853 /* Handle Closed Caption sample buffers.
5854 * The input buffer metadata must be writable,
5855 * but time/duration etc not yet set and need not be preserved */
5857 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5860 GstBuffer *outbuf = NULL;
5865 gst_buffer_map (buf, &map, GST_MAP_READ);
5867 /* empty buffer is sent to terminate previous subtitle */
5868 if (map.size <= 2) {
5869 gst_buffer_unmap (buf, &map);
5870 gst_buffer_unref (buf);
5874 /* For closed caption, we need to extract the information from the
5875 * [cdat],[cdt2] or [ccdp] atom */
5876 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5877 gst_buffer_unmap (buf, &map);
5879 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5880 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5882 /* Conversion failed or there's nothing */
5884 gst_buffer_unref (buf);
5889 /* DVD subpicture specific sample handling.
5890 * the input buffer metadata must be writable,
5891 * but time/duration etc not yet set and need not be preserved */
5893 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5896 /* send a one time dvd clut event */
5897 if (stream->pending_event && stream->pad)
5898 gst_pad_push_event (stream->pad, stream->pending_event);
5899 stream->pending_event = NULL;
5901 /* empty buffer is sent to terminate previous subtitle */
5902 if (gst_buffer_get_size (buf) <= 2) {
5903 gst_buffer_unref (buf);
5907 /* That's all the processing needed for subpictures */
5911 /* Timed text formats
5912 * the input buffer metadata must be writable,
5913 * but time/duration etc not yet set and need not be preserved */
5915 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5918 GstBuffer *outbuf = NULL;
5923 /* not many cases for now */
5924 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5925 stream->subtype != FOURCC_sbtl)) {
5929 gst_buffer_map (buf, &map, GST_MAP_READ);
5931 /* empty buffer is sent to terminate previous subtitle */
5932 if (map.size <= 2) {
5933 gst_buffer_unmap (buf, &map);
5934 gst_buffer_unref (buf);
5938 nsize = GST_READ_UINT16_BE (map.data);
5939 nsize = MIN (nsize, map.size - 2);
5941 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5944 /* takes care of UTF-8 validation or UTF-16 recognition,
5945 * no other encoding expected */
5946 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5947 gst_buffer_unmap (buf, &map);
5950 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5951 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5953 /* this should not really happen unless the subtitle is corrupted */
5955 gst_buffer_unref (buf);
5957 /* FIXME ? convert optional subsequent style info to markup */
5962 /* WebVTT sample handling according to 14496-30 */
5964 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5967 GstBuffer *outbuf = NULL;
5970 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5971 g_assert_not_reached (); /* The buffer must be mappable */
5974 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5975 GstEvent *gap = NULL;
5976 /* Push a gap event */
5977 stream->segment.position = GST_BUFFER_PTS (buf);
5979 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5980 gst_pad_push_event (stream->pad, gap);
5982 if (GST_BUFFER_DURATION_IS_VALID (buf))
5983 stream->segment.position += GST_BUFFER_DURATION (buf);
5986 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5987 GST_BUFFER_DURATION (buf), map.data, map.size);
5988 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5991 gst_buffer_unmap (buf, &map);
5992 gst_buffer_unref (buf);
5997 static GstFlowReturn
5998 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6001 GstFlowReturn ret = GST_FLOW_OK;
6002 GstClockTime pts, duration;
6004 if (stream->need_clip)
6005 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
6007 if (G_UNLIKELY (buf == NULL))
6010 if (G_UNLIKELY (stream->discont)) {
6011 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6012 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
6013 stream->discont = FALSE;
6015 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6018 GST_LOG_OBJECT (qtdemux,
6019 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
6020 ", duration %" GST_TIME_FORMAT " on pad %s",
6021 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
6022 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
6023 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
6025 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
6026 GstStructure *crypto_info;
6027 QtDemuxAavdEncryptionInfo *info =
6028 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
6030 crypto_info = gst_structure_copy (info->default_properties);
6031 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6032 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
6035 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
6036 || stream->protection_scheme_type == FOURCC_cbcs)) {
6037 GstStructure *crypto_info;
6038 QtDemuxCencSampleSetInfo *info =
6039 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6043 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
6044 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
6045 GST_PTR_FORMAT, event);
6046 gst_pad_push_event (stream->pad, event);
6049 if (info->crypto_info == NULL) {
6050 if (stream->protection_scheme_type == FOURCC_cbcs) {
6051 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
6052 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
6053 GST_ERROR_OBJECT (qtdemux,
6054 "failed to attach cbcs metadata to buffer");
6055 qtdemux_gst_structure_free (crypto_info);
6057 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
6060 GST_DEBUG_OBJECT (qtdemux,
6061 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
6064 /* The end of the crypto_info array matches our n_samples position,
6065 * so count backward from there */
6066 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
6067 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
6068 /* steal structure from array */
6069 crypto_info = g_ptr_array_index (info->crypto_info, index);
6070 g_ptr_array_index (info->crypto_info, index) = NULL;
6071 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
6072 info->crypto_info->len);
6073 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6074 GST_ERROR_OBJECT (qtdemux,
6075 "failed to attach cenc metadata to buffer");
6077 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
6078 index, stream->sample_index);
6083 if (stream->alignment > 1)
6084 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6086 pts = GST_BUFFER_PTS (buf);
6087 duration = GST_BUFFER_DURATION (buf);
6089 ret = gst_pad_push (stream->pad, buf);
6091 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6092 /* mark position in stream, we'll need this to know when to send GAP event */
6093 stream->segment.position = pts + duration;
6101 static GstFlowReturn
6102 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6105 GstFlowReturn ret = GST_FLOW_OK;
6107 if (stream->subtype == FOURCC_clcp
6108 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6110 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6111 guint n_triplets, i;
6112 guint field1_off = 0, field2_off = 0;
6114 /* We have to split CEA608 buffers so that each outgoing buffer contains
6115 * one byte pair per field according to the framerate of the video track.
6117 * If there is only a single byte pair per field we don't have to do
6121 gst_buffer_map (buf, &map, GST_MAP_READ);
6123 n_triplets = map.size / 3;
6124 for (i = 0; i < n_triplets; i++) {
6125 if (map.data[3 * i] & 0x80)
6131 g_assert (n_field1 || n_field2);
6133 /* If there's more than 1 frame we have to split, otherwise we can just
6135 if (n_field1 > 1 || n_field2 > 1) {
6137 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6138 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6140 for (i = 0; i < n_output_buffers; i++) {
6142 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6146 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6147 outptr = outmap.data;
6150 gboolean found = FALSE;
6152 while (map.data + field1_off < map.data + map.size) {
6153 if (map.data[field1_off] & 0x80) {
6154 memcpy (outptr, &map.data[field1_off], 3);
6163 const guint8 empty[] = { 0x80, 0x80, 0x80 };
6165 memcpy (outptr, empty, 3);
6172 gboolean found = FALSE;
6174 while (map.data + field2_off < map.data + map.size) {
6175 if ((map.data[field2_off] & 0x80) == 0) {
6176 memcpy (outptr, &map.data[field2_off], 3);
6185 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6187 memcpy (outptr, empty, 3);
6193 gst_buffer_unmap (outbuf, &outmap);
6195 GST_BUFFER_PTS (outbuf) =
6196 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6197 GST_SECOND * CUR_STREAM (stream)->fps_d,
6198 CUR_STREAM (stream)->fps_n);
6199 GST_BUFFER_DURATION (outbuf) =
6200 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6201 CUR_STREAM (stream)->fps_n);
6202 GST_BUFFER_OFFSET (outbuf) = -1;
6203 GST_BUFFER_OFFSET_END (outbuf) = -1;
6205 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6207 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6210 gst_buffer_unmap (buf, &map);
6211 gst_buffer_unref (buf);
6213 gst_buffer_unmap (buf, &map);
6214 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6217 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6223 /* Sets a buffer's attributes properly and pushes it downstream.
6224 * Also checks for additional actions and custom processing that may
6225 * need to be done first.
6227 static GstFlowReturn
6228 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6229 QtDemuxStream * stream, GstBuffer * buf,
6230 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6231 gboolean keyframe, GstClockTime position, guint64 byte_position)
6233 GstFlowReturn ret = GST_FLOW_OK;
6235 /* offset the timestamps according to the edit list */
6237 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6241 gst_buffer_map (buf, &map, GST_MAP_READ);
6242 url = g_strndup ((gchar *) map.data, map.size);
6243 gst_buffer_unmap (buf, &map);
6244 if (url != NULL && strlen (url) != 0) {
6245 /* we have RTSP redirect now */
6246 g_free (qtdemux->redirect_location);
6247 qtdemux->redirect_location = g_strdup (url);
6248 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6249 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6250 gst_structure_new ("redirect",
6251 "new-location", G_TYPE_STRING, url, NULL)));
6253 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6259 /* position reporting */
6260 if (qtdemux->segment.rate >= 0) {
6261 qtdemux->segment.position = position;
6262 gst_qtdemux_sync_streams (qtdemux);
6265 if (G_UNLIKELY (!stream->pad)) {
6266 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6267 gst_buffer_unref (buf);
6271 /* send out pending buffers */
6272 while (stream->buffers) {
6273 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6275 if (G_UNLIKELY (stream->discont)) {
6276 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6277 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6278 stream->discont = FALSE;
6280 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6283 if (stream->alignment > 1)
6284 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6285 gst_pad_push (stream->pad, buffer);
6287 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6290 /* we're going to modify the metadata */
6291 buf = gst_buffer_make_writable (buf);
6293 if (qtdemux->start_utc_time != GST_CLOCK_TIME_NONE) {
6294 static GstStaticCaps unix_caps = GST_STATIC_CAPS ("timestamp/x-unix");
6295 GstCaps *caps = gst_static_caps_get (&unix_caps);
6296 gst_buffer_add_reference_timestamp_meta (buf, caps,
6297 pts + qtdemux->start_utc_time - stream->cslg_shift,
6298 GST_CLOCK_TIME_NONE);
6299 gst_caps_unref (caps);
6302 GST_BUFFER_DTS (buf) = dts;
6303 GST_BUFFER_PTS (buf) = pts;
6304 GST_BUFFER_DURATION (buf) = duration;
6305 GST_BUFFER_OFFSET (buf) = -1;
6306 GST_BUFFER_OFFSET_END (buf) = -1;
6308 if (G_UNLIKELY (stream->process_func))
6309 buf = stream->process_func (qtdemux, stream, buf);
6316 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6317 stream->on_keyframe = FALSE;
6319 stream->on_keyframe = TRUE;
6322 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6323 gst_buffer_append_memory (buf,
6324 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6326 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6327 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6330 if (G_UNLIKELY (qtdemux->element_index)) {
6331 GstClockTime stream_time;
6334 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6336 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6337 GST_LOG_OBJECT (qtdemux,
6338 "adding association %" GST_TIME_FORMAT "-> %"
6339 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6340 gst_index_add_association (qtdemux->element_index,
6342 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6343 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6344 GST_FORMAT_BYTES, byte_position, NULL);
6349 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6355 static const QtDemuxRandomAccessEntry *
6356 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6357 GstClockTime pos, gboolean after)
6359 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6360 guint n_entries = stream->n_ra_entries;
6363 /* we assume the table is sorted */
6364 for (i = 0; i < n_entries; ++i) {
6365 if (entries[i].ts > pos)
6369 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6370 * probably okay to assume that the index lists the very first fragment */
6377 return &entries[i - 1];
6381 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6383 const QtDemuxRandomAccessEntry *best_entry = NULL;
6386 GST_OBJECT_LOCK (qtdemux);
6388 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6390 /* first see if we can determine where to go to using mfra,
6391 * before we start clearing things */
6392 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6393 const QtDemuxRandomAccessEntry *entry;
6394 QtDemuxStream *stream;
6395 gboolean is_audio_or_video;
6397 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6399 if (stream->ra_entries == NULL)
6402 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6403 is_audio_or_video = TRUE;
6405 is_audio_or_video = FALSE;
6408 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6409 stream->time_position, !is_audio_or_video);
6411 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6412 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6414 stream->pending_seek = entry;
6416 /* decide position to jump to just based on audio/video tracks, not subs */
6417 if (!is_audio_or_video)
6420 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6424 /* no luck, will handle seek otherwise */
6425 if (best_entry == NULL) {
6426 GST_OBJECT_UNLOCK (qtdemux);
6430 /* ok, now we can prepare for processing as of located moof */
6431 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6432 QtDemuxStream *stream;
6434 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6436 g_free (stream->samples);
6437 stream->samples = NULL;
6438 stream->n_samples = 0;
6439 stream->stbl_index = -1; /* no samples have yet been parsed */
6440 stream->sample_index = -1;
6442 if (stream->protection_scheme_info) {
6443 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6444 if (stream->protection_scheme_type == FOURCC_cenc
6445 || stream->protection_scheme_type == FOURCC_cbcs) {
6446 QtDemuxCencSampleSetInfo *info =
6447 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6448 if (info->crypto_info) {
6449 g_ptr_array_free (info->crypto_info, TRUE);
6450 info->crypto_info = NULL;
6456 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6457 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6458 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6459 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6461 qtdemux->moof_offset = best_entry->moof_offset;
6463 qtdemux_add_fragmented_samples (qtdemux);
6465 GST_OBJECT_UNLOCK (qtdemux);
6469 static GstFlowReturn
6470 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6472 GstFlowReturn ret = GST_FLOW_OK;
6473 GstBuffer *buf = NULL;
6474 QtDemuxStream *stream, *target_stream = NULL;
6475 GstClockTime min_time;
6477 GstClockTime dts = GST_CLOCK_TIME_NONE;
6478 GstClockTime pts = GST_CLOCK_TIME_NONE;
6479 GstClockTime duration = 0;
6480 gboolean keyframe = FALSE;
6481 guint sample_size = 0;
6482 guint num_samples = 1;
6487 if (qtdemux->fragmented_seek_pending) {
6488 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6489 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6490 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6491 qtdemux->fragmented_seek_pending = FALSE;
6493 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6497 /* Figure out the next stream sample to output, min_time is expressed in
6498 * global time and runs over the edit list segments. */
6499 min_time = G_MAXUINT64;
6500 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6501 GstClockTime position;
6503 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6504 position = stream->time_position;
6506 if (!GST_CLOCK_TIME_IS_VALID (position))
6509 if (stream->segment_index != -1) {
6510 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6511 position += segment->media_start;
6514 /* position of -1 is EOS */
6515 if (position < min_time) {
6516 min_time = position;
6517 target_stream = stream;
6521 if (G_UNLIKELY (target_stream == NULL)) {
6522 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6526 /* check for segment end */
6527 if (G_UNLIKELY (qtdemux->segment.stop != -1
6528 && qtdemux->segment.rate >= 0
6529 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6530 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6531 target_stream->time_position = GST_CLOCK_TIME_NONE;
6535 /* fetch info for the current sample of this stream */
6536 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, target_stream,
6537 &empty, &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6540 /* Send catche-up GAP event for each other stream if required.
6541 * This logic will be applied only for positive rate */
6542 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux) &&
6543 qtdemux->segment.rate >= 0; i++) {
6544 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6546 if (stream == target_stream ||
6547 !GST_CLOCK_TIME_IS_VALID (stream->segment.stop) ||
6548 !GST_CLOCK_TIME_IS_VALID (stream->segment.position))
6552 GstClockTime gap_threshold;
6553 /* kind of running time with offset segment.base and segment.start */
6554 GstClockTime pseudo_target_time = target_stream->segment.base;
6555 GstClockTime pseudo_cur_time = stream->segment.base;
6557 /* make sure positive offset, segment.position can be smallr than
6558 * segment.start for some reasons */
6559 if (target_stream->segment.position >= target_stream->segment.start) {
6560 pseudo_target_time +=
6561 (target_stream->segment.position - target_stream->segment.start);
6564 if (stream->segment.position >= stream->segment.start)
6565 pseudo_cur_time += (stream->segment.position - stream->segment.start);
6567 /* Only send gap events on non-subtitle streams if lagging way behind. */
6568 if (stream->subtype == FOURCC_subp
6569 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6570 stream->subtype == FOURCC_wvtt)
6571 gap_threshold = 1 * GST_SECOND;
6573 gap_threshold = 3 * GST_SECOND;
6575 /* send gap events until the stream catches up */
6576 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6577 while (GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6578 pseudo_cur_time + gap_threshold < pseudo_target_time) {
6580 gst_event_new_gap (stream->segment.position, gap_threshold);
6581 GST_LOG_OBJECT (stream->pad, "Sending %" GST_PTR_FORMAT, gap);
6583 gst_pad_push_event (stream->pad, gap);
6584 stream->segment.position += gap_threshold;
6585 pseudo_cur_time += gap_threshold;
6590 stream = target_stream;
6592 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6593 if (stream->new_caps) {
6594 gst_qtdemux_configure_stream (qtdemux, stream);
6595 qtdemux_do_allocation (stream, qtdemux);
6598 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6599 if (G_UNLIKELY (qtdemux->segment.
6600 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6601 if (stream->subtype == FOURCC_vide) {
6603 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6606 } else if (qtdemux->trickmode_interval > 0) {
6607 GstClockTimeDiff interval;
6609 if (qtdemux->segment.rate > 0)
6610 interval = stream->time_position - stream->last_keyframe_dts;
6612 interval = stream->last_keyframe_dts - stream->time_position;
6614 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6615 && interval < qtdemux->trickmode_interval) {
6616 GST_LOG_OBJECT (qtdemux,
6617 "Skipping keyframe within interval on track-id %u",
6621 stream->last_keyframe_dts = stream->time_position;
6627 GST_DEBUG_OBJECT (qtdemux,
6628 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6629 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6630 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6631 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6632 GST_TIME_ARGS (duration));
6634 if (G_UNLIKELY (empty)) {
6635 /* empty segment, push a gap if there's a second or more
6636 * difference and move to the next one */
6637 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6638 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6639 stream->segment.position = pts + duration;
6643 /* hmm, empty sample, skip and move to next sample */
6644 if (G_UNLIKELY (sample_size <= 0))
6647 /* last pushed sample was out of boundary, goto next sample */
6648 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6651 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6652 GST_DEBUG_OBJECT (qtdemux,
6653 "size %d larger than stream max_buffer_size %d, trimming",
6654 sample_size, stream->max_buffer_size);
6656 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6657 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6658 && sample_size < stream->min_buffer_size) {
6659 guint start_sample_index = stream->sample_index;
6660 guint accumulated_size = sample_size;
6661 guint64 expected_next_offset = offset + sample_size;
6663 GST_DEBUG_OBJECT (qtdemux,
6664 "size %d smaller than stream min_buffer_size %d, combining with the next",
6665 sample_size, stream->min_buffer_size);
6667 while (stream->sample_index < stream->to_sample
6668 && stream->sample_index + 1 < stream->n_samples) {
6669 const QtDemuxSample *next_sample;
6671 /* Increment temporarily */
6672 stream->sample_index++;
6674 /* Failed to parse sample so let's go back to the previous one that was
6675 * still successful */
6676 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6677 stream->sample_index--;
6681 next_sample = &stream->samples[stream->sample_index];
6683 /* Not contiguous with the previous sample so let's go back to the
6684 * previous one that was still successful */
6685 if (next_sample->offset != expected_next_offset) {
6686 stream->sample_index--;
6690 accumulated_size += next_sample->size;
6691 expected_next_offset += next_sample->size;
6692 if (accumulated_size >= stream->min_buffer_size)
6696 num_samples = stream->sample_index + 1 - start_sample_index;
6697 stream->sample_index = start_sample_index;
6698 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6699 num_samples, accumulated_size);
6700 size = accumulated_size;
6705 if (qtdemux->cenc_aux_info_offset > 0) {
6708 GstBuffer *aux_info = NULL;
6710 /* pull the data stored before the sample */
6712 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6713 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6714 if (G_UNLIKELY (ret != GST_FLOW_OK))
6716 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6717 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6718 gst_byte_reader_init (&br, map.data + 8, map.size);
6719 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6720 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6721 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6722 gst_buffer_unmap (aux_info, &map);
6723 gst_buffer_unref (aux_info);
6724 ret = GST_FLOW_ERROR;
6727 gst_buffer_unmap (aux_info, &map);
6728 gst_buffer_unref (aux_info);
6731 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6734 if (stream->use_allocator) {
6735 /* if we have a per-stream allocator, use it */
6736 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6739 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6741 if (G_UNLIKELY (ret != GST_FLOW_OK))
6744 /* Update for both splitting and combining of samples */
6745 if (size != sample_size) {
6746 pts += gst_util_uint64_scale_int (GST_SECOND,
6747 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6750 gst_util_uint64_scale_int (GST_SECOND,
6751 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6754 gst_util_uint64_scale_int (GST_SECOND,
6755 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6758 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6759 dts, pts, duration, keyframe, min_time, offset);
6761 if (size < sample_size) {
6762 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6763 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6765 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6767 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6768 if (time_position >= segment->media_start) {
6769 /* inside the segment, update time_position, looks very familiar to
6770 * GStreamer segments, doesn't it? */
6771 stream->time_position = (time_position - segment->media_start) +
6774 /* not yet in segment, time does not yet increment. This means
6775 * that we are still prerolling keyframes to the decoder so it can
6776 * decode the first sample of the segment. */
6777 stream->time_position = segment->time;
6779 } else if (size > sample_size) {
6780 /* Increase to the last sample we already pulled so that advancing
6781 * below brings us to the next sample we need to pull */
6782 stream->sample_index += num_samples - 1;
6786 GST_OBJECT_LOCK (qtdemux);
6787 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6788 GST_OBJECT_UNLOCK (qtdemux);
6789 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6790 * we have no more data for the pad to push */
6791 if (ret == GST_FLOW_EOS)
6794 stream->offset_in_sample += size;
6795 if (stream->offset_in_sample >= sample_size) {
6796 gst_qtdemux_advance_sample (qtdemux, stream);
6801 gst_qtdemux_advance_sample (qtdemux, stream);
6809 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6815 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6816 /* EOS will be raised if all are EOS */
6823 gst_qtdemux_loop (GstPad * pad)
6825 GstQTDemux *qtdemux;
6829 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6831 cur_offset = qtdemux->offset;
6832 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6833 cur_offset, qt_demux_state_string (qtdemux->state));
6835 switch (qtdemux->state) {
6836 case QTDEMUX_STATE_INITIAL:
6837 case QTDEMUX_STATE_HEADER:
6838 ret = gst_qtdemux_loop_state_header (qtdemux);
6840 case QTDEMUX_STATE_MOVIE:
6841 ret = gst_qtdemux_loop_state_movie (qtdemux);
6842 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6843 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6851 /* if something went wrong, pause */
6852 if (ret != GST_FLOW_OK)
6856 gst_object_unref (qtdemux);
6862 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6863 (NULL), ("streaming stopped, invalid state"));
6864 gst_pad_pause_task (pad);
6865 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6870 const gchar *reason = gst_flow_get_name (ret);
6872 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6874 gst_pad_pause_task (pad);
6876 /* fatal errors need special actions */
6878 if (ret == GST_FLOW_EOS) {
6879 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6880 /* we have no streams, post an error */
6881 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6883 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6886 if ((stop = qtdemux->segment.stop) == -1)
6887 stop = qtdemux->segment.duration;
6889 if (qtdemux->segment.rate >= 0) {
6890 GstMessage *message;
6893 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6894 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6895 GST_FORMAT_TIME, stop);
6896 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6897 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6898 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6899 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6901 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6902 gst_qtdemux_push_event (qtdemux, event);
6904 GstMessage *message;
6907 /* For Reverse Playback */
6908 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6909 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6910 GST_FORMAT_TIME, qtdemux->segment.start);
6911 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6912 qtdemux->segment.start);
6913 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6914 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6915 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6917 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6918 gst_qtdemux_push_event (qtdemux, event);
6923 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6924 event = gst_event_new_eos ();
6925 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6926 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6927 gst_qtdemux_push_event (qtdemux, event);
6929 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6930 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6931 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6940 * Returns if there are samples to be played.
6943 has_next_entry (GstQTDemux * demux)
6945 QtDemuxStream *stream;
6948 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6950 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6951 stream = QTDEMUX_NTH_STREAM (demux, i);
6953 if (stream->sample_index == -1) {
6954 stream->sample_index = 0;
6955 stream->offset_in_sample = 0;
6958 if (stream->sample_index >= stream->n_samples) {
6959 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6962 GST_DEBUG_OBJECT (demux, "Found a sample");
6966 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6973 * Returns the size of the first entry at the current offset.
6974 * If -1, there are none (which means EOS or empty file).
6977 next_entry_size (GstQTDemux * demux)
6979 QtDemuxStream *stream, *target_stream = NULL;
6980 guint64 smalloffs = (guint64) - 1;
6981 QtDemuxSample *sample;
6984 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6987 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6988 stream = QTDEMUX_NTH_STREAM (demux, i);
6990 if (stream->sample_index == -1) {
6991 stream->sample_index = 0;
6992 stream->offset_in_sample = 0;
6995 if (stream->sample_index >= stream->n_samples) {
6996 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
7000 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
7001 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
7002 stream->sample_index);
7006 sample = &stream->samples[stream->sample_index];
7008 GST_LOG_OBJECT (demux,
7009 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
7010 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
7011 stream->sample_index, sample->offset, sample->size);
7013 if (((smalloffs == -1)
7014 || (sample->offset < smalloffs)) && (sample->size)) {
7015 smalloffs = sample->offset;
7016 target_stream = stream;
7023 GST_LOG_OBJECT (demux,
7024 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
7025 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
7027 stream = target_stream;
7028 sample = &stream->samples[stream->sample_index];
7030 if (sample->offset >= demux->offset) {
7031 demux->todrop = sample->offset - demux->offset;
7032 return sample->size + demux->todrop;
7035 GST_DEBUG_OBJECT (demux,
7036 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
7041 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
7043 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
7045 gst_element_post_message (GST_ELEMENT_CAST (demux),
7046 gst_message_new_element (GST_OBJECT_CAST (demux),
7047 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
7051 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
7056 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
7059 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
7060 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
7061 GST_SEEK_TYPE_NONE, -1);
7063 /* store seqnum to drop flush events, they don't need to reach downstream */
7064 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
7065 res = gst_pad_push_event (demux->sinkpad, event);
7066 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
7071 /* check for seekable upstream, above and beyond a mere query */
7073 gst_qtdemux_check_seekability (GstQTDemux * demux)
7076 gboolean seekable = FALSE;
7077 gint64 start = -1, stop = -1;
7079 if (demux->upstream_size)
7082 if (demux->upstream_format_is_time)
7085 query = gst_query_new_seeking (GST_FORMAT_BYTES);
7086 if (!gst_pad_peer_query (demux->sinkpad, query)) {
7087 GST_DEBUG_OBJECT (demux, "seeking query failed");
7091 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
7093 /* try harder to query upstream size if we didn't get it the first time */
7094 if (seekable && stop == -1) {
7095 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
7096 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
7099 /* if upstream doesn't know the size, it's likely that it's not seekable in
7100 * practice even if it technically may be seekable */
7101 if (seekable && (start != 0 || stop <= start)) {
7102 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
7107 gst_query_unref (query);
7109 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
7110 G_GUINT64_FORMAT ")", seekable, start, stop);
7111 demux->upstream_seekable = seekable;
7112 demux->upstream_size = seekable ? stop : -1;
7116 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
7118 g_return_if_fail (bytes <= demux->todrop);
7120 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
7121 gst_adapter_flush (demux->adapter, bytes);
7122 demux->neededbytes -= bytes;
7123 demux->offset += bytes;
7124 demux->todrop -= bytes;
7127 /* PUSH-MODE only: Send a segment, if not done already. */
7129 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
7131 if (G_UNLIKELY (demux->need_segment)) {
7134 if (!demux->upstream_format_is_time) {
7135 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
7137 GstEvent *segment_event;
7138 segment_event = gst_event_new_segment (&demux->segment);
7139 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
7140 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
7141 gst_qtdemux_push_event (demux, segment_event);
7144 demux->need_segment = FALSE;
7146 /* clear to send tags on all streams */
7147 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7148 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7149 gst_qtdemux_push_tags (demux, stream);
7150 if (CUR_STREAM (stream)->sparse) {
7151 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
7152 gst_pad_push_event (stream->pad,
7153 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7159 /* Used for push mode only. */
7161 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7162 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7164 GstClockTime ts, dur;
7168 stream->segments[segment_index].duration - (pos -
7169 stream->segments[segment_index].time);
7170 stream->time_position += dur;
7172 /* Only gaps with a duration of at least one second are propagated.
7173 * Same workaround as in pull mode.
7174 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7175 if (dur >= GST_SECOND) {
7177 gap = gst_event_new_gap (ts, dur);
7179 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7180 "segment: %" GST_PTR_FORMAT, gap);
7181 gst_pad_push_event (stream->pad, gap);
7185 static GstFlowReturn
7186 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7190 demux = GST_QTDEMUX (parent);
7192 GST_DEBUG_OBJECT (demux,
7193 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7194 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7195 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7196 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7197 gst_buffer_get_size (inbuf), demux->offset);
7199 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7200 gboolean is_gap_input = FALSE;
7203 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7205 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7206 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7209 /* Check if we can land back on our feet in the case where upstream is
7210 * handling the seeking/pushing of samples with gaps in between (like
7211 * in the case of trick-mode DASH for example) */
7212 if (demux->upstream_format_is_time
7213 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7214 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7216 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7217 GST_LOG_OBJECT (demux,
7218 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7219 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7221 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7222 stream, GST_BUFFER_OFFSET (inbuf));
7224 QtDemuxSample *sample = &stream->samples[res];
7225 GST_LOG_OBJECT (demux,
7226 "Checking if sample %d from track-id %u is valid (offset:%"
7227 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7228 stream->track_id, sample->offset, sample->size);
7229 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7230 GST_LOG_OBJECT (demux,
7231 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7233 is_gap_input = TRUE;
7234 /* We can go back to standard playback mode */
7235 demux->state = QTDEMUX_STATE_MOVIE;
7236 /* Remember which sample this stream is at */
7237 stream->sample_index = res;
7238 /* Finally update all push-based values to the expected values */
7239 demux->neededbytes = stream->samples[res].size;
7240 demux->offset = GST_BUFFER_OFFSET (inbuf);
7242 demux->mdatsize - demux->offset + demux->mdatoffset;
7247 if (!is_gap_input) {
7248 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7249 /* Reset state if it's a real discont */
7250 demux->neededbytes = 16;
7251 demux->state = QTDEMUX_STATE_INITIAL;
7252 demux->offset = GST_BUFFER_OFFSET (inbuf);
7253 gst_adapter_clear (demux->adapter);
7256 /* Reverse fragmented playback, need to flush all we have before
7257 * consuming a new fragment.
7258 * The samples array have the timestamps calculated by accumulating the
7259 * durations but this won't work for reverse playback of fragments as
7260 * the timestamps of a subsequent fragment should be smaller than the
7261 * previously received one. */
7262 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7263 gst_qtdemux_process_adapter (demux, TRUE);
7264 g_ptr_array_foreach (demux->active_streams,
7265 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7269 gst_adapter_push (demux->adapter, inbuf);
7271 GST_DEBUG_OBJECT (demux,
7272 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7273 demux->neededbytes, gst_adapter_available (demux->adapter));
7275 return gst_qtdemux_process_adapter (demux, FALSE);
7278 static GstFlowReturn
7279 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7281 GstFlowReturn ret = GST_FLOW_OK;
7283 /* we never really mean to buffer that much */
7284 if (demux->neededbytes == -1) {
7288 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7289 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7291 #ifndef GST_DISABLE_GST_DEBUG
7293 guint64 discont_offset, distance_from_discont;
7295 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7296 distance_from_discont =
7297 gst_adapter_distance_from_discont (demux->adapter);
7299 GST_DEBUG_OBJECT (demux,
7300 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7301 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7302 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7303 demux->offset, discont_offset, distance_from_discont);
7307 switch (demux->state) {
7308 case QTDEMUX_STATE_INITIAL:{
7313 gst_qtdemux_check_seekability (demux);
7315 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7317 /* get fourcc/length, set neededbytes */
7318 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7320 gst_adapter_unmap (demux->adapter);
7322 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7323 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7325 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7326 (_("This file is invalid and cannot be played.")),
7327 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7328 GST_FOURCC_ARGS (fourcc)));
7329 ret = GST_FLOW_ERROR;
7332 if (fourcc == FOURCC_mdat) {
7333 gint next_entry = next_entry_size (demux);
7334 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7335 || !demux->fragmented)) {
7336 /* we have the headers, start playback */
7337 demux->state = QTDEMUX_STATE_MOVIE;
7338 demux->neededbytes = next_entry;
7339 demux->mdatleft = size;
7340 demux->mdatsize = demux->mdatleft;
7342 /* no headers yet, try to get them */
7345 guint64 old, target;
7348 old = demux->offset;
7349 target = old + size;
7351 /* try to jump over the atom with a seek */
7352 /* only bother if it seems worth doing so,
7353 * and avoids possible upstream/server problems */
7354 if (demux->upstream_seekable &&
7355 demux->upstream_size > 4 * (1 << 20)) {
7356 res = qtdemux_seek_offset (demux, target);
7358 GST_DEBUG_OBJECT (demux, "skipping seek");
7363 GST_DEBUG_OBJECT (demux, "seek success");
7364 /* remember the offset fo the first mdat so we can seek back to it
7365 * after we have the headers */
7366 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7367 demux->first_mdat = old;
7368 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7371 /* seek worked, continue reading */
7372 demux->offset = target;
7373 demux->neededbytes = 16;
7374 demux->state = QTDEMUX_STATE_INITIAL;
7376 /* seek failed, need to buffer */
7377 demux->offset = old;
7378 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7379 /* there may be multiple mdat (or alike) buffers */
7381 if (demux->mdatbuffer)
7382 bs = gst_buffer_get_size (demux->mdatbuffer);
7385 if (size + bs > 10 * (1 << 20))
7387 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7388 demux->neededbytes = size;
7389 if (!demux->mdatbuffer)
7390 demux->mdatoffset = demux->offset;
7393 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7394 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7395 (_("This file is invalid and cannot be played.")),
7396 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7397 GST_FOURCC_ARGS (fourcc), size));
7398 ret = GST_FLOW_ERROR;
7401 /* this means we already started buffering and still no moov header,
7402 * let's continue buffering everything till we get moov */
7403 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7404 || fourcc == FOURCC_moof))
7406 demux->neededbytes = size;
7407 demux->state = QTDEMUX_STATE_HEADER;
7411 case QTDEMUX_STATE_HEADER:{
7415 GST_DEBUG_OBJECT (demux, "In header");
7417 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7419 /* parse the header */
7420 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7422 if (fourcc == FOURCC_moov) {
7423 /* in usual fragmented setup we could try to scan for more
7424 * and end up at the the moov (after mdat) again */
7425 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7427 || demux->last_moov_offset == demux->offset)) {
7428 GST_DEBUG_OBJECT (demux,
7429 "Skipping moov atom as we have (this) one already");
7431 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7433 if (demux->got_moov && demux->fragmented) {
7434 GST_DEBUG_OBJECT (demux,
7435 "Got a second moov, clean up data from old one");
7436 if (demux->moov_node_compressed) {
7437 g_node_destroy (demux->moov_node_compressed);
7438 if (demux->moov_node)
7439 g_free (demux->moov_node->data);
7441 demux->moov_node_compressed = NULL;
7442 if (demux->moov_node)
7443 g_node_destroy (demux->moov_node);
7444 demux->moov_node = NULL;
7445 demux->start_utc_time = GST_CLOCK_TIME_NONE;
7448 demux->last_moov_offset = demux->offset;
7450 /* Update streams with new moov */
7451 gst_qtdemux_stream_concat (demux,
7452 demux->old_streams, demux->active_streams);
7454 qtdemux_parse_moov (demux, data, demux->neededbytes);
7455 qtdemux_node_dump (demux, demux->moov_node);
7456 qtdemux_parse_tree (demux);
7457 qtdemux_prepare_streams (demux);
7458 QTDEMUX_EXPOSE_LOCK (demux);
7459 qtdemux_expose_streams (demux);
7460 QTDEMUX_EXPOSE_UNLOCK (demux);
7462 demux->got_moov = TRUE;
7464 gst_qtdemux_check_send_pending_segment (demux);
7466 if (demux->moov_node_compressed) {
7467 g_node_destroy (demux->moov_node_compressed);
7468 g_free (demux->moov_node->data);
7470 demux->moov_node_compressed = NULL;
7471 g_node_destroy (demux->moov_node);
7472 demux->moov_node = NULL;
7473 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7475 } else if (fourcc == FOURCC_moof) {
7476 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7478 GstClockTime prev_pts;
7479 guint64 prev_offset;
7480 guint64 adapter_discont_offset, adapter_discont_dist;
7482 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7485 * The timestamp of the moof buffer is relevant as some scenarios
7486 * won't have the initial timestamp in the atoms. Whenever a new
7487 * buffer has started, we get that buffer's PTS and use it as a base
7488 * timestamp for the trun entries.
7490 * To keep track of the current buffer timestamp and starting point
7491 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7492 * from the beginning of the buffer, with the distance and demux->offset
7493 * we know if it is still the same buffer or not.
7495 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7496 prev_offset = demux->offset - dist;
7497 if (demux->fragment_start_offset == -1
7498 || prev_offset > demux->fragment_start_offset) {
7499 demux->fragment_start_offset = prev_offset;
7500 demux->fragment_start = prev_pts;
7501 GST_DEBUG_OBJECT (demux,
7502 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7503 GST_TIME_FORMAT, demux->fragment_start_offset,
7504 GST_TIME_ARGS (demux->fragment_start));
7507 /* We can't use prev_offset() here because this would require
7508 * upstream to set consistent and correct offsets on all buffers
7509 * since the discont. Nothing ever did that in the past and we
7510 * would break backwards compatibility here then.
7511 * Instead take the offset we had at the last discont and count
7512 * the bytes from there. This works with old code as there would
7513 * be no discont between moov and moof, and also works with
7514 * adaptivedemux which correctly sets offset and will set the
7515 * DISCONT flag accordingly when needed.
7517 * We also only do this for upstream TIME segments as otherwise
7518 * there are potential backwards compatibility problems with
7519 * seeking in PUSH mode and upstream providing inconsistent
7521 adapter_discont_offset =
7522 gst_adapter_offset_at_discont (demux->adapter);
7523 adapter_discont_dist =
7524 gst_adapter_distance_from_discont (demux->adapter);
7526 GST_DEBUG_OBJECT (demux,
7527 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7528 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7529 demux->offset, adapter_discont_offset, adapter_discont_dist);
7531 if (demux->upstream_format_is_time) {
7532 demux->moof_offset = adapter_discont_offset;
7533 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7534 demux->moof_offset += adapter_discont_dist;
7535 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7536 demux->moof_offset = demux->offset;
7538 demux->moof_offset = demux->offset;
7541 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7542 demux->moof_offset, NULL)) {
7543 gst_adapter_unmap (demux->adapter);
7544 ret = GST_FLOW_ERROR;
7548 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7549 if (demux->mss_mode && !demux->exposed) {
7550 QTDEMUX_EXPOSE_LOCK (demux);
7551 qtdemux_expose_streams (demux);
7552 QTDEMUX_EXPOSE_UNLOCK (demux);
7555 gst_qtdemux_check_send_pending_segment (demux);
7557 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7559 } else if (fourcc == FOURCC_ftyp) {
7560 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7561 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7562 } else if (fourcc == FOURCC_uuid) {
7563 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7564 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7565 } else if (fourcc == FOURCC_sidx) {
7566 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7567 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7568 } else if (fourcc == FOURCC_meta) {
7569 GNode *node, *child;
7570 GstByteReader child_data;
7572 node = g_node_new ((gpointer) data);
7573 qtdemux_parse_node (demux, node, data, demux->neededbytes);
7575 /* Parse ONVIF Export File Format CorrectStartTime box if available */
7577 qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb,
7579 qtdemux_parse_cstb (demux, &child_data);
7582 g_node_destroy (node);
7586 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7590 /* [free] and [skip] are padding atoms */
7591 GST_DEBUG_OBJECT (demux,
7592 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7593 GST_FOURCC_ARGS (fourcc));
7596 GST_WARNING_OBJECT (demux,
7597 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7598 GST_FOURCC_ARGS (fourcc));
7599 /* Let's jump that one and go back to initial state */
7603 gst_adapter_unmap (demux->adapter);
7606 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7607 gsize remaining_data_size = 0;
7609 /* the mdat was before the header */
7610 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7611 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7612 /* restore our adapter/offset view of things with upstream;
7613 * put preceding buffered data ahead of current moov data.
7614 * This should also handle evil mdat, moov, mdat cases and alike */
7615 gst_adapter_flush (demux->adapter, demux->neededbytes);
7617 /* Store any remaining data after the mdat for later usage */
7618 remaining_data_size = gst_adapter_available (demux->adapter);
7619 if (remaining_data_size > 0) {
7620 g_assert (demux->restoredata_buffer == NULL);
7621 demux->restoredata_buffer =
7622 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7623 demux->restoredata_offset = demux->offset + demux->neededbytes;
7624 GST_DEBUG_OBJECT (demux,
7625 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7626 G_GUINT64_FORMAT, remaining_data_size,
7627 demux->restoredata_offset);
7630 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7631 demux->mdatbuffer = NULL;
7632 demux->offset = demux->mdatoffset;
7633 demux->neededbytes = next_entry_size (demux);
7634 demux->state = QTDEMUX_STATE_MOVIE;
7635 demux->mdatleft = gst_adapter_available (demux->adapter);
7636 demux->mdatsize = demux->mdatleft;
7638 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7639 gst_adapter_flush (demux->adapter, demux->neededbytes);
7641 /* only go back to the mdat if there are samples to play */
7642 if (demux->got_moov && demux->first_mdat != -1
7643 && has_next_entry (demux)) {
7646 /* we need to seek back */
7647 res = qtdemux_seek_offset (demux, demux->first_mdat);
7649 demux->offset = demux->first_mdat;
7651 GST_DEBUG_OBJECT (demux, "Seek back failed");
7654 demux->offset += demux->neededbytes;
7656 demux->neededbytes = 16;
7657 demux->state = QTDEMUX_STATE_INITIAL;
7662 case QTDEMUX_STATE_BUFFER_MDAT:{
7666 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7668 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7669 gst_buffer_extract (buf, 0, fourcc, 4);
7670 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7671 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7672 if (demux->mdatbuffer)
7673 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7675 demux->mdatbuffer = buf;
7676 demux->offset += demux->neededbytes;
7677 demux->neededbytes = 16;
7678 demux->state = QTDEMUX_STATE_INITIAL;
7679 gst_qtdemux_post_progress (demux, 1, 1);
7683 case QTDEMUX_STATE_MOVIE:{
7684 QtDemuxStream *stream = NULL;
7685 QtDemuxSample *sample;
7686 GstClockTime dts, pts, duration;
7690 GST_DEBUG_OBJECT (demux,
7691 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7693 if (demux->fragmented) {
7694 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7696 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7697 /* if needed data starts within this atom,
7698 * then it should not exceed this atom */
7699 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7700 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7701 (_("This file is invalid and cannot be played.")),
7702 ("sample data crosses atom boundary"));
7703 ret = GST_FLOW_ERROR;
7706 demux->mdatleft -= demux->neededbytes;
7708 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7709 /* so we are dropping more than left in this atom */
7710 gst_qtdemux_drop_data (demux, demux->mdatleft);
7711 demux->mdatleft = 0;
7713 /* need to resume atom parsing so we do not miss any other pieces */
7714 demux->state = QTDEMUX_STATE_INITIAL;
7715 demux->neededbytes = 16;
7717 /* check if there was any stored post mdat data from previous buffers */
7718 if (demux->restoredata_buffer) {
7719 g_assert (gst_adapter_available (demux->adapter) == 0);
7721 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7722 demux->restoredata_buffer = NULL;
7723 demux->offset = demux->restoredata_offset;
7730 if (demux->todrop) {
7731 if (demux->cenc_aux_info_offset > 0) {
7735 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7736 data = gst_adapter_map (demux->adapter, demux->todrop);
7737 gst_byte_reader_init (&br, data + 8, demux->todrop);
7738 if (!qtdemux_parse_cenc_aux_info (demux,
7739 QTDEMUX_NTH_STREAM (demux, 0), &br,
7740 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7741 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7742 ret = GST_FLOW_ERROR;
7743 gst_adapter_unmap (demux->adapter);
7744 g_free (demux->cenc_aux_info_sizes);
7745 demux->cenc_aux_info_sizes = NULL;
7748 demux->cenc_aux_info_offset = 0;
7749 g_free (demux->cenc_aux_info_sizes);
7750 demux->cenc_aux_info_sizes = NULL;
7751 gst_adapter_unmap (demux->adapter);
7753 gst_qtdemux_drop_data (demux, demux->todrop);
7757 /* initial newsegment sent here after having added pads,
7758 * possible others in sink_event */
7759 gst_qtdemux_check_send_pending_segment (demux);
7761 /* Figure out which stream this packet belongs to */
7762 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7763 stream = QTDEMUX_NTH_STREAM (demux, i);
7764 if (stream->sample_index >= stream->n_samples) {
7765 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7769 GST_LOG_OBJECT (demux,
7770 "Checking track-id %u (sample_index:%d / offset:%"
7771 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7772 stream->sample_index,
7773 stream->samples[stream->sample_index].offset,
7774 stream->samples[stream->sample_index].size);
7776 if (stream->samples[stream->sample_index].offset == demux->offset)
7780 if (G_UNLIKELY (stream == NULL))
7781 goto unknown_stream;
7783 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7785 if (stream->new_caps) {
7786 gst_qtdemux_configure_stream (demux, stream);
7789 /* Put data in a buffer, set timestamps, caps, ... */
7790 sample = &stream->samples[stream->sample_index];
7792 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7793 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7794 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7796 dts = QTSAMPLE_DTS (stream, sample);
7797 pts = QTSAMPLE_PTS (stream, sample);
7798 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7799 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7801 /* check for segment end */
7802 if (G_UNLIKELY (demux->segment.stop != -1
7803 && demux->segment.stop <= pts && stream->on_keyframe)
7804 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7805 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7806 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7808 /* skip this data, stream is EOS */
7809 gst_adapter_flush (demux->adapter, demux->neededbytes);
7810 demux->offset += demux->neededbytes;
7812 /* check if all streams are eos */
7814 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7815 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7824 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7826 /* FIXME: should either be an assert or a plain check */
7827 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7829 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7830 dts, pts, duration, keyframe, dts, demux->offset);
7834 GST_OBJECT_LOCK (demux);
7835 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7836 GST_OBJECT_UNLOCK (demux);
7838 /* skip this data, stream is EOS */
7839 gst_adapter_flush (demux->adapter, demux->neededbytes);
7842 stream->sample_index++;
7843 stream->offset_in_sample = 0;
7845 /* update current offset and figure out size of next buffer */
7846 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7847 demux->offset, demux->neededbytes);
7848 demux->offset += demux->neededbytes;
7849 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7853 if (ret == GST_FLOW_EOS) {
7854 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7855 demux->neededbytes = -1;
7859 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7860 if (demux->fragmented) {
7861 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7862 /* there may be more to follow, only finish this atom */
7863 demux->todrop = demux->mdatleft;
7864 demux->neededbytes = demux->todrop;
7869 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7870 goto non_ok_unlinked_flow;
7879 /* when buffering movie data, at least show user something is happening */
7880 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7881 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7882 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7883 demux->neededbytes);
7890 non_ok_unlinked_flow:
7892 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7893 gst_flow_get_name (ret));
7898 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7899 ret = GST_FLOW_ERROR;
7904 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7910 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7911 (NULL), ("qtdemuxer invalid state %d", demux->state));
7912 ret = GST_FLOW_ERROR;
7917 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7918 (NULL), ("no 'moov' atom within the first 10 MB"));
7919 ret = GST_FLOW_ERROR;
7925 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7930 query = gst_query_new_scheduling ();
7932 if (!gst_pad_peer_query (sinkpad, query)) {
7933 gst_query_unref (query);
7937 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7938 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7939 gst_query_unref (query);
7944 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7945 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7949 GST_DEBUG_OBJECT (sinkpad, "activating push");
7950 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7955 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7956 GstPadMode mode, gboolean active)
7959 GstQTDemux *demux = GST_QTDEMUX (parent);
7962 case GST_PAD_MODE_PUSH:
7963 demux->pullbased = FALSE;
7966 case GST_PAD_MODE_PULL:
7968 demux->pullbased = TRUE;
7969 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7972 res = gst_pad_stop_task (sinkpad);
7984 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7990 memset (&z, 0, sizeof (z));
7995 if ((ret = inflateInit (&z)) != Z_OK) {
7996 GST_ERROR ("inflateInit() returned %d", ret);
8000 z.next_in = z_buffer;
8001 z.avail_in = z_length;
8003 buffer = (guint8 *) g_malloc (*length);
8004 z.avail_out = *length;
8005 z.next_out = (Bytef *) buffer;
8007 ret = inflate (&z, Z_NO_FLUSH);
8008 if (ret == Z_STREAM_END) {
8010 } else if (ret != Z_OK) {
8011 GST_WARNING ("inflate() returned %d", ret);
8015 if (*length > G_MAXUINT - 4096 || *length > QTDEMUX_MAX_SAMPLE_INDEX_SIZE) {
8016 GST_WARNING ("too big decompressed data");
8022 buffer = (guint8 *) g_realloc (buffer, *length);
8023 z.next_out = (Bytef *) (buffer + z.total_out);
8024 z.avail_out += *length - z.total_out;
8025 } while (z.avail_in > 0);
8027 if (ret != Z_STREAM_END) {
8032 *length = z.total_out;
8039 #endif /* HAVE_ZLIB */
8042 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
8046 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
8048 /* counts as header data */
8049 qtdemux->header_size += length;
8051 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
8052 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
8054 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
8061 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
8062 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
8063 if (dcom == NULL || cmvd == NULL)
8064 goto invalid_compression;
8066 dcom_len = QT_UINT32 (dcom->data);
8068 goto invalid_compression;
8070 method = QT_FOURCC ((guint8 *) dcom->data + 8);
8074 guint uncompressed_length;
8075 guint compressed_length;
8079 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
8081 goto invalid_compression;
8083 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
8084 compressed_length = cmvd_len - 12;
8085 GST_LOG ("length = %u", uncompressed_length);
8088 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
8089 compressed_length, &uncompressed_length);
8092 qtdemux->moov_node_compressed = qtdemux->moov_node;
8093 qtdemux->moov_node = g_node_new (buf);
8095 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
8096 uncompressed_length);
8100 #endif /* HAVE_ZLIB */
8102 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
8103 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
8110 invalid_compression:
8112 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
8118 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
8121 while (G_UNLIKELY (buf < end)) {
8125 if (G_UNLIKELY (buf + 4 > end)) {
8126 GST_LOG_OBJECT (qtdemux, "buffer overrun");
8129 len = QT_UINT32 (buf);
8130 if (G_UNLIKELY (len == 0)) {
8131 GST_LOG_OBJECT (qtdemux, "empty container");
8134 if (G_UNLIKELY (len < 8)) {
8135 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
8138 if (G_UNLIKELY (len > (end - buf))) {
8139 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
8140 (gint) (end - buf));
8144 child = g_node_new ((guint8 *) buf);
8145 g_node_append (node, child);
8146 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
8147 qtdemux_parse_node (qtdemux, child, buf, len);
8155 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
8158 int len = QT_UINT32 (xdxt->data);
8159 guint8 *buf = xdxt->data;
8160 guint8 *end = buf + len;
8163 /* skip size and type */
8171 size = QT_UINT32 (buf);
8172 type = QT_FOURCC (buf + 4);
8174 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
8176 if (buf + size > end || size <= 0)
8182 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8183 GST_FOURCC_ARGS (type));
8187 buffer = gst_buffer_new_and_alloc (size);
8188 gst_buffer_fill (buffer, 0, buf, size);
8189 stream->buffers = g_slist_append (stream->buffers, buffer);
8190 GST_LOG_OBJECT (qtdemux, "parsing theora header");
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 comment");
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 codebook");
8205 GST_WARNING_OBJECT (qtdemux,
8206 "unknown theora cookie %" GST_FOURCC_FORMAT,
8207 GST_FOURCC_ARGS (type));
8216 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8220 guint32 node_length = 0;
8221 const QtNodeType *type;
8224 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8226 if (G_UNLIKELY (length < 8))
8227 goto not_enough_data;
8229 node_length = QT_UINT32 (buffer);
8230 fourcc = QT_FOURCC (buffer + 4);
8232 /* ignore empty nodes */
8233 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8236 type = qtdemux_type_get (fourcc);
8238 end = buffer + length;
8240 GST_LOG_OBJECT (qtdemux,
8241 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8242 GST_FOURCC_ARGS (fourcc), node_length, type->name);
8244 if (node_length > length)
8245 goto broken_atom_size;
8247 if (type->flags & QT_FLAG_CONTAINER) {
8248 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8253 if (node_length < 20) {
8254 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8257 GST_DEBUG_OBJECT (qtdemux,
8258 "parsing stsd (sample table, sample description) atom");
8259 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8260 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8272 /* also read alac (or whatever) in stead of mp4a in the following,
8273 * since a similar layout is used in other cases as well */
8274 if (fourcc == FOURCC_mp4a)
8276 else if (fourcc == FOURCC_fLaC)
8281 /* There are two things we might encounter here: a true mp4a atom, and
8282 an mp4a entry in an stsd atom. The latter is what we're interested
8283 in, and it looks like an atom, but isn't really one. The true mp4a
8284 atom is short, so we detect it based on length here. */
8285 if (length < min_size) {
8286 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8287 GST_FOURCC_ARGS (fourcc));
8291 /* 'version' here is the sound sample description version. Types 0 and
8292 1 are documented in the QTFF reference, but type 2 is not: it's
8293 described in Apple header files instead (struct SoundDescriptionV2
8295 version = QT_UINT16 (buffer + 16);
8297 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8298 GST_FOURCC_ARGS (fourcc), version);
8300 /* parse any esds descriptors */
8312 GST_WARNING_OBJECT (qtdemux,
8313 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8314 GST_FOURCC_ARGS (fourcc), version);
8319 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8347 /* codec_data is contained inside these atoms, which all have
8348 * the same format. */
8349 /* video sample description size is 86 bytes without extension.
8350 * node_length have to be bigger than 86 bytes because video sample
8351 * description can include extensions such as esds, fiel, glbl, etc. */
8352 if (node_length < 86) {
8353 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8354 " sample description length too short (%u < 86)",
8355 GST_FOURCC_ARGS (fourcc), node_length);
8359 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8360 GST_FOURCC_ARGS (fourcc));
8362 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8364 * revision level (2 bytes) : must be set to 0. */
8365 version = QT_UINT32 (buffer + 16);
8366 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8368 /* compressor name : PASCAL string and informative purposes
8369 * first byte : the number of bytes to be displayed.
8370 * it has to be less than 32 because it is reserved
8371 * space of 32 bytes total including itself. */
8372 str_len = QT_UINT8 (buffer + 50);
8374 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8375 (char *) buffer + 51);
8377 GST_WARNING_OBJECT (qtdemux,
8378 "compressorname length too big (%u > 31)", str_len);
8380 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8382 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8387 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8389 /* You are reading this correctly. QTFF specifies that the
8390 * metadata atom is a short atom, whereas ISO BMFF specifies
8391 * it's a full atom. But since so many people are doing things
8392 * differently, we actually peek into the atom to see which
8395 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8396 GST_FOURCC_ARGS (fourcc));
8399 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8400 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8401 * starts with a 'hdlr' atom */
8402 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8403 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8404 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8405 * with version/flags both set to zero */
8406 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8408 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8413 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8414 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8415 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8424 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8425 GST_FOURCC_ARGS (fourcc));
8429 version = QT_UINT32 (buffer + 12);
8430 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8437 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8442 if (length < offset) {
8443 GST_WARNING_OBJECT (qtdemux,
8444 "skipping too small %" GST_FOURCC_FORMAT " box",
8445 GST_FOURCC_ARGS (fourcc));
8448 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8454 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8459 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8464 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8468 if (!strcmp (type->name, "unknown"))
8469 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8473 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8474 GST_FOURCC_ARGS (fourcc));
8480 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8481 (_("This file is corrupt and cannot be played.")),
8482 ("Not enough data for an atom header, got only %u bytes", length));
8487 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8488 (_("This file is corrupt and cannot be played.")),
8489 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8490 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8497 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8499 /* FIXME: This can only reliably work if demuxers have a
8500 * separate streaming thread per srcpad. This should be
8501 * done in a demuxer base class, which integrates parts
8504 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8509 query = gst_query_new_allocation (stream->caps, FALSE);
8511 if (!gst_pad_peer_query (stream->pad, query)) {
8512 /* not a problem, just debug a little */
8513 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8516 if (stream->allocator)
8517 gst_object_unref (stream->allocator);
8519 if (gst_query_get_n_allocation_params (query) > 0) {
8520 /* try the allocator */
8521 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8523 stream->use_allocator = TRUE;
8525 stream->allocator = NULL;
8526 gst_allocation_params_init (&stream->params);
8527 stream->use_allocator = FALSE;
8529 gst_query_unref (query);
8534 pad_query (const GValue * item, GValue * value, gpointer user_data)
8536 GstPad *pad = g_value_get_object (item);
8537 GstQuery *query = user_data;
8540 res = gst_pad_peer_query (pad, query);
8543 g_value_set_boolean (value, TRUE);
8547 GST_INFO_OBJECT (pad, "pad peer query failed");
8552 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8553 GstPadDirection direction)
8556 GstIteratorFoldFunction func = pad_query;
8557 GValue res = { 0, };
8559 g_value_init (&res, G_TYPE_BOOLEAN);
8560 g_value_set_boolean (&res, FALSE);
8563 if (direction == GST_PAD_SRC)
8564 it = gst_element_iterate_src_pads (element);
8566 it = gst_element_iterate_sink_pads (element);
8568 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8569 gst_iterator_resync (it);
8571 gst_iterator_free (it);
8573 return g_value_get_boolean (&res);
8577 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8578 QtDemuxStream * stream)
8582 GstElement *element = GST_ELEMENT (qtdemux);
8584 gchar **filtered_sys_ids;
8585 GValue event_list = G_VALUE_INIT;
8588 /* 1. Check if we already have the context. */
8589 if (qtdemux->preferred_protection_system_id != NULL) {
8590 GST_LOG_OBJECT (element,
8591 "already have the protection context, no need to request it again");
8595 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8596 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8597 (const gchar **) qtdemux->protection_system_ids->pdata);
8599 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8600 qtdemux->protection_system_ids->len - 1);
8601 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8602 "decryptors for %u of them, running context request",
8603 qtdemux->protection_system_ids->len,
8604 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8607 if (stream->protection_scheme_event_queue.length) {
8608 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8609 stream->protection_scheme_event_queue.length);
8610 walk = stream->protection_scheme_event_queue.tail;
8612 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8613 qtdemux->protection_event_queue.length);
8614 walk = qtdemux->protection_event_queue.tail;
8617 g_value_init (&event_list, GST_TYPE_LIST);
8618 for (; walk; walk = g_list_previous (walk)) {
8619 GValue *event_value = g_new0 (GValue, 1);
8620 g_value_init (event_value, GST_TYPE_EVENT);
8621 g_value_set_boxed (event_value, walk->data);
8622 gst_value_list_append_and_take_value (&event_list, event_value);
8625 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8626 * check if downstream already has a context of the specific type
8627 * 2b) Query upstream as above.
8629 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8630 st = gst_query_writable_structure (query);
8631 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8632 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8634 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8635 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8636 gst_query_parse_context (query, &ctxt);
8637 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8638 gst_element_set_context (element, ctxt);
8639 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8640 gst_query_parse_context (query, &ctxt);
8641 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8642 gst_element_set_context (element, ctxt);
8644 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8645 * the required context type and afterwards check if a
8646 * usable context was set now as in 1). The message could
8647 * be handled by the parent bins of the element and the
8652 GST_INFO_OBJECT (element, "posting need context message");
8653 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8654 "drm-preferred-decryption-system-id");
8655 st = (GstStructure *) gst_message_get_structure (msg);
8656 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8657 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8660 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8661 gst_element_post_message (element, msg);
8664 g_strfreev (filtered_sys_ids);
8665 g_value_unset (&event_list);
8666 gst_query_unref (query);
8670 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8671 QtDemuxStream * stream)
8674 const gchar *selected_system = NULL;
8676 g_return_val_if_fail (qtdemux != NULL, FALSE);
8677 g_return_val_if_fail (stream != NULL, FALSE);
8678 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8681 if (stream->protection_scheme_type == FOURCC_aavd) {
8682 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8683 if (!gst_structure_has_name (s, "application/x-aavd")) {
8684 gst_structure_set (s,
8685 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8687 gst_structure_set_name (s, "application/x-aavd");
8692 if (stream->protection_scheme_type != FOURCC_cenc
8693 && stream->protection_scheme_type != FOURCC_cbcs) {
8694 GST_ERROR_OBJECT (qtdemux,
8695 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8696 GST_FOURCC_ARGS (stream->protection_scheme_type));
8700 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8701 if (!gst_structure_has_name (s, "application/x-cenc")) {
8702 gst_structure_set (s,
8703 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8704 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8705 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8707 gst_structure_set_name (s, "application/x-cenc");
8710 if (qtdemux->protection_system_ids == NULL) {
8711 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8712 "cenc protection system information has been found, not setting a "
8713 "protection system UUID");
8717 gst_qtdemux_request_protection_context (qtdemux, stream);
8718 if (qtdemux->preferred_protection_system_id != NULL) {
8719 const gchar *preferred_system_array[] =
8720 { qtdemux->preferred_protection_system_id, NULL };
8722 selected_system = gst_protection_select_system (preferred_system_array);
8724 if (selected_system) {
8725 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8726 qtdemux->preferred_protection_system_id);
8728 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8729 "because there is no available decryptor",
8730 qtdemux->preferred_protection_system_id);
8734 if (!selected_system) {
8735 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8736 selected_system = gst_protection_select_system ((const gchar **)
8737 qtdemux->protection_system_ids->pdata);
8738 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8739 qtdemux->protection_system_ids->len - 1);
8742 if (!selected_system) {
8743 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8744 "suitable decryptor element has been found");
8748 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8751 gst_structure_set (s,
8752 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8759 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8761 /* fps is calculated base on the duration of the average framerate since
8762 * qt does not have a fixed framerate. */
8763 gboolean fps_available = TRUE;
8764 guint32 first_duration = 0;
8766 if (stream->n_samples > 0)
8767 first_duration = stream->samples[0].duration;
8769 if ((stream->n_samples == 1 && first_duration == 0)
8770 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8772 CUR_STREAM (stream)->fps_n = 0;
8773 CUR_STREAM (stream)->fps_d = 1;
8775 if (stream->duration == 0 || stream->n_samples < 2) {
8776 CUR_STREAM (stream)->fps_n = stream->timescale;
8777 CUR_STREAM (stream)->fps_d = 1;
8778 fps_available = FALSE;
8780 GstClockTime avg_duration;
8784 /* duration and n_samples can be updated for fragmented format
8785 * so, framerate of fragmented format is calculated using data in a moof */
8786 if (qtdemux->fragmented && stream->n_samples_moof > 0
8787 && stream->duration_moof > 0) {
8788 n_samples = stream->n_samples_moof;
8789 duration = stream->duration_moof;
8791 n_samples = stream->n_samples;
8792 duration = stream->duration;
8795 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8796 /* stream->duration is guint64, timescale, n_samples are guint32 */
8798 gst_util_uint64_scale_round (duration -
8799 first_duration, GST_SECOND,
8800 (guint64) (stream->timescale) * (n_samples - 1));
8802 GST_LOG_OBJECT (qtdemux,
8803 "Calculating avg sample duration based on stream (or moof) duration %"
8805 " minus first sample %u, leaving %d samples gives %"
8806 GST_TIME_FORMAT, duration, first_duration,
8807 n_samples - 1, GST_TIME_ARGS (avg_duration));
8810 gst_video_guess_framerate (avg_duration,
8811 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8813 GST_DEBUG_OBJECT (qtdemux,
8814 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8815 stream->timescale, CUR_STREAM (stream)->fps_n,
8816 CUR_STREAM (stream)->fps_d);
8820 return fps_available;
8824 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8826 if (stream->subtype == FOURCC_vide) {
8827 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8829 if (CUR_STREAM (stream)->caps) {
8830 CUR_STREAM (stream)->caps =
8831 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8833 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8834 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8835 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8836 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8838 /* set framerate if calculated framerate is reliable */
8839 if (fps_available) {
8840 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8841 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8842 CUR_STREAM (stream)->fps_d, NULL);
8845 /* calculate pixel-aspect-ratio using display width and height */
8846 GST_DEBUG_OBJECT (qtdemux,
8847 "video size %dx%d, target display size %dx%d",
8848 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8849 stream->display_width, stream->display_height);
8850 /* qt file might have pasp atom */
8851 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8852 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8853 CUR_STREAM (stream)->par_h);
8854 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8855 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8856 CUR_STREAM (stream)->par_h, NULL);
8857 } else if (stream->display_width > 0 && stream->display_height > 0
8858 && CUR_STREAM (stream)->width > 0
8859 && CUR_STREAM (stream)->height > 0) {
8862 /* calculate the pixel aspect ratio using the display and pixel w/h */
8863 n = stream->display_width * CUR_STREAM (stream)->height;
8864 d = stream->display_height * CUR_STREAM (stream)->width;
8867 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8868 CUR_STREAM (stream)->par_w = n;
8869 CUR_STREAM (stream)->par_h = d;
8870 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8871 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8872 CUR_STREAM (stream)->par_h, NULL);
8875 if (CUR_STREAM (stream)->interlace_mode > 0) {
8876 if (CUR_STREAM (stream)->interlace_mode == 1) {
8877 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8878 G_TYPE_STRING, "progressive", NULL);
8879 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8880 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8881 G_TYPE_STRING, "interleaved", NULL);
8882 if (CUR_STREAM (stream)->field_order == 9) {
8883 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8884 G_TYPE_STRING, "top-field-first", NULL);
8885 } else if (CUR_STREAM (stream)->field_order == 14) {
8886 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8887 G_TYPE_STRING, "bottom-field-first", NULL);
8892 /* Create incomplete colorimetry here if needed */
8893 if (CUR_STREAM (stream)->colorimetry.range ||
8894 CUR_STREAM (stream)->colorimetry.matrix ||
8895 CUR_STREAM (stream)->colorimetry.transfer
8896 || CUR_STREAM (stream)->colorimetry.primaries) {
8897 gchar *colorimetry =
8898 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8899 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8900 G_TYPE_STRING, colorimetry, NULL);
8901 g_free (colorimetry);
8904 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8905 guint par_w = 1, par_h = 1;
8907 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8908 par_w = CUR_STREAM (stream)->par_w;
8909 par_h = CUR_STREAM (stream)->par_h;
8912 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8913 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8915 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8918 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8919 "multiview-mode", G_TYPE_STRING,
8920 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8921 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8922 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8927 else if (stream->subtype == FOURCC_soun) {
8928 if (CUR_STREAM (stream)->caps) {
8929 CUR_STREAM (stream)->caps =
8930 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8931 if (CUR_STREAM (stream)->rate > 0)
8932 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8933 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8934 if (CUR_STREAM (stream)->n_channels > 0)
8935 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8936 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8937 if (CUR_STREAM (stream)->n_channels > 2) {
8938 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8939 * correctly; this is just the minimum we can do - assume
8940 * we don't actually have any channel positions. */
8941 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8942 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8947 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8948 const GstStructure *s;
8949 QtDemuxStream *fps_stream = NULL;
8950 gboolean fps_available = FALSE;
8952 /* CEA608 closed caption tracks are a bit special in that each sample
8953 * can contain CCs for multiple frames, and CCs can be omitted and have to
8954 * be inferred from the duration of the sample then.
8956 * As such we take the framerate from the (first) video track here for
8957 * CEA608 as there must be one CC byte pair for every video frame
8958 * according to the spec.
8960 * For CEA708 all is fine and there is one sample per frame.
8963 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8964 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8967 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8968 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8970 if (tmp->subtype == FOURCC_vide) {
8977 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8978 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8979 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8982 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8983 fps_stream = stream;
8986 CUR_STREAM (stream)->caps =
8987 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8989 /* set framerate if calculated framerate is reliable */
8990 if (fps_available) {
8991 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8992 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8993 CUR_STREAM (stream)->fps_d, NULL);
8998 gboolean forward_collection = FALSE;
8999 GstCaps *prev_caps = NULL;
9001 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
9002 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
9003 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
9004 gst_pad_set_active (stream->pad, TRUE);
9006 gst_pad_use_fixed_caps (stream->pad);
9008 if (stream->protected) {
9009 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
9010 GST_ERROR_OBJECT (qtdemux,
9011 "Failed to configure protected stream caps.");
9016 if (stream->new_stream) {
9018 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
9021 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
9024 gst_event_parse_stream_flags (event, &stream_flags);
9025 if (gst_event_parse_group_id (event, &qtdemux->group_id))
9026 qtdemux->have_group_id = TRUE;
9028 qtdemux->have_group_id = FALSE;
9029 gst_event_unref (event);
9030 } else if (!qtdemux->have_group_id) {
9031 qtdemux->have_group_id = TRUE;
9032 qtdemux->group_id = gst_util_group_id_next ();
9035 stream->new_stream = FALSE;
9036 event = gst_event_new_stream_start (stream->stream_id);
9037 if (qtdemux->have_group_id)
9038 gst_event_set_group_id (event, qtdemux->group_id);
9039 if (stream->disabled)
9040 stream_flags |= GST_STREAM_FLAG_UNSELECT;
9041 if (CUR_STREAM (stream)->sparse) {
9042 stream_flags |= GST_STREAM_FLAG_SPARSE;
9044 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
9046 gst_event_set_stream_flags (event, stream_flags);
9047 gst_pad_push_event (stream->pad, event);
9049 forward_collection = TRUE;
9052 prev_caps = gst_pad_get_current_caps (stream->pad);
9054 if (CUR_STREAM (stream)->caps) {
9056 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
9057 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
9058 CUR_STREAM (stream)->caps);
9059 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
9061 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
9064 GST_WARNING_OBJECT (qtdemux, "stream without caps");
9068 gst_caps_unref (prev_caps);
9069 stream->new_caps = FALSE;
9071 if (forward_collection) {
9072 /* Forward upstream collection and selection if any */
9073 GstEvent *upstream_event = gst_pad_get_sticky_event (qtdemux->sinkpad,
9074 GST_EVENT_STREAM_COLLECTION, 0);
9076 gst_pad_push_event (stream->pad, upstream_event);
9083 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
9084 QtDemuxStream * stream)
9086 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
9089 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
9090 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
9091 if (G_UNLIKELY (stream->stsd_sample_description_id >=
9092 stream->stsd_entries_length)) {
9093 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
9094 (_("This file is invalid and cannot be played.")),
9095 ("New sample description id is out of bounds (%d >= %d)",
9096 stream->stsd_sample_description_id, stream->stsd_entries_length));
9098 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
9099 stream->new_caps = TRUE;
9104 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
9105 QtDemuxStream * stream, GstTagList * list)
9107 gboolean ret = TRUE;
9109 if (stream->subtype == FOURCC_vide) {
9110 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9113 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9116 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9117 gst_object_unref (stream->pad);
9123 qtdemux->n_video_streams++;
9124 } else if (stream->subtype == FOURCC_soun) {
9125 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
9128 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9130 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9131 gst_object_unref (stream->pad);
9136 qtdemux->n_audio_streams++;
9137 } else if (stream->subtype == FOURCC_strm) {
9138 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9139 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9140 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9141 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
9142 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9145 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9147 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9148 gst_object_unref (stream->pad);
9153 qtdemux->n_sub_streams++;
9154 } else if (stream->subtype == FOURCC_meta) {
9155 gchar *name = g_strdup_printf ("meta_%u", qtdemux->n_meta_streams);
9158 gst_pad_new_from_static_template (&gst_qtdemux_metasrc_template, name);
9160 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9161 gst_object_unref (stream->pad);
9166 qtdemux->n_meta_streams++;
9167 } else if (CUR_STREAM (stream)->caps) {
9168 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9171 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9173 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9174 gst_object_unref (stream->pad);
9179 qtdemux->n_video_streams++;
9181 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9188 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9189 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9190 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9191 GST_OBJECT_LOCK (qtdemux);
9192 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9193 GST_OBJECT_UNLOCK (qtdemux);
9195 if (stream->stream_tags)
9196 gst_tag_list_unref (stream->stream_tags);
9197 stream->stream_tags = list;
9199 /* global tags go on each pad anyway */
9200 stream->send_global_tags = TRUE;
9201 /* send upstream GST_EVENT_PROTECTION events that were received before
9202 this source pad was created */
9203 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9204 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9208 gst_tag_list_unref (list);
9212 /* find next atom with @fourcc starting at @offset */
9213 static GstFlowReturn
9214 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9215 guint64 * length, guint32 fourcc)
9221 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9222 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9228 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9229 if (G_UNLIKELY (ret != GST_FLOW_OK))
9231 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9234 gst_buffer_unref (buf);
9237 gst_buffer_map (buf, &map, GST_MAP_READ);
9238 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9239 gst_buffer_unmap (buf, &map);
9240 gst_buffer_unref (buf);
9242 if (G_UNLIKELY (*length == 0)) {
9243 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9244 ret = GST_FLOW_ERROR;
9248 if (lfourcc == fourcc) {
9249 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9250 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9253 GST_LOG_OBJECT (qtdemux,
9254 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9255 GST_FOURCC_ARGS (lfourcc), *offset);
9256 if (*offset == G_MAXUINT64)
9266 /* might simply have had last one */
9267 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9272 /* should only do something in pull mode */
9273 /* call with OBJECT lock */
9274 static GstFlowReturn
9275 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9277 guint64 length, offset;
9278 GstBuffer *buf = NULL;
9279 GstFlowReturn ret = GST_FLOW_OK;
9280 GstFlowReturn res = GST_FLOW_OK;
9283 offset = qtdemux->moof_offset;
9284 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9287 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9288 return GST_FLOW_EOS;
9291 /* best not do pull etc with lock held */
9292 GST_OBJECT_UNLOCK (qtdemux);
9294 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9295 if (ret != GST_FLOW_OK)
9298 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9299 if (G_UNLIKELY (ret != GST_FLOW_OK))
9301 gst_buffer_map (buf, &map, GST_MAP_READ);
9302 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9303 gst_buffer_unmap (buf, &map);
9304 gst_buffer_unref (buf);
9309 gst_buffer_unmap (buf, &map);
9310 gst_buffer_unref (buf);
9314 /* look for next moof */
9315 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9316 if (G_UNLIKELY (ret != GST_FLOW_OK))
9320 GST_OBJECT_LOCK (qtdemux);
9322 qtdemux->moof_offset = offset;
9328 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9330 res = GST_FLOW_ERROR;
9335 /* maybe upstream temporarily flushing */
9336 if (ret != GST_FLOW_FLUSHING) {
9337 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9340 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9341 /* resume at current position next time */
9349 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9353 gint32 stts_duration;
9354 GstByteWriter stsc, stts, stsz;
9356 /* Each sample has a different size, which we don't support for merging */
9357 if (stream->sample_size == 0) {
9358 GST_DEBUG_OBJECT (qtdemux,
9359 "Not all samples have the same size, not merging");
9363 /* The stream has a ctts table, we don't support that */
9364 if (stream->ctts_present) {
9365 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9369 /* If there's a sync sample table also ignore this stream */
9370 if (stream->stps_present || stream->stss_present) {
9371 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9375 /* If chunks are considered samples already ignore this stream */
9376 if (stream->chunks_are_samples) {
9377 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9381 /* Require that all samples have the same duration */
9382 if (stream->n_sample_times > 1) {
9383 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9387 /* Parse the stts to get the sample duration and number of samples */
9388 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9389 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9391 /* Parse the number of chunks from the stco manually because the
9392 * reader is already behind that */
9393 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9395 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9398 /* Now parse stsc, convert chunks into single samples and generate a
9399 * new stsc, stts and stsz from this information */
9400 gst_byte_writer_init (&stsc);
9401 gst_byte_writer_init (&stts);
9402 gst_byte_writer_init (&stsz);
9404 /* Note: we skip fourccs, size, version, flags and other fields of the new
9405 * atoms as the byte readers with them are already behind that position
9406 * anyway and only update the values of those inside the stream directly.
9408 stream->n_sample_times = 0;
9409 stream->n_samples = 0;
9410 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9412 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9414 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9415 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9416 sample_description_id =
9417 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9419 if (i == stream->n_samples_per_chunk - 1) {
9420 /* +1 because first_chunk is 1-based */
9421 last_chunk = num_chunks + 1;
9423 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9426 GST_DEBUG_OBJECT (qtdemux,
9427 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9428 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9430 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9431 /* One sample in this chunk */
9432 gst_byte_writer_put_uint32_be (&stsc, 1);
9433 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9435 /* For each chunk write a stts and stsz entry now */
9436 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9437 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9438 for (j = first_chunk; j < last_chunk; j++) {
9439 gst_byte_writer_put_uint32_be (&stsz,
9440 stream->sample_size * samples_per_chunk);
9443 stream->n_sample_times += 1;
9444 stream->n_samples += last_chunk - first_chunk;
9447 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9449 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9450 stream->n_samples, stream->n_sample_times);
9452 /* We don't have a fixed sample size anymore */
9453 stream->sample_size = 0;
9455 /* Free old data for the atoms */
9456 g_free ((gpointer) stream->stsz.data);
9457 stream->stsz.data = NULL;
9458 g_free ((gpointer) stream->stsc.data);
9459 stream->stsc.data = NULL;
9460 g_free ((gpointer) stream->stts.data);
9461 stream->stts.data = NULL;
9463 /* Store new data and replace byte readers */
9464 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9465 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9466 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9467 stream->stts.size = gst_byte_writer_get_size (&stts);
9468 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9469 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9470 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9471 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9472 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9475 /* initialise bytereaders for stbl sub-atoms */
9477 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9479 stream->stbl_index = -1; /* no samples have yet been parsed */
9480 stream->sample_index = -1;
9482 /* time-to-sample atom */
9483 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9486 /* copy atom data into a new buffer for later use */
9487 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9489 /* skip version + flags */
9490 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9491 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9493 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9495 /* make sure there's enough data */
9496 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9497 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9498 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9499 stream->n_sample_times);
9500 if (!stream->n_sample_times)
9504 /* sync sample atom */
9505 stream->stps_present = FALSE;
9506 if ((stream->stss_present =
9507 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9508 &stream->stss) ? TRUE : FALSE) == TRUE) {
9509 /* copy atom data into a new buffer for later use */
9510 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9512 /* skip version + flags */
9513 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9514 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9517 if (stream->n_sample_syncs) {
9518 /* make sure there's enough data */
9519 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9523 /* partial sync sample atom */
9524 if ((stream->stps_present =
9525 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9526 &stream->stps) ? TRUE : FALSE) == TRUE) {
9527 /* copy atom data into a new buffer for later use */
9528 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9530 /* skip version + flags */
9531 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9532 !gst_byte_reader_get_uint32_be (&stream->stps,
9533 &stream->n_sample_partial_syncs))
9536 /* if there are no entries, the stss table contains the real
9538 if (stream->n_sample_partial_syncs) {
9539 /* make sure there's enough data */
9540 if (!qt_atom_parser_has_chunks (&stream->stps,
9541 stream->n_sample_partial_syncs, 4))
9548 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9551 /* copy atom data into a new buffer for later use */
9552 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9554 /* skip version + flags */
9555 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9556 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9559 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9562 if (!stream->n_samples)
9565 /* sample-to-chunk atom */
9566 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9569 /* copy atom data into a new buffer for later use */
9570 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9572 /* skip version + flags */
9573 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9574 !gst_byte_reader_get_uint32_be (&stream->stsc,
9575 &stream->n_samples_per_chunk))
9578 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9579 stream->n_samples_per_chunk);
9581 /* make sure there's enough data */
9582 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9588 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9589 stream->co_size = sizeof (guint32);
9590 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9592 stream->co_size = sizeof (guint64);
9596 /* copy atom data into a new buffer for later use */
9597 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9599 /* skip version + flags */
9600 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9603 /* chunks_are_samples == TRUE means treat chunks as samples */
9604 stream->chunks_are_samples = stream->sample_size
9605 && !CUR_STREAM (stream)->sampled;
9606 if (stream->chunks_are_samples) {
9607 /* treat chunks as samples */
9608 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9611 /* skip number of entries */
9612 if (!gst_byte_reader_skip (&stream->stco, 4))
9615 /* make sure there are enough data in the stsz atom */
9616 if (!stream->sample_size) {
9617 /* different sizes for each sample */
9618 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9623 /* composition time-to-sample */
9624 if ((stream->ctts_present =
9625 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9626 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9627 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9628 guint8 ctts_version;
9629 gboolean checked_ctts = FALSE;
9631 /* copy atom data into a new buffer for later use */
9632 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9634 /* version 1 has signed offsets */
9635 if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9639 if (!gst_byte_reader_skip (&stream->ctts, 3)
9640 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9641 &stream->n_composition_times))
9644 /* make sure there's enough data */
9645 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9649 /* This is optional, if missing we iterate the ctts */
9650 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9651 guint8 cslg_version;
9653 /* cslg version 1 has 64 bit fields */
9654 if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9658 if (!gst_byte_reader_skip (&cslg, 3))
9661 if (cslg_version == 0) {
9662 gint32 composition_to_dts_shift;
9664 if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9667 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9669 gint64 composition_to_dts_shift;
9671 if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9674 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9677 gint32 cslg_least = 0;
9678 guint num_entries, pos;
9681 pos = gst_byte_reader_get_pos (&stream->ctts);
9682 num_entries = stream->n_composition_times;
9684 checked_ctts = TRUE;
9686 stream->cslg_shift = 0;
9688 for (i = 0; i < num_entries; i++) {
9691 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9692 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9693 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9694 * slightly inaccurate PTS could be more usable than corrupted one */
9695 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9696 && ABS (offset) / 2 > stream->duration)) {
9697 GST_WARNING_OBJECT (qtdemux,
9698 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9699 " larger than duration %" G_GUINT64_FORMAT, offset,
9702 stream->cslg_shift = 0;
9703 stream->ctts_present = FALSE;
9707 /* Don't consider "no decode samples" with offset G_MININT32
9708 * for the DTS/PTS shift */
9709 if (offset != G_MININT32 && offset < cslg_least)
9710 cslg_least = offset;
9714 stream->cslg_shift = -cslg_least;
9716 stream->cslg_shift = 0;
9718 /* reset the reader so we can generate sample table */
9719 gst_byte_reader_set_pos (&stream->ctts, pos);
9722 /* Check if ctts values are looking reasonable if that didn't happen above */
9723 if (!checked_ctts) {
9724 guint num_entries, pos;
9727 pos = gst_byte_reader_get_pos (&stream->ctts);
9728 num_entries = stream->n_composition_times;
9730 for (i = 0; i < num_entries; i++) {
9733 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9734 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9735 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9736 * slightly inaccurate PTS could be more usable than corrupted one */
9737 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9738 && ABS (offset) / 2 > stream->duration)) {
9739 GST_WARNING_OBJECT (qtdemux,
9740 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9741 " larger than duration %" G_GUINT64_FORMAT, offset,
9744 stream->cslg_shift = 0;
9745 stream->ctts_present = FALSE;
9750 /* reset the reader so we can generate sample table */
9751 gst_byte_reader_set_pos (&stream->ctts, pos);
9754 /* Ensure the cslg_shift value is consistent so we can use it
9755 * unconditionally to produce TS and Segment */
9756 stream->cslg_shift = 0;
9759 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
9760 stream->cslg_shift);
9762 /* For raw audio streams especially we might want to merge the samples
9763 * to not output one audio sample per buffer. We're doing this here
9764 * before allocating the sample tables so that from this point onwards
9765 * the number of container samples are static */
9766 if (stream->min_buffer_size > 0) {
9767 qtdemux_merge_sample_table (qtdemux, stream);
9771 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9772 stream->n_samples, (guint) sizeof (QtDemuxSample),
9773 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9775 if (stream->n_samples >=
9776 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9777 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9778 "be larger than %uMB (broken file?)", stream->n_samples,
9779 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9783 g_assert (stream->samples == NULL);
9784 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9785 if (!stream->samples) {
9786 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9795 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9796 (_("This file is corrupt and cannot be played.")), (NULL));
9801 gst_qtdemux_stbl_free (stream);
9802 if (!qtdemux->fragmented) {
9803 /* not quite good */
9804 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9807 /* may pick up samples elsewhere */
9813 /* collect samples from the next sample to be parsed up to sample @n for @stream
9814 * by reading the info from @stbl
9816 * This code can be executed from both the streaming thread and the seeking
9817 * thread so it takes the object lock to protect itself
9820 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9823 QtDemuxSample *samples, *first, *cur, *last;
9824 guint32 n_samples_per_chunk;
9827 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9828 GST_FOURCC_FORMAT ", pad %s",
9829 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9830 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9832 n_samples = stream->n_samples;
9835 goto out_of_samples;
9837 GST_OBJECT_LOCK (qtdemux);
9838 if (n <= stream->stbl_index)
9839 goto already_parsed;
9841 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9843 if (!stream->stsz.data) {
9844 /* so we already parsed and passed all the moov samples;
9845 * onto fragmented ones */
9846 g_assert (qtdemux->fragmented);
9850 /* pointer to the sample table */
9851 samples = stream->samples;
9853 /* starts from -1, moves to the next sample index to parse */
9854 stream->stbl_index++;
9856 /* keep track of the first and last sample to fill */
9857 first = &samples[stream->stbl_index];
9860 if (!stream->chunks_are_samples) {
9861 /* set the sample sizes */
9862 if (stream->sample_size == 0) {
9863 /* different sizes for each sample */
9864 for (cur = first; cur <= last; cur++) {
9865 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9866 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9867 (guint) (cur - samples), cur->size);
9870 /* samples have the same size */
9871 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9872 for (cur = first; cur <= last; cur++)
9873 cur->size = stream->sample_size;
9877 n_samples_per_chunk = stream->n_samples_per_chunk;
9880 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9883 if (stream->stsc_chunk_index >= stream->last_chunk
9884 || stream->stsc_chunk_index < stream->first_chunk) {
9885 stream->first_chunk =
9886 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9887 stream->samples_per_chunk =
9888 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9890 stream->stsd_sample_description_id =
9891 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9893 /* chunk numbers are counted from 1 it seems */
9894 if (G_UNLIKELY (stream->first_chunk == 0))
9897 --stream->first_chunk;
9899 /* the last chunk of each entry is calculated by taking the first chunk
9900 * of the next entry; except if there is no next, where we fake it with
9902 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9903 stream->last_chunk = G_MAXUINT32;
9905 stream->last_chunk =
9906 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9907 if (G_UNLIKELY (stream->last_chunk == 0))
9910 --stream->last_chunk;
9913 GST_LOG_OBJECT (qtdemux,
9914 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9915 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9916 stream->samples_per_chunk, stream->stsd_sample_description_id);
9918 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9921 if (stream->last_chunk != G_MAXUINT32) {
9922 if (!qt_atom_parser_peek_sub (&stream->stco,
9923 stream->first_chunk * stream->co_size,
9924 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9929 stream->co_chunk = stream->stco;
9930 if (!gst_byte_reader_skip (&stream->co_chunk,
9931 stream->first_chunk * stream->co_size))
9935 stream->stsc_chunk_index = stream->first_chunk;
9938 last_chunk = stream->last_chunk;
9940 if (stream->chunks_are_samples) {
9941 cur = &samples[stream->stsc_chunk_index];
9943 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9946 stream->stsc_chunk_index = j;
9951 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9954 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9955 "%" G_GUINT64_FORMAT, j, cur->offset);
9957 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9958 CUR_STREAM (stream)->bytes_per_frame > 0) {
9960 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9961 CUR_STREAM (stream)->samples_per_frame *
9962 CUR_STREAM (stream)->bytes_per_frame;
9964 cur->size = stream->samples_per_chunk;
9967 GST_DEBUG_OBJECT (qtdemux,
9968 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9969 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9970 stream->stco_sample_index)), cur->size);
9972 cur->timestamp = stream->stco_sample_index;
9973 cur->duration = stream->samples_per_chunk;
9974 cur->keyframe = TRUE;
9977 stream->stco_sample_index += stream->samples_per_chunk;
9979 stream->stsc_chunk_index = j;
9981 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9982 guint32 samples_per_chunk;
9983 guint64 chunk_offset;
9985 if (!stream->stsc_sample_index
9986 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9987 &stream->chunk_offset))
9990 samples_per_chunk = stream->samples_per_chunk;
9991 chunk_offset = stream->chunk_offset;
9993 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9994 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9995 G_GUINT64_FORMAT " and size %d",
9996 (guint) (cur - samples), chunk_offset, cur->size);
9998 cur->offset = chunk_offset;
9999 chunk_offset += cur->size;
10002 if (G_UNLIKELY (cur > last)) {
10004 stream->stsc_sample_index = k + 1;
10005 stream->chunk_offset = chunk_offset;
10006 stream->stsc_chunk_index = j;
10010 stream->stsc_sample_index = 0;
10012 stream->stsc_chunk_index = j;
10014 stream->stsc_index++;
10017 if (stream->chunks_are_samples)
10021 guint32 n_sample_times;
10023 n_sample_times = stream->n_sample_times;
10026 for (i = stream->stts_index; i < n_sample_times; i++) {
10027 guint32 stts_samples;
10028 gint32 stts_duration;
10031 if (stream->stts_sample_index >= stream->stts_samples
10032 || !stream->stts_sample_index) {
10034 stream->stts_samples =
10035 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10036 stream->stts_duration =
10037 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10039 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
10040 i, stream->stts_samples, stream->stts_duration);
10042 stream->stts_sample_index = 0;
10045 stts_samples = stream->stts_samples;
10046 stts_duration = stream->stts_duration;
10047 stts_time = stream->stts_time;
10049 for (j = stream->stts_sample_index; j < stts_samples; j++) {
10050 GST_DEBUG_OBJECT (qtdemux,
10051 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
10052 (guint) (cur - samples), j,
10053 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
10055 cur->timestamp = stts_time;
10056 cur->duration = stts_duration;
10058 /* avoid 32-bit wrap-around,
10059 * but still mind possible 'negative' duration */
10060 stts_time += (gint64) stts_duration;
10063 if (G_UNLIKELY (cur > last)) {
10065 stream->stts_time = stts_time;
10066 stream->stts_sample_index = j + 1;
10067 if (stream->stts_sample_index >= stream->stts_samples)
10068 stream->stts_index++;
10072 stream->stts_sample_index = 0;
10073 stream->stts_time = stts_time;
10074 stream->stts_index++;
10076 /* fill up empty timestamps with the last timestamp, this can happen when
10077 * the last samples do not decode and so we don't have timestamps for them.
10078 * We however look at the last timestamp to estimate the track length so we
10079 * need something in here. */
10080 for (; cur < last; cur++) {
10081 GST_DEBUG_OBJECT (qtdemux,
10082 "fill sample %d: timestamp %" GST_TIME_FORMAT,
10083 (guint) (cur - samples),
10084 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
10085 cur->timestamp = stream->stts_time;
10086 cur->duration = -1;
10091 /* sample sync, can be NULL */
10092 if (stream->stss_present == TRUE) {
10093 guint32 n_sample_syncs;
10095 n_sample_syncs = stream->n_sample_syncs;
10097 if (!n_sample_syncs) {
10098 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
10099 stream->all_keyframe = TRUE;
10101 for (i = stream->stss_index; i < n_sample_syncs; i++) {
10102 /* note that the first sample is index 1, not 0 */
10105 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
10107 if (G_LIKELY (index > 0 && index <= n_samples)) {
10109 samples[index].keyframe = TRUE;
10110 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10111 /* and exit if we have enough samples */
10112 if (G_UNLIKELY (index >= n)) {
10119 stream->stss_index = i;
10122 /* stps marks partial sync frames like open GOP I-Frames */
10123 if (stream->stps_present == TRUE) {
10124 guint32 n_sample_partial_syncs;
10126 n_sample_partial_syncs = stream->n_sample_partial_syncs;
10128 /* if there are no entries, the stss table contains the real
10130 if (n_sample_partial_syncs) {
10131 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
10132 /* note that the first sample is index 1, not 0 */
10135 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
10137 if (G_LIKELY (index > 0 && index <= n_samples)) {
10139 samples[index].keyframe = TRUE;
10140 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10141 /* and exit if we have enough samples */
10142 if (G_UNLIKELY (index >= n)) {
10149 stream->stps_index = i;
10153 /* no stss, all samples are keyframes */
10154 stream->all_keyframe = TRUE;
10155 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10160 /* composition time to sample */
10161 if (stream->ctts_present == TRUE) {
10162 guint32 n_composition_times;
10163 guint32 ctts_count;
10164 gint32 ctts_soffset;
10166 /* Fill in the pts_offsets */
10168 n_composition_times = stream->n_composition_times;
10170 for (i = stream->ctts_index; i < n_composition_times; i++) {
10171 if (stream->ctts_sample_index >= stream->ctts_count
10172 || !stream->ctts_sample_index) {
10173 stream->ctts_count =
10174 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10175 stream->ctts_soffset =
10176 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10177 stream->ctts_sample_index = 0;
10180 ctts_count = stream->ctts_count;
10181 ctts_soffset = stream->ctts_soffset;
10183 /* FIXME: Set offset to 0 for "no decode samples". This needs
10184 * to be handled in a codec specific manner ideally. */
10185 if (ctts_soffset == G_MININT32)
10188 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10189 cur->pts_offset = ctts_soffset;
10192 if (G_UNLIKELY (cur > last)) {
10194 stream->ctts_sample_index = j + 1;
10198 stream->ctts_sample_index = 0;
10199 stream->ctts_index++;
10203 stream->stbl_index = n;
10204 /* if index has been completely parsed, free data that is no-longer needed */
10205 if (n + 1 == stream->n_samples) {
10206 gst_qtdemux_stbl_free (stream);
10207 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10208 if (qtdemux->pullbased) {
10209 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10210 while (n + 1 == stream->n_samples)
10211 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10215 GST_OBJECT_UNLOCK (qtdemux);
10222 GST_LOG_OBJECT (qtdemux,
10223 "Tried to parse up to sample %u but this sample has already been parsed",
10225 /* if fragmented, there may be more */
10226 if (qtdemux->fragmented && n == stream->stbl_index)
10228 GST_OBJECT_UNLOCK (qtdemux);
10234 GST_LOG_OBJECT (qtdemux,
10235 "Tried to parse up to sample %u but there are only %u samples", n + 1,
10236 stream->n_samples);
10237 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10238 (_("This file is corrupt and cannot be played.")), (NULL));
10243 GST_OBJECT_UNLOCK (qtdemux);
10244 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10245 (_("This file is corrupt and cannot be played.")), (NULL));
10250 /* collect all segment info for @stream.
10253 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10257 /* accept edts if they contain gaps at start and there is only
10258 * one media segment */
10259 gboolean allow_pushbased_edts = TRUE;
10260 gint media_segments_count = 0;
10262 /* parse and prepare segment info from the edit list */
10263 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10264 stream->n_segments = 0;
10265 stream->segments = NULL;
10266 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10269 gint segment_number, entry_size;
10271 GstClockTime stime;
10272 const guint8 *buffer;
10276 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10277 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10280 buffer = elst->data;
10282 size = QT_UINT32 (buffer);
10283 /* version, flags, n_segments */
10285 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10288 version = QT_UINT8 (buffer + 8);
10289 entry_size = (version == 1) ? 20 : 12;
10291 n_segments = QT_UINT32 (buffer + 12);
10293 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10294 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10298 /* we might allocate a bit too much, at least allocate 1 segment */
10299 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10301 /* segments always start from 0 */
10305 for (segment_number = 0; segment_number < n_segments; segment_number++) {
10307 guint64 media_time;
10308 gboolean empty_edit = FALSE;
10309 QtDemuxSegment *segment;
10311 GstClockTime media_start = GST_CLOCK_TIME_NONE;
10313 if (version == 1) {
10314 media_time = QT_UINT64 (buffer + 8);
10315 duration = QT_UINT64 (buffer);
10316 if (media_time == G_MAXUINT64)
10319 media_time = QT_UINT32 (buffer + 4);
10320 duration = QT_UINT32 (buffer);
10321 if (media_time == G_MAXUINT32)
10326 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10328 segment = &stream->segments[segment_number];
10330 /* time and duration expressed in global timescale */
10331 segment->time = stime;
10332 if (duration != 0 || empty_edit) {
10333 /* edge case: empty edits with duration=zero are treated here.
10334 * (files should not have these anyway). */
10336 /* add non scaled values so we don't cause roundoff errors */
10338 stime = QTTIME_TO_GSTTIME (qtdemux, time);
10339 segment->duration = stime - segment->time;
10341 /* zero duration does not imply media_start == media_stop
10342 * but, only specify media_start. The edit ends with the track. */
10343 stime = segment->duration = GST_CLOCK_TIME_NONE;
10344 /* Don't allow more edits after this one. */
10345 n_segments = segment_number + 1;
10347 segment->stop_time = stime;
10349 segment->trak_media_start = media_time;
10350 /* media_time expressed in stream timescale */
10352 segment->media_start = media_start;
10353 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10354 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10355 media_segments_count++;
10357 segment->media_start = GST_CLOCK_TIME_NONE;
10358 segment->media_stop = GST_CLOCK_TIME_NONE;
10360 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10362 if (rate_int <= 1) {
10363 /* 0 is not allowed, some programs write 1 instead of the floating point
10365 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10369 segment->rate = rate_int / 65536.0;
10372 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10373 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10374 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10375 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10376 segment_number, GST_TIME_ARGS (segment->time),
10377 GST_TIME_ARGS (segment->duration),
10378 GST_TIME_ARGS (segment->media_start), media_time,
10379 GST_TIME_ARGS (segment->media_stop),
10380 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10381 stream->timescale);
10382 if (segment->stop_time > qtdemux->segment.stop &&
10383 !qtdemux->upstream_format_is_time) {
10384 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10385 " extends to %" GST_TIME_FORMAT
10386 " past the end of the declared movie duration %" GST_TIME_FORMAT
10387 " movie segment will be extended", segment_number,
10388 GST_TIME_ARGS (segment->stop_time),
10389 GST_TIME_ARGS (qtdemux->segment.stop));
10390 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10393 buffer += entry_size;
10395 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10396 stream->n_segments = n_segments;
10397 if (media_segments_count != 1)
10398 allow_pushbased_edts = FALSE;
10402 /* push based does not handle segments, so act accordingly here,
10403 * and warn if applicable */
10404 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10405 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10406 /* remove and use default one below, we stream like it anyway */
10407 g_free (stream->segments);
10408 stream->segments = NULL;
10409 stream->n_segments = 0;
10412 /* no segments, create one to play the complete trak */
10413 if (stream->n_segments == 0) {
10414 GstClockTime stream_duration =
10415 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10417 if (stream->segments == NULL)
10418 stream->segments = g_new (QtDemuxSegment, 1);
10420 /* represent unknown our way */
10421 if (stream_duration == 0)
10422 stream_duration = GST_CLOCK_TIME_NONE;
10424 stream->segments[0].time = 0;
10425 stream->segments[0].stop_time = stream_duration;
10426 stream->segments[0].duration = stream_duration;
10427 stream->segments[0].media_start = 0;
10428 stream->segments[0].media_stop = stream_duration;
10429 stream->segments[0].rate = 1.0;
10430 stream->segments[0].trak_media_start = 0;
10432 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10433 GST_TIME_ARGS (stream_duration));
10434 stream->n_segments = 1;
10435 stream->dummy_segment = TRUE;
10437 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10443 * Parses the stsd atom of a svq3 trak looking for
10444 * the SMI and gama atoms.
10447 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10448 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10450 const guint8 *_gamma = NULL;
10451 GstBuffer *_seqh = NULL;
10452 const guint8 *stsd_data = stsd_entry_data;
10453 guint32 length = QT_UINT32 (stsd_data);
10457 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10463 version = QT_UINT16 (stsd_data);
10464 if (version == 3) {
10465 if (length >= 70) {
10468 while (length > 8) {
10469 guint32 fourcc, size;
10470 const guint8 *data;
10471 size = QT_UINT32 (stsd_data);
10472 fourcc = QT_FOURCC (stsd_data + 4);
10473 data = stsd_data + 8;
10476 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10477 "svq3 atom parsing");
10486 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10487 " for gama atom, expected 12", size);
10492 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10494 if (_seqh != NULL) {
10495 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10496 " found, ignoring");
10498 seqh_size = QT_UINT32 (data + 4);
10499 if (seqh_size > 0) {
10500 _seqh = gst_buffer_new_and_alloc (seqh_size);
10501 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10508 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10509 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10513 if (size <= length) {
10519 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10522 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10523 G_GUINT16_FORMAT, version);
10533 } else if (_seqh) {
10534 gst_buffer_unref (_seqh);
10539 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10542 GstByteReader dref;
10546 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10547 * atom that might contain a 'data' atom with the rtsp uri.
10548 * This case was reported in bug #597497, some info about
10549 * the hndl atom can be found in TN1195
10551 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10552 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10555 guint32 dref_num_entries = 0;
10556 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10557 gst_byte_reader_skip (&dref, 4) &&
10558 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10561 /* search dref entries for hndl atom */
10562 for (i = 0; i < dref_num_entries; i++) {
10563 guint32 size = 0, type;
10564 guint8 string_len = 0;
10565 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10566 qt_atom_parser_get_fourcc (&dref, &type)) {
10567 if (type == FOURCC_hndl) {
10568 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10570 /* skip data reference handle bytes and the
10571 * following pascal string and some extra 4
10572 * bytes I have no idea what are */
10573 if (!gst_byte_reader_skip (&dref, 4) ||
10574 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10575 !gst_byte_reader_skip (&dref, string_len + 4)) {
10576 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10580 /* iterate over the atoms to find the data atom */
10581 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10585 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10586 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10587 if (atom_type == FOURCC_data) {
10588 const guint8 *uri_aux = NULL;
10590 /* found the data atom that might contain the rtsp uri */
10591 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10592 "hndl atom, interpreting it as an URI");
10593 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10595 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10596 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10598 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10599 "didn't contain a rtsp address");
10601 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10606 /* skipping to the next entry */
10607 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10610 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10617 /* skip to the next entry */
10618 if (!gst_byte_reader_skip (&dref, size - 8))
10621 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10624 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10630 #define AMR_NB_ALL_MODES 0x81ff
10631 #define AMR_WB_ALL_MODES 0x83ff
10633 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10635 /* The 'damr' atom is of the form:
10637 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10638 * 32 b 8 b 16 b 8 b 8 b
10640 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10641 * represents the highest mode used in the stream (and thus the maximum
10642 * bitrate), with a couple of special cases as seen below.
10645 /* Map of frame type ID -> bitrate */
10646 static const guint nb_bitrates[] = {
10647 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10649 static const guint wb_bitrates[] = {
10650 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10656 gst_buffer_map (buf, &map, GST_MAP_READ);
10658 if (map.size != 0x11) {
10659 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10663 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10664 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10665 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10669 mode_set = QT_UINT16 (map.data + 13);
10671 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10672 max_mode = 7 + (wb ? 1 : 0);
10674 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10675 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10677 if (max_mode == -1) {
10678 GST_DEBUG ("No mode indication was found (mode set) = %x",
10683 gst_buffer_unmap (buf, &map);
10684 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10687 gst_buffer_unmap (buf, &map);
10692 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10693 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10696 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10702 if (gst_byte_reader_get_remaining (reader) < 36)
10705 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10706 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10707 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10708 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10709 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10710 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10711 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10712 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10713 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10715 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10716 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10717 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10719 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10720 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10722 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10723 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10730 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10731 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10738 * This macro will only compare value abdegh, it expects cfi to have already
10741 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10742 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10744 /* only handle the cases where the last column has standard values */
10745 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10746 const gchar *rotation_tag = NULL;
10748 /* no rotation needed */
10749 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10751 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10752 rotation_tag = "rotate-90";
10753 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10754 rotation_tag = "rotate-180";
10755 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10756 rotation_tag = "rotate-270";
10758 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10761 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10762 GST_STR_NULL (rotation_tag));
10763 if (rotation_tag != NULL) {
10764 if (*taglist == NULL)
10765 *taglist = gst_tag_list_new_empty ();
10766 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10767 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10770 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10775 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10776 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10780 GstBuffer *adrm_buf = NULL;
10781 QtDemuxAavdEncryptionInfo *info;
10783 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10784 if (G_UNLIKELY (!adrm)) {
10785 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10788 adrm_size = QT_UINT32 (adrm->data);
10789 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10791 stream->protection_scheme_type = FOURCC_aavd;
10793 if (!stream->protection_scheme_info)
10794 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10796 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10798 if (info->default_properties)
10799 gst_structure_free (info->default_properties);
10800 info->default_properties = gst_structure_new ("application/x-aavd",
10801 "encrypted", G_TYPE_BOOLEAN, TRUE,
10802 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10803 gst_buffer_unref (adrm_buf);
10805 *original_fmt = FOURCC_mp4a;
10809 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10810 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10811 * Common Encryption (cenc), the function will also parse the tenc box (defined
10812 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10813 * (typically an enc[v|a|t|s] sample entry); the function will set
10814 * @original_fmt to the fourcc of the original unencrypted stream format.
10815 * Returns TRUE if successful; FALSE otherwise. */
10817 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10818 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10824 QtDemuxCencSampleSetInfo *info;
10826 const guint8 *tenc_data;
10828 g_return_val_if_fail (qtdemux != NULL, FALSE);
10829 g_return_val_if_fail (stream != NULL, FALSE);
10830 g_return_val_if_fail (container != NULL, FALSE);
10831 g_return_val_if_fail (original_fmt != NULL, FALSE);
10833 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10834 if (G_UNLIKELY (!sinf)) {
10835 if (stream->protection_scheme_type == FOURCC_cenc
10836 || stream->protection_scheme_type == FOURCC_cbcs) {
10837 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10838 "mandatory for Common Encryption");
10844 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10845 if (G_UNLIKELY (!frma)) {
10846 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10850 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10851 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10852 GST_FOURCC_ARGS (*original_fmt));
10854 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10856 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10859 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10860 stream->protection_scheme_version =
10861 QT_UINT32 ((const guint8 *) schm->data + 16);
10863 GST_DEBUG_OBJECT (qtdemux,
10864 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10865 "protection_scheme_version: %#010x",
10866 GST_FOURCC_ARGS (stream->protection_scheme_type),
10867 stream->protection_scheme_version);
10869 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10871 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10874 if (stream->protection_scheme_type != FOURCC_cenc &&
10875 stream->protection_scheme_type != FOURCC_piff &&
10876 stream->protection_scheme_type != FOURCC_cbcs) {
10877 GST_ERROR_OBJECT (qtdemux,
10878 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10879 GST_FOURCC_ARGS (stream->protection_scheme_type));
10883 if (G_UNLIKELY (!stream->protection_scheme_info))
10884 stream->protection_scheme_info =
10885 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10887 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10889 if (stream->protection_scheme_type == FOURCC_cenc
10890 || stream->protection_scheme_type == FOURCC_cbcs) {
10891 guint8 is_encrypted;
10893 guint8 constant_iv_size = 0;
10894 const guint8 *default_kid;
10895 guint8 crypt_byte_block = 0;
10896 guint8 skip_byte_block = 0;
10897 const guint8 *constant_iv = NULL;
10899 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10901 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10902 "which is mandatory for Common Encryption");
10905 tenc_data = (const guint8 *) tenc->data + 12;
10906 is_encrypted = QT_UINT8 (tenc_data + 2);
10907 iv_size = QT_UINT8 (tenc_data + 3);
10908 default_kid = (tenc_data + 4);
10909 if (stream->protection_scheme_type == FOURCC_cbcs) {
10910 guint8 possible_pattern_info;
10911 if (iv_size == 0) {
10912 constant_iv_size = QT_UINT8 (tenc_data + 20);
10913 if (constant_iv_size != 8 && constant_iv_size != 16) {
10914 GST_ERROR_OBJECT (qtdemux,
10915 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10918 constant_iv = (tenc_data + 21);
10920 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10921 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10922 skip_byte_block = possible_pattern_info & 0x0f;
10924 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10925 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10926 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10927 } else if (stream->protection_scheme_type == FOURCC_piff) {
10929 static const guint8 piff_track_encryption_uuid[] = {
10930 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10931 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10934 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10936 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10937 "which is mandatory for Common Encryption");
10941 tenc_data = (const guint8 *) tenc->data + 8;
10942 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10943 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10944 GST_ERROR_OBJECT (qtdemux,
10945 "Unsupported track encryption box with uuid: %s", box_uuid);
10949 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10950 gst_byte_reader_init (&br, tenc_data, 20);
10951 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10952 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10955 stream->protection_scheme_type = FOURCC_cenc;
10962 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10963 QtDemuxStream ** stream2)
10965 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10969 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10974 /*parse svmi header if existing */
10975 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10977 guint len = QT_UINT32 ((guint8 *) svmi->data);
10978 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10980 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10981 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10982 guint8 frame_type, frame_layout;
10983 guint32 stereo_mono_change_count;
10988 /* MPEG-A stereo video */
10989 if (qtdemux->major_brand == FOURCC_ss02)
10990 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10992 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10993 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10994 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10996 switch (frame_type) {
10998 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
11001 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
11004 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
11007 /* mode 3 is primary/secondary view sequence, ie
11008 * left/right views in separate tracks. See section 7.2
11009 * of ISO/IEC 23000-11:2009 */
11010 /* In the future this might be supported using related
11011 * streams, like an enhancement track - if files like this
11013 GST_FIXME_OBJECT (qtdemux,
11014 "Implement stereo video in separate streams");
11017 if ((frame_layout & 0x1) == 0)
11018 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
11020 GST_LOG_OBJECT (qtdemux,
11021 "StereoVideo: composition type: %u, is_left_first: %u",
11022 frame_type, frame_layout);
11024 if (stereo_mono_change_count > 1) {
11025 GST_FIXME_OBJECT (qtdemux,
11026 "Mixed-mono flags are not yet supported in qtdemux.");
11029 stream->multiview_mode = mode;
11030 stream->multiview_flags = flags;
11037 /* parse the traks.
11038 * With each track we associate a new QtDemuxStream that contains all the info
11040 * traks that do not decode to something (like strm traks) will not have a pad.
11043 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
11045 GstByteReader tkhd;
11059 QtDemuxStream *stream = NULL;
11060 const guint8 *stsd_data;
11061 const guint8 *stsd_entry_data;
11062 guint remaining_stsd_len;
11063 guint stsd_entry_count;
11065 guint16 lang_code; /* quicktime lang code or packed iso code */
11067 guint32 tkhd_flags = 0;
11068 guint8 tkhd_version = 0;
11069 guint32 w = 0, h = 0;
11070 guint value_size, stsd_len, len;
11074 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
11076 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
11077 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
11078 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
11081 /* pick between 64 or 32 bits */
11082 value_size = tkhd_version == 1 ? 8 : 4;
11083 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
11084 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
11087 /* Check if current moov has duplicated track_id */
11088 if (qtdemux_find_stream (qtdemux, track_id))
11089 goto existing_stream;
11091 stream = _create_stream (qtdemux, track_id);
11092 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11094 /* need defaults for fragments */
11095 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
11097 if ((tkhd_flags & 1) == 0)
11098 stream->disabled = TRUE;
11100 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
11101 tkhd_version, tkhd_flags, stream->track_id);
11103 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
11106 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
11107 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
11108 if (qtdemux->major_brand != FOURCC_mjp2 ||
11109 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
11113 len = QT_UINT32 ((guint8 *) mdhd->data);
11114 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
11115 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
11116 if (version == 0x01000000) {
11119 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
11120 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
11121 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
11125 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
11126 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
11127 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
11130 if (lang_code < 0x400) {
11131 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
11132 } else if (lang_code == 0x7fff) {
11133 stream->lang_id[0] = 0; /* unspecified */
11135 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11136 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11137 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11138 stream->lang_id[3] = 0;
11141 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11142 stream->timescale);
11143 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11145 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11146 lang_code, stream->lang_id);
11148 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11151 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11152 /* chapters track reference */
11153 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11155 gsize length = GST_READ_UINT32_BE (chap->data);
11156 if (qtdemux->chapters_track_id)
11157 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11159 if (length >= 12) {
11160 qtdemux->chapters_track_id =
11161 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11166 /* fragmented files may have bogus duration in moov */
11167 if (!qtdemux->fragmented &&
11168 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11169 guint64 tdur1, tdur2;
11171 /* don't overflow */
11172 tdur1 = stream->timescale * (guint64) qtdemux->duration;
11173 tdur2 = qtdemux->timescale * (guint64) stream->duration;
11176 * some of those trailers, nowadays, have prologue images that are
11177 * themselves video tracks as well. I haven't really found a way to
11178 * identify those yet, except for just looking at their duration. */
11179 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11180 GST_WARNING_OBJECT (qtdemux,
11181 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11182 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11183 "found, assuming preview image or something; skipping track",
11184 stream->duration, stream->timescale, qtdemux->duration,
11185 qtdemux->timescale);
11186 gst_qtdemux_stream_unref (stream);
11191 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11194 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11195 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11197 len = QT_UINT32 ((guint8 *) hdlr->data);
11199 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11200 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11201 GST_FOURCC_ARGS (stream->subtype));
11203 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11206 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11209 /* Parse out svmi (and later st3d/sv3d) atoms */
11210 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
11213 /* parse rest of tkhd */
11214 if (stream->subtype == FOURCC_vide) {
11217 /* version 1 uses some 64-bit ints */
11218 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11221 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11224 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11225 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11228 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11229 &stream->stream_tags);
11233 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11235 stsd_data = (const guint8 *) stsd->data;
11237 /* stsd should at least have one entry */
11238 stsd_len = QT_UINT32 (stsd_data);
11239 if (stsd_len < 24) {
11240 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11241 if (stream->subtype == FOURCC_vivo) {
11242 gst_qtdemux_stream_unref (stream);
11249 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11250 /* each stsd entry must contain at least 8 bytes */
11251 if (stream->stsd_entries_length == 0
11252 || stream->stsd_entries_length > stsd_len / 8) {
11253 stream->stsd_entries_length = 0;
11256 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11257 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
11258 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
11260 stsd_entry_data = stsd_data + 16;
11261 remaining_stsd_len = stsd_len - 16;
11262 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11264 gchar *codec = NULL;
11265 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11267 /* and that entry should fit within stsd */
11268 len = QT_UINT32 (stsd_entry_data);
11269 if (len > remaining_stsd_len)
11272 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11273 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
11274 GST_FOURCC_ARGS (entry->fourcc));
11275 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
11277 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11278 goto error_encrypted;
11280 if (fourcc == FOURCC_aavd) {
11281 if (stream->subtype != FOURCC_soun) {
11282 GST_ERROR_OBJECT (qtdemux,
11283 "Unexpeced stsd type 'aavd' outside 'soun' track");
11285 /* encrypted audio with sound sample description v0 */
11286 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11287 stream->protected = TRUE;
11288 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11289 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11293 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11294 /* FIXME this looks wrong, there might be multiple children
11295 * with the same type */
11296 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11297 stream->protected = TRUE;
11298 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11299 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11302 if (stream->subtype == FOURCC_vide) {
11307 gint depth, palette_size, palette_count;
11308 guint32 *palette_data = NULL;
11310 entry->sampled = TRUE;
11312 stream->display_width = w >> 16;
11313 stream->display_height = h >> 16;
11316 if (len < 86) /* TODO verify */
11319 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11320 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11321 entry->fps_n = 0; /* this is filled in later */
11322 entry->fps_d = 0; /* this is filled in later */
11323 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11324 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11326 /* if color_table_id is 0, ctab atom must follow; however some files
11327 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11328 * if color table is not present we'll correct the value */
11329 if (entry->color_table_id == 0 &&
11331 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11332 entry->color_table_id = -1;
11335 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11336 entry->width, entry->height, entry->bits_per_sample,
11337 entry->color_table_id);
11339 depth = entry->bits_per_sample;
11341 /* more than 32 bits means grayscale */
11342 gray = (depth > 32);
11343 /* low 32 bits specify the depth */
11346 /* different number of palette entries is determined by depth. */
11348 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11349 palette_count = (1 << depth);
11350 palette_size = palette_count * 4;
11352 if (entry->color_table_id) {
11353 switch (palette_count) {
11357 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11360 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11365 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11367 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11372 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11375 g_memdup2 (ff_qt_default_palette_256, palette_size);
11378 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11379 (_("The video in this file might not play correctly.")),
11380 ("unsupported palette depth %d", depth));
11384 gint i, j, start, end;
11390 start = QT_UINT32 (stsd_entry_data + offset + 70);
11391 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11392 end = QT_UINT16 (stsd_entry_data + offset + 76);
11394 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11395 start, end, palette_count);
11402 if (len < 94 + (end - start) * 8)
11405 /* palette is always the same size */
11406 palette_data = g_malloc0 (256 * 4);
11407 palette_size = 256 * 4;
11409 for (j = 0, i = start; i <= end; j++, i++) {
11410 guint32 a, r, g, b;
11412 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11413 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11414 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11415 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11417 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11418 (g & 0xff00) | (b >> 8);
11423 gst_caps_unref (entry->caps);
11426 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11428 if (G_UNLIKELY (!entry->caps)) {
11429 g_free (palette_data);
11430 goto unknown_stream;
11434 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11435 GST_TAG_VIDEO_CODEC, codec, NULL);
11440 if (palette_data) {
11443 if (entry->rgb8_palette)
11444 gst_memory_unref (entry->rgb8_palette);
11445 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11446 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11448 s = gst_caps_get_structure (entry->caps, 0);
11450 /* non-raw video has a palette_data property. raw video has the palette as
11451 * an extra plane that we append to the output buffers before we push
11453 if (!gst_structure_has_name (s, "video/x-raw")) {
11454 GstBuffer *palette;
11456 palette = gst_buffer_new ();
11457 gst_buffer_append_memory (palette, entry->rgb8_palette);
11458 entry->rgb8_palette = NULL;
11460 gst_caps_set_simple (entry->caps, "palette_data",
11461 GST_TYPE_BUFFER, palette, NULL);
11462 gst_buffer_unref (palette);
11464 } else if (palette_count != 0) {
11465 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11466 (NULL), ("Unsupported palette depth %d", depth));
11469 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11470 QT_UINT16 (stsd_entry_data + offset + 32));
11476 /* pick 'the' stsd child */
11477 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11478 // We should skip parsing the stsd for non-protected streams if
11479 // the entry doesn't match the fourcc, since they don't change
11480 // format. However, for protected streams we can have partial
11481 // encryption, where parts of the stream are encrypted and parts
11482 // not. For both parts of such streams, we should ensure the
11483 // esds overrides are parsed for both from the stsd.
11484 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11485 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11487 else if (!stream->protected)
11492 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11493 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11494 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11495 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11499 const guint8 *pasp_data = (const guint8 *) pasp->data;
11500 gint len = QT_UINT32 (pasp_data);
11503 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11504 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11506 CUR_STREAM (stream)->par_w = 0;
11507 CUR_STREAM (stream)->par_h = 0;
11510 CUR_STREAM (stream)->par_w = 0;
11511 CUR_STREAM (stream)->par_h = 0;
11515 const guint8 *fiel_data = (const guint8 *) fiel->data;
11516 gint len = QT_UINT32 (fiel_data);
11519 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11520 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11525 const guint8 *colr_data = (const guint8 *) colr->data;
11526 gint len = QT_UINT32 (colr_data);
11528 if (len == 19 || len == 18) {
11529 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11531 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11532 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11533 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11534 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11535 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11537 CUR_STREAM (stream)->colorimetry.primaries =
11538 gst_video_color_primaries_from_iso (primaries);
11539 CUR_STREAM (stream)->colorimetry.transfer =
11540 gst_video_transfer_function_from_iso (transfer_function);
11541 CUR_STREAM (stream)->colorimetry.matrix =
11542 gst_video_color_matrix_from_iso (matrix);
11543 CUR_STREAM (stream)->colorimetry.range =
11544 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11545 GST_VIDEO_COLOR_RANGE_16_235;
11547 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11550 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11555 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11556 stream->stream_tags);
11563 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11564 const guint8 *avc_data = stsd_entry_data + 0x56;
11567 while (len >= 0x8) {
11570 if (QT_UINT32 (avc_data) <= len)
11571 size = QT_UINT32 (avc_data) - 0x8;
11576 /* No real data, so break out */
11579 switch (QT_FOURCC (avc_data + 0x4)) {
11582 /* parse, if found */
11585 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11587 /* First 4 bytes are the length of the atom, the next 4 bytes
11588 * are the fourcc, the next 1 byte is the version, and the
11589 * subsequent bytes are profile_tier_level structure like data. */
11590 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11591 avc_data + 8 + 1, size - 1);
11592 buf = gst_buffer_new_and_alloc (size);
11593 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11594 gst_caps_set_simple (entry->caps,
11595 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11596 gst_buffer_unref (buf);
11604 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11606 /* First 4 bytes are the length of the atom, the next 4 bytes
11607 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11608 * next 1 byte is the version, and the
11609 * subsequent bytes are sequence parameter set like data. */
11611 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11613 gst_codec_utils_h264_caps_set_level_and_profile
11614 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11616 buf = gst_buffer_new_and_alloc (size);
11617 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11618 gst_caps_set_simple (entry->caps,
11619 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11620 gst_buffer_unref (buf);
11626 guint avg_bitrate, max_bitrate;
11628 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11632 max_bitrate = QT_UINT32 (avc_data + 0xc);
11633 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11635 if (!max_bitrate && !avg_bitrate)
11638 /* Some muxers seem to swap the average and maximum bitrates
11639 * (I'm looking at you, YouTube), so we swap for sanity. */
11640 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11641 guint temp = avg_bitrate;
11643 avg_bitrate = max_bitrate;
11644 max_bitrate = temp;
11647 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11648 gst_tag_list_add (stream->stream_tags,
11649 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11650 max_bitrate, NULL);
11652 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11653 gst_tag_list_add (stream->stream_tags,
11654 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11666 avc_data += size + 8;
11677 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11678 const guint8 *hevc_data = stsd_entry_data + 0x56;
11681 while (len >= 0x8) {
11684 if (QT_UINT32 (hevc_data) <= len)
11685 size = QT_UINT32 (hevc_data) - 0x8;
11690 /* No real data, so break out */
11693 switch (QT_FOURCC (hevc_data + 0x4)) {
11696 /* parse, if found */
11699 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11701 /* First 4 bytes are the length of the atom, the next 4 bytes
11702 * are the fourcc, the next 1 byte is the version, and the
11703 * subsequent bytes are sequence parameter set like data. */
11704 gst_codec_utils_h265_caps_set_level_tier_and_profile
11705 (entry->caps, hevc_data + 8 + 1, size - 1);
11707 buf = gst_buffer_new_and_alloc (size);
11708 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11709 gst_caps_set_simple (entry->caps,
11710 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11711 gst_buffer_unref (buf);
11718 hevc_data += size + 8;
11731 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11732 GST_FOURCC_ARGS (fourcc));
11734 /* codec data might be in glbl extension atom */
11736 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11742 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11744 len = QT_UINT32 (data);
11747 buf = gst_buffer_new_and_alloc (len);
11748 gst_buffer_fill (buf, 0, data + 8, len);
11749 gst_caps_set_simple (entry->caps,
11750 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11751 gst_buffer_unref (buf);
11758 /* see annex I of the jpeg2000 spec */
11759 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11760 const guint8 *data;
11761 const gchar *colorspace = NULL;
11763 guint32 ncomp_map = 0;
11764 gint32 *comp_map = NULL;
11765 guint32 nchan_def = 0;
11766 gint32 *chan_def = NULL;
11768 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11769 /* some required atoms */
11770 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11773 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11777 /* number of components; redundant with info in codestream, but useful
11779 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11780 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11782 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11784 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11787 GST_DEBUG_OBJECT (qtdemux, "found colr");
11788 /* extract colour space info */
11789 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11790 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11792 colorspace = "sRGB";
11795 colorspace = "GRAY";
11798 colorspace = "sYUV";
11806 /* colr is required, and only values 16, 17, and 18 are specified,
11807 so error if we have no colorspace */
11810 /* extract component mapping */
11811 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11813 guint32 cmap_len = 0;
11815 cmap_len = QT_UINT32 (cmap->data);
11816 if (cmap_len >= 8) {
11817 /* normal box, subtract off header */
11819 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11820 if (cmap_len % 4 == 0) {
11821 ncomp_map = (cmap_len / 4);
11822 comp_map = g_new0 (gint32, ncomp_map);
11823 for (i = 0; i < ncomp_map; i++) {
11826 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11827 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11828 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11829 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11834 /* extract channel definitions */
11835 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11837 guint32 cdef_len = 0;
11839 cdef_len = QT_UINT32 (cdef->data);
11840 if (cdef_len >= 10) {
11841 /* normal box, subtract off header and len */
11843 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11844 if (cdef_len % 6 == 0) {
11845 nchan_def = (cdef_len / 6);
11846 chan_def = g_new0 (gint32, nchan_def);
11847 for (i = 0; i < nchan_def; i++)
11849 for (i = 0; i < nchan_def; i++) {
11850 guint16 cn, typ, asoc;
11851 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11852 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11853 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11854 if (cn < nchan_def) {
11857 chan_def[cn] = asoc;
11860 chan_def[cn] = 0; /* alpha */
11863 chan_def[cn] = -typ;
11871 gst_caps_set_simple (entry->caps,
11872 "num-components", G_TYPE_INT, ncomp, NULL);
11873 gst_caps_set_simple (entry->caps,
11874 "colorspace", G_TYPE_STRING, colorspace, NULL);
11877 GValue arr = { 0, };
11878 GValue elt = { 0, };
11880 g_value_init (&arr, GST_TYPE_ARRAY);
11881 g_value_init (&elt, G_TYPE_INT);
11882 for (i = 0; i < ncomp_map; i++) {
11883 g_value_set_int (&elt, comp_map[i]);
11884 gst_value_array_append_value (&arr, &elt);
11886 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11887 "component-map", &arr);
11888 g_value_unset (&elt);
11889 g_value_unset (&arr);
11894 GValue arr = { 0, };
11895 GValue elt = { 0, };
11897 g_value_init (&arr, GST_TYPE_ARRAY);
11898 g_value_init (&elt, G_TYPE_INT);
11899 for (i = 0; i < nchan_def; i++) {
11900 g_value_set_int (&elt, chan_def[i]);
11901 gst_value_array_append_value (&arr, &elt);
11903 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11904 "channel-definitions", &arr);
11905 g_value_unset (&elt);
11906 g_value_unset (&arr);
11910 /* some optional atoms */
11911 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11912 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11914 /* indicate possible fields in caps */
11916 data = (guint8 *) field->data + 8;
11918 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11919 (gint) * data, NULL);
11921 /* add codec_data if provided */
11926 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11927 data = prefix->data;
11928 len = QT_UINT32 (data);
11931 buf = gst_buffer_new_and_alloc (len);
11932 gst_buffer_fill (buf, 0, data + 8, len);
11933 gst_caps_set_simple (entry->caps,
11934 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11935 gst_buffer_unref (buf);
11944 GstBuffer *seqh = NULL;
11945 const guint8 *gamma_data = NULL;
11946 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11948 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11951 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11952 QT_FP32 (gamma_data), NULL);
11955 /* sorry for the bad name, but we don't know what this is, other
11956 * than its own fourcc */
11957 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11959 gst_buffer_unref (seqh);
11962 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11963 buf = gst_buffer_new_and_alloc (len);
11964 gst_buffer_fill (buf, 0, stsd_data, len);
11965 gst_caps_set_simple (entry->caps,
11966 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11967 gst_buffer_unref (buf);
11972 /* https://developer.apple.com/standards/qtff-2001.pdf,
11973 * page 92, "Video Sample Description", under table 3.1 */
11976 const gint compressor_offset =
11977 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11978 const gint min_size = compressor_offset + 32 + 2 + 2;
11981 guint16 color_table_id = 0;
11984 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11986 /* recover information on interlaced/progressive */
11987 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11991 len = QT_UINT32 (jpeg->data);
11992 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11994 if (len >= min_size) {
11995 gst_byte_reader_init (&br, jpeg->data, len);
11997 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11998 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11999 if (color_table_id != 0) {
12000 /* the spec says there can be concatenated chunks in the data, and we want
12001 * to find one called field. Walk through them. */
12002 gint offset = min_size;
12003 while (offset + 8 < len) {
12004 guint32 size = 0, tag;
12005 ok = gst_byte_reader_get_uint32_le (&br, &size);
12006 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
12007 if (!ok || size < 8) {
12008 GST_WARNING_OBJECT (qtdemux,
12009 "Failed to walk optional chunk list");
12012 GST_DEBUG_OBJECT (qtdemux,
12013 "Found optional %4.4s chunk, size %u",
12014 (const char *) &tag, size);
12015 if (tag == FOURCC_fiel) {
12016 guint8 n_fields = 0, ordering = 0;
12017 gst_byte_reader_get_uint8 (&br, &n_fields);
12018 gst_byte_reader_get_uint8 (&br, &ordering);
12019 if (n_fields == 1 || n_fields == 2) {
12020 GST_DEBUG_OBJECT (qtdemux,
12021 "Found fiel tag with %u fields, ordering %u",
12022 n_fields, ordering);
12024 gst_caps_set_simple (CUR_STREAM (stream)->caps,
12025 "interlace-mode", G_TYPE_STRING, "interleaved",
12028 GST_WARNING_OBJECT (qtdemux,
12029 "Found fiel tag with invalid fields (%u)", n_fields);
12035 GST_DEBUG_OBJECT (qtdemux,
12036 "Color table ID is 0, not trying to get interlacedness");
12039 GST_WARNING_OBJECT (qtdemux,
12040 "Length of jpeg chunk is too small, not trying to get interlacedness");
12048 gst_caps_set_simple (entry->caps,
12049 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
12055 GNode *xith, *xdxt;
12057 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
12058 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12062 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
12066 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
12067 /* collect the headers and store them in a stream list so that we can
12068 * send them out first */
12069 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
12079 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
12080 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12083 ovc1_data = ovc1->data;
12084 ovc1_len = QT_UINT32 (ovc1_data);
12085 if (ovc1_len <= 198) {
12086 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
12089 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
12090 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
12091 gst_caps_set_simple (entry->caps,
12092 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12093 gst_buffer_unref (buf);
12098 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12099 const guint8 *vc1_data = stsd_entry_data + 0x56;
12105 if (QT_UINT32 (vc1_data) <= len)
12106 size = QT_UINT32 (vc1_data) - 8;
12111 /* No real data, so break out */
12114 switch (QT_FOURCC (vc1_data + 0x4)) {
12115 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
12119 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
12120 buf = gst_buffer_new_and_alloc (size);
12121 gst_buffer_fill (buf, 0, vc1_data + 8, size);
12122 gst_caps_set_simple (entry->caps,
12123 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12124 gst_buffer_unref (buf);
12131 vc1_data += size + 8;
12137 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12138 const guint8 *av1_data = stsd_entry_data + 0x56;
12141 while (len >= 0x8) {
12144 if (QT_UINT32 (av1_data) <= len)
12145 size = QT_UINT32 (av1_data) - 0x8;
12150 /* No real data, so break out */
12153 switch (QT_FOURCC (av1_data + 0x4)) {
12156 /* parse, if found */
12158 guint8 pres_delay_field;
12160 GST_DEBUG_OBJECT (qtdemux,
12161 "found av1C codec_data in stsd of size %d", size);
12163 /* not enough data, just ignore and hope for the best */
12168 * 4 bytes: atom length
12173 * 1 bits: initial_presentation_delay_present
12174 * 4 bits: initial_presentation_delay (if present else reserved
12178 if (av1_data[9] != 0) {
12179 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
12183 /* We skip initial_presentation_delay* for now */
12184 pres_delay_field = *(av1_data + 12);
12185 if (pres_delay_field & (1 << 5)) {
12186 gst_caps_set_simple (entry->caps,
12187 "presentation-delay", G_TYPE_INT,
12188 (gint) (pres_delay_field & 0x0F) + 1, NULL);
12191 buf = gst_buffer_new_and_alloc (size - 5);
12192 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12193 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12194 gst_caps_set_simple (entry->caps,
12195 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12196 gst_buffer_unref (buf);
12205 av1_data += size + 8;
12211 /* TODO: Need to parse vpcC for VP8 codec too.
12212 * Note that VPCodecConfigurationBox (vpcC) is defined for
12213 * vp08, vp09, and vp10 fourcc. */
12216 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12217 const guint8 *vpcc_data = stsd_entry_data + 0x56;
12220 while (len >= 0x8) {
12223 if (QT_UINT32 (vpcc_data) <= len)
12224 size = QT_UINT32 (vpcc_data) - 0x8;
12229 /* No real data, so break out */
12232 switch (QT_FOURCC (vpcc_data + 0x4)) {
12235 const gchar *profile_str = NULL;
12236 const gchar *chroma_format_str = NULL;
12239 guint8 chroma_format;
12240 GstVideoColorimetry cinfo;
12242 /* parse, if found */
12243 GST_DEBUG_OBJECT (qtdemux,
12244 "found vp codec_data in stsd of size %d", size);
12246 /* the meaning of "size" is length of the atom body, excluding
12247 * atom length and fourcc fields */
12252 * 4 bytes: atom length
12259 * 3 bits: chromaSubsampling
12260 * 1 bit: videoFullRangeFlag
12261 * 1 byte: colourPrimaries
12262 * 1 byte: transferCharacteristics
12263 * 1 byte: matrixCoefficients
12264 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
12265 * rest: codecIntializationData (not used for vp8 and vp9)
12268 if (vpcc_data[8] != 1) {
12269 GST_WARNING_OBJECT (qtdemux,
12270 "unknown vpcC version %d", vpcc_data[8]);
12274 profile = vpcc_data[12];
12293 gst_caps_set_simple (entry->caps,
12294 "profile", G_TYPE_STRING, profile_str, NULL);
12297 /* skip level, the VP9 spec v0.6 defines only one level atm,
12298 * but webm spec define various ones. Add level to caps
12299 * if we really need it then */
12301 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12302 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12303 gst_caps_set_simple (entry->caps,
12304 "bit-depth-luma", G_TYPE_UINT, bitdepth,
12305 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12308 chroma_format = (vpcc_data[14] & 0xe) >> 1;
12309 switch (chroma_format) {
12312 chroma_format_str = "4:2:0";
12315 chroma_format_str = "4:2:2";
12318 chroma_format_str = "4:4:4";
12324 if (chroma_format_str) {
12325 gst_caps_set_simple (entry->caps,
12326 "chroma-format", G_TYPE_STRING, chroma_format_str,
12330 if ((vpcc_data[14] & 0x1) != 0)
12331 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12333 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12335 gst_video_color_primaries_from_iso (vpcc_data[15]);
12337 gst_video_transfer_function_from_iso (vpcc_data[16]);
12339 gst_video_color_matrix_from_iso (vpcc_data[17]);
12341 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12342 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12343 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12344 /* set this only if all values are known, otherwise this
12345 * might overwrite valid ones parsed from other color box */
12346 CUR_STREAM (stream)->colorimetry = cinfo;
12355 vpcc_data += size + 8;
12365 GST_INFO_OBJECT (qtdemux,
12366 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12367 GST_FOURCC_ARGS (fourcc), entry->caps);
12369 } else if (stream->subtype == FOURCC_soun) {
12371 int version, samplesize;
12372 guint16 compression_id;
12373 gboolean amrwb = FALSE;
12376 /* sample description entry (16) + sound sample description v0 (20) */
12380 version = QT_UINT32 (stsd_entry_data + offset);
12381 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12382 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12383 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12384 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12386 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12387 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12388 QT_UINT32 (stsd_entry_data + offset + 4));
12389 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12390 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12391 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12392 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12393 QT_UINT16 (stsd_entry_data + offset + 14));
12394 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12396 if (compression_id == 0xfffe)
12397 entry->sampled = TRUE;
12399 /* first assume uncompressed audio */
12400 entry->bytes_per_sample = samplesize / 8;
12401 entry->samples_per_frame = entry->n_channels;
12402 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12403 entry->samples_per_packet = entry->samples_per_frame;
12404 entry->bytes_per_packet = entry->bytes_per_sample;
12408 if (version == 0x00010000) {
12409 /* sample description entry (16) + sound sample description v1 (20+16) */
12413 /* take information from here over the normal sample description */
12414 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12415 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12416 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12417 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12419 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12420 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12421 entry->samples_per_packet);
12422 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12423 entry->bytes_per_packet);
12424 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12425 entry->bytes_per_frame);
12426 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12427 entry->bytes_per_sample);
12429 if (!entry->sampled && entry->bytes_per_packet) {
12430 entry->samples_per_frame = (entry->bytes_per_frame /
12431 entry->bytes_per_packet) * entry->samples_per_packet;
12432 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12433 entry->samples_per_frame);
12435 } else if (version == 0x00020000) {
12436 /* sample description entry (16) + sound sample description v2 (56) */
12440 /* take information from here over the normal sample description */
12441 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12442 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12443 entry->samples_per_frame = entry->n_channels;
12444 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12445 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12446 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12447 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12449 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12450 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12451 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12452 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12453 entry->bytes_per_sample * 8);
12454 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12455 QT_UINT32 (stsd_entry_data + offset + 24));
12456 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12457 entry->bytes_per_packet);
12458 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12459 entry->samples_per_packet);
12460 } else if (version != 0x00000) {
12461 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12466 /* Yes, these have to be hard-coded */
12469 entry->samples_per_packet = 6;
12470 entry->bytes_per_packet = 1;
12471 entry->bytes_per_frame = 1 * entry->n_channels;
12472 entry->bytes_per_sample = 1;
12473 entry->samples_per_frame = 6 * entry->n_channels;
12478 entry->samples_per_packet = 3;
12479 entry->bytes_per_packet = 1;
12480 entry->bytes_per_frame = 1 * entry->n_channels;
12481 entry->bytes_per_sample = 1;
12482 entry->samples_per_frame = 3 * entry->n_channels;
12487 entry->samples_per_packet = 64;
12488 entry->bytes_per_packet = 34;
12489 entry->bytes_per_frame = 34 * entry->n_channels;
12490 entry->bytes_per_sample = 2;
12491 entry->samples_per_frame = 64 * entry->n_channels;
12497 entry->samples_per_packet = 1;
12498 entry->bytes_per_packet = 1;
12499 entry->bytes_per_frame = 1 * entry->n_channels;
12500 entry->bytes_per_sample = 1;
12501 entry->samples_per_frame = 1 * entry->n_channels;
12506 entry->samples_per_packet = 160;
12507 entry->bytes_per_packet = 33;
12508 entry->bytes_per_frame = 33 * entry->n_channels;
12509 entry->bytes_per_sample = 2;
12510 entry->samples_per_frame = 160 * entry->n_channels;
12513 /* fix up any invalid header information from above */
12518 /* Sometimes these are set to 0 in the sound sample descriptions so
12519 * let's try to infer useful values from the other information we
12520 * have available */
12521 if (entry->bytes_per_sample == 0)
12522 entry->bytes_per_sample =
12523 entry->bytes_per_frame / entry->n_channels;
12524 if (entry->bytes_per_sample == 0)
12525 entry->bytes_per_sample = samplesize / 8;
12527 if (entry->bytes_per_frame == 0)
12528 entry->bytes_per_frame =
12529 entry->bytes_per_sample * entry->n_channels;
12531 if (entry->bytes_per_packet == 0)
12532 entry->bytes_per_packet = entry->bytes_per_sample;
12534 if (entry->samples_per_frame == 0)
12535 entry->samples_per_frame = entry->n_channels;
12537 if (entry->samples_per_packet == 0)
12538 entry->samples_per_packet = entry->samples_per_frame;
12548 entry->bytes_per_sample = 3;
12552 entry->bytes_per_sample = 4;
12555 entry->bytes_per_sample = 8;
12558 entry->bytes_per_sample = 2;
12561 g_assert_not_reached ();
12564 entry->samples_per_frame = entry->n_channels;
12565 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12566 entry->samples_per_packet = entry->samples_per_frame;
12567 entry->bytes_per_packet = entry->bytes_per_sample;
12575 gst_caps_unref (entry->caps);
12577 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12578 stsd_entry_data + 32, len - 16, &codec);
12589 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12591 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12593 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12595 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12598 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12599 const gchar *format_str;
12603 format_str = (enda_value) ? "S24LE" : "S24BE";
12606 format_str = (enda_value) ? "S32LE" : "S32BE";
12609 format_str = (enda_value) ? "F32LE" : "F32BE";
12612 format_str = (enda_value) ? "F64LE" : "F64BE";
12615 g_assert_not_reached ();
12618 gst_caps_set_simple (entry->caps,
12619 "format", G_TYPE_STRING, format_str, NULL);
12625 const guint8 *owma_data;
12626 const gchar *codec_name = NULL;
12630 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12631 /* FIXME this should also be gst_riff_strf_auds,
12632 * but the latter one is actually missing bits-per-sample :( */
12637 gint32 nSamplesPerSec;
12638 gint32 nAvgBytesPerSec;
12639 gint16 nBlockAlign;
12640 gint16 wBitsPerSample;
12643 WAVEFORMATEX *wfex;
12645 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12646 owma_data = stsd_entry_data;
12647 owma_len = QT_UINT32 (owma_data);
12648 if (owma_len <= 54) {
12649 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12652 wfex = (WAVEFORMATEX *) (owma_data + 36);
12653 buf = gst_buffer_new_and_alloc (owma_len - 54);
12654 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12655 if (wfex->wFormatTag == 0x0161) {
12656 codec_name = "Windows Media Audio";
12658 } else if (wfex->wFormatTag == 0x0162) {
12659 codec_name = "Windows Media Audio 9 Pro";
12661 } else if (wfex->wFormatTag == 0x0163) {
12662 codec_name = "Windows Media Audio 9 Lossless";
12663 /* is that correct? gstffmpegcodecmap.c is missing it, but
12664 * fluendo codec seems to support it */
12668 gst_caps_set_simple (entry->caps,
12669 "codec_data", GST_TYPE_BUFFER, buf,
12670 "wmaversion", G_TYPE_INT, version,
12671 "block_align", G_TYPE_INT,
12672 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12673 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12674 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12675 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12676 gst_buffer_unref (buf);
12680 codec = g_strdup (codec_name);
12686 gint len = QT_UINT32 (stsd_entry_data) - offset;
12687 const guint8 *wfex_data = stsd_entry_data + offset;
12688 const gchar *codec_name = NULL;
12690 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12691 /* FIXME this should also be gst_riff_strf_auds,
12692 * but the latter one is actually missing bits-per-sample :( */
12697 gint32 nSamplesPerSec;
12698 gint32 nAvgBytesPerSec;
12699 gint16 nBlockAlign;
12700 gint16 wBitsPerSample;
12705 /* FIXME: unify with similar wavformatex parsing code above */
12706 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12712 if (QT_UINT32 (wfex_data) <= len)
12713 size = QT_UINT32 (wfex_data) - 8;
12718 /* No real data, so break out */
12721 switch (QT_FOURCC (wfex_data + 4)) {
12722 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12724 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12729 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12730 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12731 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12732 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12733 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12734 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12735 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12737 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12738 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12739 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12740 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12741 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12742 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12744 if (wfex.wFormatTag == 0x0161) {
12745 codec_name = "Windows Media Audio";
12747 } else if (wfex.wFormatTag == 0x0162) {
12748 codec_name = "Windows Media Audio 9 Pro";
12750 } else if (wfex.wFormatTag == 0x0163) {
12751 codec_name = "Windows Media Audio 9 Lossless";
12752 /* is that correct? gstffmpegcodecmap.c is missing it, but
12753 * fluendo codec seems to support it */
12757 gst_caps_set_simple (entry->caps,
12758 "wmaversion", G_TYPE_INT, version,
12759 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12760 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12761 "width", G_TYPE_INT, wfex.wBitsPerSample,
12762 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12764 if (size > wfex.cbSize) {
12767 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12768 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12769 size - wfex.cbSize);
12770 gst_caps_set_simple (entry->caps,
12771 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12772 gst_buffer_unref (buf);
12774 GST_WARNING_OBJECT (qtdemux, "no codec data");
12779 codec = g_strdup (codec_name);
12787 wfex_data += size + 8;
12793 const guint8 *dops_data;
12794 guint8 *channel_mapping = NULL;
12797 guint8 channel_mapping_family;
12798 guint8 stream_count;
12799 guint8 coupled_count;
12802 version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12804 dops_data = stsd_entry_data + 51;
12806 dops_data = stsd_entry_data + 35;
12808 channels = GST_READ_UINT8 (dops_data + 10);
12809 rate = GST_READ_UINT32_LE (dops_data + 13);
12810 channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12811 stream_count = GST_READ_UINT8 (dops_data + 20);
12812 coupled_count = GST_READ_UINT8 (dops_data + 21);
12814 if (channels > 0) {
12815 channel_mapping = g_malloc (channels * sizeof (guint8));
12816 for (i = 0; i < channels; i++)
12817 channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12820 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12821 channel_mapping_family, stream_count, coupled_count,
12823 g_free (channel_mapping);
12834 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12835 GST_TAG_AUDIO_CODEC, codec, NULL);
12839 /* some bitrate info may have ended up in caps */
12840 s = gst_caps_get_structure (entry->caps, 0);
12841 gst_structure_get_int (s, "bitrate", &bitrate);
12843 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12844 GST_TAG_BITRATE, bitrate, NULL);
12848 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12849 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12850 if (stream->protected) {
12851 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12852 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12854 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12864 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12866 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12868 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12872 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12873 16 bits is a byte-swapped wave-style codec identifier,
12874 and we can find a WAVE header internally to a 'wave' atom here.
12875 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12876 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12879 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12880 if (len < offset + 20) {
12881 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12883 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12884 const guint8 *data = stsd_entry_data + offset + 16;
12886 GNode *waveheadernode;
12888 wavenode = g_node_new ((guint8 *) data);
12889 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12890 const guint8 *waveheader;
12893 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12894 if (waveheadernode) {
12895 waveheader = (const guint8 *) waveheadernode->data;
12896 headerlen = QT_UINT32 (waveheader);
12898 if (headerlen > 8) {
12899 gst_riff_strf_auds *header = NULL;
12900 GstBuffer *headerbuf;
12906 headerbuf = gst_buffer_new_and_alloc (headerlen);
12907 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12909 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12910 headerbuf, &header, &extra)) {
12911 gst_caps_unref (entry->caps);
12912 /* FIXME: Need to do something with the channel reorder map */
12914 gst_riff_create_audio_caps (header->format, NULL, header,
12915 extra, NULL, NULL, NULL);
12918 gst_buffer_unref (extra);
12923 GST_DEBUG ("Didn't find waveheadernode for this codec");
12925 g_node_destroy (wavenode);
12928 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12929 stream->stream_tags);
12933 /* FIXME: what is in the chunk? */
12936 gint len = QT_UINT32 (stsd_data);
12938 /* seems to be always = 116 = 0x74 */
12944 gint len = QT_UINT32 (stsd_entry_data);
12947 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12949 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12950 gst_caps_set_simple (entry->caps,
12951 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12952 gst_buffer_unref (buf);
12954 gst_caps_set_simple (entry->caps,
12955 "samplesize", G_TYPE_INT, samplesize, NULL);
12960 GNode *alac, *wave = NULL;
12962 /* apparently, m4a has this atom appended directly in the stsd entry,
12963 * while mov has it in a wave atom */
12964 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12966 /* alac now refers to stsd entry atom */
12967 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12969 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12971 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12974 const guint8 *alac_data = alac->data;
12975 gint len = QT_UINT32 (alac->data);
12979 GST_DEBUG_OBJECT (qtdemux,
12980 "discarding alac atom with unexpected len %d", len);
12982 /* codec-data contains alac atom size and prefix,
12983 * ffmpeg likes it that way, not quite gst-ish though ...*/
12984 buf = gst_buffer_new_and_alloc (len);
12985 gst_buffer_fill (buf, 0, alac->data, len);
12986 gst_caps_set_simple (entry->caps,
12987 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12988 gst_buffer_unref (buf);
12990 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12991 entry->n_channels = QT_UINT8 (alac_data + 21);
12992 entry->rate = QT_UINT32 (alac_data + 32);
12993 samplesize = QT_UINT8 (alac_data + 16 + 1);
12996 gst_caps_set_simple (entry->caps,
12997 "samplesize", G_TYPE_INT, samplesize, NULL);
13002 /* The codingname of the sample entry is 'fLaC' */
13003 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
13006 /* The 'dfLa' box is added to the sample entry to convey
13007 initializing information for the decoder. */
13008 const GNode *dfla =
13009 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
13012 const guint32 len = QT_UINT32 (dfla->data);
13014 /* Must contain at least dfLa box header (12),
13015 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
13017 GST_DEBUG_OBJECT (qtdemux,
13018 "discarding dfla atom with unexpected len %d", len);
13020 /* skip dfLa header to get the METADATA_BLOCKs */
13021 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
13022 const guint32 metadata_blocks_len = len - 12;
13024 gchar *stream_marker = g_strdup ("fLaC");
13025 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
13026 strlen (stream_marker));
13029 guint32 remainder = 0;
13030 guint32 block_size = 0;
13031 gboolean is_last = FALSE;
13033 GValue array = G_VALUE_INIT;
13034 GValue value = G_VALUE_INIT;
13036 g_value_init (&array, GST_TYPE_ARRAY);
13037 g_value_init (&value, GST_TYPE_BUFFER);
13039 gst_value_set_buffer (&value, block);
13040 gst_value_array_append_value (&array, &value);
13041 g_value_reset (&value);
13043 gst_buffer_unref (block);
13045 /* check there's at least one METADATA_BLOCK_HEADER's worth
13046 * of data, and we haven't already finished parsing */
13047 while (!is_last && ((index + 3) < metadata_blocks_len)) {
13048 remainder = metadata_blocks_len - index;
13050 /* add the METADATA_BLOCK_HEADER size to the signalled size */
13052 (metadata_blocks[index + 1] << 16) +
13053 (metadata_blocks[index + 2] << 8) +
13054 metadata_blocks[index + 3];
13056 /* be careful not to read off end of box */
13057 if (block_size > remainder) {
13061 is_last = metadata_blocks[index] >> 7;
13063 block = gst_buffer_new_and_alloc (block_size);
13065 gst_buffer_fill (block, 0, &metadata_blocks[index],
13068 gst_value_set_buffer (&value, block);
13069 gst_value_array_append_value (&array, &value);
13070 g_value_reset (&value);
13072 gst_buffer_unref (block);
13074 index += block_size;
13077 /* only append the metadata if we successfully read all of it */
13079 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
13080 (stream)->caps, 0), "streamheader", &array);
13082 GST_WARNING_OBJECT (qtdemux,
13083 "discarding all METADATA_BLOCKs due to invalid "
13084 "block_size %d at idx %d, rem %d", block_size, index,
13088 g_value_unset (&value);
13089 g_value_unset (&array);
13091 /* The sample rate obtained from the stsd may not be accurate
13092 * since it cannot represent rates greater than 65535Hz, so
13093 * override that value with the sample rate from the
13094 * METADATA_BLOCK_STREAMINFO block */
13095 CUR_STREAM (stream)->rate =
13096 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
13107 gint len = QT_UINT32 (stsd_entry_data);
13110 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
13113 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
13115 /* If we have enough data, let's try to get the 'damr' atom. See
13116 * the 3GPP container spec (26.244) for more details. */
13117 if ((len - 0x34) > 8 &&
13118 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
13119 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13120 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
13123 gst_caps_set_simple (entry->caps,
13124 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13125 gst_buffer_unref (buf);
13131 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
13132 gint len = QT_UINT32 (stsd_entry_data);
13133 guint16 sound_version = 0;
13134 /* FIXME: Can this be determined somehow? There doesn't seem to be
13135 * anything in mp4a atom that specifis compression */
13137 guint16 channels = entry->n_channels;
13138 guint32 time_scale = (guint32) entry->rate;
13139 gint sample_rate_index = -1;
13142 sound_version = QT_UINT16 (stsd_entry_data + 16);
13144 if (sound_version == 1) {
13145 channels = QT_UINT16 (stsd_entry_data + 24);
13146 time_scale = QT_UINT32 (stsd_entry_data + 30);
13148 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
13152 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
13156 sample_rate_index =
13157 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
13158 if (sample_rate_index >= 0 && channels > 0) {
13159 guint8 codec_data[2];
13162 /* build AAC codec data */
13163 codec_data[0] = profile << 3;
13164 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
13165 codec_data[1] = (sample_rate_index & 0x01) << 7;
13166 codec_data[1] |= (channels & 0xF) << 3;
13168 buf = gst_buffer_new_and_alloc (2);
13169 gst_buffer_fill (buf, 0, codec_data, 2);
13170 gst_caps_set_simple (entry->caps,
13171 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13172 gst_buffer_unref (buf);
13182 /* Fully handled elsewhere */
13185 GST_INFO_OBJECT (qtdemux,
13186 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13190 GST_INFO_OBJECT (qtdemux,
13191 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13192 GST_FOURCC_ARGS (fourcc), entry->caps);
13194 } else if (stream->subtype == FOURCC_strm) {
13195 if (fourcc == FOURCC_rtsp) {
13196 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
13198 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
13199 GST_FOURCC_ARGS (fourcc));
13200 goto unknown_stream;
13202 entry->sampled = TRUE;
13203 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
13204 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
13205 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
13207 entry->sampled = TRUE;
13208 entry->sparse = TRUE;
13211 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13214 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13215 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13220 /* hunt for sort-of codec data */
13224 GNode *mp4s = NULL;
13225 GNode *esds = NULL;
13227 /* look for palette in a stsd->mp4s->esds sub-atom */
13228 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
13230 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
13231 if (esds == NULL) {
13233 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13237 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13238 stream->stream_tags);
13242 GST_INFO_OBJECT (qtdemux,
13243 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13246 GST_INFO_OBJECT (qtdemux,
13247 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13248 GST_FOURCC_ARGS (fourcc), entry->caps);
13249 } else if (stream->subtype == FOURCC_meta) {
13250 entry->sampled = TRUE;
13251 entry->sparse = TRUE;
13254 qtdemux_meta_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13257 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13258 GST_TAG_CODEC, codec, NULL);
13263 GST_INFO_OBJECT (qtdemux,
13264 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13265 GST_FOURCC_ARGS (fourcc), entry->caps);
13267 /* everything in 1 sample */
13268 entry->sampled = TRUE;
13271 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13274 if (entry->caps == NULL)
13275 goto unknown_stream;
13278 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13279 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13285 /* promote to sampled format */
13286 if (entry->fourcc == FOURCC_samr) {
13287 /* force mono 8000 Hz for AMR */
13288 entry->sampled = TRUE;
13289 entry->n_channels = 1;
13290 entry->rate = 8000;
13291 } else if (entry->fourcc == FOURCC_sawb) {
13292 /* force mono 16000 Hz for AMR-WB */
13293 entry->sampled = TRUE;
13294 entry->n_channels = 1;
13295 entry->rate = 16000;
13296 } else if (entry->fourcc == FOURCC_mp4a) {
13297 entry->sampled = TRUE;
13301 stsd_entry_data += len;
13302 remaining_stsd_len -= len;
13306 /* collect sample information */
13307 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13308 goto samples_failed;
13310 if (qtdemux->fragmented) {
13313 /* need all moov samples as basis; probably not many if any at all */
13314 /* prevent moof parsing taking of at this time */
13315 offset = qtdemux->moof_offset;
13316 qtdemux->moof_offset = 0;
13317 if (stream->n_samples &&
13318 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13319 qtdemux->moof_offset = offset;
13320 goto samples_failed;
13322 qtdemux->moof_offset = offset;
13323 /* movie duration more reliable in this case (e.g. mehd) */
13324 if (qtdemux->segment.duration &&
13325 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13327 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13330 /* configure segments */
13331 if (!qtdemux_parse_segments (qtdemux, stream, trak))
13332 goto segments_failed;
13334 /* add some language tag, if useful */
13335 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13336 strcmp (stream->lang_id, "und")) {
13337 const gchar *lang_code;
13339 /* convert ISO 639-2 code to ISO 639-1 */
13340 lang_code = gst_tag_get_language_code (stream->lang_id);
13341 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13342 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13345 /* Check for UDTA tags */
13346 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13347 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13350 /* Insert and sort new stream in track-id order.
13351 * This will help in comparing old/new streams during stream update check */
13352 g_ptr_array_add (qtdemux->active_streams, stream);
13353 g_ptr_array_sort (qtdemux->active_streams,
13354 (GCompareFunc) qtdemux_track_id_compare_func);
13355 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13356 QTDEMUX_N_STREAMS (qtdemux));
13363 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13364 (_("This file is corrupt and cannot be played.")), (NULL));
13366 gst_qtdemux_stream_unref (stream);
13371 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13372 gst_qtdemux_stream_unref (stream);
13378 /* we posted an error already */
13379 /* free stbl sub-atoms */
13380 gst_qtdemux_stbl_free (stream);
13381 gst_qtdemux_stream_unref (stream);
13386 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13392 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13393 GST_FOURCC_ARGS (stream->subtype));
13394 gst_qtdemux_stream_unref (stream);
13399 /* If we can estimate the overall bitrate, and don't have information about the
13400 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13401 * the overall bitrate minus the sum of the bitrates of all other streams. This
13402 * should be useful for the common case where we have one audio and one video
13403 * stream and can estimate the bitrate of one, but not the other. */
13405 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13407 QtDemuxStream *stream = NULL;
13408 gint64 size, sys_bitrate, sum_bitrate = 0;
13409 GstClockTime duration;
13413 if (qtdemux->fragmented)
13416 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13418 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13420 GST_DEBUG_OBJECT (qtdemux,
13421 "Size in bytes of the stream not known - bailing");
13425 /* Subtract the header size */
13426 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13427 size, qtdemux->header_size);
13429 if (size < qtdemux->header_size)
13432 size = size - qtdemux->header_size;
13434 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13435 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13439 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13440 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13441 switch (str->subtype) {
13444 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13445 CUR_STREAM (str)->caps);
13446 /* retrieve bitrate, prefer avg then max */
13448 if (str->stream_tags) {
13449 if (gst_tag_list_get_uint (str->stream_tags,
13450 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13451 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13452 if (gst_tag_list_get_uint (str->stream_tags,
13453 GST_TAG_NOMINAL_BITRATE, &bitrate))
13454 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13455 if (gst_tag_list_get_uint (str->stream_tags,
13456 GST_TAG_BITRATE, &bitrate))
13457 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13460 sum_bitrate += bitrate;
13463 GST_DEBUG_OBJECT (qtdemux,
13464 ">1 stream with unknown bitrate - bailing");
13471 /* For other subtypes, we assume no significant impact on bitrate */
13477 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13481 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13483 if (sys_bitrate < sum_bitrate) {
13484 /* This can happen, since sum_bitrate might be derived from maximum
13485 * bitrates and not average bitrates */
13486 GST_DEBUG_OBJECT (qtdemux,
13487 "System bitrate less than sum bitrate - bailing");
13491 bitrate = sys_bitrate - sum_bitrate;
13492 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13493 ", Stream bitrate = %u", sys_bitrate, bitrate);
13495 if (!stream->stream_tags)
13496 stream->stream_tags = gst_tag_list_new_empty ();
13498 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13500 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13501 GST_TAG_BITRATE, bitrate, NULL);
13504 static GstFlowReturn
13505 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13507 GstFlowReturn ret = GST_FLOW_OK;
13510 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13512 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13513 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13514 guint32 sample_num = 0;
13516 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13517 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13519 if (qtdemux->fragmented && qtdemux->pullbased) {
13520 /* need all moov samples first */
13521 GST_OBJECT_LOCK (qtdemux);
13522 while (stream->n_samples == 0)
13523 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13525 GST_OBJECT_UNLOCK (qtdemux);
13527 /* discard any stray moof */
13528 qtdemux->moof_offset = 0;
13531 /* prepare braking */
13532 if (ret != GST_FLOW_ERROR)
13535 /* in pull mode, we should have parsed some sample info by now;
13536 * and quite some code will not handle no samples.
13537 * in push mode, we'll just have to deal with it */
13538 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13539 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13540 g_ptr_array_remove_index (qtdemux->active_streams, i);
13543 } else if (stream->track_id == qtdemux->chapters_track_id &&
13544 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13545 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13546 so that it doesn't look like a subtitle track */
13547 g_ptr_array_remove_index (qtdemux->active_streams, i);
13552 /* parse the initial sample for use in setting the frame rate cap */
13553 while (sample_num == 0 && sample_num < stream->n_samples) {
13554 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13564 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13566 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13570 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13574 /* Different length, updated */
13575 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13578 /* streams in list are sorted in track-id order */
13579 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13580 /* Different stream-id, updated */
13581 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13582 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13590 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13591 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13593 /* Connect old stream's srcpad to new stream */
13594 newstream->pad = oldstream->pad;
13595 oldstream->pad = NULL;
13597 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13598 * case we need to force one through */
13599 newstream->new_stream = newstream->pad != NULL
13600 && GST_PAD_IS_EOS (newstream->pad);
13602 return gst_qtdemux_configure_stream (qtdemux, newstream);
13606 qtdemux_update_streams (GstQTDemux * qtdemux)
13609 g_assert (qtdemux->streams_aware);
13611 /* At below, figure out which stream in active_streams has identical stream-id
13612 * with that of in old_streams. If there is matching stream-id,
13613 * corresponding newstream will not be exposed again,
13614 * but demux will reuse srcpad of matched old stream
13616 * active_streams : newly created streams from the latest moov
13617 * old_streams : existing streams (belong to previous moov)
13620 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13621 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13622 QtDemuxStream *oldstream = NULL;
13625 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13626 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13628 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13629 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13630 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13632 /* null pad stream cannot be reused */
13633 if (oldstream->pad == NULL)
13638 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13640 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13643 /* we don't need to preserve order of old streams */
13644 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13648 /* now we have all info and can expose */
13649 list = stream->stream_tags;
13650 stream->stream_tags = NULL;
13651 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13659 /* Must be called with expose lock */
13660 static GstFlowReturn
13661 qtdemux_expose_streams (GstQTDemux * qtdemux)
13665 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13667 if (!qtdemux_is_streams_update (qtdemux)) {
13668 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13669 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13670 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13671 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13672 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13673 return GST_FLOW_ERROR;
13676 g_ptr_array_set_size (qtdemux->old_streams, 0);
13677 qtdemux->need_segment = TRUE;
13679 return GST_FLOW_OK;
13682 if (qtdemux->streams_aware) {
13683 if (!qtdemux_update_streams (qtdemux))
13684 return GST_FLOW_ERROR;
13686 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13687 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13690 /* now we have all info and can expose */
13691 list = stream->stream_tags;
13692 stream->stream_tags = NULL;
13693 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13694 return GST_FLOW_ERROR;
13699 gst_qtdemux_guess_bitrate (qtdemux);
13701 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13703 /* If we have still old_streams, it's no more used stream */
13704 for (i = 0; i < qtdemux->old_streams->len; i++) {
13705 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13710 event = gst_event_new_eos ();
13711 if (qtdemux->segment_seqnum)
13712 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13714 gst_pad_push_event (stream->pad, event);
13718 g_ptr_array_set_size (qtdemux->old_streams, 0);
13720 /* check if we should post a redirect in case there is a single trak
13721 * and it is a redirecting trak */
13722 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13723 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13726 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13727 "an external content");
13728 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13729 gst_structure_new ("redirect",
13730 "new-location", G_TYPE_STRING,
13731 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13732 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13733 g_free (qtdemux->redirect_location);
13734 qtdemux->redirect_location =
13735 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13738 g_ptr_array_foreach (qtdemux->active_streams,
13739 (GFunc) qtdemux_do_allocation, qtdemux);
13741 qtdemux->need_segment = TRUE;
13743 qtdemux->exposed = TRUE;
13744 return GST_FLOW_OK;
13749 GstStructure *structure; /* helper for sort function */
13751 guint min_req_bitrate;
13752 guint min_req_qt_version;
13756 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13758 GstQtReference *ref_a = (GstQtReference *) a;
13759 GstQtReference *ref_b = (GstQtReference *) b;
13761 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13762 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13764 /* known bitrates go before unknown; higher bitrates go first */
13765 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13768 /* sort the redirects and post a message for the application.
13771 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13773 GstQtReference *best;
13776 GValue list_val = { 0, };
13779 g_assert (references != NULL);
13781 references = g_list_sort (references, qtdemux_redirects_sort_func);
13783 best = (GstQtReference *) references->data;
13785 g_value_init (&list_val, GST_TYPE_LIST);
13787 for (l = references; l != NULL; l = l->next) {
13788 GstQtReference *ref = (GstQtReference *) l->data;
13789 GValue struct_val = { 0, };
13791 ref->structure = gst_structure_new ("redirect",
13792 "new-location", G_TYPE_STRING, ref->location, NULL);
13794 if (ref->min_req_bitrate > 0) {
13795 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13796 ref->min_req_bitrate, NULL);
13799 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13800 g_value_set_boxed (&struct_val, ref->structure);
13801 gst_value_list_append_value (&list_val, &struct_val);
13802 g_value_unset (&struct_val);
13803 /* don't free anything here yet, since we need best->structure below */
13806 g_assert (best != NULL);
13807 s = gst_structure_copy (best->structure);
13809 if (g_list_length (references) > 1) {
13810 gst_structure_set_value (s, "locations", &list_val);
13813 g_value_unset (&list_val);
13815 for (l = references; l != NULL; l = l->next) {
13816 GstQtReference *ref = (GstQtReference *) l->data;
13818 gst_structure_free (ref->structure);
13819 g_free (ref->location);
13822 g_list_free (references);
13824 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13825 g_free (qtdemux->redirect_location);
13826 qtdemux->redirect_location =
13827 g_strdup (gst_structure_get_string (s, "new-location"));
13828 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13829 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13832 /* look for redirect nodes, collect all redirect information and
13836 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13838 GNode *rmra, *rmda, *rdrf;
13840 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13842 GList *redirects = NULL;
13844 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13846 GstQtReference ref = { NULL, NULL, 0, 0 };
13847 GNode *rmdr, *rmvc;
13849 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13850 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13851 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13852 ref.min_req_bitrate);
13855 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13856 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13857 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13859 #ifndef GST_DISABLE_GST_DEBUG
13860 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13862 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13864 GST_LOG_OBJECT (qtdemux,
13865 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13866 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13867 bitmask, check_type);
13868 if (package == FOURCC_qtim && check_type == 0) {
13869 ref.min_req_qt_version = version;
13873 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13879 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13880 if (ref_len > 20) {
13881 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13882 ref_data = (guint8 *) rdrf->data + 20;
13883 if (ref_type == FOURCC_alis) {
13884 guint record_len, record_version, fn_len;
13886 if (ref_len > 70) {
13887 /* MacOSX alias record, google for alias-layout.txt */
13888 record_len = QT_UINT16 (ref_data + 4);
13889 record_version = QT_UINT16 (ref_data + 4 + 2);
13890 fn_len = QT_UINT8 (ref_data + 50);
13891 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13892 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13895 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13898 } else if (ref_type == FOURCC_url_) {
13899 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13901 GST_DEBUG_OBJECT (qtdemux,
13902 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13903 GST_FOURCC_ARGS (ref_type));
13905 if (ref.location != NULL) {
13906 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13908 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13910 GST_WARNING_OBJECT (qtdemux,
13911 "Failed to extract redirect location from rdrf atom");
13914 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13918 /* look for others */
13919 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13922 if (redirects != NULL) {
13923 qtdemux_process_redirects (qtdemux, redirects);
13929 static GstTagList *
13930 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13934 if (tags == NULL) {
13935 tags = gst_tag_list_new_empty ();
13936 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13939 if (qtdemux->major_brand == FOURCC_mjp2)
13940 fmt = "Motion JPEG 2000";
13941 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13943 else if (qtdemux->major_brand == FOURCC_qt__)
13945 else if (qtdemux->fragmented)
13948 fmt = "ISO MP4/M4A";
13950 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13951 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13953 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13959 /* we have read the complete moov node now.
13960 * This function parses all of the relevant info, creates the traks and
13961 * prepares all data structures for playback
13964 qtdemux_parse_tree (GstQTDemux * qtdemux)
13971 guint64 creation_time;
13972 GstDateTime *datetime = NULL;
13975 /* make sure we have a usable taglist */
13976 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13978 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13979 if (mvhd == NULL) {
13980 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13981 return qtdemux_parse_redirects (qtdemux);
13984 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13985 if (version == 1) {
13986 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13987 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13988 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13989 } else if (version == 0) {
13990 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13991 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13992 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13994 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13998 /* Moving qt creation time (secs since 1904) to unix time */
13999 if (creation_time != 0) {
14000 /* Try to use epoch first as it should be faster and more commonly found */
14001 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
14004 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
14005 /* some data cleansing sanity */
14006 now_s = g_get_real_time () / G_USEC_PER_SEC;
14007 if (now_s + 24 * 3600 < creation_time) {
14008 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
14010 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
14013 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
14014 GDateTime *dt, *dt_local;
14016 dt = g_date_time_add_seconds (base_dt, creation_time);
14017 dt_local = g_date_time_to_local (dt);
14018 datetime = gst_date_time_new_from_g_date_time (dt_local);
14020 g_date_time_unref (base_dt);
14021 g_date_time_unref (dt);
14025 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
14026 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
14028 gst_date_time_unref (datetime);
14031 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
14032 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
14034 /* check for fragmented file and get some (default) data */
14035 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
14038 GstByteReader mehd_data;
14040 /* let track parsing or anyone know weird stuff might happen ... */
14041 qtdemux->fragmented = TRUE;
14043 /* compensate for total duration */
14044 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
14046 qtdemux_parse_mehd (qtdemux, &mehd_data);
14049 /* Update the movie segment duration, unless it was directly given to us
14050 * by upstream. Otherwise let it as is, as we don't want to mangle the
14051 * duration provided by upstream that may come e.g. from a MPD file. */
14052 if (!qtdemux->upstream_format_is_time) {
14053 GstClockTime duration;
14054 /* set duration in the segment info */
14055 gst_qtdemux_get_duration (qtdemux, &duration);
14056 qtdemux->segment.duration = duration;
14057 /* also do not exceed duration; stop is set that way post seek anyway,
14058 * and segment activation falls back to duration,
14059 * whereas loop only checks stop, so let's align this here as well */
14060 qtdemux->segment.stop = duration;
14063 /* parse all traks */
14064 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
14066 qtdemux_parse_trak (qtdemux, trak);
14067 /* iterate all siblings */
14068 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
14071 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14074 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
14076 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14078 GST_LOG_OBJECT (qtdemux, "No udta node found.");
14081 /* maybe also some tags in meta box */
14082 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
14084 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
14085 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14087 GST_LOG_OBJECT (qtdemux, "No meta node found.");
14090 /* parse any protection system info */
14091 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
14093 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
14094 qtdemux_parse_pssh (qtdemux, pssh);
14095 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
14098 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
14103 /* taken from ffmpeg */
14105 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14117 len = (len << 7) | (c & 0x7f);
14126 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14127 gsize codec_data_size)
14129 GList *list = NULL;
14130 guint8 *p = codec_data;
14131 gint i, offset, num_packets;
14132 guint *length, last;
14134 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14136 if (codec_data == NULL || codec_data_size == 0)
14139 /* start of the stream and vorbis audio or theora video, need to
14140 * send the codec_priv data as first three packets */
14141 num_packets = p[0] + 1;
14142 GST_DEBUG_OBJECT (qtdemux,
14143 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14144 (guint) num_packets, codec_data_size);
14146 /* Let's put some limits, Don't think there even is a xiph codec
14147 * with more than 3-4 headers */
14148 if (G_UNLIKELY (num_packets > 16)) {
14149 GST_WARNING_OBJECT (qtdemux,
14150 "Unlikely number of xiph headers, most likely not valid");
14154 length = g_alloca (num_packets * sizeof (guint));
14158 /* first packets, read length values */
14159 for (i = 0; i < num_packets - 1; i++) {
14161 while (offset < codec_data_size) {
14162 length[i] += p[offset];
14163 if (p[offset++] != 0xff)
14168 if (offset + last > codec_data_size)
14171 /* last packet is the remaining size */
14172 length[i] = codec_data_size - offset - last;
14174 for (i = 0; i < num_packets; i++) {
14177 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14179 if (offset + length[i] > codec_data_size)
14182 hdr = gst_buffer_new_memdup (p + offset, length[i]);
14183 list = g_list_append (list, hdr);
14185 offset += length[i];
14194 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14200 /* this can change the codec originally present in @list */
14202 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14203 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14205 int len = QT_UINT32 (esds->data);
14206 guint8 *ptr = esds->data;
14207 guint8 *end = ptr + len;
14209 guint8 *data_ptr = NULL;
14211 guint8 object_type_id = 0;
14212 guint8 stream_type = 0;
14213 const char *codec_name = NULL;
14214 GstCaps *caps = NULL;
14216 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14218 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14220 while (ptr + 1 < end) {
14221 tag = QT_UINT8 (ptr);
14222 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14224 len = read_descr_size (ptr, end, &ptr);
14225 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14227 /* Check the stated amount of data is available for reading */
14228 if (len < 0 || ptr + len > end)
14232 case ES_DESCRIPTOR_TAG:
14233 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14234 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14237 case DECODER_CONFIG_DESC_TAG:{
14238 guint max_bitrate, avg_bitrate;
14240 object_type_id = QT_UINT8 (ptr);
14241 stream_type = QT_UINT8 (ptr + 1) >> 2;
14242 max_bitrate = QT_UINT32 (ptr + 5);
14243 avg_bitrate = QT_UINT32 (ptr + 9);
14244 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14245 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14246 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14247 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14248 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14249 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14250 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14251 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14253 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14254 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14255 avg_bitrate, NULL);
14260 case DECODER_SPECIFIC_INFO_TAG:
14261 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14262 if (object_type_id == 0xe0 && len == 0x40) {
14268 GST_DEBUG_OBJECT (qtdemux,
14269 "Have VOBSUB palette. Creating palette event");
14270 /* move to decConfigDescr data and read palette */
14272 for (i = 0; i < 16; i++) {
14273 clut[i] = QT_UINT32 (data);
14277 s = gst_structure_new ("application/x-gst-dvd", "event",
14278 G_TYPE_STRING, "dvd-spu-clut-change",
14279 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14280 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14281 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14282 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14283 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14284 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14285 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14286 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14289 /* store event and trigger custom processing */
14290 stream->pending_event =
14291 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14293 /* Generic codec_data handler puts it on the caps */
14300 case SL_CONFIG_DESC_TAG:
14301 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14305 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14307 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14313 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14314 * in use, and should also be used to override some other parameters for some
14316 switch (object_type_id) {
14317 case 0x20: /* MPEG-4 */
14318 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14319 * profile_and_level_indication */
14320 if (data_ptr != NULL && data_len >= 5 &&
14321 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14322 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14323 data_ptr + 4, data_len - 4);
14325 break; /* Nothing special needed here */
14326 case 0x21: /* H.264 */
14327 codec_name = "H.264 / AVC";
14328 caps = gst_caps_new_simple ("video/x-h264",
14329 "stream-format", G_TYPE_STRING, "avc",
14330 "alignment", G_TYPE_STRING, "au", NULL);
14332 case 0x40: /* AAC (any) */
14333 case 0x66: /* AAC Main */
14334 case 0x67: /* AAC LC */
14335 case 0x68: /* AAC SSR */
14336 /* Override channels and rate based on the codec_data, as it's often
14338 /* Only do so for basic setup without HE-AAC extension */
14339 if (data_ptr && data_len == 2) {
14340 guint channels, rate;
14342 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14344 entry->n_channels = channels;
14346 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14348 entry->rate = rate;
14351 /* Set level and profile if possible */
14352 if (data_ptr != NULL && data_len >= 2) {
14353 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14354 data_ptr, data_len);
14356 const gchar *profile_str = NULL;
14359 guint8 *codec_data;
14360 gint rate_idx, profile;
14362 /* No codec_data, let's invent something.
14363 * FIXME: This is wrong for SBR! */
14365 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14367 buffer = gst_buffer_new_and_alloc (2);
14368 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14369 codec_data = map.data;
14372 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14375 switch (object_type_id) {
14377 profile_str = "main";
14381 profile_str = "lc";
14385 profile_str = "ssr";
14393 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14395 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14397 gst_buffer_unmap (buffer, &map);
14398 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14399 GST_TYPE_BUFFER, buffer, NULL);
14400 gst_buffer_unref (buffer);
14403 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14404 G_TYPE_STRING, profile_str, NULL);
14408 case 0x60: /* MPEG-2, various profiles */
14414 codec_name = "MPEG-2 video";
14415 caps = gst_caps_new_simple ("video/mpeg",
14416 "mpegversion", G_TYPE_INT, 2,
14417 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14419 case 0x69: /* MPEG-2 BC audio */
14420 case 0x6B: /* MPEG-1 audio */
14421 caps = gst_caps_new_simple ("audio/mpeg",
14422 "mpegversion", G_TYPE_INT, 1, NULL);
14423 codec_name = "MPEG-1 audio";
14425 case 0x6A: /* MPEG-1 */
14426 codec_name = "MPEG-1 video";
14427 caps = gst_caps_new_simple ("video/mpeg",
14428 "mpegversion", G_TYPE_INT, 1,
14429 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14431 case 0x6C: /* MJPEG */
14433 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14435 codec_name = "Motion-JPEG";
14437 case 0x6D: /* PNG */
14439 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14441 codec_name = "PNG still images";
14443 case 0x6E: /* JPEG2000 */
14444 codec_name = "JPEG-2000";
14445 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14447 case 0xA4: /* Dirac */
14448 codec_name = "Dirac";
14449 caps = gst_caps_new_empty_simple ("video/x-dirac");
14451 case 0xA5: /* AC3 */
14452 codec_name = "AC-3 audio";
14453 caps = gst_caps_new_simple ("audio/x-ac3",
14454 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14456 case 0xA9: /* AC3 */
14457 codec_name = "DTS audio";
14458 caps = gst_caps_new_simple ("audio/x-dts",
14459 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14462 if (stream_type == 0x05 && data_ptr) {
14464 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14467 GValue arr_val = G_VALUE_INIT;
14468 GValue buf_val = G_VALUE_INIT;
14471 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14472 codec_name = "Vorbis";
14473 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14474 g_value_init (&arr_val, GST_TYPE_ARRAY);
14475 g_value_init (&buf_val, GST_TYPE_BUFFER);
14476 for (tmp = headers; tmp; tmp = tmp->next) {
14477 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14478 gst_value_array_append_value (&arr_val, &buf_val);
14480 s = gst_caps_get_structure (caps, 0);
14481 gst_structure_take_value (s, "streamheader", &arr_val);
14482 g_value_unset (&buf_val);
14483 g_list_free (headers);
14490 case 0xE1: /* QCELP */
14491 /* QCELP, the codec_data is a riff tag (little endian) with
14492 * 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). */
14493 caps = gst_caps_new_empty_simple ("audio/qcelp");
14494 codec_name = "QCELP";
14500 /* If we have a replacement caps, then change our caps for this stream */
14502 gst_caps_unref (entry->caps);
14503 entry->caps = caps;
14506 if (codec_name && list)
14507 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14508 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14510 /* Add the codec_data attribute to caps, if we have it */
14514 buffer = gst_buffer_new_and_alloc (data_len);
14515 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14517 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14518 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14520 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14522 gst_buffer_unref (buffer);
14527 static inline GstCaps *
14528 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14532 char *s, fourstr[5];
14534 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14535 for (i = 0; i < 4; i++) {
14536 if (!g_ascii_isalnum (fourstr[i]))
14539 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14540 caps = gst_caps_new_empty_simple (s);
14545 #define _codec(name) \
14547 if (codec_name) { \
14548 *codec_name = g_strdup (name); \
14553 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14554 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14555 const guint8 * stsd_entry_data, gchar ** codec_name)
14557 GstCaps *caps = NULL;
14558 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14562 _codec ("PNG still images");
14563 caps = gst_caps_new_empty_simple ("image/png");
14566 _codec ("JPEG still images");
14568 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14571 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14572 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14573 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14574 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14575 _codec ("Motion-JPEG");
14577 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14580 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14581 _codec ("Motion-JPEG format B");
14582 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14585 _codec ("JPEG-2000");
14586 /* override to what it should be according to spec, avoid palette_data */
14587 entry->bits_per_sample = 24;
14588 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14591 _codec ("Sorensen video v.3");
14592 caps = gst_caps_new_simple ("video/x-svq",
14593 "svqversion", G_TYPE_INT, 3, NULL);
14595 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14596 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14597 _codec ("Sorensen video v.1");
14598 caps = gst_caps_new_simple ("video/x-svq",
14599 "svqversion", G_TYPE_INT, 1, NULL);
14601 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14602 caps = gst_caps_new_empty_simple ("video/x-raw");
14603 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14604 _codec ("Windows Raw RGB");
14605 stream->alignment = 32;
14611 bps = QT_UINT16 (stsd_entry_data + 82);
14614 format = GST_VIDEO_FORMAT_RGB15;
14617 format = GST_VIDEO_FORMAT_RGB16;
14620 format = GST_VIDEO_FORMAT_RGB;
14623 format = GST_VIDEO_FORMAT_ARGB;
14631 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14632 format = GST_VIDEO_FORMAT_I420;
14634 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14635 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14636 format = GST_VIDEO_FORMAT_I420;
14639 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14640 format = GST_VIDEO_FORMAT_UYVY;
14642 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14643 format = GST_VIDEO_FORMAT_v308;
14645 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14646 format = GST_VIDEO_FORMAT_v216;
14649 format = GST_VIDEO_FORMAT_v210;
14651 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14652 format = GST_VIDEO_FORMAT_r210;
14654 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14655 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14656 format = GST_VIDEO_FORMAT_v410;
14659 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14660 * but different order than AYUV
14661 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14662 format = GST_VIDEO_FORMAT_v408;
14665 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14666 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14667 _codec ("MPEG-1 video");
14668 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14669 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14671 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14672 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14673 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14674 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14675 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14676 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14677 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14678 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14679 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14680 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14681 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14682 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14683 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14684 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14685 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14686 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14687 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14688 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14689 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14690 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14691 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14692 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14693 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14694 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14695 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14696 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14697 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14698 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14699 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14700 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14701 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14702 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14703 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14704 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14705 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14706 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14707 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14708 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14709 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14710 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14711 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14712 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14713 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14714 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14715 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14716 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14717 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14718 _codec ("MPEG-2 video");
14719 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14720 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14722 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14723 _codec ("GIF still images");
14724 caps = gst_caps_new_empty_simple ("image/gif");
14727 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14729 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14731 /* ffmpeg uses the height/width props, don't know why */
14732 caps = gst_caps_new_simple ("video/x-h263",
14733 "variant", G_TYPE_STRING, "itu", NULL);
14737 _codec ("MPEG-4 video");
14738 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14739 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14741 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14742 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14743 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14744 caps = gst_caps_new_simple ("video/x-msmpeg",
14745 "msmpegversion", G_TYPE_INT, 43, NULL);
14747 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14749 caps = gst_caps_new_simple ("video/x-divx",
14750 "divxversion", G_TYPE_INT, 3, NULL);
14752 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14753 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14755 caps = gst_caps_new_simple ("video/x-divx",
14756 "divxversion", G_TYPE_INT, 4, NULL);
14758 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14760 caps = gst_caps_new_simple ("video/x-divx",
14761 "divxversion", G_TYPE_INT, 5, NULL);
14764 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14766 caps = gst_caps_new_simple ("video/x-ffv",
14767 "ffvversion", G_TYPE_INT, 1, NULL);
14770 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14771 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14776 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14777 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14778 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14782 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14783 _codec ("Cinepak");
14784 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14786 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14787 _codec ("Apple QuickDraw");
14788 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14790 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14791 _codec ("Apple video");
14792 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14797 _codec ("H.264 / AVC");
14798 caps = gst_caps_new_simple ("video/x-h264",
14799 "stream-format", G_TYPE_STRING, "avc",
14800 "alignment", G_TYPE_STRING, "au", NULL);
14804 _codec ("H.264 / AVC");
14805 caps = gst_caps_new_simple ("video/x-h264",
14806 "stream-format", G_TYPE_STRING, "avc3",
14807 "alignment", G_TYPE_STRING, "au", NULL);
14812 _codec ("H.265 / HEVC");
14813 caps = gst_caps_new_simple ("video/x-h265",
14814 "stream-format", G_TYPE_STRING, "hvc1",
14815 "alignment", G_TYPE_STRING, "au", NULL);
14819 _codec ("H.265 / HEVC");
14820 caps = gst_caps_new_simple ("video/x-h265",
14821 "stream-format", G_TYPE_STRING, "hev1",
14822 "alignment", G_TYPE_STRING, "au", NULL);
14825 _codec ("Run-length encoding");
14826 caps = gst_caps_new_simple ("video/x-rle",
14827 "layout", G_TYPE_STRING, "quicktime", NULL);
14830 _codec ("Run-length encoding");
14831 caps = gst_caps_new_simple ("video/x-rle",
14832 "layout", G_TYPE_STRING, "microsoft", NULL);
14834 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14835 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14836 _codec ("Indeo Video 3");
14837 caps = gst_caps_new_simple ("video/x-indeo",
14838 "indeoversion", G_TYPE_INT, 3, NULL);
14840 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14841 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14842 _codec ("Intel Video 4");
14843 caps = gst_caps_new_simple ("video/x-indeo",
14844 "indeoversion", G_TYPE_INT, 4, NULL);
14848 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14849 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14850 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14851 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14852 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14853 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14854 _codec ("DV Video");
14855 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14856 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14858 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14859 case FOURCC_dv5p: /* DVCPRO50 PAL */
14860 _codec ("DVCPro50 Video");
14861 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14862 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14864 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14865 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14866 _codec ("DVCProHD Video");
14867 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14868 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14870 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14871 _codec ("Apple Graphics (SMC)");
14872 caps = gst_caps_new_empty_simple ("video/x-smc");
14874 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14876 caps = gst_caps_new_empty_simple ("video/x-vp3");
14878 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14879 _codec ("VP6 Flash");
14880 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14884 caps = gst_caps_new_empty_simple ("video/x-theora");
14885 /* theora uses one byte of padding in the data stream because it does not
14886 * allow 0 sized packets while theora does */
14887 entry->padding = 1;
14891 caps = gst_caps_new_empty_simple ("video/x-dirac");
14893 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14894 _codec ("TIFF still images");
14895 caps = gst_caps_new_empty_simple ("image/tiff");
14897 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14898 _codec ("Apple Intermediate Codec");
14899 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14901 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14902 _codec ("AVID DNxHD");
14903 caps = gst_caps_from_string ("video/x-dnxhd");
14907 _codec ("On2 VP8");
14908 caps = gst_caps_from_string ("video/x-vp8");
14911 _codec ("Google VP9");
14912 caps = gst_caps_from_string ("video/x-vp9");
14915 _codec ("Apple ProRes LT");
14917 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14921 _codec ("Apple ProRes HQ");
14923 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14927 _codec ("Apple ProRes");
14929 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14933 _codec ("Apple ProRes Proxy");
14935 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14939 _codec ("Apple ProRes 4444");
14941 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14944 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14945 if (entry->bits_per_sample > 0) {
14946 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14951 _codec ("Apple ProRes 4444 XQ");
14953 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14956 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14957 if (entry->bits_per_sample > 0) {
14958 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14963 _codec ("GoPro CineForm");
14964 caps = gst_caps_from_string ("video/x-cineform");
14969 caps = gst_caps_new_simple ("video/x-wmv",
14970 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14974 caps = gst_caps_new_simple ("video/x-av1",
14975 "alignment", G_TYPE_STRING, "tu", NULL);
14977 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14980 caps = _get_unknown_codec_name ("video", fourcc);
14985 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14988 gst_video_info_init (&info);
14989 gst_video_info_set_format (&info, format, entry->width, entry->height);
14991 caps = gst_video_info_to_caps (&info);
14992 *codec_name = gst_pb_utils_get_codec_description (caps);
14994 /* enable clipping for raw video streams */
14995 stream->need_clip = TRUE;
14996 stream->alignment = 32;
15003 round_up_pow2 (guint n)
15015 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15016 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
15017 int len, gchar ** codec_name)
15020 const GstStructure *s;
15023 GstAudioFormat format = 0;
15026 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15028 depth = entry->bytes_per_packet * 8;
15031 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
15033 /* 8-bit audio is unsigned */
15035 format = GST_AUDIO_FORMAT_U8;
15036 /* otherwise it's signed and big-endian just like 'twos' */
15038 endian = G_BIG_ENDIAN;
15045 endian = G_LITTLE_ENDIAN;
15048 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
15050 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
15054 caps = gst_caps_new_simple ("audio/x-raw",
15055 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15056 "layout", G_TYPE_STRING, "interleaved", NULL);
15057 stream->alignment = GST_ROUND_UP_8 (depth);
15058 stream->alignment = round_up_pow2 (stream->alignment);
15062 _codec ("Raw 64-bit floating-point audio");
15063 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15065 caps = gst_caps_new_simple ("audio/x-raw",
15066 "format", G_TYPE_STRING, "F64BE",
15067 "layout", G_TYPE_STRING, "interleaved", NULL);
15068 stream->alignment = 8;
15071 _codec ("Raw 32-bit floating-point audio");
15072 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15074 caps = gst_caps_new_simple ("audio/x-raw",
15075 "format", G_TYPE_STRING, "F32BE",
15076 "layout", G_TYPE_STRING, "interleaved", NULL);
15077 stream->alignment = 4;
15080 _codec ("Raw 24-bit PCM audio");
15081 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15083 caps = gst_caps_new_simple ("audio/x-raw",
15084 "format", G_TYPE_STRING, "S24BE",
15085 "layout", G_TYPE_STRING, "interleaved", NULL);
15086 stream->alignment = 4;
15089 _codec ("Raw 32-bit PCM audio");
15090 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15092 caps = gst_caps_new_simple ("audio/x-raw",
15093 "format", G_TYPE_STRING, "S32BE",
15094 "layout", G_TYPE_STRING, "interleaved", NULL);
15095 stream->alignment = 4;
15098 _codec ("Raw 16-bit PCM audio");
15099 caps = gst_caps_new_simple ("audio/x-raw",
15100 "format", G_TYPE_STRING, "S16LE",
15101 "layout", G_TYPE_STRING, "interleaved", NULL);
15102 stream->alignment = 2;
15105 _codec ("Mu-law audio");
15106 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
15109 _codec ("A-law audio");
15110 caps = gst_caps_new_empty_simple ("audio/x-alaw");
15114 _codec ("Microsoft ADPCM");
15115 /* Microsoft ADPCM-ACM code 2 */
15116 caps = gst_caps_new_simple ("audio/x-adpcm",
15117 "layout", G_TYPE_STRING, "microsoft", NULL);
15121 _codec ("DVI/IMA ADPCM");
15122 caps = gst_caps_new_simple ("audio/x-adpcm",
15123 "layout", G_TYPE_STRING, "dvi", NULL);
15127 _codec ("DVI/Intel IMA ADPCM");
15128 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15129 caps = gst_caps_new_simple ("audio/x-adpcm",
15130 "layout", G_TYPE_STRING, "quicktime", NULL);
15134 /* MPEG layer 3, CBR only (pre QT4.1) */
15137 _codec ("MPEG-1 layer 3");
15138 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15139 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15140 "mpegversion", G_TYPE_INT, 1, NULL);
15142 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15143 _codec ("MPEG-1 layer 2");
15145 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15146 "mpegversion", G_TYPE_INT, 1, NULL);
15149 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15150 _codec ("EAC-3 audio");
15151 caps = gst_caps_new_simple ("audio/x-eac3",
15152 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15153 entry->sampled = TRUE;
15155 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15157 _codec ("AC-3 audio");
15158 caps = gst_caps_new_simple ("audio/x-ac3",
15159 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15160 entry->sampled = TRUE;
15162 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15163 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15164 _codec ("DTS audio");
15165 caps = gst_caps_new_simple ("audio/x-dts",
15166 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15167 entry->sampled = TRUE;
15169 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15170 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15171 _codec ("DTS-HD audio");
15172 caps = gst_caps_new_simple ("audio/x-dts",
15173 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15174 entry->sampled = TRUE;
15178 caps = gst_caps_new_simple ("audio/x-mace",
15179 "maceversion", G_TYPE_INT, 3, NULL);
15183 caps = gst_caps_new_simple ("audio/x-mace",
15184 "maceversion", G_TYPE_INT, 6, NULL);
15186 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15188 caps = gst_caps_new_empty_simple ("application/ogg");
15190 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15191 _codec ("DV audio");
15192 caps = gst_caps_new_empty_simple ("audio/x-dv");
15195 _codec ("MPEG-4 AAC audio");
15196 caps = gst_caps_new_simple ("audio/mpeg",
15197 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15198 "stream-format", G_TYPE_STRING, "raw", NULL);
15200 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15201 _codec ("QDesign Music");
15202 caps = gst_caps_new_empty_simple ("audio/x-qdm");
15205 _codec ("QDesign Music v.2");
15206 /* FIXME: QDesign music version 2 (no constant) */
15207 if (FALSE && data) {
15208 caps = gst_caps_new_simple ("audio/x-qdm2",
15209 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15210 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15211 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15213 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15217 _codec ("GSM audio");
15218 caps = gst_caps_new_empty_simple ("audio/x-gsm");
15221 _codec ("AMR audio");
15222 caps = gst_caps_new_empty_simple ("audio/AMR");
15225 _codec ("AMR-WB audio");
15226 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15229 _codec ("Quicktime IMA ADPCM");
15230 caps = gst_caps_new_simple ("audio/x-adpcm",
15231 "layout", G_TYPE_STRING, "quicktime", NULL);
15234 _codec ("Apple lossless audio");
15235 caps = gst_caps_new_empty_simple ("audio/x-alac");
15238 _codec ("Free Lossless Audio Codec");
15239 caps = gst_caps_new_simple ("audio/x-flac",
15240 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15242 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15243 _codec ("QualComm PureVoice");
15244 caps = gst_caps_from_string ("audio/qcelp");
15249 caps = gst_caps_new_empty_simple ("audio/x-wma");
15253 caps = gst_caps_new_empty_simple ("audio/x-opus");
15260 GstAudioFormat format;
15263 FLAG_IS_FLOAT = 0x1,
15264 FLAG_IS_BIG_ENDIAN = 0x2,
15265 FLAG_IS_SIGNED = 0x4,
15266 FLAG_IS_PACKED = 0x8,
15267 FLAG_IS_ALIGNED_HIGH = 0x10,
15268 FLAG_IS_NON_INTERLEAVED = 0x20
15270 _codec ("Raw LPCM audio");
15272 if (data && len >= 36) {
15273 depth = QT_UINT32 (data + 24);
15274 flags = QT_UINT32 (data + 28);
15275 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15277 if ((flags & FLAG_IS_FLOAT) == 0) {
15282 if ((flags & FLAG_IS_ALIGNED_HIGH))
15285 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15286 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15287 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15288 caps = gst_caps_new_simple ("audio/x-raw",
15289 "format", G_TYPE_STRING,
15291 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15292 "UNKNOWN", "layout", G_TYPE_STRING,
15293 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15294 "interleaved", NULL);
15295 stream->alignment = GST_ROUND_UP_8 (depth);
15296 stream->alignment = round_up_pow2 (stream->alignment);
15301 if (flags & FLAG_IS_BIG_ENDIAN)
15302 format = GST_AUDIO_FORMAT_F64BE;
15304 format = GST_AUDIO_FORMAT_F64LE;
15306 if (flags & FLAG_IS_BIG_ENDIAN)
15307 format = GST_AUDIO_FORMAT_F32BE;
15309 format = GST_AUDIO_FORMAT_F32LE;
15311 caps = gst_caps_new_simple ("audio/x-raw",
15312 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15313 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15314 "non-interleaved" : "interleaved", NULL);
15315 stream->alignment = width / 8;
15319 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15322 caps = gst_caps_new_empty_simple ("audio/x-ac4");
15325 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15329 caps = _get_unknown_codec_name ("audio", fourcc);
15335 GstCaps *templ_caps =
15336 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15337 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15338 gst_caps_unref (caps);
15339 gst_caps_unref (templ_caps);
15340 caps = intersection;
15343 /* enable clipping for raw audio streams */
15344 s = gst_caps_get_structure (caps, 0);
15345 name = gst_structure_get_name (s);
15346 if (g_str_has_prefix (name, "audio/x-raw")) {
15347 stream->need_clip = TRUE;
15348 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15349 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15350 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15351 stream->max_buffer_size);
15357 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15358 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15359 const guint8 * stsd_entry_data, gchar ** codec_name)
15363 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15367 _codec ("DVD subtitle");
15368 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15369 stream->process_func = gst_qtdemux_process_buffer_dvd;
15372 _codec ("Quicktime timed text");
15375 _codec ("3GPP timed text");
15377 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15379 /* actual text piece needs to be extracted */
15380 stream->process_func = gst_qtdemux_process_buffer_text;
15383 _codec ("XML subtitles");
15384 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15389 const gchar *buf = "WEBVTT\n\n";
15391 _codec ("WebVTT subtitles");
15392 caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15393 stream->process_func = gst_qtdemux_process_buffer_wvtt;
15395 /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15396 buffer = gst_buffer_new_and_alloc (8);
15397 gst_buffer_fill (buffer, 0, buf, 8);
15398 stream->buffers = g_slist_append (stream->buffers, buffer);
15403 _codec ("CEA 608 Closed Caption");
15405 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15406 G_TYPE_STRING, "s334-1a", NULL);
15407 stream->process_func = gst_qtdemux_process_buffer_clcp;
15408 stream->need_split = TRUE;
15411 _codec ("CEA 708 Closed Caption");
15413 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15414 G_TYPE_STRING, "cdp", NULL);
15415 stream->process_func = gst_qtdemux_process_buffer_clcp;
15420 caps = _get_unknown_codec_name ("text", fourcc);
15428 qtdemux_meta_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15429 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15430 const guint8 * stsd_entry_data, gchar ** codec_name)
15432 GstCaps *caps = NULL;
15434 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15438 gsize size = QT_UINT32 (stsd_entry_data);
15439 GstByteReader reader = GST_BYTE_READER_INIT (stsd_entry_data, size);
15440 const gchar *content_encoding;
15441 const gchar *namespaces;
15442 const gchar *schema_locations;
15444 if (!gst_byte_reader_skip (&reader, 8 + 6 + 2)) {
15445 GST_WARNING_OBJECT (qtdemux, "Too short metx sample entry");
15449 if (!gst_byte_reader_get_string (&reader, &content_encoding) ||
15450 !gst_byte_reader_get_string (&reader, &namespaces) ||
15451 !gst_byte_reader_get_string (&reader, &schema_locations)) {
15452 GST_WARNING_OBJECT (qtdemux, "Too short metx sample entry");
15456 if (strstr (namespaces, "http://www.onvif.org/ver10/schema") != 0) {
15457 if (content_encoding == NULL || *content_encoding == '\0'
15458 || g_ascii_strcasecmp (content_encoding, "xml") == 0) {
15459 _codec ("ONVIF Timed XML MetaData");
15461 gst_caps_new_simple ("application/x-onvif-metadata", "parsed",
15462 G_TYPE_BOOLEAN, TRUE, "encoding", G_TYPE_STRING, "utf8", NULL);
15464 GST_DEBUG_OBJECT (qtdemux, "Unknown content encoding: %s",
15468 GST_DEBUG_OBJECT (qtdemux, "Unknown metadata namespaces: %s",
15479 caps = _get_unknown_codec_name ("meta", fourcc);
15485 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15486 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15487 const guint8 * stsd_entry_data, gchar ** codec_name)
15493 _codec ("MPEG 1 video");
15494 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15495 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15505 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15506 const gchar * system_id)
15510 if (!qtdemux->protection_system_ids)
15511 qtdemux->protection_system_ids =
15512 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15513 /* Check whether we already have an entry for this system ID. */
15514 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15515 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15516 if (g_ascii_strcasecmp (system_id, id) == 0) {
15520 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15521 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,