2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
12 * Copyright (C) <2016> British Broadcasting Corporation
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with this library; if not, write to the
26 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
31 * SECTION:element-qtdemux
34 * Demuxes a .mov file into raw or compressed audio and/or video streams.
36 * This element supports both push and pull-based scheduling, depending on the
37 * capabilities of the upstream elements.
39 * ## Example launch line
41 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
42 * ]| Play (parse and decode) a .mov file and try to output it to
43 * an automatically detected soundcard and videosink. If the MOV file contains
44 * compressed audio or video data, this will only work if you have the
45 * right decoder elements/plugins installed.
53 #include <glib/gi18n-lib.h>
55 #include <glib/gprintf.h>
56 #include <gst/base/base.h>
57 #include <gst/tag/tag.h>
58 #include <gst/audio/audio.h>
59 #include <gst/riff/riff.h>
60 #include <gst/pbutils/pbutils.h>
62 #include "gstisomp4elements.h"
63 #include "qtatomparser.h"
64 #include "qtdemux_types.h"
65 #include "qtdemux_dump.h"
67 #include "descriptors.h"
68 #include "qtdemux_lang.h"
70 #include "qtpalette.h"
71 #include "qtdemux_tags.h"
72 #include "qtdemux_tree.h"
73 #include "qtdemux-webvtt.h"
79 #include <gst/math-compat.h>
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
97 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
99 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
101 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
103 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
104 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
105 #define QTDEMUX_NTH_STREAM(demux,idx) \
106 QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
107 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
108 QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
110 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
112 GST_DEBUG_CATEGORY (qtdemux_debug);
113 #define GST_CAT_DEFAULT qtdemux_debug
115 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
116 typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
118 /* Macros for converting to/from timescale */
119 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
120 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
122 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
123 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
125 /* timestamp is the DTS */
126 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
127 /* timestamp + offset + cslg_shift is the outgoing PTS */
128 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
129 /* timestamp + offset is the PTS used for internal seek calculations */
130 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
131 /* timestamp + duration - dts is the duration */
132 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
134 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
136 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
137 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
138 GST_TRACE("Locking from thread %p", g_thread_self()); \
139 g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
140 GST_TRACE("Locked from thread %p", g_thread_self()); \
143 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
144 GST_TRACE("Unlocking from thread %p", g_thread_self()); \
145 g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
149 * Quicktime has tracks and segments. A track is a continuous piece of
150 * multimedia content. The track is not always played from start to finish but
151 * instead, pieces of the track are 'cut out' and played in sequence. This is
152 * what the segments do.
154 * Inside the track we have keyframes (K) and delta frames. The track has its
155 * own timing, which starts from 0 and extends to end. The position in the track
156 * is called the media_time.
158 * The segments now describe the pieces that should be played from this track
159 * and are basically tuples of media_time/duration/rate entries. We can have
160 * multiple segments and they are all played after one another. An example:
162 * segment 1: media_time: 1 second, duration: 1 second, rate 1
163 * segment 2: media_time: 3 second, duration: 2 second, rate 2
165 * To correctly play back this track, one must play: 1 second of media starting
166 * from media_time 1 followed by 2 seconds of media starting from media_time 3
169 * Each of the segments will be played at a specific time, the first segment at
170 * time 0, the second one after the duration of the first one, etc.. Note that
171 * the time in resulting playback is not identical to the media_time of the
174 * Visually, assuming the track has 4 second of media_time:
177 * .-----------------------------------------------------------.
178 * track: | K.....K.........K........K.......K.......K...........K... |
179 * '-----------------------------------------------------------'
181 * .------------^ ^ .----------^ ^
182 * / .-------------' / .------------------'
184 * .--------------. .--------------.
185 * | segment 1 | | segment 2 |
186 * '--------------' '--------------'
188 * The challenge here is to cut out the right pieces of the track for each of
189 * the playback segments. This fortunately can easily be done with the SEGMENT
190 * events of GStreamer.
192 * For playback of segment 1, we need to provide the decoder with the keyframe
193 * (a), in the above figure, but we must instruct it only to output the decoded
194 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
195 * position set to the time of the segment: 0.
197 * We then proceed to push data from keyframe (a) to frame (b). The decoder
198 * decodes but clips all before media_time 1.
200 * After finishing a segment, we push out a new SEGMENT event with the clipping
201 * boundaries of the new data.
203 * This is a good usecase for the GStreamer accumulated SEGMENT events.
206 struct _QtDemuxSegment
208 /* global time and duration, all gst time */
210 GstClockTime stop_time;
211 GstClockTime duration;
212 /* media time of trak, all gst time */
213 GstClockTime media_start;
214 GstClockTime media_stop;
216 /* Media start time in trak timescale units */
217 guint32 trak_media_start;
220 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
222 /* Used with fragmented MP4 files (mfra atom) */
223 struct _QtDemuxRandomAccessEntry
230 /* Contains properties and cryptographic info for a set of samples from a
231 * track protected using Common Encryption (cenc) */
232 struct _QtDemuxCencSampleSetInfo
234 GstStructure *default_properties;
236 /* @crypto_info holds one GstStructure per sample */
237 GPtrArray *crypto_info;
240 struct _QtDemuxAavdEncryptionInfo
242 GstStructure *default_properties;
246 qt_demux_state_string (enum QtDemuxState state)
249 case QTDEMUX_STATE_INITIAL:
251 case QTDEMUX_STATE_HEADER:
253 case QTDEMUX_STATE_MOVIE:
255 case QTDEMUX_STATE_BUFFER_MDAT:
256 return "<BUFFER_MDAT>";
262 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
264 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
266 static GstStaticPadTemplate gst_qtdemux_sink_template =
267 GST_STATIC_PAD_TEMPLATE ("sink",
270 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
274 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
275 GST_STATIC_PAD_TEMPLATE ("video_%u",
278 GST_STATIC_CAPS_ANY);
280 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
281 GST_STATIC_PAD_TEMPLATE ("audio_%u",
284 GST_STATIC_CAPS_ANY);
286 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
287 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
290 GST_STATIC_CAPS_ANY);
292 static GstStaticPadTemplate gst_qtdemux_metasrc_template =
293 GST_STATIC_PAD_TEMPLATE ("meta_%u",
296 GST_STATIC_CAPS_ANY);
298 #define gst_qtdemux_parent_class parent_class
299 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
300 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
301 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
303 static void gst_qtdemux_dispose (GObject * object);
304 static void gst_qtdemux_finalize (GObject * object);
307 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
308 GstClockTime media_time);
310 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
311 QtDemuxStream * str, gint64 media_offset);
314 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
315 static GstIndex *gst_qtdemux_get_index (GstElement * element);
317 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
318 GstStateChange transition);
319 static void gst_qtdemux_set_context (GstElement * element,
320 GstContext * context);
321 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
322 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
323 GstObject * parent, GstPadMode mode, gboolean active);
325 static void gst_qtdemux_loop (GstPad * pad);
326 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
328 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
330 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
332 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
333 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
334 QtDemuxStream * stream);
335 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
336 QtDemuxStream * stream);
337 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
340 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
342 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
343 const guint8 * buffer, guint length);
344 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
345 const guint8 * buffer, guint length);
346 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
348 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
349 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
351 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
352 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
353 const guint8 * stsd_entry_data, gchar ** codec_name);
354 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
355 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
356 const guint8 * data, int len, gchar ** codec_name);
357 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
358 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
359 gchar ** codec_name);
360 static GstCaps *qtdemux_meta_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
361 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
362 gchar ** codec_name);
363 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
364 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
365 const guint8 * stsd_entry_data, gchar ** codec_name);
367 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
368 QtDemuxStream * stream, guint32 n);
369 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
370 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
371 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
372 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
373 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
374 static void qtdemux_do_allocation (QtDemuxStream * stream,
375 GstQTDemux * qtdemux);
376 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
377 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
378 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
379 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
380 GstClockTime * _start, GstClockTime * _stop);
381 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
382 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
384 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
385 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
387 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
389 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
390 QtDemuxStream * stream, guint sample_index);
391 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
393 static void qtdemux_gst_structure_free (GstStructure * gststructure);
394 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
397 gst_qtdemux_class_init (GstQTDemuxClass * klass)
399 GObjectClass *gobject_class;
400 GstElementClass *gstelement_class;
402 gobject_class = (GObjectClass *) klass;
403 gstelement_class = (GstElementClass *) klass;
405 parent_class = g_type_class_peek_parent (klass);
407 gobject_class->dispose = gst_qtdemux_dispose;
408 gobject_class->finalize = gst_qtdemux_finalize;
410 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
412 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
413 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
415 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
417 gst_tag_register_musicbrainz_tags ();
419 gst_element_class_add_static_pad_template (gstelement_class,
420 &gst_qtdemux_sink_template);
421 gst_element_class_add_static_pad_template (gstelement_class,
422 &gst_qtdemux_videosrc_template);
423 gst_element_class_add_static_pad_template (gstelement_class,
424 &gst_qtdemux_audiosrc_template);
425 gst_element_class_add_static_pad_template (gstelement_class,
426 &gst_qtdemux_subsrc_template);
427 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
429 "Demultiplex a QuickTime file into audio and video streams",
430 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
432 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
437 gst_qtdemux_init (GstQTDemux * qtdemux)
440 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
441 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
442 gst_pad_set_activatemode_function (qtdemux->sinkpad,
443 qtdemux_sink_activate_mode);
444 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
445 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
446 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
447 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
449 qtdemux->adapter = gst_adapter_new ();
450 g_queue_init (&qtdemux->protection_event_queue);
451 qtdemux->flowcombiner = gst_flow_combiner_new ();
452 g_mutex_init (&qtdemux->expose_lock);
454 qtdemux->active_streams = g_ptr_array_new_with_free_func
455 ((GDestroyNotify) gst_qtdemux_stream_unref);
456 qtdemux->old_streams = g_ptr_array_new_with_free_func
457 ((GDestroyNotify) gst_qtdemux_stream_unref);
459 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
461 gst_qtdemux_reset (qtdemux, TRUE);
465 gst_qtdemux_finalize (GObject * object)
467 GstQTDemux *qtdemux = GST_QTDEMUX (object);
469 g_free (qtdemux->redirect_location);
471 G_OBJECT_CLASS (parent_class)->finalize (object);
475 gst_qtdemux_dispose (GObject * object)
477 GstQTDemux *qtdemux = GST_QTDEMUX (object);
479 if (qtdemux->adapter) {
480 g_object_unref (G_OBJECT (qtdemux->adapter));
481 qtdemux->adapter = NULL;
483 gst_tag_list_unref (qtdemux->tag_list);
484 gst_flow_combiner_free (qtdemux->flowcombiner);
485 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
487 g_queue_clear (&qtdemux->protection_event_queue);
489 g_free (qtdemux->cenc_aux_info_sizes);
490 qtdemux->cenc_aux_info_sizes = NULL;
491 g_mutex_clear (&qtdemux->expose_lock);
493 g_ptr_array_free (qtdemux->active_streams, TRUE);
494 g_ptr_array_free (qtdemux->old_streams, TRUE);
496 G_OBJECT_CLASS (parent_class)->dispose (object);
500 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
502 if (qtdemux->redirect_location) {
503 GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
504 (_("This file contains no playable streams.")),
505 ("no known streams found, a redirect message has been posted"),
506 ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
508 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
509 (_("This file contains no playable streams.")),
510 ("no known streams found"));
515 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
517 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
518 mem, size, 0, size, mem, free_func);
522 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
529 if (G_UNLIKELY (size == 0)) {
531 GstBuffer *tmp = NULL;
533 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
534 if (ret != GST_FLOW_OK)
537 gst_buffer_map (tmp, &map, GST_MAP_READ);
538 size = QT_UINT32 (map.data);
539 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
541 gst_buffer_unmap (tmp, &map);
542 gst_buffer_unref (tmp);
545 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
546 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
547 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
548 /* we're pulling header but already got most interesting bits,
549 * so never mind the rest (e.g. tags) (that much) */
550 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
554 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
555 (_("This file is invalid and cannot be played.")),
556 ("atom has bogus size %" G_GUINT64_FORMAT, size));
557 return GST_FLOW_ERROR;
561 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
563 if (G_UNLIKELY (flow != GST_FLOW_OK))
566 bsize = gst_buffer_get_size (*buf);
567 /* Catch short reads - we don't want any partial atoms */
568 if (G_UNLIKELY (bsize < size)) {
569 GST_WARNING_OBJECT (qtdemux,
570 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
571 gst_buffer_unref (*buf);
581 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
582 GstFormat src_format, gint64 src_value, GstFormat dest_format,
586 QtDemuxStream *stream = gst_pad_get_element_private (pad);
589 if (stream->subtype != FOURCC_vide) {
594 switch (src_format) {
595 case GST_FORMAT_TIME:
596 switch (dest_format) {
597 case GST_FORMAT_BYTES:{
598 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
604 *dest_value = stream->samples[index].offset;
606 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
607 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
608 GST_TIME_ARGS (src_value), *dest_value);
616 case GST_FORMAT_BYTES:
617 switch (dest_format) {
618 case GST_FORMAT_TIME:{
620 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
629 QTSTREAMTIME_TO_GSTTIME (stream,
630 stream->samples[index].timestamp);
631 GST_DEBUG_OBJECT (qtdemux,
632 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
633 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
652 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
654 gboolean res = FALSE;
656 *duration = GST_CLOCK_TIME_NONE;
658 if (qtdemux->duration != 0 &&
659 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
660 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
663 *duration = GST_CLOCK_TIME_NONE;
670 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
673 gboolean res = FALSE;
674 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
676 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
678 switch (GST_QUERY_TYPE (query)) {
679 case GST_QUERY_POSITION:{
682 gst_query_parse_position (query, &fmt, NULL);
683 if (fmt == GST_FORMAT_TIME
684 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
685 gst_query_set_position (query, GST_FORMAT_TIME,
686 qtdemux->segment.position);
691 case GST_QUERY_DURATION:{
694 gst_query_parse_duration (query, &fmt, NULL);
695 if (fmt == GST_FORMAT_TIME) {
696 /* First try to query upstream */
697 res = gst_pad_query_default (pad, parent, query);
699 GstClockTime duration;
700 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
701 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
708 case GST_QUERY_CONVERT:{
709 GstFormat src_fmt, dest_fmt;
710 gint64 src_value, dest_value = 0;
712 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
714 res = gst_qtdemux_src_convert (qtdemux, pad,
715 src_fmt, src_value, dest_fmt, &dest_value);
717 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
721 case GST_QUERY_FORMATS:
722 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
725 case GST_QUERY_SEEKING:{
729 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
731 if (fmt == GST_FORMAT_BYTES) {
732 /* We always refuse BYTES seeks from downstream */
736 /* try upstream first */
737 res = gst_pad_query_default (pad, parent, query);
740 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
741 if (fmt == GST_FORMAT_TIME) {
742 GstClockTime duration;
744 gst_qtdemux_get_duration (qtdemux, &duration);
746 if (!qtdemux->pullbased) {
749 /* we might be able with help from upstream */
751 q = gst_query_new_seeking (GST_FORMAT_BYTES);
752 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
753 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
754 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
758 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
764 case GST_QUERY_SEGMENT:
769 format = qtdemux->segment.format;
772 gst_segment_to_stream_time (&qtdemux->segment, format,
773 qtdemux->segment.start);
774 if ((stop = qtdemux->segment.stop) == -1)
775 stop = qtdemux->segment.duration;
777 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
779 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
784 res = gst_pad_query_default (pad, parent, query);
792 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
794 if (G_LIKELY (stream->pad)) {
795 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
796 GST_DEBUG_PAD_NAME (stream->pad));
798 if (!gst_tag_list_is_empty (stream->stream_tags)) {
799 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
800 stream->stream_tags);
801 gst_pad_push_event (stream->pad,
802 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
805 if (G_UNLIKELY (stream->send_global_tags)) {
806 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
808 gst_pad_push_event (stream->pad,
809 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
810 stream->send_global_tags = FALSE;
815 /* push event on all source pads; takes ownership of the event */
817 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
819 gboolean has_valid_stream = FALSE;
820 GstEventType etype = GST_EVENT_TYPE (event);
823 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
824 GST_EVENT_TYPE_NAME (event));
826 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
828 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
829 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
831 if ((pad = stream->pad)) {
832 has_valid_stream = TRUE;
834 if (etype == GST_EVENT_EOS) {
835 /* let's not send twice */
836 if (stream->sent_eos)
838 stream->sent_eos = TRUE;
841 gst_pad_push_event (pad, gst_event_ref (event));
845 gst_event_unref (event);
847 /* if it is EOS and there are no pads, post an error */
848 if (!has_valid_stream && etype == GST_EVENT_EOS) {
849 gst_qtdemux_post_no_playable_stream_error (qtdemux);
859 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
861 if ((gint64) s1->timestamp > *media_time)
863 if ((gint64) s1->timestamp == *media_time)
869 /* find the index of the sample that includes the data for @media_time using a
870 * binary search. Only to be called in optimized cases of linear search below.
872 * Returns the index of the sample with the corresponding *DTS*.
875 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
878 QtDemuxSample *result;
881 /* convert media_time to mov format */
883 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
885 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
886 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
887 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
889 if (G_LIKELY (result))
890 index = result - str->samples;
899 /* find the index of the sample that includes the data for @media_offset using a
902 * Returns the index of the sample.
905 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
906 QtDemuxStream * str, gint64 media_offset)
908 QtDemuxSample *result = str->samples;
911 if (result == NULL || str->n_samples == 0)
914 if (media_offset == result->offset)
918 while (index < str->n_samples - 1) {
919 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
922 if (media_offset < result->offset)
933 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
938 /* find the index of the sample that includes the data for @media_time using a
939 * linear search, and keeping in mind that not all samples may have been parsed
940 * yet. If possible, it will delegate to binary search.
942 * Returns the index of the sample.
945 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
946 GstClockTime media_time)
950 QtDemuxSample *sample;
952 /* convert media_time to mov format */
954 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
956 sample = str->samples;
957 if (mov_time == sample->timestamp + sample->pts_offset)
960 /* use faster search if requested time in already parsed range */
961 sample = str->samples + str->stbl_index;
962 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
963 index = gst_qtdemux_find_index (qtdemux, str, media_time);
964 sample = str->samples + index;
966 while (index < str->n_samples - 1) {
967 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
970 sample = str->samples + index + 1;
971 if (mov_time < sample->timestamp) {
972 sample = str->samples + index;
980 /* sample->timestamp is now <= media_time, need to find the corresponding
981 * PTS now by looking backwards */
982 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
984 sample = str->samples + index;
992 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
997 /* find the index of the keyframe needed to decode the sample at @index
998 * of stream @str, or of a subsequent keyframe (depending on @next)
1000 * Returns the index of the keyframe.
1003 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1004 guint32 index, gboolean next)
1006 guint32 new_index = index;
1008 if (index >= str->n_samples) {
1009 new_index = str->n_samples;
1013 /* all keyframes, return index */
1014 if (str->all_keyframe) {
1019 /* else search until we have a keyframe */
1020 while (new_index < str->n_samples) {
1021 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1024 if (str->samples[new_index].keyframe)
1036 if (new_index == str->n_samples) {
1037 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1042 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1043 "gave %u", next ? "after" : "before", index, new_index);
1050 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1055 /* find the segment for @time_position for @stream
1057 * Returns the index of the segment containing @time_position.
1058 * Returns the last segment and sets the @eos variable to TRUE
1059 * if the time is beyond the end. @eos may be NULL
1062 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1063 GstClockTime time_position)
1068 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1069 GST_TIME_ARGS (time_position));
1072 for (i = 0; i < stream->n_segments; i++) {
1073 QtDemuxSegment *segment = &stream->segments[i];
1075 GST_LOG_OBJECT (stream->pad,
1076 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1077 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1079 /* For the last segment we include stop_time in the last segment */
1080 if (i < stream->n_segments - 1) {
1081 if (segment->time <= time_position && time_position < segment->stop_time) {
1082 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1087 /* Last segment always matches */
1095 /* move the stream @str to the sample position @index.
1097 * Updates @str->sample_index and marks discontinuity if needed.
1100 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1103 /* no change needed */
1104 if (index == str->sample_index)
1107 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1110 /* position changed, we have a discont */
1111 str->sample_index = index;
1112 str->offset_in_sample = 0;
1113 /* Each time we move in the stream we store the position where we are
1115 str->from_sample = index;
1116 str->discont = TRUE;
1120 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1121 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1124 gint64 min_byte_offset = -1;
1127 min_offset = desired_time;
1129 /* for each stream, find the index of the sample in the segment
1130 * and move back to the previous keyframe. */
1131 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1133 guint32 index, kindex;
1135 GstClockTime media_start;
1136 GstClockTime media_time;
1137 GstClockTime seg_time;
1138 QtDemuxSegment *seg;
1139 gboolean empty_segment = FALSE;
1141 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1143 if (CUR_STREAM (str)->sparse && !use_sparse)
1146 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1147 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1149 /* get segment and time in the segment */
1150 seg = &str->segments[seg_idx];
1151 seg_time = (desired_time - seg->time) * seg->rate;
1153 while (QTSEGMENT_IS_EMPTY (seg)) {
1155 empty_segment = TRUE;
1156 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1159 if (seg_idx == str->n_segments)
1161 seg = &str->segments[seg_idx];
1164 if (seg_idx == str->n_segments) {
1165 /* FIXME track shouldn't have the last segment as empty, but if it
1166 * happens we better handle it */
1170 /* get the media time in the segment */
1171 media_start = seg->media_start + seg_time;
1173 /* get the index of the sample with media time */
1174 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1175 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1176 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1177 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1180 /* shift to next frame if we are looking for next keyframe */
1181 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1182 && index < str->stbl_index)
1185 if (!empty_segment) {
1186 /* find previous keyframe */
1187 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1189 /* we will settle for one before if none found after */
1190 if (next && kindex == -1)
1191 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1193 /* Update the requested time whenever a keyframe was found, to make it
1194 * accurate and avoid having the first buffer fall outside of the segment
1199 /* get timestamp of keyframe */
1200 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1201 GST_DEBUG_OBJECT (qtdemux,
1202 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1203 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1204 str->samples[kindex].offset);
1206 /* keyframes in the segment get a chance to change the
1207 * desired_offset. keyframes out of the segment are
1209 if (media_time >= seg->media_start) {
1210 GstClockTime seg_time;
1212 /* this keyframe is inside the segment, convert back to
1214 seg_time = (media_time - seg->media_start) + seg->time;
1215 if ((!next && (seg_time < min_offset)) ||
1216 (next && (seg_time > min_offset)))
1217 min_offset = seg_time;
1222 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1223 min_byte_offset = str->samples[index].offset;
1227 *key_time = min_offset;
1229 *key_offset = min_byte_offset;
1233 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1234 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1238 g_return_val_if_fail (format != NULL, FALSE);
1239 g_return_val_if_fail (cur != NULL, FALSE);
1240 g_return_val_if_fail (stop != NULL, FALSE);
1242 if (*format == GST_FORMAT_TIME)
1246 if (cur_type != GST_SEEK_TYPE_NONE)
1247 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1248 if (res && stop_type != GST_SEEK_TYPE_NONE)
1249 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1252 *format = GST_FORMAT_TIME;
1257 /* perform seek in push based mode:
1258 find BYTE position to move to based on time and delegate to upstream
1261 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1266 GstSeekType cur_type, stop_type;
1267 gint64 cur, stop, key_cur;
1270 gint64 original_stop;
1273 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1275 gst_event_parse_seek (event, &rate, &format, &flags,
1276 &cur_type, &cur, &stop_type, &stop);
1277 seqnum = gst_event_get_seqnum (event);
1279 /* Directly send the instant-rate-change event here before taking the
1280 * stream-lock so that it can be applied as soon as possible */
1281 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1284 /* instant rate change only supported if direction does not change. All
1285 * other requirements are already checked before creating the seek event
1286 * but let's double-check here to be sure */
1287 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1288 (qtdemux->segment.rate < 0 && rate > 0) ||
1289 cur_type != GST_SEEK_TYPE_NONE ||
1290 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1291 GST_ERROR_OBJECT (qtdemux,
1292 "Instant rate change seeks only supported in the "
1293 "same direction, without flushing and position change");
1297 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1298 (GstSegmentFlags) flags);
1299 gst_event_set_seqnum (ev, seqnum);
1300 gst_qtdemux_push_event (qtdemux, ev);
1304 /* only forward streaming and seeking is possible */
1306 goto unsupported_seek;
1308 /* convert to TIME if needed and possible */
1309 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1313 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1314 * the original stop position to use when upstream pushes the new segment
1316 original_stop = stop;
1319 /* find reasonable corresponding BYTE position,
1320 * also try to mind about keyframes, since we can not go back a bit for them
1322 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1323 * mostly just work, but let's not yet boldly go there ... */
1324 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1329 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1330 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1333 GST_OBJECT_LOCK (qtdemux);
1334 qtdemux->seek_offset = byte_cur;
1335 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1336 qtdemux->push_seek_start = cur;
1338 qtdemux->push_seek_start = key_cur;
1341 if (stop_type == GST_SEEK_TYPE_NONE) {
1342 qtdemux->push_seek_stop = qtdemux->segment.stop;
1344 qtdemux->push_seek_stop = original_stop;
1346 GST_OBJECT_UNLOCK (qtdemux);
1348 qtdemux->segment_seqnum = seqnum;
1349 /* BYTE seek event */
1350 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1352 gst_event_set_seqnum (event, seqnum);
1353 res = gst_pad_push_event (qtdemux->sinkpad, event);
1360 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1366 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1371 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1376 /* perform the seek.
1378 * We set all segment_indexes in the streams to unknown and
1379 * adjust the time_position to the desired position. this is enough
1380 * to trigger a segment switch in the streaming thread to start
1381 * streaming from the desired position.
1383 * Keyframe seeking is a little more complicated when dealing with
1384 * segments. Ideally we want to move to the previous keyframe in
1385 * the segment but there might not be a keyframe in the segment. In
1386 * fact, none of the segments could contain a keyframe. We take a
1387 * practical approach: seek to the previous keyframe in the segment,
1388 * if there is none, seek to the beginning of the segment.
1390 * Called with STREAM_LOCK
1393 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1394 guint32 seqnum, GstSeekFlags flags)
1396 gint64 desired_offset;
1399 desired_offset = segment->position;
1401 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1402 GST_TIME_ARGS (desired_offset));
1404 /* may not have enough fragmented info to do this adjustment,
1405 * and we can't scan (and probably should not) at this time with
1406 * possibly flushing upstream */
1407 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1409 gboolean next, before, after;
1411 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1412 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1413 next = after && !before;
1414 if (segment->rate < 0)
1417 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1419 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1420 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1421 desired_offset = min_offset;
1424 /* and set all streams to the final position */
1425 GST_OBJECT_LOCK (qtdemux);
1426 gst_flow_combiner_reset (qtdemux->flowcombiner);
1427 GST_OBJECT_UNLOCK (qtdemux);
1428 qtdemux->segment_seqnum = seqnum;
1429 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1430 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1432 stream->time_position = desired_offset;
1433 stream->accumulated_base = 0;
1434 stream->sample_index = -1;
1435 stream->offset_in_sample = 0;
1436 stream->segment_index = -1;
1437 stream->sent_eos = FALSE;
1438 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1440 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1441 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1443 segment->position = desired_offset;
1444 if (segment->rate >= 0) {
1445 segment->start = desired_offset;
1446 /* We need to update time as we update start in that direction */
1447 segment->time = desired_offset;
1449 /* we stop at the end */
1450 if (segment->stop == -1)
1451 segment->stop = segment->duration;
1453 segment->stop = desired_offset;
1456 if (qtdemux->fragmented)
1457 qtdemux->fragmented_seek_pending = TRUE;
1462 /* do a seek in pull based mode */
1464 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1469 GstSeekType cur_type, stop_type;
1471 gboolean flush, instant_rate_change;
1473 GstSegment seeksegment;
1474 guint32 seqnum = GST_SEQNUM_INVALID;
1475 GstEvent *flush_event;
1478 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1480 gst_event_parse_seek (event, &rate, &format, &flags,
1481 &cur_type, &cur, &stop_type, &stop);
1482 seqnum = gst_event_get_seqnum (event);
1484 /* we have to have a format as the segment format. Try to convert
1486 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1490 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1492 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1493 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1495 /* Directly send the instant-rate-change event here before taking the
1496 * stream-lock so that it can be applied as soon as possible */
1497 if (instant_rate_change) {
1500 /* instant rate change only supported if direction does not change. All
1501 * other requirements are already checked before creating the seek event
1502 * but let's double-check here to be sure */
1503 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1504 (qtdemux->segment.rate < 0 && rate > 0) ||
1505 cur_type != GST_SEEK_TYPE_NONE ||
1506 stop_type != GST_SEEK_TYPE_NONE || flush) {
1507 GST_ERROR_OBJECT (qtdemux,
1508 "Instant rate change seeks only supported in the "
1509 "same direction, without flushing and position change");
1513 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1514 (GstSegmentFlags) flags);
1515 gst_event_set_seqnum (ev, seqnum);
1516 gst_qtdemux_push_event (qtdemux, ev);
1520 /* stop streaming, either by flushing or by pausing the task */
1522 flush_event = gst_event_new_flush_start ();
1523 if (seqnum != GST_SEQNUM_INVALID)
1524 gst_event_set_seqnum (flush_event, seqnum);
1525 /* unlock upstream pull_range */
1526 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1527 /* make sure out loop function exits */
1528 gst_qtdemux_push_event (qtdemux, flush_event);
1530 /* non flushing seek, pause the task */
1531 gst_pad_pause_task (qtdemux->sinkpad);
1534 /* wait for streaming to finish */
1535 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1537 /* copy segment, we need this because we still need the old
1538 * segment when we close the current segment. */
1539 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1541 /* configure the segment with the seek variables */
1542 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1543 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1544 cur_type, cur, stop_type, stop, &update)) {
1546 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1548 /* now do the seek */
1549 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1552 /* prepare for streaming again */
1554 flush_event = gst_event_new_flush_stop (TRUE);
1555 if (seqnum != GST_SEQNUM_INVALID)
1556 gst_event_set_seqnum (flush_event, seqnum);
1558 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1559 gst_qtdemux_push_event (qtdemux, flush_event);
1562 /* commit the new segment */
1563 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1565 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1566 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1567 qtdemux->segment.format, qtdemux->segment.position);
1568 if (seqnum != GST_SEQNUM_INVALID)
1569 gst_message_set_seqnum (msg, seqnum);
1570 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1573 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1574 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1575 qtdemux->sinkpad, NULL);
1577 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1584 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1590 qtdemux_ensure_index (GstQTDemux * qtdemux)
1594 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1596 /* Build complete index */
1597 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1598 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1600 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1601 GST_LOG_OBJECT (qtdemux,
1602 "Building complete index of track-id %u for seeking failed!",
1612 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1615 gboolean res = TRUE;
1616 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1618 switch (GST_EVENT_TYPE (event)) {
1619 case GST_EVENT_RECONFIGURE:
1620 GST_OBJECT_LOCK (qtdemux);
1621 gst_flow_combiner_reset (qtdemux->flowcombiner);
1622 GST_OBJECT_UNLOCK (qtdemux);
1623 res = gst_pad_event_default (pad, parent, event);
1625 case GST_EVENT_SEEK:
1627 GstSeekFlags flags = 0;
1628 GstFormat seek_format;
1629 gboolean instant_rate_change;
1631 #ifndef GST_DISABLE_GST_DEBUG
1632 GstClockTime ts = gst_util_get_timestamp ();
1634 guint32 seqnum = gst_event_get_seqnum (event);
1636 qtdemux->received_seek = TRUE;
1638 gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1640 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1642 if (seqnum == qtdemux->segment_seqnum) {
1643 GST_LOG_OBJECT (pad,
1644 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1645 gst_event_unref (event);
1649 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1650 /* seek should be handled by upstream, we might need to re-download fragments */
1651 GST_DEBUG_OBJECT (qtdemux,
1652 "let upstream handle seek for fragmented playback");
1656 if (seek_format == GST_FORMAT_BYTES) {
1657 GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1658 gst_event_unref (event);
1662 gst_event_parse_seek_trickmode_interval (event,
1663 &qtdemux->trickmode_interval);
1665 /* Build complete index for seeking;
1666 * if not a fragmented file at least and we're really doing a seek,
1667 * not just an instant-rate-change */
1668 if (!qtdemux->fragmented && !instant_rate_change) {
1669 if (!qtdemux_ensure_index (qtdemux))
1672 #ifndef GST_DISABLE_GST_DEBUG
1673 ts = gst_util_get_timestamp () - ts;
1674 GST_INFO_OBJECT (qtdemux,
1675 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1677 if (qtdemux->pullbased) {
1678 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1679 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1680 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1682 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1683 && QTDEMUX_N_STREAMS (qtdemux)
1684 && !qtdemux->fragmented) {
1685 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1687 GST_DEBUG_OBJECT (qtdemux,
1688 "ignoring seek in push mode in current state");
1691 gst_event_unref (event);
1696 res = gst_pad_event_default (pad, parent, event);
1706 GST_ERROR_OBJECT (qtdemux, "Index failed");
1707 gst_event_unref (event);
1713 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1715 * If @fw is false, the coding order is explored backwards.
1717 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1718 * sample is found for that track.
1720 * The stream and sample index of the sample with the minimum offset in the direction explored
1721 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1723 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1724 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1725 * @_stream and @_index. */
1727 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1728 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1731 gint64 time, min_time;
1732 QtDemuxStream *stream;
1739 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1742 gboolean set_sample;
1744 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1751 i = str->n_samples - 1;
1755 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1756 if (str->samples[i].size == 0)
1759 if (fw && (str->samples[i].offset < byte_pos))
1762 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1765 /* move stream to first available sample */
1767 gst_qtdemux_move_stream (qtdemux, str, i);
1771 /* avoid index from sparse streams since they might be far away */
1772 if (!CUR_STREAM (str)->sparse) {
1773 /* determine min/max time */
1774 time = QTSAMPLE_PTS (str, &str->samples[i]);
1775 if (min_time == -1 || (!fw && time > min_time) ||
1776 (fw && time < min_time)) {
1780 /* determine stream with leading sample, to get its position */
1782 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1783 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1791 /* no sample for this stream, mark eos */
1793 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1804 /* Copied from mpegtsbase code */
1805 /* FIXME: replace this function when we add new util function for stream-id creation */
1807 _get_upstream_id (GstQTDemux * demux)
1809 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1812 /* Try to create one from the upstream URI, else use a randome number */
1816 /* Try to generate one from the URI query and
1817 * if it fails take a random number instead */
1818 query = gst_query_new_uri ();
1819 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1820 gst_query_parse_uri (query, &uri);
1826 /* And then generate an SHA256 sum of the URI */
1827 cs = g_checksum_new (G_CHECKSUM_SHA256);
1828 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1830 upstream_id = g_strdup (g_checksum_get_string (cs));
1831 g_checksum_free (cs);
1833 /* Just get some random number if the URI query fails */
1834 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1835 "implementing a deterministic way of creating a stream-id");
1837 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1838 g_random_int (), g_random_int ());
1841 gst_query_unref (query);
1846 static QtDemuxStream *
1847 _create_stream (GstQTDemux * demux, guint32 track_id)
1849 QtDemuxStream *stream;
1852 stream = g_new0 (QtDemuxStream, 1);
1853 stream->demux = demux;
1854 stream->track_id = track_id;
1855 upstream_id = _get_upstream_id (demux);
1856 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1857 g_free (upstream_id);
1858 /* new streams always need a discont */
1859 stream->discont = TRUE;
1860 /* we enable clipping for raw audio/video streams */
1861 stream->need_clip = FALSE;
1862 stream->process_func = NULL;
1863 stream->segment_index = -1;
1864 stream->time_position = 0;
1865 stream->sample_index = -1;
1866 stream->offset_in_sample = 0;
1867 stream->new_stream = TRUE;
1868 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1869 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1870 stream->protected = FALSE;
1871 stream->protection_scheme_type = 0;
1872 stream->protection_scheme_version = 0;
1873 stream->protection_scheme_info = NULL;
1874 stream->n_samples_moof = 0;
1875 stream->duration_moof = 0;
1876 stream->duration_last_moof = 0;
1877 stream->alignment = 1;
1878 stream->stream_tags = gst_tag_list_new_empty ();
1879 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1880 g_queue_init (&stream->protection_scheme_event_queue);
1881 stream->ref_count = 1;
1882 /* consistent default for push based mode */
1883 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1888 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1890 GstStructure *structure;
1891 const gchar *variant;
1892 const GstCaps *mediacaps = NULL;
1894 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1896 structure = gst_caps_get_structure (caps, 0);
1897 variant = gst_structure_get_string (structure, "variant");
1899 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1900 QtDemuxStream *stream;
1901 const GValue *value;
1903 demux->fragmented = TRUE;
1904 demux->mss_mode = TRUE;
1906 if (QTDEMUX_N_STREAMS (demux) > 1) {
1907 /* can't do this, we can only renegotiate for another mss format */
1911 value = gst_structure_get_value (structure, "media-caps");
1914 const GValue *timescale_v;
1916 /* TODO update when stream changes during playback */
1918 if (QTDEMUX_N_STREAMS (demux) == 0) {
1919 stream = _create_stream (demux, 1);
1920 g_ptr_array_add (demux->active_streams, stream);
1921 /* mss has no stsd/stsd entry, use id 0 as default */
1922 stream->stsd_entries_length = 1;
1923 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1924 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1926 stream = QTDEMUX_NTH_STREAM (demux, 0);
1929 timescale_v = gst_structure_get_value (structure, "timescale");
1931 stream->timescale = g_value_get_uint64 (timescale_v);
1933 /* default mss timescale */
1934 stream->timescale = 10000000;
1936 demux->timescale = stream->timescale;
1938 mediacaps = gst_value_get_caps (value);
1939 if (!CUR_STREAM (stream)->caps
1940 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1941 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1943 stream->new_caps = TRUE;
1945 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1946 structure = gst_caps_get_structure (mediacaps, 0);
1947 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1948 stream->subtype = FOURCC_vide;
1950 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1951 gst_structure_get_int (structure, "height",
1952 &CUR_STREAM (stream)->height);
1953 gst_structure_get_fraction (structure, "framerate",
1954 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1955 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1957 stream->subtype = FOURCC_soun;
1958 gst_structure_get_int (structure, "channels",
1959 &CUR_STREAM (stream)->n_channels);
1960 gst_structure_get_int (structure, "rate", &rate);
1961 CUR_STREAM (stream)->rate = rate;
1962 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1963 if (gst_structure_has_field (structure, "original-media-type")) {
1964 const gchar *media_type =
1965 gst_structure_get_string (structure, "original-media-type");
1966 if (g_str_has_prefix (media_type, "video")) {
1967 stream->subtype = FOURCC_vide;
1968 } else if (g_str_has_prefix (media_type, "audio")) {
1969 stream->subtype = FOURCC_soun;
1974 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1976 demux->mss_mode = FALSE;
1983 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1987 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1989 if (hard || qtdemux->upstream_format_is_time) {
1990 qtdemux->state = QTDEMUX_STATE_INITIAL;
1991 qtdemux->neededbytes = 16;
1992 qtdemux->todrop = 0;
1993 qtdemux->pullbased = FALSE;
1994 g_clear_pointer (&qtdemux->redirect_location, g_free);
1995 qtdemux->first_mdat = -1;
1996 qtdemux->header_size = 0;
1997 qtdemux->mdatoffset = -1;
1998 qtdemux->restoredata_offset = -1;
1999 if (qtdemux->mdatbuffer)
2000 gst_buffer_unref (qtdemux->mdatbuffer);
2001 if (qtdemux->restoredata_buffer)
2002 gst_buffer_unref (qtdemux->restoredata_buffer);
2003 qtdemux->mdatbuffer = NULL;
2004 qtdemux->restoredata_buffer = NULL;
2005 qtdemux->mdatleft = 0;
2006 qtdemux->mdatsize = 0;
2007 if (qtdemux->comp_brands)
2008 gst_buffer_unref (qtdemux->comp_brands);
2009 qtdemux->comp_brands = NULL;
2010 qtdemux->last_moov_offset = -1;
2011 if (qtdemux->moov_node_compressed) {
2012 g_node_destroy (qtdemux->moov_node_compressed);
2013 if (qtdemux->moov_node)
2014 g_free (qtdemux->moov_node->data);
2016 qtdemux->moov_node_compressed = NULL;
2017 if (qtdemux->moov_node)
2018 g_node_destroy (qtdemux->moov_node);
2019 qtdemux->moov_node = NULL;
2020 if (qtdemux->tag_list)
2021 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2022 qtdemux->tag_list = gst_tag_list_new_empty ();
2023 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2025 if (qtdemux->element_index)
2026 gst_object_unref (qtdemux->element_index);
2027 qtdemux->element_index = NULL;
2029 qtdemux->major_brand = 0;
2030 qtdemux->upstream_format_is_time = FALSE;
2031 qtdemux->upstream_seekable = FALSE;
2032 qtdemux->upstream_size = 0;
2034 qtdemux->fragment_start = -1;
2035 qtdemux->fragment_start_offset = -1;
2036 qtdemux->duration = 0;
2037 qtdemux->moof_offset = 0;
2038 qtdemux->chapters_track_id = 0;
2039 qtdemux->have_group_id = FALSE;
2040 qtdemux->group_id = G_MAXUINT;
2042 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2044 g_queue_clear (&qtdemux->protection_event_queue);
2046 qtdemux->received_seek = FALSE;
2047 qtdemux->first_moof_already_parsed = FALSE;
2049 qtdemux->offset = 0;
2050 gst_adapter_clear (qtdemux->adapter);
2051 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2052 qtdemux->need_segment = TRUE;
2055 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2056 qtdemux->trickmode_interval = 0;
2057 g_ptr_array_set_size (qtdemux->active_streams, 0);
2058 g_ptr_array_set_size (qtdemux->old_streams, 0);
2059 qtdemux->n_video_streams = 0;
2060 qtdemux->n_audio_streams = 0;
2061 qtdemux->n_sub_streams = 0;
2062 qtdemux->n_meta_streams = 0;
2063 qtdemux->exposed = FALSE;
2064 qtdemux->fragmented = FALSE;
2065 qtdemux->mss_mode = FALSE;
2066 gst_caps_replace (&qtdemux->media_caps, NULL);
2067 qtdemux->timescale = 0;
2068 qtdemux->got_moov = FALSE;
2069 qtdemux->start_utc_time = GST_CLOCK_TIME_NONE;
2070 qtdemux->cenc_aux_info_offset = 0;
2071 qtdemux->cenc_aux_info_sizes = NULL;
2072 qtdemux->cenc_aux_sample_count = 0;
2073 if (qtdemux->protection_system_ids) {
2074 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2075 qtdemux->protection_system_ids = NULL;
2077 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2078 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2079 GST_BIN_FLAG_STREAMS_AWARE);
2081 if (qtdemux->preferred_protection_system_id) {
2082 g_free (qtdemux->preferred_protection_system_id);
2083 qtdemux->preferred_protection_system_id = NULL;
2085 } else if (qtdemux->mss_mode) {
2086 gst_flow_combiner_reset (qtdemux->flowcombiner);
2087 g_ptr_array_foreach (qtdemux->active_streams,
2088 (GFunc) gst_qtdemux_stream_clear, NULL);
2090 gst_flow_combiner_reset (qtdemux->flowcombiner);
2091 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2092 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2093 stream->sent_eos = FALSE;
2094 stream->time_position = 0;
2095 stream->accumulated_base = 0;
2096 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2102 /* Maps the @segment to the qt edts internal segments and pushes
2103 * the corresponding segment event.
2105 * If it ends up being at a empty segment, a gap will be pushed and the next
2106 * edts segment will be activated in sequence.
2108 * To be used in push-mode only */
2110 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2114 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2115 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2117 stream->time_position = segment->start;
2119 /* in push mode we should be guaranteed that we will have empty segments
2120 * at the beginning and then one segment after, other scenarios are not
2121 * supported and are discarded when parsing the edts */
2122 for (i = 0; i < stream->n_segments; i++) {
2123 if (stream->segments[i].stop_time > segment->start) {
2124 /* push the empty segment and move to the next one */
2125 gst_qtdemux_activate_segment (qtdemux, stream, i,
2126 stream->time_position);
2127 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2128 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2129 stream->time_position);
2131 /* accumulate previous segments */
2132 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2133 stream->accumulated_base +=
2134 (stream->segment.stop -
2135 stream->segment.start) / ABS (stream->segment.rate);
2139 g_assert (i == stream->n_segments - 1);
2146 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2157 for (i = 0; i < len; i++) {
2158 QtDemuxStream *stream = g_ptr_array_index (src, i);
2160 #ifndef GST_DISABLE_GST_DEBUG
2161 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2162 stream, GST_STR_NULL (stream->stream_id), dest);
2164 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2167 g_ptr_array_set_size (src, 0);
2171 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2174 GstQTDemux *demux = GST_QTDEMUX (parent);
2175 gboolean res = TRUE;
2177 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2179 switch (GST_EVENT_TYPE (event)) {
2180 case GST_EVENT_SEGMENT:
2183 QtDemuxStream *stream;
2187 /* some debug output */
2188 gst_event_copy_segment (event, &segment);
2189 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2192 if (segment.format == GST_FORMAT_TIME) {
2193 demux->upstream_format_is_time = TRUE;
2194 demux->segment_seqnum = gst_event_get_seqnum (event);
2196 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2197 "not in time format");
2199 /* chain will send initial newsegment after pads have been added */
2200 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2201 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2206 /* check if this matches a time seek we received previously
2207 * FIXME for backwards compatibility reasons we use the
2208 * seek_offset here to compare. In the future we might want to
2209 * change this to use the seqnum as it uniquely should identify
2210 * the segment that corresponds to the seek. */
2211 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2212 ", received segment offset %" G_GINT64_FORMAT,
2213 demux->seek_offset, segment.start);
2214 if (segment.format == GST_FORMAT_BYTES
2215 && demux->seek_offset == segment.start) {
2216 GST_OBJECT_LOCK (demux);
2217 offset = segment.start;
2219 segment.format = GST_FORMAT_TIME;
2220 segment.start = demux->push_seek_start;
2221 segment.stop = demux->push_seek_stop;
2222 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2223 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2224 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2225 GST_OBJECT_UNLOCK (demux);
2228 /* we only expect a BYTE segment, e.g. following a seek */
2229 if (segment.format == GST_FORMAT_BYTES) {
2230 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2231 offset = segment.start;
2233 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2234 NULL, (gint64 *) & segment.start);
2235 if ((gint64) segment.start < 0)
2238 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2239 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2240 NULL, (gint64 *) & segment.stop);
2241 /* keyframe seeking should already arrange for start >= stop,
2242 * but make sure in other rare cases */
2243 segment.stop = MAX (segment.stop, segment.start);
2245 } else if (segment.format == GST_FORMAT_TIME) {
2246 /* push all data on the adapter before starting this
2248 gst_qtdemux_process_adapter (demux, TRUE);
2250 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2254 /* We shouldn't modify upstream driven TIME FORMAT segment */
2255 if (!demux->upstream_format_is_time) {
2256 /* accept upstream's notion of segment and distribute along */
2257 segment.format = GST_FORMAT_TIME;
2258 segment.position = segment.time = segment.start;
2259 segment.duration = demux->segment.duration;
2260 segment.base = gst_segment_to_running_time (&demux->segment,
2261 GST_FORMAT_TIME, demux->segment.position);
2264 gst_segment_copy_into (&segment, &demux->segment);
2265 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2267 /* map segment to internal qt segments and push on each stream */
2268 if (QTDEMUX_N_STREAMS (demux)) {
2269 demux->need_segment = TRUE;
2270 gst_qtdemux_check_send_pending_segment (demux);
2273 /* clear leftover in current segment, if any */
2274 gst_adapter_clear (demux->adapter);
2276 /* set up streaming thread */
2277 demux->offset = offset;
2278 if (demux->upstream_format_is_time) {
2279 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2280 "set values to restart reading from a new atom");
2281 demux->neededbytes = 16;
2284 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2287 demux->todrop = stream->samples[idx].offset - offset;
2288 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2290 /* set up for EOS */
2291 demux->neededbytes = -1;
2296 gst_event_unref (event);
2300 case GST_EVENT_FLUSH_START:
2302 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2303 gst_event_unref (event);
2306 QTDEMUX_EXPOSE_LOCK (demux);
2307 res = gst_pad_event_default (demux->sinkpad, parent, event);
2308 QTDEMUX_EXPOSE_UNLOCK (demux);
2311 case GST_EVENT_FLUSH_STOP:
2315 dur = demux->segment.duration;
2316 gst_qtdemux_reset (demux, FALSE);
2317 demux->segment.duration = dur;
2319 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2320 gst_event_unref (event);
2326 /* If we are in push mode, and get an EOS before we've seen any streams,
2327 * then error out - we have nowhere to send the EOS */
2328 if (!demux->pullbased) {
2330 gboolean has_valid_stream = FALSE;
2331 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2332 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2333 has_valid_stream = TRUE;
2337 if (!has_valid_stream)
2338 gst_qtdemux_post_no_playable_stream_error (demux);
2340 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2341 (guint) gst_adapter_available (demux->adapter));
2342 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2348 case GST_EVENT_CAPS:{
2349 GstCaps *caps = NULL;
2351 gst_event_parse_caps (event, &caps);
2352 gst_qtdemux_setcaps (demux, caps);
2354 gst_event_unref (event);
2357 case GST_EVENT_PROTECTION:
2359 const gchar *system_id = NULL;
2361 gst_event_parse_protection (event, &system_id, NULL, NULL);
2362 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2364 gst_qtdemux_append_protection_system_id (demux, system_id);
2365 /* save the event for later, for source pads that have not been created */
2366 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2367 /* send it to all pads that already exist */
2368 gst_qtdemux_push_event (demux, event);
2372 case GST_EVENT_STREAM_START:
2375 gst_event_unref (event);
2377 /* Drain all the buffers */
2378 gst_qtdemux_process_adapter (demux, TRUE);
2379 gst_qtdemux_reset (demux, FALSE);
2380 /* We expect new moov box after new stream-start event */
2381 if (demux->exposed) {
2382 gst_qtdemux_stream_concat (demux,
2383 demux->old_streams, demux->active_streams);
2392 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2399 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2402 GstQTDemux *demux = GST_QTDEMUX (parent);
2403 gboolean res = FALSE;
2405 switch (GST_QUERY_TYPE (query)) {
2406 case GST_QUERY_BITRATE:
2408 GstClockTime duration;
2410 /* populate demux->upstream_size if not done yet */
2411 gst_qtdemux_check_seekability (demux);
2413 if (demux->upstream_size != -1
2414 && gst_qtdemux_get_duration (demux, &duration)) {
2416 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2419 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2420 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2421 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2423 /* TODO: better results based on ranges/index tables */
2424 gst_query_set_bitrate (query, bitrate);
2430 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2440 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2442 GstQTDemux *demux = GST_QTDEMUX (element);
2444 GST_OBJECT_LOCK (demux);
2445 if (demux->element_index)
2446 gst_object_unref (demux->element_index);
2448 demux->element_index = gst_object_ref (index);
2450 demux->element_index = NULL;
2452 GST_OBJECT_UNLOCK (demux);
2453 /* object lock might be taken again */
2455 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2456 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2457 demux->element_index, demux->index_id);
2461 gst_qtdemux_get_index (GstElement * element)
2463 GstIndex *result = NULL;
2464 GstQTDemux *demux = GST_QTDEMUX (element);
2466 GST_OBJECT_LOCK (demux);
2467 if (demux->element_index)
2468 result = gst_object_ref (demux->element_index);
2469 GST_OBJECT_UNLOCK (demux);
2471 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2478 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2480 g_free ((gpointer) stream->stco.data);
2481 stream->stco.data = NULL;
2482 g_free ((gpointer) stream->stsz.data);
2483 stream->stsz.data = NULL;
2484 g_free ((gpointer) stream->stsc.data);
2485 stream->stsc.data = NULL;
2486 g_free ((gpointer) stream->stts.data);
2487 stream->stts.data = NULL;
2488 g_free ((gpointer) stream->stss.data);
2489 stream->stss.data = NULL;
2490 g_free ((gpointer) stream->stps.data);
2491 stream->stps.data = NULL;
2492 g_free ((gpointer) stream->ctts.data);
2493 stream->ctts.data = NULL;
2497 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2499 g_free (stream->segments);
2500 stream->segments = NULL;
2501 stream->segment_index = -1;
2502 stream->accumulated_base = 0;
2506 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2508 g_free (stream->samples);
2509 stream->samples = NULL;
2510 gst_qtdemux_stbl_free (stream);
2513 g_free (stream->ra_entries);
2514 stream->ra_entries = NULL;
2515 stream->n_ra_entries = 0;
2517 stream->sample_index = -1;
2518 stream->stbl_index = -1;
2519 stream->n_samples = 0;
2520 stream->time_position = 0;
2522 stream->n_samples_moof = 0;
2523 stream->duration_moof = 0;
2524 stream->duration_last_moof = 0;
2528 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2531 if (stream->allocator)
2532 gst_object_unref (stream->allocator);
2533 while (stream->buffers) {
2534 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2535 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2537 for (i = 0; i < stream->stsd_entries_length; i++) {
2538 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2539 if (entry->rgb8_palette) {
2540 gst_memory_unref (entry->rgb8_palette);
2541 entry->rgb8_palette = NULL;
2543 entry->sparse = FALSE;
2546 if (stream->stream_tags)
2547 gst_tag_list_unref (stream->stream_tags);
2549 stream->stream_tags = gst_tag_list_new_empty ();
2550 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2551 g_free (stream->redirect_uri);
2552 stream->redirect_uri = NULL;
2553 stream->sent_eos = FALSE;
2554 stream->protected = FALSE;
2555 if (stream->protection_scheme_info) {
2556 if (stream->protection_scheme_type == FOURCC_cenc
2557 || stream->protection_scheme_type == FOURCC_cbcs) {
2558 QtDemuxCencSampleSetInfo *info =
2559 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2560 if (info->default_properties)
2561 gst_structure_free (info->default_properties);
2562 if (info->crypto_info)
2563 g_ptr_array_free (info->crypto_info, TRUE);
2565 if (stream->protection_scheme_type == FOURCC_aavd) {
2566 QtDemuxAavdEncryptionInfo *info =
2567 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2568 if (info->default_properties)
2569 gst_structure_free (info->default_properties);
2571 g_free (stream->protection_scheme_info);
2572 stream->protection_scheme_info = NULL;
2574 stream->protection_scheme_type = 0;
2575 stream->protection_scheme_version = 0;
2576 g_queue_foreach (&stream->protection_scheme_event_queue,
2577 (GFunc) gst_event_unref, NULL);
2578 g_queue_clear (&stream->protection_scheme_event_queue);
2579 gst_qtdemux_stream_flush_segments_data (stream);
2580 gst_qtdemux_stream_flush_samples_data (stream);
2584 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2587 gst_qtdemux_stream_clear (stream);
2588 for (i = 0; i < stream->stsd_entries_length; i++) {
2589 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2591 gst_caps_unref (entry->caps);
2595 g_free (stream->stsd_entries);
2596 stream->stsd_entries = NULL;
2597 stream->stsd_entries_length = 0;
2600 static QtDemuxStream *
2601 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2603 g_atomic_int_add (&stream->ref_count, 1);
2609 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2611 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2612 gst_qtdemux_stream_reset (stream);
2613 gst_tag_list_unref (stream->stream_tags);
2615 GstQTDemux *demux = stream->demux;
2616 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2617 GST_OBJECT_LOCK (demux);
2618 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2619 GST_OBJECT_UNLOCK (demux);
2621 g_free (stream->stream_id);
2626 static GstStateChangeReturn
2627 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2629 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2630 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2632 switch (transition) {
2633 case GST_STATE_CHANGE_READY_TO_PAUSED:
2634 gst_qtdemux_reset (qtdemux, TRUE);
2640 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2642 switch (transition) {
2643 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2644 gst_qtdemux_reset (qtdemux, TRUE);
2655 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2657 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2659 g_return_if_fail (GST_IS_CONTEXT (context));
2661 if (gst_context_has_context_type (context,
2662 "drm-preferred-decryption-system-id")) {
2663 const GstStructure *s;
2665 s = gst_context_get_structure (context);
2666 g_free (qtdemux->preferred_protection_system_id);
2667 qtdemux->preferred_protection_system_id =
2668 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2669 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2670 qtdemux->preferred_protection_system_id);
2673 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2677 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2679 /* counts as header data */
2680 qtdemux->header_size += length;
2682 /* only consider at least a sufficiently complete ftyp atom */
2685 guint32 minor_version;
2688 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2689 GST_DEBUG_OBJECT (qtdemux, "ftyp major brand: %" GST_FOURCC_FORMAT,
2690 GST_FOURCC_ARGS (qtdemux->major_brand));
2691 minor_version = QT_UINT32 (buffer + 12);
2692 GST_DEBUG_OBJECT (qtdemux, "ftyp minor version: %u", minor_version);
2693 if (qtdemux->comp_brands)
2694 gst_buffer_unref (qtdemux->comp_brands);
2695 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2696 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2699 length = length - 16;
2700 while (length > 0) {
2701 GST_DEBUG_OBJECT (qtdemux, "ftyp compatible brand: %" GST_FOURCC_FORMAT,
2702 GST_FOURCC_ARGS (QT_FOURCC (p)));
2710 qtdemux_parse_styp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2712 /* only consider at least a sufficiently complete styp atom */
2715 guint32 major_brand;
2716 guint32 minor_version;
2719 major_brand = QT_FOURCC (buffer + 8);
2720 GST_DEBUG_OBJECT (qtdemux, "styp major brand: %" GST_FOURCC_FORMAT,
2721 GST_FOURCC_ARGS (major_brand));
2722 minor_version = QT_UINT32 (buffer + 12);
2723 GST_DEBUG_OBJECT (qtdemux, "styp minor version: %u", minor_version);
2724 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2725 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2728 length = length - 16;
2729 while (length > 0) {
2730 GST_DEBUG_OBJECT (qtdemux, "styp compatible brand: %" GST_FOURCC_FORMAT,
2731 GST_FOURCC_ARGS (QT_FOURCC (p)));
2739 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2740 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2741 guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2742 guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2743 const guint8 * constant_iv)
2745 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2746 gst_buffer_fill (kid_buf, 0, kid, 16);
2747 if (info->default_properties)
2748 gst_structure_free (info->default_properties);
2749 info->default_properties =
2750 gst_structure_new ("application/x-cenc",
2751 "iv_size", G_TYPE_UINT, iv_size,
2752 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2753 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2754 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2755 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2756 gst_buffer_unref (kid_buf);
2757 if (protection_scheme_type == FOURCC_cbcs) {
2758 if (crypt_byte_block != 0 || skip_byte_block != 0) {
2759 gst_structure_set (info->default_properties, "crypt_byte_block",
2760 G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2761 skip_byte_block, NULL);
2763 if (constant_iv != NULL) {
2764 GstBuffer *constant_iv_buf =
2765 gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2766 gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2767 gst_structure_set (info->default_properties, "constant_iv_size",
2768 G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2770 gst_buffer_unref (constant_iv_buf);
2772 gst_structure_set (info->default_properties, "cipher-mode",
2773 G_TYPE_STRING, "cbcs", NULL);
2775 gst_structure_set (info->default_properties, "cipher-mode",
2776 G_TYPE_STRING, "cenc", NULL);
2781 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2782 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2784 guint32 algorithm_id = 0;
2786 gboolean is_encrypted = TRUE;
2789 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2790 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2795 if (algorithm_id == 0) {
2796 is_encrypted = FALSE;
2797 } else if (algorithm_id == 1) {
2798 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2799 } else if (algorithm_id == 2) {
2800 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2803 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2806 if (!gst_byte_reader_get_data (br, 16, &kid))
2809 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2810 is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2811 gst_structure_set (info->default_properties, "piff_algorithm_id",
2812 G_TYPE_UINT, algorithm_id, NULL);
2818 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2826 QtDemuxStream *stream;
2827 GstStructure *structure;
2828 QtDemuxCencSampleSetInfo *ss_info = NULL;
2829 const gchar *system_id;
2830 gboolean uses_sub_sample_encryption = FALSE;
2831 guint32 sample_count;
2833 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2836 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2838 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2839 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2840 GST_WARNING_OBJECT (qtdemux,
2841 "Attempting PIFF box parsing on an unencrypted stream.");
2845 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2846 G_TYPE_STRING, &system_id, NULL);
2847 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2849 stream->protected = TRUE;
2850 stream->protection_scheme_type = FOURCC_cenc;
2852 if (!stream->protection_scheme_info)
2853 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2855 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2856 if (!ss_info->default_properties) {
2857 ss_info->default_properties =
2858 gst_structure_new ("application/x-cenc",
2859 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2864 if (ss_info->crypto_info) {
2865 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2866 g_ptr_array_free (ss_info->crypto_info, TRUE);
2867 ss_info->crypto_info = NULL;
2871 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2873 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2874 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2878 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2879 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2883 if ((flags & 0x000001)) {
2884 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2887 } else if ((flags & 0x000002)) {
2888 uses_sub_sample_encryption = TRUE;
2891 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2893 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2897 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2898 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2902 ss_info->crypto_info =
2903 g_ptr_array_new_full (sample_count,
2904 (GDestroyNotify) qtdemux_gst_structure_free);
2906 for (i = 0; i < sample_count; ++i) {
2907 GstStructure *properties;
2911 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2912 if (properties == NULL) {
2913 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2914 qtdemux->cenc_aux_sample_count = i;
2918 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2919 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2920 gst_structure_free (properties);
2921 qtdemux->cenc_aux_sample_count = i;
2924 buf = gst_buffer_new_wrapped (data, iv_size);
2925 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2926 gst_buffer_unref (buf);
2928 if (uses_sub_sample_encryption) {
2929 guint16 n_subsamples;
2930 const GValue *kid_buf_value;
2932 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2933 || n_subsamples == 0) {
2934 GST_ERROR_OBJECT (qtdemux,
2935 "failed to get subsample count for sample %u", i);
2936 gst_structure_free (properties);
2937 qtdemux->cenc_aux_sample_count = i;
2940 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2941 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2942 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2944 gst_structure_free (properties);
2945 qtdemux->cenc_aux_sample_count = i;
2948 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2951 gst_structure_get_value (ss_info->default_properties, "kid");
2953 gst_structure_set (properties,
2954 "subsample_count", G_TYPE_UINT, n_subsamples,
2955 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2956 gst_structure_set_value (properties, "kid", kid_buf_value);
2957 gst_buffer_unref (buf);
2959 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2962 g_ptr_array_add (ss_info->crypto_info, properties);
2965 qtdemux->cenc_aux_sample_count = sample_count;
2969 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2971 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2972 0x97, 0xA9, 0x42, 0xE8,
2973 0x9C, 0x71, 0x99, 0x94,
2974 0x91, 0xE3, 0xAF, 0xAC
2976 static const guint8 playready_uuid[] = {
2977 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2978 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2981 static const guint8 piff_sample_encryption_uuid[] = {
2982 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2983 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2988 /* counts as header data */
2989 qtdemux->header_size += length;
2991 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2993 if (length <= offset + 16) {
2994 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2998 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
3000 GstTagList *taglist;
3002 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3003 length - offset - 16, NULL);
3004 taglist = gst_tag_list_from_xmp_buffer (buf);
3005 gst_buffer_unref (buf);
3007 /* make sure we have a usable taglist */
3008 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3010 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3012 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3014 const gunichar2 *s_utf16;
3017 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3018 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3019 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3020 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3024 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3025 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3027 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3028 qtdemux_parse_piff (qtdemux, buffer, length, offset);
3030 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3031 GST_READ_UINT32_LE (buffer + offset),
3032 GST_READ_UINT32_LE (buffer + offset + 4),
3033 GST_READ_UINT32_LE (buffer + offset + 8),
3034 GST_READ_UINT32_LE (buffer + offset + 12));
3039 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3041 GstSidxParser sidx_parser;
3042 GstIsoffParserResult res;
3045 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3048 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3050 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3051 if (res == GST_ISOFF_QT_PARSER_DONE) {
3052 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3054 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3058 qtdemux_parse_cstb (GstQTDemux * qtdemux, GstByteReader * data)
3061 guint32 entry_count;
3063 GST_DEBUG_OBJECT (qtdemux, "Parsing CorrectStartTime box");
3065 qtdemux->start_utc_time = GST_CLOCK_TIME_NONE;
3067 if (gst_byte_reader_get_remaining (data) < 4) {
3068 GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box");
3072 entry_count = gst_byte_reader_get_uint32_be_unchecked (data);
3073 if (entry_count == 0)
3076 /* XXX: We assume that all start times are the same as different start times
3077 * would violate the MP4 synchronization model, so we just take the first
3078 * one here and apply it to all tracks.
3081 if (gst_byte_reader_get_remaining (data) < entry_count * 12) {
3082 GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box");
3087 gst_byte_reader_skip_unchecked (data, 4);
3089 /* In 100ns intervals */
3090 start_time = gst_byte_reader_get_uint64_be_unchecked (data);
3092 /* Convert from Jan 1 1601 to Jan 1 1970 */
3093 if (start_time < 11644473600 * G_GUINT64_CONSTANT (10000000)) {
3094 GST_WARNING_OBJECT (qtdemux, "Start UTC time before UNIX epoch");
3097 start_time -= 11644473600 * G_GUINT64_CONSTANT (10000000);
3099 /* Convert to GstClockTime */
3102 GST_DEBUG_OBJECT (qtdemux, "Start UTC time: %" GST_TIME_FORMAT,
3103 GST_TIME_ARGS (start_time));
3105 qtdemux->start_utc_time = start_time;
3108 /* caller verifies at least 8 bytes in buf */
3110 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3111 guint64 * plength, guint32 * pfourcc)
3116 length = QT_UINT32 (data);
3117 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3118 fourcc = QT_FOURCC (data + 4);
3119 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3122 length = G_MAXUINT64;
3123 } else if (length == 1 && size >= 16) {
3124 /* this means we have an extended size, which is the 64 bit value of
3125 * the next 8 bytes */
3126 length = QT_UINT64 (data + 8);
3127 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3137 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3139 guint32 version = 0;
3140 GstClockTime duration = 0;
3142 if (!gst_byte_reader_get_uint32_be (br, &version))
3147 if (!gst_byte_reader_get_uint64_be (br, &duration))
3152 if (!gst_byte_reader_get_uint32_be (br, &dur))
3157 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3158 qtdemux->duration = duration;
3164 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3170 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3171 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3173 if (!stream->parsed_trex && qtdemux->moov_node) {
3175 GstByteReader trex_data;
3177 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3179 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3182 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3184 /* skip version/flags */
3185 if (!gst_byte_reader_skip (&trex_data, 4))
3187 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3189 if (id != stream->track_id)
3191 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3193 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3195 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3197 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3200 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3201 "duration %d, size %d, flags 0x%x", stream->track_id,
3204 stream->parsed_trex = TRUE;
3205 stream->def_sample_description_index = sdi;
3206 stream->def_sample_duration = dur;
3207 stream->def_sample_size = size;
3208 stream->def_sample_flags = flags;
3211 /* iterate all siblings */
3212 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3218 *ds_duration = stream->def_sample_duration;
3219 *ds_size = stream->def_sample_size;
3220 *ds_flags = stream->def_sample_flags;
3222 /* even then, above values are better than random ... */
3223 if (G_UNLIKELY (!stream->parsed_trex)) {
3224 GST_WARNING_OBJECT (qtdemux,
3225 "failed to find fragment defaults for stream %d", stream->track_id);
3232 /* This method should be called whenever a more accurate duration might
3233 * have been found. It will update all relevant variables if/where needed
3236 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3240 GstClockTime prevdur;
3242 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3244 if (movdur > qtdemux->duration) {
3245 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3246 GST_DEBUG_OBJECT (qtdemux,
3247 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3248 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3249 qtdemux->duration = movdur;
3250 GST_DEBUG_OBJECT (qtdemux,
3251 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3252 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3253 GST_TIME_ARGS (qtdemux->segment.stop));
3254 if (qtdemux->segment.duration == prevdur) {
3255 /* If the current segment has duration/stop identical to previous duration
3256 * update them also (because they were set at that point in time with
3257 * the wrong duration */
3258 /* We convert the value *from* the timescale version to avoid rounding errors */
3259 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3260 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3261 qtdemux->segment.duration = fixeddur;
3262 qtdemux->segment.stop = fixeddur;
3266 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3267 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3269 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3270 if (movdur > stream->duration) {
3271 GST_DEBUG_OBJECT (qtdemux,
3272 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3273 GST_TIME_ARGS (duration));
3274 stream->duration = movdur;
3275 /* internal duration tracking state has been updated above, so */
3276 /* preserve an open-ended dummy segment rather than repeatedly updating
3277 * it and spamming downstream accordingly with segment events */
3278 /* also mangle the edit list end time when fragmented with a single edit
3279 * list that may only cover any non-fragmented data */
3280 if ((stream->dummy_segment ||
3281 (qtdemux->fragmented && stream->n_segments == 1)) &&
3282 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3283 /* Update all dummy values to new duration */
3284 stream->segments[0].stop_time = duration;
3285 stream->segments[0].duration = duration;
3286 stream->segments[0].media_stop = duration;
3288 /* let downstream know we possibly have a new stop time */
3289 if (stream->segment_index != -1) {
3292 if (qtdemux->segment.rate >= 0) {
3293 pos = stream->segment.start;
3295 pos = stream->segment.stop;
3298 gst_qtdemux_stream_update_segment (qtdemux, stream,
3299 stream->segment_index, pos, NULL, NULL);
3307 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3308 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3309 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3310 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3313 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3315 gint32 data_offset = 0;
3317 guint32 flags = 0, first_flags = 0, samples_count = 0;
3320 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3321 QtDemuxSample *sample;
3322 gboolean ismv = FALSE;
3323 gint64 initial_offset;
3326 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3327 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3328 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3329 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3331 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3332 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3336 /* presence of stss or not can't really tell us much,
3337 * and flags and so on tend to be marginally reliable in these files */
3338 if (stream->subtype == FOURCC_soun) {
3339 GST_DEBUG_OBJECT (qtdemux,
3340 "sound track in fragmented file; marking all keyframes");
3341 stream->all_keyframe = TRUE;
3344 if (!gst_byte_reader_get_uint8 (trun, &version) ||
3345 !gst_byte_reader_get_uint24_be (trun, &flags))
3348 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3351 if (flags & TR_DATA_OFFSET) {
3352 /* note this is really signed */
3353 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3355 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3356 /* default base offset = first byte of moof */
3357 if (*base_offset == -1) {
3358 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3359 *base_offset = moof_offset;
3361 *running_offset = *base_offset + data_offset;
3363 /* if no offset at all, that would mean data starts at moof start,
3364 * which is a bit wrong and is ismv crappy way, so compensate
3365 * assuming data is in mdat following moof */
3366 if (*base_offset == -1) {
3367 *base_offset = moof_offset + moof_length + 8;
3368 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3371 if (*running_offset == -1)
3372 *running_offset = *base_offset;
3375 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3377 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3378 data_offset, flags, samples_count);
3380 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3381 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3382 GST_DEBUG_OBJECT (qtdemux,
3383 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3384 flags ^= TR_FIRST_SAMPLE_FLAGS;
3386 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3388 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3392 /* FIXME ? spec says other bits should also be checked to determine
3393 * entry size (and prefix size for that matter) */
3395 dur_offset = size_offset = 0;
3396 if (flags & TR_SAMPLE_DURATION) {
3397 GST_LOG_OBJECT (qtdemux, "entry duration present");
3398 dur_offset = entry_size;
3401 if (flags & TR_SAMPLE_SIZE) {
3402 GST_LOG_OBJECT (qtdemux, "entry size present");
3403 size_offset = entry_size;
3406 if (flags & TR_SAMPLE_FLAGS) {
3407 GST_LOG_OBJECT (qtdemux, "entry flags present");
3408 flags_offset = entry_size;
3411 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3412 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3413 ct_offset = entry_size;
3417 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3419 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3421 if (stream->n_samples + samples_count >=
3422 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3425 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3426 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3427 (stream->n_samples + samples_count) *
3428 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3430 /* create a new array of samples if it's the first sample parsed */
3431 if (stream->n_samples == 0) {
3432 g_assert (stream->samples == NULL);
3433 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3434 /* or try to reallocate it with space enough to insert the new samples */
3436 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3437 stream->n_samples + samples_count);
3438 if (stream->samples == NULL)
3441 if (qtdemux->fragment_start != -1) {
3442 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3443 qtdemux->fragment_start = -1;
3445 if (stream->n_samples == 0) {
3446 if (decode_ts > 0) {
3447 timestamp = decode_ts;
3448 } else if (stream->pending_seek != NULL) {
3449 /* if we don't have a timestamp from a tfdt box, we'll use the one
3450 * from the mfra seek table */
3451 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3452 GST_TIME_ARGS (stream->pending_seek->ts));
3454 /* FIXME: this is not fully correct, the timestamp refers to the random
3455 * access sample refered to in the tfra entry, which may not necessarily
3456 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3457 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3462 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3463 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3464 GST_TIME_ARGS (gst_ts));
3466 /* subsequent fragments extend stream */
3468 stream->samples[stream->n_samples - 1].timestamp +
3469 stream->samples[stream->n_samples - 1].duration;
3471 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3472 * difference (1 sec.) between decode_ts and timestamp, prefer the
3474 if (has_tfdt && !qtdemux->upstream_format_is_time
3475 && ABSDIFF (decode_ts, timestamp) >
3476 MAX (stream->duration_last_moof / 2,
3477 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3478 GST_INFO_OBJECT (qtdemux,
3479 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3480 ") are significantly different (more than %" GST_TIME_FORMAT
3481 "), using decode_ts",
3482 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3483 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3484 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3485 MAX (stream->duration_last_moof / 2,
3486 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3487 timestamp = decode_ts;
3490 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3491 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3492 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3496 initial_offset = *running_offset;
3498 sample = stream->samples + stream->n_samples;
3499 for (i = 0; i < samples_count; i++) {
3500 guint32 dur, size, sflags;
3503 /* first read sample data */
3504 if (flags & TR_SAMPLE_DURATION) {
3505 dur = QT_UINT32 (data + dur_offset);
3507 dur = d_sample_duration;
3509 if (flags & TR_SAMPLE_SIZE) {
3510 size = QT_UINT32 (data + size_offset);
3512 size = d_sample_size;
3514 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3516 sflags = first_flags;
3518 sflags = d_sample_flags;
3520 } else if (flags & TR_SAMPLE_FLAGS) {
3521 sflags = QT_UINT32 (data + flags_offset);
3523 sflags = d_sample_flags;
3526 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3527 /* Read offsets as signed numbers regardless of trun version as very
3528 * high offsets are unlikely and there are files out there that use
3529 * version=0 truns with negative offsets */
3530 ct = QT_UINT32 (data + ct_offset);
3532 /* FIXME: Set offset to 0 for "no decode samples". This needs
3533 * to be handled in a codec specific manner ideally. */
3534 if (ct == G_MININT32)
3541 /* fill the sample information */
3542 sample->offset = *running_offset;
3543 sample->pts_offset = ct;
3544 sample->size = size;
3545 sample->timestamp = timestamp;
3546 sample->duration = dur;
3547 /* sample-is-difference-sample */
3548 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3549 * now idea how it relates to bitfield other than massive LE/BE confusion */
3550 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3551 *running_offset += size;
3553 stream->duration_moof += dur;
3560 /* Shift PTS/DTS to allow for negative composition offsets while keeping
3561 * A/V sync in place. This is similar to the code handling ctts/cslg in the
3562 * non-fragmented case.
3565 stream->cslg_shift = -min_ct;
3567 stream->cslg_shift = 0;
3569 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
3570 stream->cslg_shift);
3572 /* Update total duration if needed */
3573 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3575 /* Pre-emptively figure out size of mdat based on trun information.
3576 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3577 * size, else we will still be able to use this when dealing with gap'ed
3579 qtdemux->mdatleft = *running_offset - initial_offset;
3580 qtdemux->mdatoffset = initial_offset;
3581 qtdemux->mdatsize = qtdemux->mdatleft;
3583 stream->n_samples += samples_count;
3584 stream->n_samples_moof += samples_count;
3586 if (stream->pending_seek != NULL)
3587 stream->pending_seek = NULL;
3593 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3598 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3604 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3605 "be larger than %uMB (broken file?)", stream->n_samples,
3606 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3611 /* find stream with @id */
3612 static inline QtDemuxStream *
3613 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3615 QtDemuxStream *stream;
3619 if (G_UNLIKELY (!id)) {
3620 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3624 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3625 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3626 if (stream->track_id == id)
3629 if (qtdemux->mss_mode) {
3630 /* mss should have only 1 stream anyway */
3631 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3638 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3639 guint32 * fragment_number)
3641 if (!gst_byte_reader_skip (mfhd, 4))
3643 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3648 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3654 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3655 QtDemuxStream ** stream, guint32 * default_sample_duration,
3656 guint32 * default_sample_size, guint32 * default_sample_flags,
3657 gint64 * base_offset)
3660 guint32 track_id = 0;
3662 if (!gst_byte_reader_skip (tfhd, 1) ||
3663 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3666 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3669 *stream = qtdemux_find_stream (qtdemux, track_id);
3670 if (G_UNLIKELY (!*stream))
3671 goto unknown_stream;
3673 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3674 *base_offset = qtdemux->moof_offset;
3676 if (flags & TF_BASE_DATA_OFFSET)
3677 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3680 /* obtain stream defaults */
3681 if (qtdemux_parse_trex (qtdemux, *stream,
3682 default_sample_duration, default_sample_size, default_sample_flags)) {
3684 /* Default sample description index is only valid if trex parsing succeeded */
3685 (*stream)->stsd_sample_description_id =
3686 (*stream)->def_sample_description_index - 1;
3689 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3690 guint32 sample_description_index;
3691 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3693 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3696 if (qtdemux->mss_mode) {
3697 /* mss has no stsd entry */
3698 (*stream)->stsd_sample_description_id = 0;
3701 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3702 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3705 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3706 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3709 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3710 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3717 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3722 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3728 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3729 guint64 * decode_time)
3731 guint32 version = 0;
3733 if (!gst_byte_reader_get_uint32_be (br, &version))
3738 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3741 guint32 dec_time = 0;
3742 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3744 *decode_time = dec_time;
3747 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3754 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3759 /* Returns a pointer to a GstStructure containing the properties of
3760 * the stream sample identified by @sample_index. The caller must unref
3761 * the returned object after use. Returns NULL if unsuccessful. */
3762 static GstStructure *
3763 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3764 QtDemuxStream * stream, guint sample_index)
3766 QtDemuxCencSampleSetInfo *info = NULL;
3768 g_return_val_if_fail (stream != NULL, NULL);
3769 g_return_val_if_fail (stream->protected, NULL);
3770 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3772 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3774 /* Currently, cenc properties for groups of samples are not supported, so
3775 * simply return a copy of the default sample properties */
3776 return gst_structure_copy (info->default_properties);
3779 /* Parses the sizes of sample auxiliary information contained within a stream,
3780 * as given in a saiz box. Returns array of sample_count guint8 size values,
3781 * or NULL on failure */
3783 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3784 GstByteReader * br, guint32 * sample_count)
3788 guint8 default_info_size;
3790 g_return_val_if_fail (qtdemux != NULL, NULL);
3791 g_return_val_if_fail (stream != NULL, NULL);
3792 g_return_val_if_fail (br != NULL, NULL);
3793 g_return_val_if_fail (sample_count != NULL, NULL);
3795 if (!gst_byte_reader_get_uint32_be (br, &flags))
3799 /* aux_info_type and aux_info_type_parameter are ignored */
3800 if (!gst_byte_reader_skip (br, 8))
3804 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3806 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3808 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3810 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3813 if (default_info_size == 0) {
3814 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3818 info_sizes = g_new (guint8, *sample_count);
3819 memset (info_sizes, default_info_size, *sample_count);
3825 /* Parses the offset of sample auxiliary information contained within a stream,
3826 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3828 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3829 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3834 guint32 aux_info_type = 0;
3835 guint32 aux_info_type_parameter = 0;
3836 guint32 entry_count;
3839 const guint8 *aux_info_type_data = NULL;
3841 g_return_val_if_fail (qtdemux != NULL, FALSE);
3842 g_return_val_if_fail (stream != NULL, FALSE);
3843 g_return_val_if_fail (br != NULL, FALSE);
3844 g_return_val_if_fail (offset != NULL, FALSE);
3846 if (!gst_byte_reader_get_uint8 (br, &version))
3849 if (!gst_byte_reader_get_uint24_be (br, &flags))
3854 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3856 aux_info_type = QT_FOURCC (aux_info_type_data);
3858 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3860 } else if (stream->protected) {
3861 aux_info_type = stream->protection_scheme_type;
3863 aux_info_type = CUR_STREAM (stream)->fourcc;
3867 *info_type = aux_info_type;
3868 if (info_type_parameter)
3869 *info_type_parameter = aux_info_type_parameter;
3871 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3872 "aux_info_type_parameter: %#06x",
3873 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3875 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3878 if (entry_count != 1) {
3879 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3884 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3886 *offset = (guint64) off_32;
3888 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3893 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3898 qtdemux_gst_structure_free (GstStructure * gststructure)
3901 gst_structure_free (gststructure);
3905 /* Parses auxiliary information relating to samples protected using
3906 * Common Encryption (cenc); the format of this information
3907 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3910 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3911 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3913 QtDemuxCencSampleSetInfo *ss_info = NULL;
3916 GPtrArray *old_crypto_info = NULL;
3917 guint old_entries = 0;
3919 g_return_val_if_fail (qtdemux != NULL, FALSE);
3920 g_return_val_if_fail (stream != NULL, FALSE);
3921 g_return_val_if_fail (br != NULL, FALSE);
3922 g_return_val_if_fail (stream->protected, FALSE);
3923 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3925 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3927 if (ss_info->crypto_info) {
3928 old_crypto_info = ss_info->crypto_info;
3929 /* Count number of non-null entries remaining at the tail end */
3930 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3931 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3937 ss_info->crypto_info =
3938 g_ptr_array_new_full (sample_count + old_entries,
3939 (GDestroyNotify) qtdemux_gst_structure_free);
3941 /* We preserve old entries because we parse the next moof in advance
3942 * of consuming all samples from the previous moof, and otherwise
3943 * we'd discard the corresponding crypto info for the samples
3944 * from the previous fragment. */
3946 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3948 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3949 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3951 g_ptr_array_index (old_crypto_info, i) = NULL;
3955 if (old_crypto_info) {
3956 /* Everything now belongs to the new array */
3957 g_ptr_array_free (old_crypto_info, TRUE);
3960 for (i = 0; i < sample_count; ++i) {
3961 GstStructure *properties;
3962 guint16 n_subsamples = 0;
3966 gboolean could_read_iv;
3968 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3969 if (properties == NULL) {
3970 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3973 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3974 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3975 gst_structure_free (properties);
3979 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3980 if (could_read_iv) {
3981 buf = gst_buffer_new_wrapped (data, iv_size);
3982 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3983 gst_buffer_unref (buf);
3984 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3985 const GValue *constant_iv_size_value =
3986 gst_structure_get_value (properties, "constant_iv_size");
3987 const GValue *constant_iv_value =
3988 gst_structure_get_value (properties, "iv");
3989 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3990 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3991 gst_structure_free (properties);
3994 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3995 gst_structure_remove_field (properties, "constant_iv_size");
3996 } else if (stream->protection_scheme_type == FOURCC_cenc) {
3997 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3998 gst_structure_free (properties);
4001 size = info_sizes[i];
4002 if (size > iv_size) {
4003 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
4004 || !(n_subsamples > 0)) {
4005 gst_structure_free (properties);
4006 GST_ERROR_OBJECT (qtdemux,
4007 "failed to get subsample count for sample %u", i);
4010 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
4011 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
4012 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
4014 gst_structure_free (properties);
4017 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
4019 gst_structure_free (properties);
4022 gst_structure_set (properties,
4023 "subsample_count", G_TYPE_UINT, n_subsamples,
4024 "subsamples", GST_TYPE_BUFFER, buf, NULL);
4025 gst_buffer_unref (buf);
4027 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
4029 g_ptr_array_add (ss_info->crypto_info, properties);
4034 /* Converts a UUID in raw byte form to a string representation, as defined in
4035 * RFC 4122. The caller takes ownership of the returned string and is
4036 * responsible for freeing it after use. */
4038 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
4040 const guint8 *uuid = (const guint8 *) uuid_bytes;
4042 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
4043 "%02x%02x-%02x%02x%02x%02x%02x%02x",
4044 uuid[0], uuid[1], uuid[2], uuid[3],
4045 uuid[4], uuid[5], uuid[6], uuid[7],
4046 uuid[8], uuid[9], uuid[10], uuid[11],
4047 uuid[12], uuid[13], uuid[14], uuid[15]);
4050 /* Parses a Protection System Specific Header box (pssh), as defined in the
4051 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
4052 * information needed by a specific content protection system in order to
4053 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
4056 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4058 gchar *sysid_string;
4059 guint32 pssh_size = QT_UINT32 (node->data);
4060 GstBuffer *pssh = NULL;
4061 GstEvent *event = NULL;
4062 guint32 parent_box_type;
4065 if (G_UNLIKELY (pssh_size < 32U)) {
4066 GST_ERROR_OBJECT (qtdemux, "invalid box size");
4071 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4073 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4075 pssh = gst_buffer_new_memdup (node->data, pssh_size);
4076 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4077 gst_buffer_get_size (pssh));
4079 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4081 /* Push an event containing the pssh box onto the queues of all streams. */
4082 event = gst_event_new_protection (sysid_string, pssh,
4083 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4084 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4085 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4086 GST_TRACE_OBJECT (qtdemux,
4087 "adding protection event for stream %s and system %s",
4088 stream->stream_id, sysid_string);
4089 g_queue_push_tail (&stream->protection_scheme_event_queue,
4090 gst_event_ref (event));
4092 g_free (sysid_string);
4093 gst_event_unref (event);
4094 gst_buffer_unref (pssh);
4099 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4100 guint64 moof_offset, QtDemuxStream * stream)
4102 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4104 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4105 GNode *saiz_node, *saio_node, *pssh_node;
4106 GstByteReader saiz_data, saio_data;
4107 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4108 gint64 base_offset, running_offset;
4110 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4112 /* NOTE @stream ignored */
4114 moof_node = g_node_new ((guint8 *) buffer);
4115 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4116 qtdemux_node_dump (qtdemux, moof_node);
4118 /* Get fragment number from mfhd and check it's valid */
4120 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4121 if (mfhd_node == NULL)
4123 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4125 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4127 /* unknown base_offset to start with */
4128 base_offset = running_offset = -1;
4129 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4131 guint64 decode_time = 0;
4133 /* Fragment Header node */
4135 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4139 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4140 &ds_size, &ds_flags, &base_offset))
4143 /* The following code assumes at most a single set of sample auxiliary
4144 * data in the fragment (consisting of a saiz box and a corresponding saio
4145 * box); in theory, however, there could be multiple sets of sample
4146 * auxiliary data in a fragment. */
4148 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4151 guint32 info_type = 0;
4153 guint32 info_type_parameter = 0;
4155 g_free (qtdemux->cenc_aux_info_sizes);
4157 qtdemux->cenc_aux_info_sizes =
4158 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4159 &qtdemux->cenc_aux_sample_count);
4160 if (qtdemux->cenc_aux_info_sizes == NULL) {
4161 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4165 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4168 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4169 g_free (qtdemux->cenc_aux_info_sizes);
4170 qtdemux->cenc_aux_info_sizes = NULL;
4174 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4175 &info_type, &info_type_parameter, &offset))) {
4176 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4177 g_free (qtdemux->cenc_aux_info_sizes);
4178 qtdemux->cenc_aux_info_sizes = NULL;
4181 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4182 offset += (guint64) (base_offset - qtdemux->moof_offset);
4183 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4184 && info_type_parameter == 0U) {
4186 if (offset > length) {
4187 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4188 qtdemux->cenc_aux_info_offset = offset;
4190 gst_byte_reader_init (&br, buffer + offset, length - offset);
4191 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4192 qtdemux->cenc_aux_info_sizes,
4193 qtdemux->cenc_aux_sample_count)) {
4194 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4195 g_free (qtdemux->cenc_aux_info_sizes);
4196 qtdemux->cenc_aux_info_sizes = NULL;
4204 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4207 /* We'll use decode_time to interpolate timestamps
4208 * in case the input timestamps are missing */
4209 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4211 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4212 " (%" GST_TIME_FORMAT ")", decode_time,
4213 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4214 decode_time) : GST_CLOCK_TIME_NONE));
4216 /* Discard the fragment buffer timestamp info to avoid using it.
4217 * Rely on tfdt instead as it is more accurate than the timestamp
4218 * that is fetched from a manifest/playlist and is usually
4220 qtdemux->fragment_start = -1;
4223 if (G_UNLIKELY (!stream)) {
4224 /* we lost track of offset, we'll need to regain it,
4225 * but can delay complaining until later or avoid doing so altogether */
4229 if (G_UNLIKELY (base_offset < -1))
4232 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4234 if (!qtdemux->pullbased) {
4235 /* Sample tables can grow enough to be problematic if the system memory
4236 * is very low (e.g. embedded devices) and the videos very long
4237 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4238 * Fortunately, we can easily discard them for each new fragment when
4239 * we know qtdemux will not receive seeks outside of the current fragment.
4240 * adaptivedemux honors this assumption.
4241 * This optimization is also useful for applications that use qtdemux as
4242 * a push-based simple demuxer, like Media Source Extensions. */
4243 gst_qtdemux_stream_flush_samples_data (stream);
4246 /* initialise moof sample data */
4247 stream->n_samples_moof = 0;
4248 stream->duration_last_moof = stream->duration_moof;
4249 stream->duration_moof = 0;
4251 /* Track Run node */
4253 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4256 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4257 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4258 &running_offset, decode_time, (tfdt_node != NULL));
4259 /* iterate all siblings */
4260 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4262 /* don't use tfdt for subsequent trun as it only refers to the first */
4266 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4268 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4269 guint32 box_length = QT_UINT32 (uuid_buffer);
4271 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4274 /* if no new base_offset provided for next traf,
4275 * base is end of current traf */
4276 base_offset = running_offset;
4277 running_offset = -1;
4279 if (stream->n_samples_moof && stream->duration_moof)
4280 stream->new_caps = TRUE;
4283 /* iterate all siblings */
4284 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4287 /* parse any protection system info */
4288 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4290 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4291 qtdemux_parse_pssh (qtdemux, pssh_node);
4292 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4295 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4296 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4298 /* Unless the user has explicitly requested another seek, perform an
4299 * internal seek to the time specified in the tfdt.
4301 * This way if the user opens a file where the first tfdt is 1 hour
4302 * into the presentation, they will not have to wait 1 hour for run
4303 * time to catch up and actual playback to start. */
4306 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4307 "performing an internal seek to %" GST_TIME_FORMAT,
4308 GST_TIME_ARGS (min_dts));
4310 qtdemux->segment.start = min_dts;
4311 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4313 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4314 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4315 stream->time_position = min_dts;
4318 /* Before this code was run a segment was already sent when the moov was
4319 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4320 * be emitted after a moov, and we can emit a second segment anyway for
4321 * special cases like this. */
4322 qtdemux->need_segment = TRUE;
4325 qtdemux->first_moof_already_parsed = TRUE;
4327 g_node_destroy (moof_node);
4332 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4337 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4342 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4347 g_node_destroy (moof_node);
4348 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4349 (_("This file is corrupt and cannot be played.")), (NULL));
4355 /* might be used if some day we actually use mfra & co
4356 * for random access to fragments,
4357 * but that will require quite some modifications and much less relying
4358 * on a sample array */
4362 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4364 QtDemuxStream *stream;
4365 guint32 ver_flags, track_id, len, num_entries, i;
4366 guint value_size, traf_size, trun_size, sample_size;
4367 guint64 time = 0, moof_offset = 0;
4369 GstBuffer *buf = NULL;
4374 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4376 if (!gst_byte_reader_skip (&tfra, 8))
4379 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4382 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4383 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4384 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4387 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4389 stream = qtdemux_find_stream (qtdemux, track_id);
4391 goto unknown_trackid;
4393 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4394 sample_size = (len & 3) + 1;
4395 trun_size = ((len & 12) >> 2) + 1;
4396 traf_size = ((len & 48) >> 4) + 1;
4398 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4399 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4401 if (num_entries == 0)
4404 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4405 value_size + value_size + traf_size + trun_size + sample_size))
4408 g_free (stream->ra_entries);
4409 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4410 stream->n_ra_entries = num_entries;
4412 for (i = 0; i < num_entries; i++) {
4413 qt_atom_parser_get_offset (&tfra, value_size, &time);
4414 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4415 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4416 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4417 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4419 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4421 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4422 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4424 stream->ra_entries[i].ts = time;
4425 stream->ra_entries[i].moof_offset = moof_offset;
4427 /* don't want to go through the entire file and read all moofs at startup */
4429 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4430 if (ret != GST_FLOW_OK)
4432 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4433 moof_offset, stream);
4434 gst_buffer_unref (buf);
4438 check_update_duration (qtdemux, time);
4445 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4450 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4455 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4461 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4463 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4464 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4465 GstBuffer *mfro = NULL, *mfra = NULL;
4467 gboolean ret = FALSE;
4468 GNode *mfra_node, *tfra_node;
4469 guint64 mfra_offset = 0;
4470 guint32 fourcc, mfra_size;
4473 /* query upstream size in bytes */
4474 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4475 goto size_query_failed;
4477 /* mfro box should be at the very end of the file */
4478 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4479 if (flow != GST_FLOW_OK)
4482 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4484 fourcc = QT_FOURCC (mfro_map.data + 4);
4485 if (fourcc != FOURCC_mfro)
4488 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4489 if (mfro_map.size < 16)
4490 goto invalid_mfro_size;
4492 mfra_size = QT_UINT32 (mfro_map.data + 12);
4493 if (mfra_size >= len)
4494 goto invalid_mfra_size;
4496 mfra_offset = len - mfra_size;
4498 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4499 mfra_offset, mfra_size);
4501 /* now get and parse mfra box */
4502 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4503 if (flow != GST_FLOW_OK)
4506 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4508 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4509 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4511 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4514 qtdemux_parse_tfra (qtdemux, tfra_node);
4515 /* iterate all siblings */
4516 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4518 g_node_destroy (mfra_node);
4520 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4526 if (mfro_map.memory != NULL)
4527 gst_buffer_unmap (mfro, &mfro_map);
4528 gst_buffer_unref (mfro);
4531 if (mfra_map.memory != NULL)
4532 gst_buffer_unmap (mfra, &mfra_map);
4533 gst_buffer_unref (mfra);
4540 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4545 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4550 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4555 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4561 add_offset (guint64 offset, guint64 advance)
4563 /* Avoid 64-bit overflow by clamping */
4564 if (offset > G_MAXUINT64 - advance)
4566 return offset + advance;
4569 static GstFlowReturn
4570 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4574 GstBuffer *buf = NULL;
4575 GstFlowReturn ret = GST_FLOW_OK;
4576 guint64 cur_offset = qtdemux->offset;
4579 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4580 if (G_UNLIKELY (ret != GST_FLOW_OK))
4582 gst_buffer_map (buf, &map, GST_MAP_READ);
4583 if (G_LIKELY (map.size >= 8))
4584 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4585 gst_buffer_unmap (buf, &map);
4586 gst_buffer_unref (buf);
4588 /* maybe we already got most we needed, so only consider this eof */
4589 if (G_UNLIKELY (length == 0)) {
4590 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4591 (_("Invalid atom size.")),
4592 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4593 GST_FOURCC_ARGS (fourcc)));
4600 /* record for later parsing when needed */
4601 if (!qtdemux->moof_offset) {
4602 qtdemux->moof_offset = qtdemux->offset;
4604 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4607 qtdemux->offset += length; /* skip moof and keep going */
4609 if (qtdemux->got_moov) {
4610 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4622 GST_LOG_OBJECT (qtdemux,
4623 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4624 GST_FOURCC_ARGS (fourcc), cur_offset);
4625 qtdemux->offset = add_offset (qtdemux->offset, length);
4630 GstBuffer *moov = NULL;
4632 if (qtdemux->got_moov) {
4633 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4634 qtdemux->offset = add_offset (qtdemux->offset, length);
4638 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4639 if (ret != GST_FLOW_OK)
4641 gst_buffer_map (moov, &map, GST_MAP_READ);
4643 if (length != map.size) {
4644 /* Some files have a 'moov' atom at the end of the file which contains
4645 * a terminal 'free' atom where the body of the atom is missing.
4646 * Check for, and permit, this special case.
4648 if (map.size >= 8) {
4649 guint8 *final_data = map.data + (map.size - 8);
4650 guint32 final_length = QT_UINT32 (final_data);
4651 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4653 if (final_fourcc == FOURCC_free
4654 && map.size + final_length - 8 == length) {
4655 /* Ok, we've found that special case. Allocate a new buffer with
4656 * that free atom actually present. */
4657 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4658 gst_buffer_fill (newmoov, 0, map.data, map.size);
4659 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4660 gst_buffer_unmap (moov, &map);
4661 gst_buffer_unref (moov);
4663 gst_buffer_map (moov, &map, GST_MAP_READ);
4668 if (length != map.size) {
4669 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4670 (_("This file is incomplete and cannot be played.")),
4671 ("We got less than expected (received %" G_GSIZE_FORMAT
4672 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4673 (guint) length, cur_offset));
4674 gst_buffer_unmap (moov, &map);
4675 gst_buffer_unref (moov);
4676 ret = GST_FLOW_ERROR;
4679 qtdemux->offset += length;
4681 qtdemux_parse_moov (qtdemux, map.data, length);
4682 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4684 qtdemux_parse_tree (qtdemux);
4685 if (qtdemux->moov_node_compressed) {
4686 g_node_destroy (qtdemux->moov_node_compressed);
4687 g_free (qtdemux->moov_node->data);
4689 qtdemux->moov_node_compressed = NULL;
4690 g_node_destroy (qtdemux->moov_node);
4691 qtdemux->moov_node = NULL;
4692 gst_buffer_unmap (moov, &map);
4693 gst_buffer_unref (moov);
4694 qtdemux->got_moov = TRUE;
4700 GstBuffer *ftyp = NULL;
4702 /* extract major brand; might come in handy for ISO vs QT issues */
4703 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4704 if (ret != GST_FLOW_OK)
4706 qtdemux->offset += length;
4707 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4708 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4709 gst_buffer_unmap (ftyp, &map);
4710 gst_buffer_unref (ftyp);
4715 GstBuffer *styp = NULL;
4717 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &styp);
4718 if (ret != GST_FLOW_OK)
4720 qtdemux->offset += length;
4721 gst_buffer_map (styp, &map, GST_MAP_READ);
4722 qtdemux_parse_styp (qtdemux, map.data, map.size);
4723 gst_buffer_unmap (styp, &map);
4724 gst_buffer_unref (styp);
4729 GstBuffer *uuid = NULL;
4731 /* uuid are extension atoms */
4732 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4733 if (ret != GST_FLOW_OK)
4735 qtdemux->offset += length;
4736 gst_buffer_map (uuid, &map, GST_MAP_READ);
4737 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4738 gst_buffer_unmap (uuid, &map);
4739 gst_buffer_unref (uuid);
4744 GstBuffer *sidx = NULL;
4745 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4746 if (ret != GST_FLOW_OK)
4748 qtdemux->offset += length;
4749 gst_buffer_map (sidx, &map, GST_MAP_READ);
4750 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4751 gst_buffer_unmap (sidx, &map);
4752 gst_buffer_unref (sidx);
4757 GstBuffer *meta = NULL;
4758 GNode *node, *child;
4759 GstByteReader child_data;
4760 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &meta);
4761 if (ret != GST_FLOW_OK)
4763 qtdemux->offset += length;
4764 gst_buffer_map (meta, &map, GST_MAP_READ);
4766 node = g_node_new (map.data);
4768 qtdemux_parse_node (qtdemux, node, map.data, map.size);
4770 /* Parse ONVIF Export File Format CorrectStartTime box if available */
4772 qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb,
4774 qtdemux_parse_cstb (qtdemux, &child_data);
4777 g_node_destroy (node);
4779 gst_buffer_unmap (meta, &map);
4780 gst_buffer_unref (meta);
4785 GstBuffer *unknown = NULL;
4787 GST_LOG_OBJECT (qtdemux,
4788 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4789 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4791 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4792 if (ret != GST_FLOW_OK)
4794 gst_buffer_map (unknown, &map, GST_MAP_READ);
4795 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4796 gst_buffer_unmap (unknown, &map);
4797 gst_buffer_unref (unknown);
4798 qtdemux->offset += length;
4804 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4805 /* digested all data, show what we have */
4806 qtdemux_prepare_streams (qtdemux);
4807 QTDEMUX_EXPOSE_LOCK (qtdemux);
4808 ret = qtdemux_expose_streams (qtdemux);
4809 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4811 qtdemux->state = QTDEMUX_STATE_MOVIE;
4812 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4819 /* Seeks to the previous keyframe of the indexed stream and
4820 * aligns other streams with respect to the keyframe timestamp
4821 * of indexed stream. Only called in case of Reverse Playback
4823 static GstFlowReturn
4824 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4826 guint32 seg_idx = 0, k_index = 0;
4827 guint32 ref_seg_idx, ref_k_index;
4828 GstClockTime k_pos = 0, last_stop = 0;
4829 QtDemuxSegment *seg = NULL;
4830 QtDemuxStream *ref_str = NULL;
4831 guint64 seg_media_start_mov; /* segment media start time in mov format */
4835 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4836 * and finally align all the other streams on that timestamp with their
4837 * respective keyframes */
4838 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4839 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4841 /* No candidate yet, take the first stream */
4847 /* So that stream has a segment, we prefer video streams */
4848 if (str->subtype == FOURCC_vide) {
4854 if (G_UNLIKELY (!ref_str)) {
4855 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4859 if (G_UNLIKELY (!ref_str->from_sample)) {
4860 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4864 /* So that stream has been playing from from_sample to to_sample. We will
4865 * get the timestamp of the previous sample and search for a keyframe before
4866 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4867 if (ref_str->subtype == FOURCC_vide) {
4868 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4869 ref_str->from_sample - 1, FALSE);
4871 if (ref_str->from_sample >= 10)
4872 k_index = ref_str->from_sample - 10;
4878 ref_str->samples[k_index].timestamp +
4879 ref_str->samples[k_index].pts_offset;
4881 /* get current segment for that stream */
4882 seg = &ref_str->segments[ref_str->segment_index];
4883 /* Use segment start in original timescale for comparisons */
4884 seg_media_start_mov = seg->trak_media_start;
4886 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4887 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4888 k_index, target_ts, seg_media_start_mov,
4889 GST_TIME_ARGS (seg->media_start));
4891 /* Crawl back through segments to find the one containing this I frame */
4892 while (target_ts < seg_media_start_mov) {
4893 GST_DEBUG_OBJECT (qtdemux,
4894 "keyframe position (sample %u) is out of segment %u " " target %"
4895 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4896 ref_str->segment_index, target_ts, seg_media_start_mov);
4898 if (G_UNLIKELY (!ref_str->segment_index)) {
4899 /* Reached first segment, let's consider it's EOS */
4902 ref_str->segment_index--;
4903 seg = &ref_str->segments[ref_str->segment_index];
4904 /* Use segment start in original timescale for comparisons */
4905 seg_media_start_mov = seg->trak_media_start;
4907 /* Calculate time position of the keyframe and where we should stop */
4909 QTSTREAMTIME_TO_GSTTIME (ref_str,
4910 target_ts - seg->trak_media_start) + seg->time;
4912 QTSTREAMTIME_TO_GSTTIME (ref_str,
4913 ref_str->samples[ref_str->from_sample].timestamp -
4914 seg->trak_media_start) + seg->time;
4916 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4917 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4918 k_index, GST_TIME_ARGS (k_pos));
4920 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4921 qtdemux->segment.position = last_stop;
4922 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4923 GST_TIME_ARGS (last_stop));
4925 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4926 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4930 ref_seg_idx = ref_str->segment_index;
4931 ref_k_index = k_index;
4933 /* Align them all on this */
4934 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4936 GstClockTime seg_time = 0;
4937 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4939 /* aligning reference stream again might lead to backing up to yet another
4940 * keyframe (due to timestamp rounding issues),
4941 * potentially putting more load on downstream; so let's try to avoid */
4942 if (str == ref_str) {
4943 seg_idx = ref_seg_idx;
4944 seg = &str->segments[seg_idx];
4945 k_index = ref_k_index;
4946 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4947 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4949 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4950 GST_DEBUG_OBJECT (qtdemux,
4951 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4952 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4954 /* get segment and time in the segment */
4955 seg = &str->segments[seg_idx];
4956 seg_time = k_pos - seg->time;
4958 /* get the media time in the segment.
4959 * No adjustment for empty "filler" segments */
4960 if (seg->media_start != GST_CLOCK_TIME_NONE)
4961 seg_time += seg->media_start;
4963 /* get the index of the sample with media time */
4964 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4965 GST_DEBUG_OBJECT (qtdemux,
4966 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4967 GST_TIME_ARGS (seg_time), index);
4969 /* find previous keyframe */
4970 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4973 /* Remember until where we want to go */
4974 str->to_sample = str->from_sample - 1;
4975 /* Define our time position */
4977 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4978 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4979 if (seg->media_start != GST_CLOCK_TIME_NONE)
4980 str->time_position -= seg->media_start;
4982 /* Now seek back in time */
4983 gst_qtdemux_move_stream (qtdemux, str, k_index);
4984 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4985 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4986 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4992 return GST_FLOW_EOS;
4996 * Gets the current qt segment start, stop and position for the
4997 * given time offset. This is used in update_segment()
5000 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
5001 QtDemuxStream * stream, GstClockTime offset,
5002 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
5004 GstClockTime seg_time;
5005 GstClockTime start, stop, time;
5006 QtDemuxSegment *segment;
5008 segment = &stream->segments[stream->segment_index];
5010 /* get time in this segment */
5011 seg_time = (offset - segment->time) * segment->rate;
5013 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
5014 GST_TIME_ARGS (seg_time));
5016 if (G_UNLIKELY (seg_time > segment->duration)) {
5017 GST_LOG_OBJECT (stream->pad,
5018 "seg_time > segment->duration %" GST_TIME_FORMAT,
5019 GST_TIME_ARGS (segment->duration));
5020 seg_time = segment->duration;
5023 /* qtdemux->segment.stop is in outside-time-realm, whereas
5024 * segment->media_stop is in track-time-realm.
5026 * In order to compare the two, we need to bring segment.stop
5027 * into the track-time-realm
5029 * FIXME - does this comment still hold? Don't see any conversion here */
5031 stop = qtdemux->segment.stop;
5032 if (stop == GST_CLOCK_TIME_NONE)
5033 stop = qtdemux->segment.duration;
5034 if (stop == GST_CLOCK_TIME_NONE)
5035 stop = segment->media_stop;
5038 MIN (segment->media_stop, stop - segment->time + segment->media_start);
5040 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5041 start = segment->time + seg_time;
5043 stop = start - seg_time + segment->duration;
5044 } else if (qtdemux->segment.rate >= 0) {
5045 start = MIN (segment->media_start + seg_time, stop);
5048 if (segment->media_start >= qtdemux->segment.start) {
5049 time = segment->time;
5051 time = segment->time + (qtdemux->segment.start - segment->media_start);
5054 start = MAX (segment->media_start, qtdemux->segment.start);
5055 stop = MIN (segment->media_start + seg_time, stop);
5064 * Updates the qt segment used for the stream and pushes a new segment event
5065 * downstream on this stream's pad.
5068 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5069 gint seg_idx, GstClockTime offset, GstClockTime * _start,
5070 GstClockTime * _stop)
5072 QtDemuxSegment *segment;
5073 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
5077 /* update the current segment */
5078 stream->segment_index = seg_idx;
5080 /* get the segment */
5081 segment = &stream->segments[seg_idx];
5083 if (G_UNLIKELY (offset < segment->time)) {
5084 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
5085 GST_TIME_ARGS (segment->time));
5089 /* segment lies beyond total indicated duration */
5090 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5091 segment->time > qtdemux->segment.duration)) {
5092 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5093 " < segment->time %" GST_TIME_FORMAT,
5094 GST_TIME_ARGS (qtdemux->segment.duration),
5095 GST_TIME_ARGS (segment->time));
5099 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5100 &start, &stop, &time);
5102 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5103 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5104 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5106 /* combine global rate with that of the segment */
5107 rate = segment->rate * qtdemux->segment.rate;
5109 /* Copy flags from main segment */
5110 stream->segment.flags = qtdemux->segment.flags;
5112 /* update the segment values used for clipping */
5113 stream->segment.offset = qtdemux->segment.offset;
5114 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5115 stream->segment.applied_rate = qtdemux->segment.applied_rate;
5116 stream->segment.rate = rate;
5117 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5118 stream->cslg_shift);
5120 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5121 stream->cslg_shift);
5123 stream->segment.stop = stop;
5124 stream->segment.time = time;
5125 stream->segment.position = stream->segment.start;
5127 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5130 /* now prepare and send the segment */
5132 event = gst_event_new_segment (&stream->segment);
5133 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5134 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5136 gst_pad_push_event (stream->pad, event);
5137 /* assume we can send more data now */
5138 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5139 /* clear to send tags on this pad now */
5140 gst_qtdemux_push_tags (qtdemux, stream);
5151 /* activate the given segment number @seg_idx of @stream at time @offset.
5152 * @offset is an absolute global position over all the segments.
5154 * This will push out a NEWSEGMENT event with the right values and
5155 * position the stream index to the first decodable sample before
5159 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5160 guint32 seg_idx, GstClockTime offset)
5162 QtDemuxSegment *segment;
5163 guint32 index, kf_index;
5164 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5166 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5167 seg_idx, GST_TIME_ARGS (offset));
5169 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5173 segment = &stream->segments[stream->segment_index];
5175 /* in the fragmented case, we pick a fragment that starts before our
5176 * desired position and rely on downstream to wait for a keyframe
5177 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5178 * tfra entries tells us which trun/sample the key unit is in, but we don't
5179 * make use of this additional information at the moment) */
5180 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5181 stream->to_sample = G_MAXUINT32;
5184 /* well, it will be taken care of below */
5185 qtdemux->fragmented_seek_pending = FALSE;
5186 /* FIXME ideally the do_fragmented_seek can be done right here,
5187 * rather than at loop level
5188 * (which might even allow handling edit lists in a fragmented file) */
5191 /* We don't need to look for a sample in push-based */
5192 if (!qtdemux->pullbased)
5195 /* and move to the keyframe before the indicated media time of the
5197 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5198 if (qtdemux->segment.rate >= 0) {
5199 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5200 stream->to_sample = G_MAXUINT32;
5201 GST_DEBUG_OBJECT (stream->pad,
5202 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5203 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5204 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5206 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5207 stream->to_sample = index;
5208 GST_DEBUG_OBJECT (stream->pad,
5209 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5210 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5211 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5214 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5215 "this is an empty segment");
5219 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5220 * encountered an error and printed a message so we return appropriately */
5224 /* we're at the right spot */
5225 if (index == stream->sample_index) {
5226 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5230 /* find keyframe of the target index */
5231 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5233 /* go back two frames to provide lead-in for non-raw audio decoders */
5234 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5235 guint32 lead_in = 2;
5236 guint32 old_index = kf_index;
5237 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5239 if (gst_structure_has_name (s, "audio/mpeg")) {
5241 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5242 && mpegversion == 1) {
5243 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5248 kf_index = MAX (kf_index, lead_in) - lead_in;
5249 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5250 GST_DEBUG_OBJECT (stream->pad,
5251 "Moving backwards %u frames to ensure sufficient sound lead-in",
5252 old_index - kf_index);
5254 kf_index = old_index;
5258 /* if we move forwards, we don't have to go back to the previous
5259 * keyframe since we already sent that. We can also just jump to
5260 * the keyframe right before the target index if there is one. */
5261 if (index > stream->sample_index) {
5262 /* moving forwards check if we move past a keyframe */
5263 if (kf_index > stream->sample_index) {
5264 GST_DEBUG_OBJECT (stream->pad,
5265 "moving forwards to keyframe at %u "
5266 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5268 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5269 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5270 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5272 GST_DEBUG_OBJECT (stream->pad,
5273 "moving forwards, keyframe at %u "
5274 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5276 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5277 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5280 GST_DEBUG_OBJECT (stream->pad,
5281 "moving backwards to %sframe at %u "
5282 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5283 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5284 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5285 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5286 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5292 /* prepare to get the current sample of @stream, getting essential values.
5294 * This function will also prepare and send the segment when needed.
5296 * Return FALSE if the stream is EOS.
5301 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5302 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5303 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5304 gboolean * keyframe)
5306 QtDemuxSample *sample;
5307 GstClockTime time_position;
5310 g_return_val_if_fail (stream != NULL, FALSE);
5312 time_position = stream->time_position;
5313 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5316 seg_idx = stream->segment_index;
5317 if (G_UNLIKELY (seg_idx == -1)) {
5318 /* find segment corresponding to time_position if we are looking
5320 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5323 /* different segment, activate it, sample_index will be set. */
5324 if (G_UNLIKELY (stream->segment_index != seg_idx))
5325 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5327 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5328 segments[stream->segment_index]))) {
5329 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5331 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5332 " prepare empty sample");
5335 *pts = *dts = time_position;
5336 *duration = seg->duration - (time_position - seg->time);
5343 if (stream->sample_index == -1)
5344 stream->sample_index = 0;
5346 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5347 stream->sample_index, stream->n_samples);
5349 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5350 if (!qtdemux->fragmented)
5353 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5357 GST_OBJECT_LOCK (qtdemux);
5358 flow = qtdemux_add_fragmented_samples (qtdemux);
5359 GST_OBJECT_UNLOCK (qtdemux);
5361 if (flow != GST_FLOW_OK)
5364 while (stream->sample_index >= stream->n_samples);
5367 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5368 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5369 stream->sample_index);
5373 /* now get the info for the sample we're at */
5374 sample = &stream->samples[stream->sample_index];
5376 *dts = QTSAMPLE_DTS (stream, sample);
5377 *pts = QTSAMPLE_PTS (stream, sample);
5378 *offset = sample->offset;
5379 *size = sample->size;
5380 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5381 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5388 stream->time_position = GST_CLOCK_TIME_NONE;
5393 /* move to the next sample in @stream.
5395 * Moves to the next segment when needed.
5398 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5400 QtDemuxSample *sample;
5401 QtDemuxSegment *segment;
5403 /* get current segment */
5404 segment = &stream->segments[stream->segment_index];
5406 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5407 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5411 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5412 /* Mark the stream as EOS */
5413 GST_DEBUG_OBJECT (qtdemux,
5414 "reached max allowed sample %u, mark EOS", stream->to_sample);
5415 stream->time_position = GST_CLOCK_TIME_NONE;
5419 /* move to next sample */
5420 stream->sample_index++;
5421 stream->offset_in_sample = 0;
5423 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5426 /* reached the last sample, we need the next segment */
5427 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5430 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5431 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5432 stream->sample_index);
5436 /* get next sample */
5437 sample = &stream->samples[stream->sample_index];
5439 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5440 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5441 GST_TIME_ARGS (segment->media_stop));
5443 /* see if we are past the segment */
5444 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5447 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5448 /* inside the segment, update time_position, looks very familiar to
5449 * GStreamer segments, doesn't it? */
5450 stream->time_position =
5451 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5453 /* not yet in segment, time does not yet increment. This means
5454 * that we are still prerolling keyframes to the decoder so it can
5455 * decode the first sample of the segment. */
5456 stream->time_position = segment->time;
5460 /* move to the next segment */
5463 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5465 if (stream->segment_index == stream->n_segments - 1) {
5466 /* are we at the end of the last segment, we're EOS */
5467 stream->time_position = GST_CLOCK_TIME_NONE;
5469 /* else we're only at the end of the current segment */
5470 stream->time_position = segment->stop_time;
5472 /* make sure we select a new segment */
5474 /* accumulate previous segments */
5475 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5476 stream->accumulated_base +=
5477 (stream->segment.stop -
5478 stream->segment.start) / ABS (stream->segment.rate);
5480 stream->segment_index = -1;
5485 gst_qtdemux_sync_streams (GstQTDemux * demux)
5489 if (QTDEMUX_N_STREAMS (demux) <= 1)
5492 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5493 QtDemuxStream *stream;
5494 GstClockTime end_time;
5496 stream = QTDEMUX_NTH_STREAM (demux, i);
5501 /* TODO advance time on subtitle streams here, if any some day */
5503 /* some clips/trailers may have unbalanced streams at the end,
5504 * so send EOS on shorter stream to prevent stalling others */
5506 /* do not mess with EOS if SEGMENT seeking */
5507 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5510 if (demux->pullbased) {
5511 /* loop mode is sample time based */
5512 if (!STREAM_IS_EOS (stream))
5515 /* push mode is byte position based */
5516 if (stream->n_samples &&
5517 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5521 if (stream->sent_eos)
5524 /* only act if some gap */
5525 end_time = stream->segments[stream->n_segments - 1].stop_time;
5526 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5527 ", stream end: %" GST_TIME_FORMAT,
5528 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5529 if (GST_CLOCK_TIME_IS_VALID (end_time)
5530 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5533 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5534 GST_PAD_NAME (stream->pad));
5535 stream->sent_eos = TRUE;
5536 event = gst_event_new_eos ();
5537 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5538 gst_event_set_seqnum (event, demux->segment_seqnum);
5539 gst_pad_push_event (stream->pad, event);
5544 /* EOS and NOT_LINKED need to be combined. This means that we return:
5546 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5547 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5549 static GstFlowReturn
5550 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5553 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5556 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5559 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5561 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5565 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5566 * completely clipped
5568 * Should be used only with raw buffers */
5570 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5573 guint64 start, stop, cstart, cstop, diff;
5574 GstClockTime pts, duration;
5576 gint num_rate, denom_rate;
5581 osize = size = gst_buffer_get_size (buf);
5584 /* depending on the type, setup the clip parameters */
5585 if (stream->subtype == FOURCC_soun) {
5586 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5587 num_rate = GST_SECOND;
5588 denom_rate = (gint) CUR_STREAM (stream)->rate;
5590 } else if (stream->subtype == FOURCC_vide) {
5592 num_rate = CUR_STREAM (stream)->fps_n;
5593 denom_rate = CUR_STREAM (stream)->fps_d;
5598 if (frame_size <= 0)
5599 goto bad_frame_size;
5601 /* we can only clip if we have a valid pts */
5602 pts = GST_BUFFER_PTS (buf);
5603 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5606 duration = GST_BUFFER_DURATION (buf);
5608 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5610 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5614 stop = start + duration;
5616 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5617 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5620 /* see if some clipping happened */
5621 diff = cstart - start;
5627 /* bring clipped time to samples and to bytes */
5628 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5631 GST_DEBUG_OBJECT (qtdemux,
5632 "clipping start to %" GST_TIME_FORMAT " %"
5633 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5639 diff = stop - cstop;
5644 /* bring clipped time to samples and then to bytes */
5645 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5647 GST_DEBUG_OBJECT (qtdemux,
5648 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5649 " bytes", GST_TIME_ARGS (cstop), diff);
5654 if (offset != 0 || size != osize)
5655 gst_buffer_resize (buf, offset, size);
5657 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5658 GST_BUFFER_PTS (buf) = pts;
5659 GST_BUFFER_DURATION (buf) = duration;
5663 /* dropped buffer */
5666 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5671 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5676 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5681 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5682 gst_buffer_unref (buf);
5688 gst_qtdemux_align_buffer (GstQTDemux * demux,
5689 GstBuffer * buffer, gsize alignment)
5693 gst_buffer_map (buffer, &map, GST_MAP_READ);
5695 if (map.size < sizeof (guintptr)) {
5696 gst_buffer_unmap (buffer, &map);
5700 if (((guintptr) map.data) & (alignment - 1)) {
5701 GstBuffer *new_buffer;
5702 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5704 new_buffer = gst_buffer_new_allocate (NULL,
5705 gst_buffer_get_size (buffer), ¶ms);
5707 /* Copy data "by hand", so ensure alignment is kept: */
5708 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5710 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5711 GST_DEBUG_OBJECT (demux,
5712 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5715 gst_buffer_unmap (buffer, &map);
5716 gst_buffer_unref (buffer);
5721 gst_buffer_unmap (buffer, &map);
5726 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5732 /* We are converting from pairs to triplets */
5733 *res = ccpair_size / 2 * 3;
5734 storage = g_malloc (*res);
5735 for (i = 0; i * 2 < ccpair_size; i += 1) {
5736 /* FIXME: Use line offset 0 as we simply can't know here */
5738 storage[i * 3] = 0x80 | 0x00;
5740 storage[i * 3] = 0x00 | 0x00;
5741 storage[i * 3 + 1] = ccpair[i * 2];
5742 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5749 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5753 guint32 atom_length, fourcc;
5754 QtDemuxStreamStsdEntry *stsd_entry;
5756 GST_MEMDUMP ("caption atom", data, size);
5758 /* There might be multiple atoms */
5763 atom_length = QT_UINT32 (data);
5764 fourcc = QT_FOURCC (data + 4);
5765 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5768 GST_DEBUG_OBJECT (stream->pad, "here");
5770 /* Check if we have something compatible */
5771 stsd_entry = CUR_STREAM (stream);
5772 switch (stsd_entry->fourcc) {
5774 guint8 *cdat = NULL, *cdt2 = NULL;
5775 gsize cdat_size = 0, cdt2_size = 0;
5776 /* Should be cdat or cdt2 */
5777 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5778 GST_WARNING_OBJECT (stream->pad,
5779 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5780 GST_FOURCC_ARGS (fourcc));
5784 /* Convert to S334-1 Annex A byte triplet */
5785 if (fourcc == FOURCC_cdat)
5786 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5788 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5789 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5792 /* Check for another atom ? */
5793 if (size > atom_length + 8) {
5794 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5795 if (size >= atom_length + new_atom_length) {
5796 fourcc = QT_FOURCC (data + atom_length + 4);
5797 if (fourcc == FOURCC_cdat) {
5800 convert_to_s334_1a (data + atom_length + 8,
5801 new_atom_length - 8, 1, &cdat_size);
5803 GST_WARNING_OBJECT (stream->pad,
5804 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5808 convert_to_s334_1a (data + atom_length + 8,
5809 new_atom_length - 8, 2, &cdt2_size);
5811 GST_WARNING_OBJECT (stream->pad,
5812 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5817 *cclen = cdat_size + cdt2_size;
5818 res = g_malloc (*cclen);
5820 memcpy (res, cdat, cdat_size);
5822 memcpy (res + cdat_size, cdt2, cdt2_size);
5828 if (fourcc != FOURCC_ccdp) {
5829 GST_WARNING_OBJECT (stream->pad,
5830 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5831 GST_FOURCC_ARGS (fourcc));
5834 *cclen = atom_length - 8;
5835 res = g_memdup2 (data + 8, *cclen);
5838 /* Keep this here in case other closed caption formats are added */
5839 g_assert_not_reached ();
5843 GST_MEMDUMP ("Output", res, *cclen);
5848 GST_WARNING ("[cdat] atom is too small or invalid");
5852 /* Handle Closed Caption sample buffers.
5853 * The input buffer metadata must be writable,
5854 * but time/duration etc not yet set and need not be preserved */
5856 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5859 GstBuffer *outbuf = NULL;
5864 gst_buffer_map (buf, &map, GST_MAP_READ);
5866 /* empty buffer is sent to terminate previous subtitle */
5867 if (map.size <= 2) {
5868 gst_buffer_unmap (buf, &map);
5869 gst_buffer_unref (buf);
5873 /* For closed caption, we need to extract the information from the
5874 * [cdat],[cdt2] or [ccdp] atom */
5875 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5876 gst_buffer_unmap (buf, &map);
5878 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5879 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5881 /* Conversion failed or there's nothing */
5883 gst_buffer_unref (buf);
5888 /* DVD subpicture specific sample handling.
5889 * the input buffer metadata must be writable,
5890 * but time/duration etc not yet set and need not be preserved */
5892 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5895 /* send a one time dvd clut event */
5896 if (stream->pending_event && stream->pad)
5897 gst_pad_push_event (stream->pad, stream->pending_event);
5898 stream->pending_event = NULL;
5900 /* empty buffer is sent to terminate previous subtitle */
5901 if (gst_buffer_get_size (buf) <= 2) {
5902 gst_buffer_unref (buf);
5906 /* That's all the processing needed for subpictures */
5910 /* Timed text formats
5911 * the input buffer metadata must be writable,
5912 * but time/duration etc not yet set and need not be preserved */
5914 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5917 GstBuffer *outbuf = NULL;
5922 /* not many cases for now */
5923 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5924 stream->subtype != FOURCC_sbtl)) {
5928 gst_buffer_map (buf, &map, GST_MAP_READ);
5930 /* empty buffer is sent to terminate previous subtitle */
5931 if (map.size <= 2) {
5932 gst_buffer_unmap (buf, &map);
5933 gst_buffer_unref (buf);
5937 nsize = GST_READ_UINT16_BE (map.data);
5938 nsize = MIN (nsize, map.size - 2);
5940 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5943 /* takes care of UTF-8 validation or UTF-16 recognition,
5944 * no other encoding expected */
5945 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5946 gst_buffer_unmap (buf, &map);
5949 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5950 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5952 /* this should not really happen unless the subtitle is corrupted */
5954 gst_buffer_unref (buf);
5956 /* FIXME ? convert optional subsequent style info to markup */
5961 /* WebVTT sample handling according to 14496-30 */
5963 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5966 GstBuffer *outbuf = NULL;
5969 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5970 g_assert_not_reached (); /* The buffer must be mappable */
5973 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5974 GstEvent *gap = NULL;
5975 /* Push a gap event */
5976 stream->segment.position = GST_BUFFER_PTS (buf);
5978 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5979 gst_pad_push_event (stream->pad, gap);
5981 if (GST_BUFFER_DURATION_IS_VALID (buf))
5982 stream->segment.position += GST_BUFFER_DURATION (buf);
5985 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5986 GST_BUFFER_DURATION (buf), map.data, map.size);
5987 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5990 gst_buffer_unmap (buf, &map);
5991 gst_buffer_unref (buf);
5996 static GstFlowReturn
5997 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6000 GstFlowReturn ret = GST_FLOW_OK;
6001 GstClockTime pts, duration;
6003 if (stream->need_clip)
6004 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
6006 if (G_UNLIKELY (buf == NULL))
6009 if (G_UNLIKELY (stream->discont)) {
6010 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6011 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
6012 stream->discont = FALSE;
6014 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6017 GST_LOG_OBJECT (qtdemux,
6018 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
6019 ", duration %" GST_TIME_FORMAT " on pad %s",
6020 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
6021 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
6022 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
6024 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
6025 GstStructure *crypto_info;
6026 QtDemuxAavdEncryptionInfo *info =
6027 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
6029 crypto_info = gst_structure_copy (info->default_properties);
6030 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6031 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
6034 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
6035 || stream->protection_scheme_type == FOURCC_cbcs)) {
6036 GstStructure *crypto_info;
6037 QtDemuxCencSampleSetInfo *info =
6038 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6042 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
6043 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
6044 GST_PTR_FORMAT, event);
6045 gst_pad_push_event (stream->pad, event);
6048 if (info->crypto_info == NULL) {
6049 if (stream->protection_scheme_type == FOURCC_cbcs) {
6050 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
6051 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
6052 GST_ERROR_OBJECT (qtdemux,
6053 "failed to attach cbcs metadata to buffer");
6054 qtdemux_gst_structure_free (crypto_info);
6056 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
6059 GST_DEBUG_OBJECT (qtdemux,
6060 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
6063 /* The end of the crypto_info array matches our n_samples position,
6064 * so count backward from there */
6065 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
6066 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
6067 /* steal structure from array */
6068 crypto_info = g_ptr_array_index (info->crypto_info, index);
6069 g_ptr_array_index (info->crypto_info, index) = NULL;
6070 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
6071 info->crypto_info->len);
6072 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6073 GST_ERROR_OBJECT (qtdemux,
6074 "failed to attach cenc metadata to buffer");
6076 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
6077 index, stream->sample_index);
6082 if (stream->alignment > 1)
6083 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6085 pts = GST_BUFFER_PTS (buf);
6086 duration = GST_BUFFER_DURATION (buf);
6088 ret = gst_pad_push (stream->pad, buf);
6090 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6091 /* mark position in stream, we'll need this to know when to send GAP event */
6092 stream->segment.position = pts + duration;
6100 static GstFlowReturn
6101 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6104 GstFlowReturn ret = GST_FLOW_OK;
6106 if (stream->subtype == FOURCC_clcp
6107 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6109 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6110 guint n_triplets, i;
6111 guint field1_off = 0, field2_off = 0;
6113 /* We have to split CEA608 buffers so that each outgoing buffer contains
6114 * one byte pair per field according to the framerate of the video track.
6116 * If there is only a single byte pair per field we don't have to do
6120 gst_buffer_map (buf, &map, GST_MAP_READ);
6122 n_triplets = map.size / 3;
6123 for (i = 0; i < n_triplets; i++) {
6124 if (map.data[3 * i] & 0x80)
6130 g_assert (n_field1 || n_field2);
6132 /* If there's more than 1 frame we have to split, otherwise we can just
6134 if (n_field1 > 1 || n_field2 > 1) {
6136 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6137 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6139 for (i = 0; i < n_output_buffers; i++) {
6141 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6145 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6146 outptr = outmap.data;
6149 gboolean found = FALSE;
6151 while (map.data + field1_off < map.data + map.size) {
6152 if (map.data[field1_off] & 0x80) {
6153 memcpy (outptr, &map.data[field1_off], 3);
6162 const guint8 empty[] = { 0x80, 0x80, 0x80 };
6164 memcpy (outptr, empty, 3);
6171 gboolean found = FALSE;
6173 while (map.data + field2_off < map.data + map.size) {
6174 if ((map.data[field2_off] & 0x80) == 0) {
6175 memcpy (outptr, &map.data[field2_off], 3);
6184 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6186 memcpy (outptr, empty, 3);
6192 gst_buffer_unmap (outbuf, &outmap);
6194 GST_BUFFER_PTS (outbuf) =
6195 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6196 GST_SECOND * CUR_STREAM (stream)->fps_d,
6197 CUR_STREAM (stream)->fps_n);
6198 GST_BUFFER_DURATION (outbuf) =
6199 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6200 CUR_STREAM (stream)->fps_n);
6201 GST_BUFFER_OFFSET (outbuf) = -1;
6202 GST_BUFFER_OFFSET_END (outbuf) = -1;
6204 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6206 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6209 gst_buffer_unmap (buf, &map);
6210 gst_buffer_unref (buf);
6212 gst_buffer_unmap (buf, &map);
6213 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6216 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6222 /* Sets a buffer's attributes properly and pushes it downstream.
6223 * Also checks for additional actions and custom processing that may
6224 * need to be done first.
6226 static GstFlowReturn
6227 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6228 QtDemuxStream * stream, GstBuffer * buf,
6229 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6230 gboolean keyframe, GstClockTime position, guint64 byte_position)
6232 GstFlowReturn ret = GST_FLOW_OK;
6234 /* offset the timestamps according to the edit list */
6236 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6240 gst_buffer_map (buf, &map, GST_MAP_READ);
6241 url = g_strndup ((gchar *) map.data, map.size);
6242 gst_buffer_unmap (buf, &map);
6243 if (url != NULL && strlen (url) != 0) {
6244 /* we have RTSP redirect now */
6245 g_free (qtdemux->redirect_location);
6246 qtdemux->redirect_location = g_strdup (url);
6247 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6248 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6249 gst_structure_new ("redirect",
6250 "new-location", G_TYPE_STRING, url, NULL)));
6252 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6258 /* position reporting */
6259 if (qtdemux->segment.rate >= 0) {
6260 qtdemux->segment.position = position;
6261 gst_qtdemux_sync_streams (qtdemux);
6264 if (G_UNLIKELY (!stream->pad)) {
6265 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6266 gst_buffer_unref (buf);
6270 /* send out pending buffers */
6271 while (stream->buffers) {
6272 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6274 if (G_UNLIKELY (stream->discont)) {
6275 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6276 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6277 stream->discont = FALSE;
6279 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6282 if (stream->alignment > 1)
6283 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6284 gst_pad_push (stream->pad, buffer);
6286 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6289 /* we're going to modify the metadata */
6290 buf = gst_buffer_make_writable (buf);
6292 if (qtdemux->start_utc_time != GST_CLOCK_TIME_NONE) {
6293 static GstStaticCaps unix_caps = GST_STATIC_CAPS ("timestamp/x-unix");
6294 GstCaps *caps = gst_static_caps_get (&unix_caps);
6295 gst_buffer_add_reference_timestamp_meta (buf, caps,
6296 pts + qtdemux->start_utc_time - stream->cslg_shift,
6297 GST_CLOCK_TIME_NONE);
6298 gst_caps_unref (caps);
6301 GST_BUFFER_DTS (buf) = dts;
6302 GST_BUFFER_PTS (buf) = pts;
6303 GST_BUFFER_DURATION (buf) = duration;
6304 GST_BUFFER_OFFSET (buf) = -1;
6305 GST_BUFFER_OFFSET_END (buf) = -1;
6307 if (G_UNLIKELY (stream->process_func))
6308 buf = stream->process_func (qtdemux, stream, buf);
6315 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6316 stream->on_keyframe = FALSE;
6318 stream->on_keyframe = TRUE;
6321 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6322 gst_buffer_append_memory (buf,
6323 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6325 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6326 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6329 if (G_UNLIKELY (qtdemux->element_index)) {
6330 GstClockTime stream_time;
6333 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6335 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6336 GST_LOG_OBJECT (qtdemux,
6337 "adding association %" GST_TIME_FORMAT "-> %"
6338 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6339 gst_index_add_association (qtdemux->element_index,
6341 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6342 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6343 GST_FORMAT_BYTES, byte_position, NULL);
6348 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6354 static const QtDemuxRandomAccessEntry *
6355 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6356 GstClockTime pos, gboolean after)
6358 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6359 guint n_entries = stream->n_ra_entries;
6362 /* we assume the table is sorted */
6363 for (i = 0; i < n_entries; ++i) {
6364 if (entries[i].ts > pos)
6368 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6369 * probably okay to assume that the index lists the very first fragment */
6376 return &entries[i - 1];
6380 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6382 const QtDemuxRandomAccessEntry *best_entry = NULL;
6385 GST_OBJECT_LOCK (qtdemux);
6387 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6389 /* first see if we can determine where to go to using mfra,
6390 * before we start clearing things */
6391 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6392 const QtDemuxRandomAccessEntry *entry;
6393 QtDemuxStream *stream;
6394 gboolean is_audio_or_video;
6396 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6398 if (stream->ra_entries == NULL)
6401 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6402 is_audio_or_video = TRUE;
6404 is_audio_or_video = FALSE;
6407 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6408 stream->time_position, !is_audio_or_video);
6410 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6411 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6413 stream->pending_seek = entry;
6415 /* decide position to jump to just based on audio/video tracks, not subs */
6416 if (!is_audio_or_video)
6419 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6423 /* no luck, will handle seek otherwise */
6424 if (best_entry == NULL) {
6425 GST_OBJECT_UNLOCK (qtdemux);
6429 /* ok, now we can prepare for processing as of located moof */
6430 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6431 QtDemuxStream *stream;
6433 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6435 g_free (stream->samples);
6436 stream->samples = NULL;
6437 stream->n_samples = 0;
6438 stream->stbl_index = -1; /* no samples have yet been parsed */
6439 stream->sample_index = -1;
6441 if (stream->protection_scheme_info) {
6442 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6443 if (stream->protection_scheme_type == FOURCC_cenc
6444 || stream->protection_scheme_type == FOURCC_cbcs) {
6445 QtDemuxCencSampleSetInfo *info =
6446 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6447 if (info->crypto_info) {
6448 g_ptr_array_free (info->crypto_info, TRUE);
6449 info->crypto_info = NULL;
6455 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6456 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6457 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6458 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6460 qtdemux->moof_offset = best_entry->moof_offset;
6462 qtdemux_add_fragmented_samples (qtdemux);
6464 GST_OBJECT_UNLOCK (qtdemux);
6468 static GstFlowReturn
6469 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6471 GstFlowReturn ret = GST_FLOW_OK;
6472 GstBuffer *buf = NULL;
6473 QtDemuxStream *stream, *target_stream = NULL;
6474 GstClockTime min_time;
6476 GstClockTime dts = GST_CLOCK_TIME_NONE;
6477 GstClockTime pts = GST_CLOCK_TIME_NONE;
6478 GstClockTime duration = 0;
6479 gboolean keyframe = FALSE;
6480 guint sample_size = 0;
6481 guint num_samples = 1;
6486 if (qtdemux->fragmented_seek_pending) {
6487 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6488 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6489 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6490 qtdemux->fragmented_seek_pending = FALSE;
6492 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6496 /* Figure out the next stream sample to output, min_time is expressed in
6497 * global time and runs over the edit list segments. */
6498 min_time = G_MAXUINT64;
6499 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6500 GstClockTime position;
6502 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6503 position = stream->time_position;
6505 if (!GST_CLOCK_TIME_IS_VALID (position))
6508 if (stream->segment_index != -1) {
6509 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6510 position += segment->media_start;
6513 /* position of -1 is EOS */
6514 if (position < min_time) {
6515 min_time = position;
6516 target_stream = stream;
6520 if (G_UNLIKELY (target_stream == NULL)) {
6521 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6525 /* check for segment end */
6526 if (G_UNLIKELY (qtdemux->segment.stop != -1
6527 && qtdemux->segment.rate >= 0
6528 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6529 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6530 target_stream->time_position = GST_CLOCK_TIME_NONE;
6534 /* fetch info for the current sample of this stream */
6535 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, target_stream,
6536 &empty, &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6539 /* Send catche-up GAP event for each other stream if required.
6540 * This logic will be applied only for positive rate */
6541 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux) &&
6542 qtdemux->segment.rate >= 0; i++) {
6543 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6545 if (stream == target_stream ||
6546 !GST_CLOCK_TIME_IS_VALID (stream->segment.stop) ||
6547 !GST_CLOCK_TIME_IS_VALID (stream->segment.position))
6551 GstClockTime gap_threshold;
6552 /* kind of running time with offset segment.base and segment.start */
6553 GstClockTime pseudo_target_time = target_stream->segment.base;
6554 GstClockTime pseudo_cur_time = stream->segment.base;
6556 /* make sure positive offset, segment.position can be smallr than
6557 * segment.start for some reasons */
6558 if (target_stream->segment.position >= target_stream->segment.start) {
6559 pseudo_target_time +=
6560 (target_stream->segment.position - target_stream->segment.start);
6563 if (stream->segment.position >= stream->segment.start)
6564 pseudo_cur_time += (stream->segment.position - stream->segment.start);
6566 /* Only send gap events on non-subtitle streams if lagging way behind. */
6567 if (stream->subtype == FOURCC_subp
6568 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6569 stream->subtype == FOURCC_wvtt)
6570 gap_threshold = 1 * GST_SECOND;
6572 gap_threshold = 3 * GST_SECOND;
6574 /* send gap events until the stream catches up */
6575 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6576 while (GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6577 pseudo_cur_time < (G_MAXUINT64 - gap_threshold) &&
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, 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,