2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
12 * Copyright (C) <2016> British Broadcasting Corporation
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with this library; if not, write to the
26 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
31 * SECTION:element-qtdemux
34 * Demuxes a .mov file into raw or compressed audio and/or video streams.
36 * This element supports both push and pull-based scheduling, depending on the
37 * capabilities of the upstream elements.
39 * ## Example launch line
41 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
42 * ]| Play (parse and decode) a .mov file and try to output it to
43 * an automatically detected soundcard and videosink. If the MOV file contains
44 * compressed audio or video data, this will only work if you have the
45 * right decoder elements/plugins installed.
53 #include <glib/gi18n-lib.h>
55 #include <glib/gprintf.h>
56 #include <gst/base/base.h>
57 #include <gst/tag/tag.h>
58 #include <gst/audio/audio.h>
59 #include <gst/riff/riff.h>
60 #include <gst/pbutils/pbutils.h>
62 #include "gstisomp4elements.h"
63 #include "qtatomparser.h"
64 #include "qtdemux_types.h"
65 #include "qtdemux_dump.h"
67 #include "descriptors.h"
68 #include "qtdemux_lang.h"
70 #include "qtpalette.h"
71 #include "qtdemux_tags.h"
72 #include "qtdemux_tree.h"
73 #include "qtdemux-webvtt.h"
79 #include <gst/math-compat.h>
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
97 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
99 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
101 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
103 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
104 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
105 #define QTDEMUX_NTH_STREAM(demux,idx) \
106 QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
107 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
108 QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
110 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
112 GST_DEBUG_CATEGORY (qtdemux_debug);
113 #define GST_CAT_DEFAULT qtdemux_debug
115 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
116 typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
118 /* Macros for converting to/from timescale */
119 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
120 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
122 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
123 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
125 /* timestamp is the DTS */
126 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
127 /* timestamp + offset + cslg_shift is the outgoing PTS */
128 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
129 /* timestamp + offset is the PTS used for internal seek calculations */
130 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
131 /* timestamp + duration - dts is the duration */
132 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
134 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
136 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
137 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
138 GST_TRACE("Locking from thread %p", g_thread_self()); \
139 g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
140 GST_TRACE("Locked from thread %p", g_thread_self()); \
143 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
144 GST_TRACE("Unlocking from thread %p", g_thread_self()); \
145 g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
149 * Quicktime has tracks and segments. A track is a continuous piece of
150 * multimedia content. The track is not always played from start to finish but
151 * instead, pieces of the track are 'cut out' and played in sequence. This is
152 * what the segments do.
154 * Inside the track we have keyframes (K) and delta frames. The track has its
155 * own timing, which starts from 0 and extends to end. The position in the track
156 * is called the media_time.
158 * The segments now describe the pieces that should be played from this track
159 * and are basically tuples of media_time/duration/rate entries. We can have
160 * multiple segments and they are all played after one another. An example:
162 * segment 1: media_time: 1 second, duration: 1 second, rate 1
163 * segment 2: media_time: 3 second, duration: 2 second, rate 2
165 * To correctly play back this track, one must play: 1 second of media starting
166 * from media_time 1 followed by 2 seconds of media starting from media_time 3
169 * Each of the segments will be played at a specific time, the first segment at
170 * time 0, the second one after the duration of the first one, etc.. Note that
171 * the time in resulting playback is not identical to the media_time of the
174 * Visually, assuming the track has 4 second of media_time:
177 * .-----------------------------------------------------------.
178 * track: | K.....K.........K........K.......K.......K...........K... |
179 * '-----------------------------------------------------------'
181 * .------------^ ^ .----------^ ^
182 * / .-------------' / .------------------'
184 * .--------------. .--------------.
185 * | segment 1 | | segment 2 |
186 * '--------------' '--------------'
188 * The challenge here is to cut out the right pieces of the track for each of
189 * the playback segments. This fortunately can easily be done with the SEGMENT
190 * events of GStreamer.
192 * For playback of segment 1, we need to provide the decoder with the keyframe
193 * (a), in the above figure, but we must instruct it only to output the decoded
194 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
195 * position set to the time of the segment: 0.
197 * We then proceed to push data from keyframe (a) to frame (b). The decoder
198 * decodes but clips all before media_time 1.
200 * After finishing a segment, we push out a new SEGMENT event with the clipping
201 * boundaries of the new data.
203 * This is a good usecase for the GStreamer accumulated SEGMENT events.
206 struct _QtDemuxSegment
208 /* global time and duration, all gst time */
210 GstClockTime stop_time;
211 GstClockTime duration;
212 /* media time of trak, all gst time */
213 GstClockTime media_start;
214 GstClockTime media_stop;
216 /* Media start time in trak timescale units */
217 guint32 trak_media_start;
220 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
222 /* Used with fragmented MP4 files (mfra atom) */
223 struct _QtDemuxRandomAccessEntry
230 /* Contains properties and cryptographic info for a set of samples from a
231 * track protected using Common Encryption (cenc) */
232 struct _QtDemuxCencSampleSetInfo
234 GstStructure *default_properties;
236 /* @crypto_info holds one GstStructure per sample */
237 GPtrArray *crypto_info;
240 struct _QtDemuxAavdEncryptionInfo
242 GstStructure *default_properties;
246 qt_demux_state_string (enum QtDemuxState state)
249 case QTDEMUX_STATE_INITIAL:
251 case QTDEMUX_STATE_HEADER:
253 case QTDEMUX_STATE_MOVIE:
255 case QTDEMUX_STATE_BUFFER_MDAT:
256 return "<BUFFER_MDAT>";
262 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
264 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
266 static GstStaticPadTemplate gst_qtdemux_sink_template =
267 GST_STATIC_PAD_TEMPLATE ("sink",
270 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
274 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
275 GST_STATIC_PAD_TEMPLATE ("video_%u",
278 GST_STATIC_CAPS_ANY);
280 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
281 GST_STATIC_PAD_TEMPLATE ("audio_%u",
284 GST_STATIC_CAPS_ANY);
286 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
287 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
290 GST_STATIC_CAPS_ANY);
292 static GstStaticPadTemplate gst_qtdemux_metasrc_template =
293 GST_STATIC_PAD_TEMPLATE ("meta_%u",
296 GST_STATIC_CAPS_ANY);
298 #define gst_qtdemux_parent_class parent_class
299 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
300 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
301 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
303 static void gst_qtdemux_dispose (GObject * object);
304 static void gst_qtdemux_finalize (GObject * object);
307 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
308 GstClockTime media_time);
310 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
311 QtDemuxStream * str, gint64 media_offset);
314 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
315 static GstIndex *gst_qtdemux_get_index (GstElement * element);
317 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
318 GstStateChange transition);
319 static void gst_qtdemux_set_context (GstElement * element,
320 GstContext * context);
321 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
322 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
323 GstObject * parent, GstPadMode mode, gboolean active);
325 static void gst_qtdemux_loop (GstPad * pad);
326 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
328 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
330 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
332 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
333 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
334 QtDemuxStream * stream);
335 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
336 QtDemuxStream * stream);
337 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
340 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
342 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
343 const guint8 * buffer, guint length);
344 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
345 const guint8 * buffer, guint length);
346 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
348 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
349 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
351 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
352 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
353 const guint8 * stsd_entry_data, gchar ** codec_name);
354 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
355 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
356 const guint8 * data, int len, gchar ** codec_name);
357 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
358 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
359 gchar ** codec_name);
360 static GstCaps *qtdemux_meta_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
361 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
362 gchar ** codec_name);
363 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
364 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
365 const guint8 * stsd_entry_data, gchar ** codec_name);
367 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
368 QtDemuxStream * stream, guint32 n);
369 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
370 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
371 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
372 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
373 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
374 static void qtdemux_do_allocation (QtDemuxStream * stream,
375 GstQTDemux * qtdemux);
376 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
377 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
378 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
379 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
380 GstClockTime * _start, GstClockTime * _stop);
381 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
382 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
384 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
385 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
387 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
389 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
390 QtDemuxStream * stream, guint sample_index);
391 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
393 static void qtdemux_gst_structure_free (GstStructure * gststructure);
394 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
397 gst_qtdemux_class_init (GstQTDemuxClass * klass)
399 GObjectClass *gobject_class;
400 GstElementClass *gstelement_class;
402 gobject_class = (GObjectClass *) klass;
403 gstelement_class = (GstElementClass *) klass;
405 parent_class = g_type_class_peek_parent (klass);
407 gobject_class->dispose = gst_qtdemux_dispose;
408 gobject_class->finalize = gst_qtdemux_finalize;
410 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
412 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
413 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
415 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
417 gst_tag_register_musicbrainz_tags ();
419 gst_element_class_add_static_pad_template (gstelement_class,
420 &gst_qtdemux_sink_template);
421 gst_element_class_add_static_pad_template (gstelement_class,
422 &gst_qtdemux_videosrc_template);
423 gst_element_class_add_static_pad_template (gstelement_class,
424 &gst_qtdemux_audiosrc_template);
425 gst_element_class_add_static_pad_template (gstelement_class,
426 &gst_qtdemux_subsrc_template);
427 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
429 "Demultiplex a QuickTime file into audio and video streams",
430 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
432 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
437 gst_qtdemux_init (GstQTDemux * qtdemux)
440 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
441 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
442 gst_pad_set_activatemode_function (qtdemux->sinkpad,
443 qtdemux_sink_activate_mode);
444 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
445 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
446 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
447 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
449 qtdemux->adapter = gst_adapter_new ();
450 g_queue_init (&qtdemux->protection_event_queue);
451 qtdemux->flowcombiner = gst_flow_combiner_new ();
452 g_mutex_init (&qtdemux->expose_lock);
454 qtdemux->active_streams = g_ptr_array_new_with_free_func
455 ((GDestroyNotify) gst_qtdemux_stream_unref);
456 qtdemux->old_streams = g_ptr_array_new_with_free_func
457 ((GDestroyNotify) gst_qtdemux_stream_unref);
459 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
461 gst_qtdemux_reset (qtdemux, TRUE);
465 gst_qtdemux_finalize (GObject * object)
467 GstQTDemux *qtdemux = GST_QTDEMUX (object);
469 g_free (qtdemux->redirect_location);
471 G_OBJECT_CLASS (parent_class)->finalize (object);
475 gst_qtdemux_dispose (GObject * object)
477 GstQTDemux *qtdemux = GST_QTDEMUX (object);
479 if (qtdemux->adapter) {
480 g_object_unref (G_OBJECT (qtdemux->adapter));
481 qtdemux->adapter = NULL;
483 gst_tag_list_unref (qtdemux->tag_list);
484 gst_flow_combiner_free (qtdemux->flowcombiner);
485 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
487 g_queue_clear (&qtdemux->protection_event_queue);
489 g_free (qtdemux->cenc_aux_info_sizes);
490 qtdemux->cenc_aux_info_sizes = NULL;
491 g_mutex_clear (&qtdemux->expose_lock);
493 g_ptr_array_free (qtdemux->active_streams, TRUE);
494 g_ptr_array_free (qtdemux->old_streams, TRUE);
496 G_OBJECT_CLASS (parent_class)->dispose (object);
500 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
502 if (qtdemux->redirect_location) {
503 GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
504 (_("This file contains no playable streams.")),
505 ("no known streams found, a redirect message has been posted"),
506 ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
508 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
509 (_("This file contains no playable streams.")),
510 ("no known streams found"));
515 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
517 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
518 mem, size, 0, size, mem, free_func);
522 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
529 if (G_UNLIKELY (size == 0)) {
531 GstBuffer *tmp = NULL;
533 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
534 if (ret != GST_FLOW_OK)
537 gst_buffer_map (tmp, &map, GST_MAP_READ);
538 size = QT_UINT32 (map.data);
539 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
541 gst_buffer_unmap (tmp, &map);
542 gst_buffer_unref (tmp);
545 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
546 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
547 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
548 /* we're pulling header but already got most interesting bits,
549 * so never mind the rest (e.g. tags) (that much) */
550 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
554 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
555 (_("This file is invalid and cannot be played.")),
556 ("atom has bogus size %" G_GUINT64_FORMAT, size));
557 return GST_FLOW_ERROR;
561 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
563 if (G_UNLIKELY (flow != GST_FLOW_OK))
566 bsize = gst_buffer_get_size (*buf);
567 /* Catch short reads - we don't want any partial atoms */
568 if (G_UNLIKELY (bsize < size)) {
569 GST_WARNING_OBJECT (qtdemux,
570 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
571 gst_buffer_unref (*buf);
581 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
582 GstFormat src_format, gint64 src_value, GstFormat dest_format,
586 QtDemuxStream *stream = gst_pad_get_element_private (pad);
589 if (stream->subtype != FOURCC_vide) {
594 switch (src_format) {
595 case GST_FORMAT_TIME:
596 switch (dest_format) {
597 case GST_FORMAT_BYTES:{
598 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
604 *dest_value = stream->samples[index].offset;
606 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
607 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
608 GST_TIME_ARGS (src_value), *dest_value);
616 case GST_FORMAT_BYTES:
617 switch (dest_format) {
618 case GST_FORMAT_TIME:{
620 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
629 QTSTREAMTIME_TO_GSTTIME (stream,
630 stream->samples[index].timestamp);
631 GST_DEBUG_OBJECT (qtdemux,
632 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
633 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
652 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
654 gboolean res = FALSE;
656 *duration = GST_CLOCK_TIME_NONE;
658 if (qtdemux->duration != 0 &&
659 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
660 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
663 *duration = GST_CLOCK_TIME_NONE;
670 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
673 gboolean res = FALSE;
674 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
676 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
678 switch (GST_QUERY_TYPE (query)) {
679 case GST_QUERY_POSITION:{
682 gst_query_parse_position (query, &fmt, NULL);
683 if (fmt == GST_FORMAT_TIME
684 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
685 gst_query_set_position (query, GST_FORMAT_TIME,
686 qtdemux->segment.position);
691 case GST_QUERY_DURATION:{
694 gst_query_parse_duration (query, &fmt, NULL);
695 if (fmt == GST_FORMAT_TIME) {
696 /* First try to query upstream */
697 res = gst_pad_query_default (pad, parent, query);
699 GstClockTime duration;
700 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
701 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
708 case GST_QUERY_CONVERT:{
709 GstFormat src_fmt, dest_fmt;
710 gint64 src_value, dest_value = 0;
712 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
714 res = gst_qtdemux_src_convert (qtdemux, pad,
715 src_fmt, src_value, dest_fmt, &dest_value);
717 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
721 case GST_QUERY_FORMATS:
722 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
725 case GST_QUERY_SEEKING:{
729 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
731 if (fmt == GST_FORMAT_BYTES) {
732 /* We always refuse BYTES seeks from downstream */
736 /* try upstream first */
737 res = gst_pad_query_default (pad, parent, query);
740 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
741 if (fmt == GST_FORMAT_TIME) {
742 GstClockTime duration;
744 gst_qtdemux_get_duration (qtdemux, &duration);
746 if (!qtdemux->pullbased) {
749 /* we might be able with help from upstream */
751 q = gst_query_new_seeking (GST_FORMAT_BYTES);
752 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
753 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
754 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
758 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
764 case GST_QUERY_SEGMENT:
769 format = qtdemux->segment.format;
772 gst_segment_to_stream_time (&qtdemux->segment, format,
773 qtdemux->segment.start);
774 if ((stop = qtdemux->segment.stop) == -1)
775 stop = qtdemux->segment.duration;
777 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
779 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
784 res = gst_pad_query_default (pad, parent, query);
792 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
794 if (G_LIKELY (stream->pad)) {
795 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
796 GST_DEBUG_PAD_NAME (stream->pad));
798 if (!gst_tag_list_is_empty (stream->stream_tags)) {
799 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
800 stream->stream_tags);
801 gst_pad_push_event (stream->pad,
802 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
805 if (G_UNLIKELY (stream->send_global_tags)) {
806 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
808 gst_pad_push_event (stream->pad,
809 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
810 stream->send_global_tags = FALSE;
815 /* push event on all source pads; takes ownership of the event */
817 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
819 gboolean has_valid_stream = FALSE;
820 GstEventType etype = GST_EVENT_TYPE (event);
823 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
824 GST_EVENT_TYPE_NAME (event));
826 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
828 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
829 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
831 if ((pad = stream->pad)) {
832 has_valid_stream = TRUE;
834 if (etype == GST_EVENT_EOS) {
835 /* let's not send twice */
836 if (stream->sent_eos)
838 stream->sent_eos = TRUE;
841 gst_pad_push_event (pad, gst_event_ref (event));
845 gst_event_unref (event);
847 /* if it is EOS and there are no pads, post an error */
848 if (!has_valid_stream && etype == GST_EVENT_EOS) {
849 gst_qtdemux_post_no_playable_stream_error (qtdemux);
859 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
861 if ((gint64) s1->timestamp > *media_time)
863 if ((gint64) s1->timestamp == *media_time)
869 /* find the index of the sample that includes the data for @media_time using a
870 * binary search. Only to be called in optimized cases of linear search below.
872 * Returns the index of the sample with the corresponding *DTS*.
875 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
878 QtDemuxSample *result;
881 /* convert media_time to mov format */
883 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
885 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
886 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
887 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
889 if (G_LIKELY (result))
890 index = result - str->samples;
899 /* find the index of the sample that includes the data for @media_offset using a
902 * Returns the index of the sample.
905 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
906 QtDemuxStream * str, gint64 media_offset)
908 QtDemuxSample *result = str->samples;
911 if (result == NULL || str->n_samples == 0)
914 if (media_offset == result->offset)
918 while (index < str->n_samples - 1) {
919 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
922 if (media_offset < result->offset)
933 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
938 /* find the index of the sample that includes the data for @media_time using a
939 * linear search, and keeping in mind that not all samples may have been parsed
940 * yet. If possible, it will delegate to binary search.
942 * Returns the index of the sample.
945 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
946 GstClockTime media_time)
950 QtDemuxSample *sample;
952 /* convert media_time to mov format */
954 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
956 sample = str->samples;
957 if (mov_time == sample->timestamp + sample->pts_offset)
960 /* use faster search if requested time in already parsed range */
961 sample = str->samples + str->stbl_index;
962 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
963 index = gst_qtdemux_find_index (qtdemux, str, media_time);
964 sample = str->samples + index;
966 while (index < str->n_samples - 1) {
967 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
970 sample = str->samples + index + 1;
971 if (mov_time < sample->timestamp) {
972 sample = str->samples + index;
980 /* sample->timestamp is now <= media_time, need to find the corresponding
981 * PTS now by looking backwards */
982 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
984 sample = str->samples + index;
992 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
997 /* find the index of the keyframe needed to decode the sample at @index
998 * of stream @str, or of a subsequent keyframe (depending on @next)
1000 * Returns the index of the keyframe.
1003 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1004 guint32 index, gboolean next)
1006 guint32 new_index = index;
1008 if (index >= str->n_samples) {
1009 new_index = str->n_samples;
1013 /* all keyframes, return index */
1014 if (str->all_keyframe) {
1019 /* else search until we have a keyframe */
1020 while (new_index < str->n_samples) {
1021 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1024 if (str->samples[new_index].keyframe)
1036 if (new_index == str->n_samples) {
1037 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1042 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1043 "gave %u", next ? "after" : "before", index, new_index);
1050 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1055 /* find the segment for @time_position for @stream
1057 * Returns the index of the segment containing @time_position.
1058 * Returns the last segment and sets the @eos variable to TRUE
1059 * if the time is beyond the end. @eos may be NULL
1062 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1063 GstClockTime time_position)
1068 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1069 GST_TIME_ARGS (time_position));
1072 for (i = 0; i < stream->n_segments; i++) {
1073 QtDemuxSegment *segment = &stream->segments[i];
1075 GST_LOG_OBJECT (stream->pad,
1076 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1077 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1079 /* For the last segment we include stop_time in the last segment */
1080 if (i < stream->n_segments - 1) {
1081 if (segment->time <= time_position && time_position < segment->stop_time) {
1082 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1087 /* Last segment always matches */
1095 /* move the stream @str to the sample position @index.
1097 * Updates @str->sample_index and marks discontinuity if needed.
1100 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1103 /* no change needed */
1104 if (index == str->sample_index)
1107 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1110 /* position changed, we have a discont */
1111 str->sample_index = index;
1112 str->offset_in_sample = 0;
1113 /* Each time we move in the stream we store the position where we are
1115 str->from_sample = index;
1116 str->discont = TRUE;
1120 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1121 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1124 gint64 min_byte_offset = -1;
1127 min_offset = desired_time;
1129 /* for each stream, find the index of the sample in the segment
1130 * and move back to the previous keyframe. */
1131 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1133 guint32 index, kindex;
1135 GstClockTime media_start;
1136 GstClockTime media_time;
1137 GstClockTime seg_time;
1138 QtDemuxSegment *seg;
1139 gboolean empty_segment = FALSE;
1141 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1143 if (CUR_STREAM (str)->sparse && !use_sparse)
1146 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1147 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1149 /* get segment and time in the segment */
1150 seg = &str->segments[seg_idx];
1151 seg_time = (desired_time - seg->time) * seg->rate;
1153 while (QTSEGMENT_IS_EMPTY (seg)) {
1155 empty_segment = TRUE;
1156 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1159 if (seg_idx == str->n_segments)
1161 seg = &str->segments[seg_idx];
1164 if (seg_idx == str->n_segments) {
1165 /* FIXME track shouldn't have the last segment as empty, but if it
1166 * happens we better handle it */
1170 /* get the media time in the segment */
1171 media_start = seg->media_start + seg_time;
1173 /* get the index of the sample with media time */
1174 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1175 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1176 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1177 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1180 /* shift to next frame if we are looking for next keyframe */
1181 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1182 && index < str->stbl_index)
1185 if (!empty_segment) {
1186 /* find previous keyframe */
1187 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1189 /* we will settle for one before if none found after */
1190 if (next && kindex == -1)
1191 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1193 /* Update the requested time whenever a keyframe was found, to make it
1194 * accurate and avoid having the first buffer fall outside of the segment
1199 /* get timestamp of keyframe */
1200 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1201 GST_DEBUG_OBJECT (qtdemux,
1202 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1203 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1204 str->samples[kindex].offset);
1206 /* keyframes in the segment get a chance to change the
1207 * desired_offset. keyframes out of the segment are
1209 if (media_time >= seg->media_start) {
1210 GstClockTime seg_time;
1212 /* this keyframe is inside the segment, convert back to
1214 seg_time = (media_time - seg->media_start) + seg->time;
1215 if ((!next && (seg_time < min_offset)) ||
1216 (next && (seg_time > min_offset)))
1217 min_offset = seg_time;
1222 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1223 min_byte_offset = str->samples[index].offset;
1227 *key_time = min_offset;
1229 *key_offset = min_byte_offset;
1233 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1234 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1238 g_return_val_if_fail (format != NULL, FALSE);
1239 g_return_val_if_fail (cur != NULL, FALSE);
1240 g_return_val_if_fail (stop != NULL, FALSE);
1242 if (*format == GST_FORMAT_TIME)
1246 if (cur_type != GST_SEEK_TYPE_NONE)
1247 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1248 if (res && stop_type != GST_SEEK_TYPE_NONE)
1249 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1252 *format = GST_FORMAT_TIME;
1257 /* perform seek in push based mode:
1258 find BYTE position to move to based on time and delegate to upstream
1261 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1266 GstSeekType cur_type, stop_type;
1267 gint64 cur, stop, key_cur;
1270 gint64 original_stop;
1273 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1275 gst_event_parse_seek (event, &rate, &format, &flags,
1276 &cur_type, &cur, &stop_type, &stop);
1277 seqnum = gst_event_get_seqnum (event);
1279 /* Directly send the instant-rate-change event here before taking the
1280 * stream-lock so that it can be applied as soon as possible */
1281 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1284 /* instant rate change only supported if direction does not change. All
1285 * other requirements are already checked before creating the seek event
1286 * but let's double-check here to be sure */
1287 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1288 (qtdemux->segment.rate < 0 && rate > 0) ||
1289 cur_type != GST_SEEK_TYPE_NONE ||
1290 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1291 GST_ERROR_OBJECT (qtdemux,
1292 "Instant rate change seeks only supported in the "
1293 "same direction, without flushing and position change");
1297 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1298 (GstSegmentFlags) flags);
1299 gst_event_set_seqnum (ev, seqnum);
1300 gst_qtdemux_push_event (qtdemux, ev);
1304 /* only forward streaming and seeking is possible */
1306 goto unsupported_seek;
1308 /* convert to TIME if needed and possible */
1309 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1313 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1314 * the original stop position to use when upstream pushes the new segment
1316 original_stop = stop;
1319 /* find reasonable corresponding BYTE position,
1320 * also try to mind about keyframes, since we can not go back a bit for them
1322 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1323 * mostly just work, but let's not yet boldly go there ... */
1324 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1329 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1330 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1333 GST_OBJECT_LOCK (qtdemux);
1334 qtdemux->seek_offset = byte_cur;
1335 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1336 qtdemux->push_seek_start = cur;
1338 qtdemux->push_seek_start = key_cur;
1341 if (stop_type == GST_SEEK_TYPE_NONE) {
1342 qtdemux->push_seek_stop = qtdemux->segment.stop;
1344 qtdemux->push_seek_stop = original_stop;
1346 GST_OBJECT_UNLOCK (qtdemux);
1348 qtdemux->segment_seqnum = seqnum;
1349 /* BYTE seek event */
1350 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1352 gst_event_set_seqnum (event, seqnum);
1353 res = gst_pad_push_event (qtdemux->sinkpad, event);
1360 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1366 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1371 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1376 /* perform the seek.
1378 * We set all segment_indexes in the streams to unknown and
1379 * adjust the time_position to the desired position. this is enough
1380 * to trigger a segment switch in the streaming thread to start
1381 * streaming from the desired position.
1383 * Keyframe seeking is a little more complicated when dealing with
1384 * segments. Ideally we want to move to the previous keyframe in
1385 * the segment but there might not be a keyframe in the segment. In
1386 * fact, none of the segments could contain a keyframe. We take a
1387 * practical approach: seek to the previous keyframe in the segment,
1388 * if there is none, seek to the beginning of the segment.
1390 * Called with STREAM_LOCK
1393 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1394 guint32 seqnum, GstSeekFlags flags)
1396 gint64 desired_offset;
1399 desired_offset = segment->position;
1401 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1402 GST_TIME_ARGS (desired_offset));
1404 /* may not have enough fragmented info to do this adjustment,
1405 * and we can't scan (and probably should not) at this time with
1406 * possibly flushing upstream */
1407 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1409 gboolean next, before, after;
1411 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1412 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1413 next = after && !before;
1414 if (segment->rate < 0)
1417 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1419 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1420 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1421 desired_offset = min_offset;
1424 /* and set all streams to the final position */
1425 GST_OBJECT_LOCK (qtdemux);
1426 gst_flow_combiner_reset (qtdemux->flowcombiner);
1427 GST_OBJECT_UNLOCK (qtdemux);
1428 qtdemux->segment_seqnum = seqnum;
1429 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1430 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1432 stream->time_position = desired_offset;
1433 stream->accumulated_base = 0;
1434 stream->sample_index = -1;
1435 stream->offset_in_sample = 0;
1436 stream->segment_index = -1;
1437 stream->sent_eos = FALSE;
1438 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1440 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1441 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1443 segment->position = desired_offset;
1444 if (segment->rate >= 0) {
1445 segment->start = desired_offset;
1446 /* We need to update time as we update start in that direction */
1447 segment->time = desired_offset;
1449 /* we stop at the end */
1450 if (segment->stop == -1)
1451 segment->stop = segment->duration;
1453 segment->stop = desired_offset;
1456 if (qtdemux->fragmented)
1457 qtdemux->fragmented_seek_pending = TRUE;
1462 /* do a seek in pull based mode */
1464 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1469 GstSeekType cur_type, stop_type;
1471 gboolean flush, instant_rate_change;
1473 GstSegment seeksegment;
1474 guint32 seqnum = GST_SEQNUM_INVALID;
1475 GstEvent *flush_event;
1478 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1480 gst_event_parse_seek (event, &rate, &format, &flags,
1481 &cur_type, &cur, &stop_type, &stop);
1482 seqnum = gst_event_get_seqnum (event);
1484 /* we have to have a format as the segment format. Try to convert
1486 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1490 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1492 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1493 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1495 /* Directly send the instant-rate-change event here before taking the
1496 * stream-lock so that it can be applied as soon as possible */
1497 if (instant_rate_change) {
1500 /* instant rate change only supported if direction does not change. All
1501 * other requirements are already checked before creating the seek event
1502 * but let's double-check here to be sure */
1503 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1504 (qtdemux->segment.rate < 0 && rate > 0) ||
1505 cur_type != GST_SEEK_TYPE_NONE ||
1506 stop_type != GST_SEEK_TYPE_NONE || flush) {
1507 GST_ERROR_OBJECT (qtdemux,
1508 "Instant rate change seeks only supported in the "
1509 "same direction, without flushing and position change");
1513 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1514 (GstSegmentFlags) flags);
1515 gst_event_set_seqnum (ev, seqnum);
1516 gst_qtdemux_push_event (qtdemux, ev);
1520 /* stop streaming, either by flushing or by pausing the task */
1522 flush_event = gst_event_new_flush_start ();
1523 if (seqnum != GST_SEQNUM_INVALID)
1524 gst_event_set_seqnum (flush_event, seqnum);
1525 /* unlock upstream pull_range */
1526 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1527 /* make sure out loop function exits */
1528 gst_qtdemux_push_event (qtdemux, flush_event);
1530 /* non flushing seek, pause the task */
1531 gst_pad_pause_task (qtdemux->sinkpad);
1534 /* wait for streaming to finish */
1535 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1537 /* copy segment, we need this because we still need the old
1538 * segment when we close the current segment. */
1539 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1541 /* configure the segment with the seek variables */
1542 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1543 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1544 cur_type, cur, stop_type, stop, &update)) {
1546 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1548 /* now do the seek */
1549 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1552 /* prepare for streaming again */
1554 flush_event = gst_event_new_flush_stop (TRUE);
1555 if (seqnum != GST_SEQNUM_INVALID)
1556 gst_event_set_seqnum (flush_event, seqnum);
1558 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1559 gst_qtdemux_push_event (qtdemux, flush_event);
1562 /* commit the new segment */
1563 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1565 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1566 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1567 qtdemux->segment.format, qtdemux->segment.position);
1568 if (seqnum != GST_SEQNUM_INVALID)
1569 gst_message_set_seqnum (msg, seqnum);
1570 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1573 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1574 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1575 qtdemux->sinkpad, NULL);
1577 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1584 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1590 qtdemux_ensure_index (GstQTDemux * qtdemux)
1594 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1596 /* Build complete index */
1597 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1598 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1600 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1601 GST_LOG_OBJECT (qtdemux,
1602 "Building complete index of track-id %u for seeking failed!",
1612 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1615 gboolean res = TRUE;
1616 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1618 switch (GST_EVENT_TYPE (event)) {
1619 case GST_EVENT_RECONFIGURE:
1620 GST_OBJECT_LOCK (qtdemux);
1621 gst_flow_combiner_reset (qtdemux->flowcombiner);
1622 GST_OBJECT_UNLOCK (qtdemux);
1623 res = gst_pad_event_default (pad, parent, event);
1625 case GST_EVENT_SEEK:
1627 GstSeekFlags flags = 0;
1628 GstFormat seek_format;
1629 gboolean instant_rate_change;
1631 #ifndef GST_DISABLE_GST_DEBUG
1632 GstClockTime ts = gst_util_get_timestamp ();
1634 guint32 seqnum = gst_event_get_seqnum (event);
1636 qtdemux->received_seek = TRUE;
1638 gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1640 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1642 if (seqnum == qtdemux->segment_seqnum) {
1643 GST_LOG_OBJECT (pad,
1644 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1645 gst_event_unref (event);
1649 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1650 /* seek should be handled by upstream, we might need to re-download fragments */
1651 GST_DEBUG_OBJECT (qtdemux,
1652 "let upstream handle seek for fragmented playback");
1656 if (seek_format == GST_FORMAT_BYTES) {
1657 GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1658 gst_event_unref (event);
1662 gst_event_parse_seek_trickmode_interval (event,
1663 &qtdemux->trickmode_interval);
1665 /* Build complete index for seeking;
1666 * if not a fragmented file at least and we're really doing a seek,
1667 * not just an instant-rate-change */
1668 if (!qtdemux->fragmented && !instant_rate_change) {
1669 if (!qtdemux_ensure_index (qtdemux))
1672 #ifndef GST_DISABLE_GST_DEBUG
1673 ts = gst_util_get_timestamp () - ts;
1674 GST_INFO_OBJECT (qtdemux,
1675 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1677 if (qtdemux->pullbased) {
1678 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1679 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1680 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1682 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1683 && QTDEMUX_N_STREAMS (qtdemux)
1684 && !qtdemux->fragmented) {
1685 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1687 GST_DEBUG_OBJECT (qtdemux,
1688 "ignoring seek in push mode in current state");
1691 gst_event_unref (event);
1696 res = gst_pad_event_default (pad, parent, event);
1706 GST_ERROR_OBJECT (qtdemux, "Index failed");
1707 gst_event_unref (event);
1713 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1715 * If @fw is false, the coding order is explored backwards.
1717 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1718 * sample is found for that track.
1720 * The stream and sample index of the sample with the minimum offset in the direction explored
1721 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1723 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1724 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1725 * @_stream and @_index. */
1727 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1728 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1731 gint64 time, min_time;
1732 QtDemuxStream *stream;
1739 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1742 gboolean set_sample;
1744 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1751 i = str->n_samples - 1;
1755 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1756 if (str->samples[i].size == 0)
1759 if (fw && (str->samples[i].offset < byte_pos))
1762 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1765 /* move stream to first available sample */
1767 gst_qtdemux_move_stream (qtdemux, str, i);
1771 /* avoid index from sparse streams since they might be far away */
1772 if (!CUR_STREAM (str)->sparse) {
1773 /* determine min/max time */
1774 time = QTSAMPLE_PTS (str, &str->samples[i]);
1775 if (min_time == -1 || (!fw && time > min_time) ||
1776 (fw && time < min_time)) {
1780 /* determine stream with leading sample, to get its position */
1782 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1783 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1791 /* no sample for this stream, mark eos */
1793 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1804 /* Copied from mpegtsbase code */
1805 /* FIXME: replace this function when we add new util function for stream-id creation */
1807 _get_upstream_id (GstQTDemux * demux)
1809 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1812 /* Try to create one from the upstream URI, else use a randome number */
1816 /* Try to generate one from the URI query and
1817 * if it fails take a random number instead */
1818 query = gst_query_new_uri ();
1819 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1820 gst_query_parse_uri (query, &uri);
1826 /* And then generate an SHA256 sum of the URI */
1827 cs = g_checksum_new (G_CHECKSUM_SHA256);
1828 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1830 upstream_id = g_strdup (g_checksum_get_string (cs));
1831 g_checksum_free (cs);
1833 /* Just get some random number if the URI query fails */
1834 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1835 "implementing a deterministic way of creating a stream-id");
1837 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1838 g_random_int (), g_random_int ());
1841 gst_query_unref (query);
1846 static QtDemuxStream *
1847 _create_stream (GstQTDemux * demux, guint32 track_id)
1849 QtDemuxStream *stream;
1852 stream = g_new0 (QtDemuxStream, 1);
1853 stream->demux = demux;
1854 stream->track_id = track_id;
1855 upstream_id = _get_upstream_id (demux);
1856 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1857 g_free (upstream_id);
1858 /* new streams always need a discont */
1859 stream->discont = TRUE;
1860 /* we enable clipping for raw audio/video streams */
1861 stream->need_clip = FALSE;
1862 stream->process_func = NULL;
1863 stream->segment_index = -1;
1864 stream->time_position = 0;
1865 stream->sample_index = -1;
1866 stream->offset_in_sample = 0;
1867 stream->new_stream = TRUE;
1868 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1869 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1870 stream->protected = FALSE;
1871 stream->protection_scheme_type = 0;
1872 stream->protection_scheme_version = 0;
1873 stream->protection_scheme_info = NULL;
1874 stream->n_samples_moof = 0;
1875 stream->duration_moof = 0;
1876 stream->duration_last_moof = 0;
1877 stream->alignment = 1;
1878 stream->stream_tags = gst_tag_list_new_empty ();
1879 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1880 g_queue_init (&stream->protection_scheme_event_queue);
1881 stream->ref_count = 1;
1882 /* consistent default for push based mode */
1883 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1888 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1890 GstStructure *structure;
1891 const gchar *variant;
1892 const GstCaps *mediacaps = NULL;
1894 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1896 structure = gst_caps_get_structure (caps, 0);
1897 variant = gst_structure_get_string (structure, "variant");
1899 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1900 QtDemuxStream *stream;
1901 const GValue *value;
1903 demux->fragmented = TRUE;
1904 demux->mss_mode = TRUE;
1906 if (QTDEMUX_N_STREAMS (demux) > 1) {
1907 /* can't do this, we can only renegotiate for another mss format */
1911 value = gst_structure_get_value (structure, "media-caps");
1914 const GValue *timescale_v;
1916 /* TODO update when stream changes during playback */
1918 if (QTDEMUX_N_STREAMS (demux) == 0) {
1919 stream = _create_stream (demux, 1);
1920 g_ptr_array_add (demux->active_streams, stream);
1921 /* mss has no stsd/stsd entry, use id 0 as default */
1922 stream->stsd_entries_length = 1;
1923 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1924 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1926 stream = QTDEMUX_NTH_STREAM (demux, 0);
1929 timescale_v = gst_structure_get_value (structure, "timescale");
1931 stream->timescale = g_value_get_uint64 (timescale_v);
1933 /* default mss timescale */
1934 stream->timescale = 10000000;
1936 demux->timescale = stream->timescale;
1938 mediacaps = gst_value_get_caps (value);
1939 if (!CUR_STREAM (stream)->caps
1940 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1941 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1943 stream->new_caps = TRUE;
1945 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1946 structure = gst_caps_get_structure (mediacaps, 0);
1947 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1948 stream->subtype = FOURCC_vide;
1950 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1951 gst_structure_get_int (structure, "height",
1952 &CUR_STREAM (stream)->height);
1953 gst_structure_get_fraction (structure, "framerate",
1954 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1955 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1957 stream->subtype = FOURCC_soun;
1958 gst_structure_get_int (structure, "channels",
1959 &CUR_STREAM (stream)->n_channels);
1960 gst_structure_get_int (structure, "rate", &rate);
1961 CUR_STREAM (stream)->rate = rate;
1962 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1963 if (gst_structure_has_field (structure, "original-media-type")) {
1964 const gchar *media_type =
1965 gst_structure_get_string (structure, "original-media-type");
1966 if (g_str_has_prefix (media_type, "video")) {
1967 stream->subtype = FOURCC_vide;
1968 } else if (g_str_has_prefix (media_type, "audio")) {
1969 stream->subtype = FOURCC_soun;
1974 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1976 demux->mss_mode = FALSE;
1983 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1987 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1989 if (hard || qtdemux->upstream_format_is_time) {
1990 qtdemux->state = QTDEMUX_STATE_INITIAL;
1991 qtdemux->neededbytes = 16;
1992 qtdemux->todrop = 0;
1993 qtdemux->pullbased = FALSE;
1994 g_clear_pointer (&qtdemux->redirect_location, g_free);
1995 qtdemux->first_mdat = -1;
1996 qtdemux->header_size = 0;
1997 qtdemux->mdatoffset = -1;
1998 qtdemux->restoredata_offset = -1;
1999 if (qtdemux->mdatbuffer)
2000 gst_buffer_unref (qtdemux->mdatbuffer);
2001 if (qtdemux->restoredata_buffer)
2002 gst_buffer_unref (qtdemux->restoredata_buffer);
2003 qtdemux->mdatbuffer = NULL;
2004 qtdemux->restoredata_buffer = NULL;
2005 qtdemux->mdatleft = 0;
2006 qtdemux->mdatsize = 0;
2007 if (qtdemux->comp_brands)
2008 gst_buffer_unref (qtdemux->comp_brands);
2009 qtdemux->comp_brands = NULL;
2010 qtdemux->last_moov_offset = -1;
2011 if (qtdemux->moov_node_compressed) {
2012 g_node_destroy (qtdemux->moov_node_compressed);
2013 if (qtdemux->moov_node)
2014 g_free (qtdemux->moov_node->data);
2016 qtdemux->moov_node_compressed = NULL;
2017 if (qtdemux->moov_node)
2018 g_node_destroy (qtdemux->moov_node);
2019 qtdemux->moov_node = NULL;
2020 if (qtdemux->tag_list)
2021 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2022 qtdemux->tag_list = gst_tag_list_new_empty ();
2023 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2025 if (qtdemux->element_index)
2026 gst_object_unref (qtdemux->element_index);
2027 qtdemux->element_index = NULL;
2029 qtdemux->major_brand = 0;
2030 qtdemux->upstream_format_is_time = FALSE;
2031 qtdemux->upstream_seekable = FALSE;
2032 qtdemux->upstream_size = 0;
2034 qtdemux->fragment_start = -1;
2035 qtdemux->fragment_start_offset = -1;
2036 qtdemux->duration = 0;
2037 qtdemux->moof_offset = 0;
2038 qtdemux->chapters_track_id = 0;
2039 qtdemux->have_group_id = FALSE;
2040 qtdemux->group_id = G_MAXUINT;
2042 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2044 g_queue_clear (&qtdemux->protection_event_queue);
2046 qtdemux->received_seek = FALSE;
2047 qtdemux->first_moof_already_parsed = FALSE;
2049 qtdemux->offset = 0;
2050 gst_adapter_clear (qtdemux->adapter);
2051 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2052 qtdemux->need_segment = TRUE;
2055 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2056 qtdemux->trickmode_interval = 0;
2057 g_ptr_array_set_size (qtdemux->active_streams, 0);
2058 g_ptr_array_set_size (qtdemux->old_streams, 0);
2059 qtdemux->n_video_streams = 0;
2060 qtdemux->n_audio_streams = 0;
2061 qtdemux->n_sub_streams = 0;
2062 qtdemux->n_meta_streams = 0;
2063 qtdemux->exposed = FALSE;
2064 qtdemux->fragmented = FALSE;
2065 qtdemux->mss_mode = FALSE;
2066 gst_caps_replace (&qtdemux->media_caps, NULL);
2067 qtdemux->timescale = 0;
2068 qtdemux->got_moov = FALSE;
2069 qtdemux->start_utc_time = GST_CLOCK_TIME_NONE;
2070 qtdemux->cenc_aux_info_offset = 0;
2071 g_free (qtdemux->cenc_aux_info_sizes);
2072 qtdemux->cenc_aux_info_sizes = NULL;
2073 qtdemux->cenc_aux_sample_count = 0;
2074 if (qtdemux->protection_system_ids) {
2075 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2076 qtdemux->protection_system_ids = NULL;
2078 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2079 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2080 GST_BIN_FLAG_STREAMS_AWARE);
2082 if (qtdemux->preferred_protection_system_id) {
2083 g_free (qtdemux->preferred_protection_system_id);
2084 qtdemux->preferred_protection_system_id = NULL;
2086 } else if (qtdemux->mss_mode) {
2087 gst_flow_combiner_reset (qtdemux->flowcombiner);
2088 g_ptr_array_foreach (qtdemux->active_streams,
2089 (GFunc) gst_qtdemux_stream_clear, NULL);
2091 gst_flow_combiner_reset (qtdemux->flowcombiner);
2092 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2093 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2094 stream->sent_eos = FALSE;
2095 stream->time_position = 0;
2096 stream->accumulated_base = 0;
2097 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2103 /* Maps the @segment to the qt edts internal segments and pushes
2104 * the corresponding segment event.
2106 * If it ends up being at a empty segment, a gap will be pushed and the next
2107 * edts segment will be activated in sequence.
2109 * To be used in push-mode only */
2111 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2115 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2116 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2118 stream->time_position = segment->start;
2120 /* in push mode we should be guaranteed that we will have empty segments
2121 * at the beginning and then one segment after, other scenarios are not
2122 * supported and are discarded when parsing the edts */
2123 for (i = 0; i < stream->n_segments; i++) {
2124 if (stream->segments[i].stop_time > segment->start) {
2125 /* push the empty segment and move to the next one */
2126 gst_qtdemux_activate_segment (qtdemux, stream, i,
2127 stream->time_position);
2128 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2129 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2130 stream->time_position);
2132 /* accumulate previous segments */
2133 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2134 stream->accumulated_base +=
2135 (stream->segment.stop -
2136 stream->segment.start) / ABS (stream->segment.rate);
2140 g_assert (i == stream->n_segments - 1);
2147 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2158 for (i = 0; i < len; i++) {
2159 QtDemuxStream *stream = g_ptr_array_index (src, i);
2161 #ifndef GST_DISABLE_GST_DEBUG
2162 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2163 stream, GST_STR_NULL (stream->stream_id), dest);
2165 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2168 g_ptr_array_set_size (src, 0);
2172 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2175 GstQTDemux *demux = GST_QTDEMUX (parent);
2176 gboolean res = TRUE;
2178 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2180 switch (GST_EVENT_TYPE (event)) {
2181 case GST_EVENT_SEGMENT:
2184 QtDemuxStream *stream;
2188 /* some debug output */
2189 gst_event_copy_segment (event, &segment);
2190 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2193 if (segment.format == GST_FORMAT_TIME) {
2194 demux->upstream_format_is_time = TRUE;
2195 demux->segment_seqnum = gst_event_get_seqnum (event);
2197 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2198 "not in time format");
2200 /* chain will send initial newsegment after pads have been added */
2201 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2202 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2207 /* check if this matches a time seek we received previously
2208 * FIXME for backwards compatibility reasons we use the
2209 * seek_offset here to compare. In the future we might want to
2210 * change this to use the seqnum as it uniquely should identify
2211 * the segment that corresponds to the seek. */
2212 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2213 ", received segment offset %" G_GINT64_FORMAT,
2214 demux->seek_offset, segment.start);
2215 if (segment.format == GST_FORMAT_BYTES
2216 && demux->seek_offset == segment.start) {
2217 GST_OBJECT_LOCK (demux);
2218 offset = segment.start;
2220 segment.format = GST_FORMAT_TIME;
2221 segment.start = demux->push_seek_start;
2222 segment.stop = demux->push_seek_stop;
2223 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2224 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2225 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2226 GST_OBJECT_UNLOCK (demux);
2229 /* we only expect a BYTE segment, e.g. following a seek */
2230 if (segment.format == GST_FORMAT_BYTES) {
2231 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2232 offset = segment.start;
2234 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2235 NULL, (gint64 *) & segment.start);
2236 if ((gint64) segment.start < 0)
2239 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2240 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2241 NULL, (gint64 *) & segment.stop);
2242 /* keyframe seeking should already arrange for start >= stop,
2243 * but make sure in other rare cases */
2244 segment.stop = MAX (segment.stop, segment.start);
2246 } else if (segment.format == GST_FORMAT_TIME) {
2247 /* push all data on the adapter before starting this
2249 gst_qtdemux_process_adapter (demux, TRUE);
2251 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2255 /* We shouldn't modify upstream driven TIME FORMAT segment */
2256 if (!demux->upstream_format_is_time) {
2257 /* accept upstream's notion of segment and distribute along */
2258 segment.format = GST_FORMAT_TIME;
2259 segment.position = segment.time = segment.start;
2260 segment.duration = demux->segment.duration;
2261 segment.base = gst_segment_to_running_time (&demux->segment,
2262 GST_FORMAT_TIME, demux->segment.position);
2265 gst_segment_copy_into (&segment, &demux->segment);
2266 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2268 /* map segment to internal qt segments and push on each stream */
2269 if (QTDEMUX_N_STREAMS (demux)) {
2270 demux->need_segment = TRUE;
2271 gst_qtdemux_check_send_pending_segment (demux);
2274 /* clear leftover in current segment, if any */
2275 gst_adapter_clear (demux->adapter);
2277 /* set up streaming thread */
2278 demux->offset = offset;
2279 if (demux->upstream_format_is_time) {
2280 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2281 "set values to restart reading from a new atom");
2282 demux->neededbytes = 16;
2285 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2288 demux->todrop = stream->samples[idx].offset - offset;
2289 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2291 /* set up for EOS */
2292 demux->neededbytes = -1;
2297 gst_event_unref (event);
2301 case GST_EVENT_FLUSH_START:
2303 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2304 gst_event_unref (event);
2307 QTDEMUX_EXPOSE_LOCK (demux);
2308 res = gst_pad_event_default (demux->sinkpad, parent, event);
2309 QTDEMUX_EXPOSE_UNLOCK (demux);
2312 case GST_EVENT_FLUSH_STOP:
2316 dur = demux->segment.duration;
2317 gst_qtdemux_reset (demux, FALSE);
2318 demux->segment.duration = dur;
2320 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2321 gst_event_unref (event);
2327 /* If we are in push mode, and get an EOS before we've seen any streams,
2328 * then error out - we have nowhere to send the EOS */
2329 if (!demux->pullbased) {
2331 gboolean has_valid_stream = FALSE;
2332 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2333 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2334 has_valid_stream = TRUE;
2338 if (!has_valid_stream)
2339 gst_qtdemux_post_no_playable_stream_error (demux);
2341 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2342 (guint) gst_adapter_available (demux->adapter));
2343 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2349 case GST_EVENT_CAPS:{
2350 GstCaps *caps = NULL;
2352 gst_event_parse_caps (event, &caps);
2353 gst_qtdemux_setcaps (demux, caps);
2355 gst_event_unref (event);
2358 case GST_EVENT_PROTECTION:
2360 const gchar *system_id = NULL;
2362 gst_event_parse_protection (event, &system_id, NULL, NULL);
2363 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2365 gst_qtdemux_append_protection_system_id (demux, system_id);
2366 /* save the event for later, for source pads that have not been created */
2367 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2368 /* send it to all pads that already exist */
2369 gst_qtdemux_push_event (demux, event);
2373 case GST_EVENT_STREAM_START:
2376 gst_event_unref (event);
2378 /* Drain all the buffers */
2379 gst_qtdemux_process_adapter (demux, TRUE);
2380 gst_qtdemux_reset (demux, FALSE);
2381 /* We expect new moov box after new stream-start event */
2382 if (demux->exposed) {
2383 gst_qtdemux_stream_concat (demux,
2384 demux->old_streams, demux->active_streams);
2393 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2400 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2403 GstQTDemux *demux = GST_QTDEMUX (parent);
2404 gboolean res = FALSE;
2406 switch (GST_QUERY_TYPE (query)) {
2407 case GST_QUERY_BITRATE:
2409 GstClockTime duration;
2411 /* populate demux->upstream_size if not done yet */
2412 gst_qtdemux_check_seekability (demux);
2414 if (demux->upstream_size != -1
2415 && gst_qtdemux_get_duration (demux, &duration)) {
2417 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2420 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2421 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2422 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2424 /* TODO: better results based on ranges/index tables */
2425 gst_query_set_bitrate (query, bitrate);
2431 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2441 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2443 GstQTDemux *demux = GST_QTDEMUX (element);
2445 GST_OBJECT_LOCK (demux);
2446 if (demux->element_index)
2447 gst_object_unref (demux->element_index);
2449 demux->element_index = gst_object_ref (index);
2451 demux->element_index = NULL;
2453 GST_OBJECT_UNLOCK (demux);
2454 /* object lock might be taken again */
2456 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2457 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2458 demux->element_index, demux->index_id);
2462 gst_qtdemux_get_index (GstElement * element)
2464 GstIndex *result = NULL;
2465 GstQTDemux *demux = GST_QTDEMUX (element);
2467 GST_OBJECT_LOCK (demux);
2468 if (demux->element_index)
2469 result = gst_object_ref (demux->element_index);
2470 GST_OBJECT_UNLOCK (demux);
2472 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2479 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2481 g_free ((gpointer) stream->stco.data);
2482 stream->stco.data = NULL;
2483 g_free ((gpointer) stream->stsz.data);
2484 stream->stsz.data = NULL;
2485 g_free ((gpointer) stream->stsc.data);
2486 stream->stsc.data = NULL;
2487 g_free ((gpointer) stream->stts.data);
2488 stream->stts.data = NULL;
2489 g_free ((gpointer) stream->stss.data);
2490 stream->stss.data = NULL;
2491 g_free ((gpointer) stream->stps.data);
2492 stream->stps.data = NULL;
2493 g_free ((gpointer) stream->ctts.data);
2494 stream->ctts.data = NULL;
2498 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2500 g_free (stream->segments);
2501 stream->segments = NULL;
2502 stream->segment_index = -1;
2503 stream->accumulated_base = 0;
2507 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2509 g_free (stream->samples);
2510 stream->samples = NULL;
2511 gst_qtdemux_stbl_free (stream);
2514 g_free (stream->ra_entries);
2515 stream->ra_entries = NULL;
2516 stream->n_ra_entries = 0;
2518 stream->sample_index = -1;
2519 stream->stbl_index = -1;
2520 stream->n_samples = 0;
2521 stream->time_position = 0;
2523 stream->n_samples_moof = 0;
2524 stream->duration_moof = 0;
2525 stream->duration_last_moof = 0;
2529 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2532 if (stream->allocator)
2533 gst_object_unref (stream->allocator);
2534 while (stream->buffers) {
2535 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2536 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2538 for (i = 0; i < stream->stsd_entries_length; i++) {
2539 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2540 if (entry->rgb8_palette) {
2541 gst_memory_unref (entry->rgb8_palette);
2542 entry->rgb8_palette = NULL;
2544 entry->sparse = FALSE;
2547 if (stream->stream_tags)
2548 gst_tag_list_unref (stream->stream_tags);
2550 stream->stream_tags = gst_tag_list_new_empty ();
2551 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2552 g_free (stream->redirect_uri);
2553 stream->redirect_uri = NULL;
2554 stream->sent_eos = FALSE;
2555 stream->protected = FALSE;
2556 if (stream->protection_scheme_info) {
2557 if (stream->protection_scheme_type == FOURCC_cenc
2558 || stream->protection_scheme_type == FOURCC_cbcs) {
2559 QtDemuxCencSampleSetInfo *info =
2560 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2561 if (info->default_properties)
2562 gst_structure_free (info->default_properties);
2563 if (info->crypto_info)
2564 g_ptr_array_free (info->crypto_info, TRUE);
2566 if (stream->protection_scheme_type == FOURCC_aavd) {
2567 QtDemuxAavdEncryptionInfo *info =
2568 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2569 if (info->default_properties)
2570 gst_structure_free (info->default_properties);
2572 g_free (stream->protection_scheme_info);
2573 stream->protection_scheme_info = NULL;
2575 stream->protection_scheme_type = 0;
2576 stream->protection_scheme_version = 0;
2577 g_queue_foreach (&stream->protection_scheme_event_queue,
2578 (GFunc) gst_event_unref, NULL);
2579 g_queue_clear (&stream->protection_scheme_event_queue);
2580 gst_qtdemux_stream_flush_segments_data (stream);
2581 gst_qtdemux_stream_flush_samples_data (stream);
2585 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2588 gst_qtdemux_stream_clear (stream);
2589 for (i = 0; i < stream->stsd_entries_length; i++) {
2590 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2592 gst_caps_unref (entry->caps);
2596 g_free (stream->stsd_entries);
2597 stream->stsd_entries = NULL;
2598 stream->stsd_entries_length = 0;
2601 static QtDemuxStream *
2602 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2604 g_atomic_int_add (&stream->ref_count, 1);
2610 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2612 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2613 gst_qtdemux_stream_reset (stream);
2614 gst_tag_list_unref (stream->stream_tags);
2616 GstQTDemux *demux = stream->demux;
2617 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2618 GST_OBJECT_LOCK (demux);
2619 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2620 GST_OBJECT_UNLOCK (demux);
2622 g_free (stream->stream_id);
2627 static GstStateChangeReturn
2628 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2630 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2631 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2633 switch (transition) {
2634 case GST_STATE_CHANGE_READY_TO_PAUSED:
2635 gst_qtdemux_reset (qtdemux, TRUE);
2641 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2643 switch (transition) {
2644 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2645 gst_qtdemux_reset (qtdemux, TRUE);
2656 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2658 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2660 g_return_if_fail (GST_IS_CONTEXT (context));
2662 if (gst_context_has_context_type (context,
2663 "drm-preferred-decryption-system-id")) {
2664 const GstStructure *s;
2666 s = gst_context_get_structure (context);
2667 g_free (qtdemux->preferred_protection_system_id);
2668 qtdemux->preferred_protection_system_id =
2669 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2670 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2671 qtdemux->preferred_protection_system_id);
2674 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2678 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2680 /* counts as header data */
2681 qtdemux->header_size += length;
2683 /* only consider at least a sufficiently complete ftyp atom */
2686 guint32 minor_version;
2689 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2690 GST_DEBUG_OBJECT (qtdemux, "ftyp major brand: %" GST_FOURCC_FORMAT,
2691 GST_FOURCC_ARGS (qtdemux->major_brand));
2692 minor_version = QT_UINT32 (buffer + 12);
2693 GST_DEBUG_OBJECT (qtdemux, "ftyp minor version: %u", minor_version);
2694 if (qtdemux->comp_brands)
2695 gst_buffer_unref (qtdemux->comp_brands);
2696 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2697 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2700 length = length - 16;
2701 while (length > 0) {
2702 GST_DEBUG_OBJECT (qtdemux, "ftyp compatible brand: %" GST_FOURCC_FORMAT,
2703 GST_FOURCC_ARGS (QT_FOURCC (p)));
2711 qtdemux_parse_styp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2713 /* only consider at least a sufficiently complete styp atom */
2716 guint32 major_brand;
2717 guint32 minor_version;
2720 major_brand = QT_FOURCC (buffer + 8);
2721 GST_DEBUG_OBJECT (qtdemux, "styp major brand: %" GST_FOURCC_FORMAT,
2722 GST_FOURCC_ARGS (major_brand));
2723 minor_version = QT_UINT32 (buffer + 12);
2724 GST_DEBUG_OBJECT (qtdemux, "styp minor version: %u", minor_version);
2725 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2726 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2729 length = length - 16;
2730 while (length > 0) {
2731 GST_DEBUG_OBJECT (qtdemux, "styp compatible brand: %" GST_FOURCC_FORMAT,
2732 GST_FOURCC_ARGS (QT_FOURCC (p)));
2740 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2741 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2742 guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2743 guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2744 const guint8 * constant_iv)
2746 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2747 gst_buffer_fill (kid_buf, 0, kid, 16);
2748 if (info->default_properties)
2749 gst_structure_free (info->default_properties);
2750 info->default_properties =
2751 gst_structure_new ("application/x-cenc",
2752 "iv_size", G_TYPE_UINT, iv_size,
2753 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2754 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2755 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2756 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2757 gst_buffer_unref (kid_buf);
2758 if (protection_scheme_type == FOURCC_cbcs) {
2759 if (crypt_byte_block != 0 || skip_byte_block != 0) {
2760 gst_structure_set (info->default_properties, "crypt_byte_block",
2761 G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2762 skip_byte_block, NULL);
2764 if (constant_iv != NULL) {
2765 GstBuffer *constant_iv_buf =
2766 gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2767 gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2768 gst_structure_set (info->default_properties, "constant_iv_size",
2769 G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2771 gst_buffer_unref (constant_iv_buf);
2773 gst_structure_set (info->default_properties, "cipher-mode",
2774 G_TYPE_STRING, "cbcs", NULL);
2776 gst_structure_set (info->default_properties, "cipher-mode",
2777 G_TYPE_STRING, "cenc", NULL);
2782 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2783 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2785 guint32 algorithm_id = 0;
2787 gboolean is_encrypted = TRUE;
2790 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2791 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2796 if (algorithm_id == 0) {
2797 is_encrypted = FALSE;
2798 } else if (algorithm_id == 1) {
2799 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2800 } else if (algorithm_id == 2) {
2801 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2804 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2807 if (!gst_byte_reader_get_data (br, 16, &kid))
2810 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2811 is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2812 gst_structure_set (info->default_properties, "piff_algorithm_id",
2813 G_TYPE_UINT, algorithm_id, NULL);
2819 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2827 QtDemuxStream *stream;
2828 GstStructure *structure;
2829 QtDemuxCencSampleSetInfo *ss_info = NULL;
2830 const gchar *system_id;
2831 gboolean uses_sub_sample_encryption = FALSE;
2832 guint32 sample_count;
2834 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2837 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2839 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2840 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2841 GST_WARNING_OBJECT (qtdemux,
2842 "Attempting PIFF box parsing on an unencrypted stream.");
2846 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2847 G_TYPE_STRING, &system_id, NULL);
2848 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2850 stream->protected = TRUE;
2851 stream->protection_scheme_type = FOURCC_cenc;
2853 if (!stream->protection_scheme_info)
2854 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2856 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2857 if (!ss_info->default_properties) {
2858 ss_info->default_properties =
2859 gst_structure_new ("application/x-cenc",
2860 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2865 if (ss_info->crypto_info) {
2866 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2867 g_ptr_array_free (ss_info->crypto_info, TRUE);
2868 ss_info->crypto_info = NULL;
2872 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2874 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2875 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2879 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2880 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2884 if ((flags & 0x000001)) {
2885 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2888 } else if ((flags & 0x000002)) {
2889 uses_sub_sample_encryption = TRUE;
2892 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2894 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2898 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2899 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2903 ss_info->crypto_info =
2904 g_ptr_array_new_full (sample_count,
2905 (GDestroyNotify) qtdemux_gst_structure_free);
2907 for (i = 0; i < sample_count; ++i) {
2908 GstStructure *properties;
2912 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2913 if (properties == NULL) {
2914 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2915 qtdemux->cenc_aux_sample_count = i;
2919 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2920 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2921 gst_structure_free (properties);
2922 qtdemux->cenc_aux_sample_count = i;
2925 buf = gst_buffer_new_wrapped (data, iv_size);
2926 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2927 gst_buffer_unref (buf);
2929 if (uses_sub_sample_encryption) {
2930 guint16 n_subsamples;
2931 const GValue *kid_buf_value;
2933 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2934 || n_subsamples == 0) {
2935 GST_ERROR_OBJECT (qtdemux,
2936 "failed to get subsample count for sample %u", i);
2937 gst_structure_free (properties);
2938 qtdemux->cenc_aux_sample_count = i;
2941 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2942 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2943 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2945 gst_structure_free (properties);
2946 qtdemux->cenc_aux_sample_count = i;
2949 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2952 gst_structure_get_value (ss_info->default_properties, "kid");
2954 gst_structure_set (properties,
2955 "subsample_count", G_TYPE_UINT, n_subsamples,
2956 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2957 gst_structure_set_value (properties, "kid", kid_buf_value);
2958 gst_buffer_unref (buf);
2960 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2963 g_ptr_array_add (ss_info->crypto_info, properties);
2966 qtdemux->cenc_aux_sample_count = sample_count;
2970 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2972 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2973 0x97, 0xA9, 0x42, 0xE8,
2974 0x9C, 0x71, 0x99, 0x94,
2975 0x91, 0xE3, 0xAF, 0xAC
2977 static const guint8 playready_uuid[] = {
2978 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2979 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2982 static const guint8 piff_sample_encryption_uuid[] = {
2983 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2984 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2989 /* counts as header data */
2990 qtdemux->header_size += length;
2992 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2994 if (length <= offset + 16) {
2995 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2999 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
3001 GstTagList *taglist;
3003 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3004 length - offset - 16, NULL);
3005 taglist = gst_tag_list_from_xmp_buffer (buf);
3006 gst_buffer_unref (buf);
3008 /* make sure we have a usable taglist */
3009 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3011 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3013 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3015 const gunichar2 *s_utf16;
3018 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3019 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3020 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3021 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3025 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3026 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3028 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3029 qtdemux_parse_piff (qtdemux, buffer, length, offset);
3031 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3032 GST_READ_UINT32_LE (buffer + offset),
3033 GST_READ_UINT32_LE (buffer + offset + 4),
3034 GST_READ_UINT32_LE (buffer + offset + 8),
3035 GST_READ_UINT32_LE (buffer + offset + 12));
3040 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3042 GstSidxParser sidx_parser;
3043 GstIsoffParserResult res;
3046 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3049 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3051 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3052 if (res == GST_ISOFF_QT_PARSER_DONE) {
3053 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3055 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3059 qtdemux_parse_cstb (GstQTDemux * qtdemux, GstByteReader * data)
3062 guint32 entry_count;
3064 GST_DEBUG_OBJECT (qtdemux, "Parsing CorrectStartTime box");
3066 qtdemux->start_utc_time = GST_CLOCK_TIME_NONE;
3068 if (gst_byte_reader_get_remaining (data) < 4) {
3069 GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box");
3073 entry_count = gst_byte_reader_get_uint32_be_unchecked (data);
3074 if (entry_count == 0)
3077 /* XXX: We assume that all start times are the same as different start times
3078 * would violate the MP4 synchronization model, so we just take the first
3079 * one here and apply it to all tracks.
3082 if (gst_byte_reader_get_remaining (data) < entry_count * 12) {
3083 GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box");
3088 gst_byte_reader_skip_unchecked (data, 4);
3090 /* In 100ns intervals */
3091 start_time = gst_byte_reader_get_uint64_be_unchecked (data);
3093 /* Convert from Jan 1 1601 to Jan 1 1970 */
3094 if (start_time < 11644473600 * G_GUINT64_CONSTANT (10000000)) {
3095 GST_WARNING_OBJECT (qtdemux, "Start UTC time before UNIX epoch");
3098 start_time -= 11644473600 * G_GUINT64_CONSTANT (10000000);
3100 /* Convert to GstClockTime */
3103 GST_DEBUG_OBJECT (qtdemux, "Start UTC time: %" GST_TIME_FORMAT,
3104 GST_TIME_ARGS (start_time));
3106 qtdemux->start_utc_time = start_time;
3109 /* caller verifies at least 8 bytes in buf */
3111 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3112 guint64 * plength, guint32 * pfourcc)
3117 length = QT_UINT32 (data);
3118 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3119 fourcc = QT_FOURCC (data + 4);
3120 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3123 length = G_MAXUINT64;
3124 } else if (length == 1 && size >= 16) {
3125 /* this means we have an extended size, which is the 64 bit value of
3126 * the next 8 bytes */
3127 length = QT_UINT64 (data + 8);
3128 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3138 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3140 guint32 version = 0;
3141 GstClockTime duration = 0;
3143 if (!gst_byte_reader_get_uint32_be (br, &version))
3148 if (!gst_byte_reader_get_uint64_be (br, &duration))
3153 if (!gst_byte_reader_get_uint32_be (br, &dur))
3158 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3159 qtdemux->duration = duration;
3165 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3171 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3172 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3174 if (!stream->parsed_trex && qtdemux->moov_node) {
3176 GstByteReader trex_data;
3178 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3180 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3183 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3185 /* skip version/flags */
3186 if (!gst_byte_reader_skip (&trex_data, 4))
3188 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3190 if (id != stream->track_id)
3192 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3194 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3196 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3198 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3201 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3202 "duration %d, size %d, flags 0x%x", stream->track_id,
3205 stream->parsed_trex = TRUE;
3206 stream->def_sample_description_index = sdi;
3207 stream->def_sample_duration = dur;
3208 stream->def_sample_size = size;
3209 stream->def_sample_flags = flags;
3212 /* iterate all siblings */
3213 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3219 *ds_duration = stream->def_sample_duration;
3220 *ds_size = stream->def_sample_size;
3221 *ds_flags = stream->def_sample_flags;
3223 /* even then, above values are better than random ... */
3224 if (G_UNLIKELY (!stream->parsed_trex)) {
3225 GST_WARNING_OBJECT (qtdemux,
3226 "failed to find fragment defaults for stream %d", stream->track_id);
3233 /* This method should be called whenever a more accurate duration might
3234 * have been found. It will update all relevant variables if/where needed
3237 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3241 GstClockTime prevdur;
3243 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3245 if (movdur > qtdemux->duration) {
3246 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3247 GST_DEBUG_OBJECT (qtdemux,
3248 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3249 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3250 qtdemux->duration = movdur;
3251 GST_DEBUG_OBJECT (qtdemux,
3252 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3253 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3254 GST_TIME_ARGS (qtdemux->segment.stop));
3255 if (qtdemux->segment.duration == prevdur) {
3256 /* If the current segment has duration/stop identical to previous duration
3257 * update them also (because they were set at that point in time with
3258 * the wrong duration */
3259 /* We convert the value *from* the timescale version to avoid rounding errors */
3260 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3261 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3262 qtdemux->segment.duration = fixeddur;
3263 qtdemux->segment.stop = fixeddur;
3267 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3268 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3270 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3271 if (movdur > stream->duration) {
3272 GST_DEBUG_OBJECT (qtdemux,
3273 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3274 GST_TIME_ARGS (duration));
3275 stream->duration = movdur;
3276 /* internal duration tracking state has been updated above, so */
3277 /* preserve an open-ended dummy segment rather than repeatedly updating
3278 * it and spamming downstream accordingly with segment events */
3279 /* also mangle the edit list end time when fragmented with a single edit
3280 * list that may only cover any non-fragmented data */
3281 if ((stream->dummy_segment ||
3282 (qtdemux->fragmented && stream->n_segments == 1)) &&
3283 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3284 /* Update all dummy values to new duration */
3285 stream->segments[0].stop_time = duration;
3286 stream->segments[0].duration = duration;
3287 stream->segments[0].media_stop = duration;
3289 /* let downstream know we possibly have a new stop time */
3290 if (stream->segment_index != -1) {
3293 if (qtdemux->segment.rate >= 0) {
3294 pos = stream->segment.start;
3296 pos = stream->segment.stop;
3299 gst_qtdemux_stream_update_segment (qtdemux, stream,
3300 stream->segment_index, pos, NULL, NULL);
3308 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3309 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3310 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3311 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3314 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3316 gint32 data_offset = 0;
3318 guint32 flags = 0, first_flags = 0, samples_count = 0;
3321 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3322 QtDemuxSample *sample;
3323 gboolean ismv = FALSE;
3324 gint64 initial_offset;
3327 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3328 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3329 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3330 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3332 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3333 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3337 /* presence of stss or not can't really tell us much,
3338 * and flags and so on tend to be marginally reliable in these files */
3339 if (stream->subtype == FOURCC_soun) {
3340 GST_DEBUG_OBJECT (qtdemux,
3341 "sound track in fragmented file; marking all keyframes");
3342 stream->all_keyframe = TRUE;
3345 if (!gst_byte_reader_get_uint8 (trun, &version) ||
3346 !gst_byte_reader_get_uint24_be (trun, &flags))
3349 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3352 if (flags & TR_DATA_OFFSET) {
3353 /* note this is really signed */
3354 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3356 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3357 /* default base offset = first byte of moof */
3358 if (*base_offset == -1) {
3359 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3360 *base_offset = moof_offset;
3362 *running_offset = *base_offset + data_offset;
3364 /* if no offset at all, that would mean data starts at moof start,
3365 * which is a bit wrong and is ismv crappy way, so compensate
3366 * assuming data is in mdat following moof */
3367 if (*base_offset == -1) {
3368 *base_offset = moof_offset + moof_length + 8;
3369 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3372 if (*running_offset == -1)
3373 *running_offset = *base_offset;
3376 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3378 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3379 data_offset, flags, samples_count);
3381 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3382 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3383 GST_DEBUG_OBJECT (qtdemux,
3384 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3385 flags ^= TR_FIRST_SAMPLE_FLAGS;
3387 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3389 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3393 /* FIXME ? spec says other bits should also be checked to determine
3394 * entry size (and prefix size for that matter) */
3396 dur_offset = size_offset = 0;
3397 if (flags & TR_SAMPLE_DURATION) {
3398 GST_LOG_OBJECT (qtdemux, "entry duration present");
3399 dur_offset = entry_size;
3402 if (flags & TR_SAMPLE_SIZE) {
3403 GST_LOG_OBJECT (qtdemux, "entry size present");
3404 size_offset = entry_size;
3407 if (flags & TR_SAMPLE_FLAGS) {
3408 GST_LOG_OBJECT (qtdemux, "entry flags present");
3409 flags_offset = entry_size;
3412 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3413 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3414 ct_offset = entry_size;
3418 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3420 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3422 if (stream->n_samples + samples_count >=
3423 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3426 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3427 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3428 (stream->n_samples + samples_count) *
3429 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3431 /* create a new array of samples if it's the first sample parsed */
3432 if (stream->n_samples == 0) {
3433 g_assert (stream->samples == NULL);
3434 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3435 /* or try to reallocate it with space enough to insert the new samples */
3437 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3438 stream->n_samples + samples_count);
3439 if (stream->samples == NULL)
3442 if (qtdemux->fragment_start != -1) {
3443 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3444 qtdemux->fragment_start = -1;
3446 if (stream->n_samples == 0) {
3447 if (decode_ts > 0) {
3448 timestamp = decode_ts;
3449 } else if (stream->pending_seek != NULL) {
3450 /* if we don't have a timestamp from a tfdt box, we'll use the one
3451 * from the mfra seek table */
3452 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3453 GST_TIME_ARGS (stream->pending_seek->ts));
3455 /* FIXME: this is not fully correct, the timestamp refers to the random
3456 * access sample refered to in the tfra entry, which may not necessarily
3457 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3458 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3463 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3464 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3465 GST_TIME_ARGS (gst_ts));
3467 /* subsequent fragments extend stream */
3469 stream->samples[stream->n_samples - 1].timestamp +
3470 stream->samples[stream->n_samples - 1].duration;
3472 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3473 * difference (1 sec.) between decode_ts and timestamp, prefer the
3475 if (has_tfdt && !qtdemux->upstream_format_is_time
3476 && ABSDIFF (decode_ts, timestamp) >
3477 MAX (stream->duration_last_moof / 2,
3478 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3479 GST_INFO_OBJECT (qtdemux,
3480 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3481 ") are significantly different (more than %" GST_TIME_FORMAT
3482 "), using decode_ts",
3483 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3484 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3485 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3486 MAX (stream->duration_last_moof / 2,
3487 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3488 timestamp = decode_ts;
3491 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3492 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3493 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3497 initial_offset = *running_offset;
3499 sample = stream->samples + stream->n_samples;
3500 for (i = 0; i < samples_count; i++) {
3501 guint32 dur, size, sflags;
3504 /* first read sample data */
3505 if (flags & TR_SAMPLE_DURATION) {
3506 dur = QT_UINT32 (data + dur_offset);
3508 dur = d_sample_duration;
3510 if (flags & TR_SAMPLE_SIZE) {
3511 size = QT_UINT32 (data + size_offset);
3513 size = d_sample_size;
3515 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3517 sflags = first_flags;
3519 sflags = d_sample_flags;
3521 } else if (flags & TR_SAMPLE_FLAGS) {
3522 sflags = QT_UINT32 (data + flags_offset);
3524 sflags = d_sample_flags;
3527 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3528 /* Read offsets as signed numbers regardless of trun version as very
3529 * high offsets are unlikely and there are files out there that use
3530 * version=0 truns with negative offsets */
3531 ct = QT_UINT32 (data + ct_offset);
3533 /* FIXME: Set offset to 0 for "no decode samples". This needs
3534 * to be handled in a codec specific manner ideally. */
3535 if (ct == G_MININT32)
3542 /* fill the sample information */
3543 sample->offset = *running_offset;
3544 sample->pts_offset = ct;
3545 sample->size = size;
3546 sample->timestamp = timestamp;
3547 sample->duration = dur;
3548 /* sample-is-difference-sample */
3549 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3550 * now idea how it relates to bitfield other than massive LE/BE confusion */
3551 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3552 *running_offset += size;
3554 stream->duration_moof += dur;
3561 /* Shift PTS/DTS to allow for negative composition offsets while keeping
3562 * A/V sync in place. This is similar to the code handling ctts/cslg in the
3563 * non-fragmented case.
3566 stream->cslg_shift = -min_ct;
3568 stream->cslg_shift = 0;
3570 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
3571 stream->cslg_shift);
3573 /* Update total duration if needed */
3574 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3576 /* Pre-emptively figure out size of mdat based on trun information.
3577 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3578 * size, else we will still be able to use this when dealing with gap'ed
3580 qtdemux->mdatleft = *running_offset - initial_offset;
3581 qtdemux->mdatoffset = initial_offset;
3582 qtdemux->mdatsize = qtdemux->mdatleft;
3584 stream->n_samples += samples_count;
3585 stream->n_samples_moof += samples_count;
3587 if (stream->pending_seek != NULL)
3588 stream->pending_seek = NULL;
3594 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3599 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3605 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3606 "be larger than %uMB (broken file?)", stream->n_samples,
3607 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3612 /* find stream with @id */
3613 static inline QtDemuxStream *
3614 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3616 QtDemuxStream *stream;
3620 if (G_UNLIKELY (!id)) {
3621 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3625 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3626 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3627 if (stream->track_id == id)
3630 if (qtdemux->mss_mode) {
3631 /* mss should have only 1 stream anyway */
3632 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3639 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3640 guint32 * fragment_number)
3642 if (!gst_byte_reader_skip (mfhd, 4))
3644 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3649 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3655 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3656 QtDemuxStream ** stream, guint32 * default_sample_duration,
3657 guint32 * default_sample_size, guint32 * default_sample_flags,
3658 gint64 * base_offset)
3661 guint32 track_id = 0;
3663 if (!gst_byte_reader_skip (tfhd, 1) ||
3664 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3667 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3670 *stream = qtdemux_find_stream (qtdemux, track_id);
3671 if (G_UNLIKELY (!*stream))
3672 goto unknown_stream;
3674 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3675 *base_offset = qtdemux->moof_offset;
3677 if (flags & TF_BASE_DATA_OFFSET)
3678 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3681 /* obtain stream defaults */
3682 if (qtdemux_parse_trex (qtdemux, *stream,
3683 default_sample_duration, default_sample_size, default_sample_flags)) {
3685 /* Default sample description index is only valid if trex parsing succeeded */
3686 (*stream)->stsd_sample_description_id =
3687 (*stream)->def_sample_description_index - 1;
3690 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3691 guint32 sample_description_index;
3692 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3694 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3697 if (qtdemux->mss_mode) {
3698 /* mss has no stsd entry */
3699 (*stream)->stsd_sample_description_id = 0;
3702 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3703 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3706 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3707 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3710 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3711 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3718 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3723 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3729 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3730 guint64 * decode_time)
3732 guint32 version = 0;
3734 if (!gst_byte_reader_get_uint32_be (br, &version))
3739 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3742 guint32 dec_time = 0;
3743 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3745 *decode_time = dec_time;
3748 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3755 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3760 /* Returns a pointer to a GstStructure containing the properties of
3761 * the stream sample identified by @sample_index. The caller must unref
3762 * the returned object after use. Returns NULL if unsuccessful. */
3763 static GstStructure *
3764 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3765 QtDemuxStream * stream, guint sample_index)
3767 QtDemuxCencSampleSetInfo *info = NULL;
3769 g_return_val_if_fail (stream != NULL, NULL);
3770 g_return_val_if_fail (stream->protected, NULL);
3771 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3773 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3775 /* Currently, cenc properties for groups of samples are not supported, so
3776 * simply return a copy of the default sample properties */
3777 return gst_structure_copy (info->default_properties);
3780 /* Parses the sizes of sample auxiliary information contained within a stream,
3781 * as given in a saiz box. Returns array of sample_count guint8 size values,
3782 * or NULL on failure */
3784 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3785 GstByteReader * br, guint32 * sample_count)
3789 guint8 default_info_size;
3791 g_return_val_if_fail (qtdemux != NULL, NULL);
3792 g_return_val_if_fail (stream != NULL, NULL);
3793 g_return_val_if_fail (br != NULL, NULL);
3794 g_return_val_if_fail (sample_count != NULL, NULL);
3796 if (!gst_byte_reader_get_uint32_be (br, &flags))
3800 /* aux_info_type and aux_info_type_parameter are ignored */
3801 if (!gst_byte_reader_skip (br, 8))
3805 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3807 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3809 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3811 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3814 if (default_info_size == 0) {
3815 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3819 info_sizes = g_new (guint8, *sample_count);
3820 memset (info_sizes, default_info_size, *sample_count);
3826 /* Parses the offset of sample auxiliary information contained within a stream,
3827 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3829 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3830 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3835 guint32 aux_info_type = 0;
3836 guint32 aux_info_type_parameter = 0;
3837 guint32 entry_count;
3840 const guint8 *aux_info_type_data = NULL;
3842 g_return_val_if_fail (qtdemux != NULL, FALSE);
3843 g_return_val_if_fail (stream != NULL, FALSE);
3844 g_return_val_if_fail (br != NULL, FALSE);
3845 g_return_val_if_fail (offset != NULL, FALSE);
3847 if (!gst_byte_reader_get_uint8 (br, &version))
3850 if (!gst_byte_reader_get_uint24_be (br, &flags))
3855 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3857 aux_info_type = QT_FOURCC (aux_info_type_data);
3859 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3861 } else if (stream->protected) {
3862 aux_info_type = stream->protection_scheme_type;
3864 aux_info_type = CUR_STREAM (stream)->fourcc;
3868 *info_type = aux_info_type;
3869 if (info_type_parameter)
3870 *info_type_parameter = aux_info_type_parameter;
3872 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3873 "aux_info_type_parameter: %#06x",
3874 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3876 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3879 if (entry_count != 1) {
3880 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3885 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3887 *offset = (guint64) off_32;
3889 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3894 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3899 qtdemux_gst_structure_free (GstStructure * gststructure)
3902 gst_structure_free (gststructure);
3906 /* Parses auxiliary information relating to samples protected using
3907 * Common Encryption (cenc); the format of this information
3908 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3911 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3912 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3914 QtDemuxCencSampleSetInfo *ss_info = NULL;
3917 GPtrArray *old_crypto_info = NULL;
3918 guint old_entries = 0;
3920 g_return_val_if_fail (qtdemux != NULL, FALSE);
3921 g_return_val_if_fail (stream != NULL, FALSE);
3922 g_return_val_if_fail (br != NULL, FALSE);
3923 g_return_val_if_fail (stream->protected, FALSE);
3924 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3926 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3928 if (ss_info->crypto_info) {
3929 old_crypto_info = ss_info->crypto_info;
3930 /* Count number of non-null entries remaining at the tail end */
3931 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3932 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3938 ss_info->crypto_info =
3939 g_ptr_array_new_full (sample_count + old_entries,
3940 (GDestroyNotify) qtdemux_gst_structure_free);
3942 /* We preserve old entries because we parse the next moof in advance
3943 * of consuming all samples from the previous moof, and otherwise
3944 * we'd discard the corresponding crypto info for the samples
3945 * from the previous fragment. */
3947 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3949 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3950 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3952 g_ptr_array_index (old_crypto_info, i) = NULL;
3956 if (old_crypto_info) {
3957 /* Everything now belongs to the new array */
3958 g_ptr_array_free (old_crypto_info, TRUE);
3961 for (i = 0; i < sample_count; ++i) {
3962 GstStructure *properties;
3963 guint16 n_subsamples = 0;
3967 gboolean could_read_iv;
3969 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3970 if (properties == NULL) {
3971 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3974 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3975 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3976 gst_structure_free (properties);
3980 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3981 if (could_read_iv) {
3982 buf = gst_buffer_new_wrapped (data, iv_size);
3983 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3984 gst_buffer_unref (buf);
3985 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3986 const GValue *constant_iv_size_value =
3987 gst_structure_get_value (properties, "constant_iv_size");
3988 const GValue *constant_iv_value =
3989 gst_structure_get_value (properties, "iv");
3990 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3991 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3992 gst_structure_free (properties);
3995 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3996 gst_structure_remove_field (properties, "constant_iv_size");
3997 } else if (stream->protection_scheme_type == FOURCC_cenc) {
3998 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3999 gst_structure_free (properties);
4002 size = info_sizes[i];
4003 if (size > iv_size) {
4004 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
4005 || !(n_subsamples > 0)) {
4006 gst_structure_free (properties);
4007 GST_ERROR_OBJECT (qtdemux,
4008 "failed to get subsample count for sample %u", i);
4011 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
4012 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
4013 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
4015 gst_structure_free (properties);
4018 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
4020 gst_structure_free (properties);
4023 gst_structure_set (properties,
4024 "subsample_count", G_TYPE_UINT, n_subsamples,
4025 "subsamples", GST_TYPE_BUFFER, buf, NULL);
4026 gst_buffer_unref (buf);
4028 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
4030 g_ptr_array_add (ss_info->crypto_info, properties);
4035 /* Converts a UUID in raw byte form to a string representation, as defined in
4036 * RFC 4122. The caller takes ownership of the returned string and is
4037 * responsible for freeing it after use. */
4039 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
4041 const guint8 *uuid = (const guint8 *) uuid_bytes;
4043 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
4044 "%02x%02x-%02x%02x%02x%02x%02x%02x",
4045 uuid[0], uuid[1], uuid[2], uuid[3],
4046 uuid[4], uuid[5], uuid[6], uuid[7],
4047 uuid[8], uuid[9], uuid[10], uuid[11],
4048 uuid[12], uuid[13], uuid[14], uuid[15]);
4051 /* Parses a Protection System Specific Header box (pssh), as defined in the
4052 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
4053 * information needed by a specific content protection system in order to
4054 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
4057 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4059 gchar *sysid_string;
4060 guint32 pssh_size = QT_UINT32 (node->data);
4061 GstBuffer *pssh = NULL;
4062 GstEvent *event = NULL;
4063 guint32 parent_box_type;
4066 if (G_UNLIKELY (pssh_size < 32U)) {
4067 GST_ERROR_OBJECT (qtdemux, "invalid box size");
4072 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4074 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4076 pssh = gst_buffer_new_memdup (node->data, pssh_size);
4077 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4078 gst_buffer_get_size (pssh));
4080 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4082 /* Push an event containing the pssh box onto the queues of all streams. */
4083 event = gst_event_new_protection (sysid_string, pssh,
4084 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4085 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4086 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4087 GST_TRACE_OBJECT (qtdemux,
4088 "adding protection event for stream %s and system %s",
4089 stream->stream_id, sysid_string);
4090 g_queue_push_tail (&stream->protection_scheme_event_queue,
4091 gst_event_ref (event));
4093 g_free (sysid_string);
4094 gst_event_unref (event);
4095 gst_buffer_unref (pssh);
4100 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4101 guint64 moof_offset, QtDemuxStream * stream)
4103 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4105 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4106 GNode *saiz_node, *saio_node, *pssh_node;
4107 GstByteReader saiz_data, saio_data;
4108 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4109 gint64 base_offset, running_offset;
4111 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4113 /* NOTE @stream ignored */
4115 moof_node = g_node_new ((guint8 *) buffer);
4116 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4117 qtdemux_node_dump (qtdemux, moof_node);
4119 /* Get fragment number from mfhd and check it's valid */
4121 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4122 if (mfhd_node == NULL)
4124 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4126 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4128 /* unknown base_offset to start with */
4129 base_offset = running_offset = -1;
4130 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4132 guint64 decode_time = 0;
4134 /* Fragment Header node */
4136 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4140 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4141 &ds_size, &ds_flags, &base_offset))
4144 /* The following code assumes at most a single set of sample auxiliary
4145 * data in the fragment (consisting of a saiz box and a corresponding saio
4146 * box); in theory, however, there could be multiple sets of sample
4147 * auxiliary data in a fragment. */
4149 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4152 guint32 info_type = 0;
4154 guint32 info_type_parameter = 0;
4156 g_free (qtdemux->cenc_aux_info_sizes);
4158 qtdemux->cenc_aux_info_sizes =
4159 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4160 &qtdemux->cenc_aux_sample_count);
4161 if (qtdemux->cenc_aux_info_sizes == NULL) {
4162 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4166 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4169 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4170 g_free (qtdemux->cenc_aux_info_sizes);
4171 qtdemux->cenc_aux_info_sizes = NULL;
4175 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4176 &info_type, &info_type_parameter, &offset))) {
4177 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4178 g_free (qtdemux->cenc_aux_info_sizes);
4179 qtdemux->cenc_aux_info_sizes = NULL;
4182 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4183 offset += (guint64) (base_offset - qtdemux->moof_offset);
4184 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4185 && info_type_parameter == 0U) {
4187 if (offset > length) {
4188 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4189 qtdemux->cenc_aux_info_offset = offset;
4191 gst_byte_reader_init (&br, buffer + offset, length - offset);
4192 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4193 qtdemux->cenc_aux_info_sizes,
4194 qtdemux->cenc_aux_sample_count)) {
4195 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4196 g_free (qtdemux->cenc_aux_info_sizes);
4197 qtdemux->cenc_aux_info_sizes = NULL;
4205 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4208 /* We'll use decode_time to interpolate timestamps
4209 * in case the input timestamps are missing */
4210 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4212 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4213 " (%" GST_TIME_FORMAT ")", decode_time,
4214 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4215 decode_time) : GST_CLOCK_TIME_NONE));
4217 /* Discard the fragment buffer timestamp info to avoid using it.
4218 * Rely on tfdt instead as it is more accurate than the timestamp
4219 * that is fetched from a manifest/playlist and is usually
4221 qtdemux->fragment_start = -1;
4224 if (G_UNLIKELY (!stream)) {
4225 /* we lost track of offset, we'll need to regain it,
4226 * but can delay complaining until later or avoid doing so altogether */
4230 if (G_UNLIKELY (base_offset < -1))
4233 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4235 if (!qtdemux->pullbased) {
4236 /* Sample tables can grow enough to be problematic if the system memory
4237 * is very low (e.g. embedded devices) and the videos very long
4238 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4239 * Fortunately, we can easily discard them for each new fragment when
4240 * we know qtdemux will not receive seeks outside of the current fragment.
4241 * adaptivedemux honors this assumption.
4242 * This optimization is also useful for applications that use qtdemux as
4243 * a push-based simple demuxer, like Media Source Extensions. */
4244 gst_qtdemux_stream_flush_samples_data (stream);
4247 /* initialise moof sample data */
4248 stream->n_samples_moof = 0;
4249 stream->duration_last_moof = stream->duration_moof;
4250 stream->duration_moof = 0;
4252 /* Track Run node */
4254 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4257 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4258 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4259 &running_offset, decode_time, (tfdt_node != NULL));
4260 /* iterate all siblings */
4261 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4263 /* don't use tfdt for subsequent trun as it only refers to the first */
4267 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4269 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4270 guint32 box_length = QT_UINT32 (uuid_buffer);
4272 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4275 /* if no new base_offset provided for next traf,
4276 * base is end of current traf */
4277 base_offset = running_offset;
4278 running_offset = -1;
4280 if (stream->n_samples_moof && stream->duration_moof)
4281 stream->new_caps = TRUE;
4284 /* iterate all siblings */
4285 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4288 /* parse any protection system info */
4289 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4291 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4292 qtdemux_parse_pssh (qtdemux, pssh_node);
4293 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4296 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4297 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4299 /* Unless the user has explicitly requested another seek, perform an
4300 * internal seek to the time specified in the tfdt.
4302 * This way if the user opens a file where the first tfdt is 1 hour
4303 * into the presentation, they will not have to wait 1 hour for run
4304 * time to catch up and actual playback to start. */
4307 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4308 "performing an internal seek to %" GST_TIME_FORMAT,
4309 GST_TIME_ARGS (min_dts));
4311 qtdemux->segment.start = min_dts;
4312 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4314 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4315 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4316 stream->time_position = min_dts;
4319 /* Before this code was run a segment was already sent when the moov was
4320 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4321 * be emitted after a moov, and we can emit a second segment anyway for
4322 * special cases like this. */
4323 qtdemux->need_segment = TRUE;
4326 qtdemux->first_moof_already_parsed = TRUE;
4328 g_node_destroy (moof_node);
4333 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4338 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4343 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4348 g_node_destroy (moof_node);
4349 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4350 (_("This file is corrupt and cannot be played.")), (NULL));
4356 /* might be used if some day we actually use mfra & co
4357 * for random access to fragments,
4358 * but that will require quite some modifications and much less relying
4359 * on a sample array */
4363 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4365 QtDemuxStream *stream;
4366 guint32 ver_flags, track_id, len, num_entries, i;
4367 guint value_size, traf_size, trun_size, sample_size;
4368 guint64 time = 0, moof_offset = 0;
4370 GstBuffer *buf = NULL;
4375 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4377 if (!gst_byte_reader_skip (&tfra, 8))
4380 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4383 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4384 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4385 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4388 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4390 stream = qtdemux_find_stream (qtdemux, track_id);
4392 goto unknown_trackid;
4394 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4395 sample_size = (len & 3) + 1;
4396 trun_size = ((len & 12) >> 2) + 1;
4397 traf_size = ((len & 48) >> 4) + 1;
4399 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4400 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4402 if (num_entries == 0)
4405 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4406 value_size + value_size + traf_size + trun_size + sample_size))
4409 g_free (stream->ra_entries);
4410 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4411 stream->n_ra_entries = num_entries;
4413 for (i = 0; i < num_entries; i++) {
4414 qt_atom_parser_get_offset (&tfra, value_size, &time);
4415 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4416 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4417 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4418 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4420 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4422 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4423 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4425 stream->ra_entries[i].ts = time;
4426 stream->ra_entries[i].moof_offset = moof_offset;
4428 /* don't want to go through the entire file and read all moofs at startup */
4430 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4431 if (ret != GST_FLOW_OK)
4433 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4434 moof_offset, stream);
4435 gst_buffer_unref (buf);
4439 check_update_duration (qtdemux, time);
4446 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4451 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4456 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4462 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4464 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4465 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4466 GstBuffer *mfro = NULL, *mfra = NULL;
4468 gboolean ret = FALSE;
4469 GNode *mfra_node, *tfra_node;
4470 guint64 mfra_offset = 0;
4471 guint32 fourcc, mfra_size;
4474 /* query upstream size in bytes */
4475 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4476 goto size_query_failed;
4478 /* mfro box should be at the very end of the file */
4479 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4480 if (flow != GST_FLOW_OK)
4483 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4485 fourcc = QT_FOURCC (mfro_map.data + 4);
4486 if (fourcc != FOURCC_mfro)
4489 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4490 if (mfro_map.size < 16)
4491 goto invalid_mfro_size;
4493 mfra_size = QT_UINT32 (mfro_map.data + 12);
4494 if (mfra_size >= len)
4495 goto invalid_mfra_size;
4497 mfra_offset = len - mfra_size;
4499 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4500 mfra_offset, mfra_size);
4502 /* now get and parse mfra box */
4503 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4504 if (flow != GST_FLOW_OK)
4507 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4509 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4510 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4512 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4515 qtdemux_parse_tfra (qtdemux, tfra_node);
4516 /* iterate all siblings */
4517 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4519 g_node_destroy (mfra_node);
4521 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4527 if (mfro_map.memory != NULL)
4528 gst_buffer_unmap (mfro, &mfro_map);
4529 gst_buffer_unref (mfro);
4532 if (mfra_map.memory != NULL)
4533 gst_buffer_unmap (mfra, &mfra_map);
4534 gst_buffer_unref (mfra);
4541 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4546 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4551 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4556 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4562 add_offset (guint64 offset, guint64 advance)
4564 /* Avoid 64-bit overflow by clamping */
4565 if (offset > G_MAXUINT64 - advance)
4567 return offset + advance;
4570 static GstFlowReturn
4571 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4575 GstBuffer *buf = NULL;
4576 GstFlowReturn ret = GST_FLOW_OK;
4577 guint64 cur_offset = qtdemux->offset;
4580 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4581 if (G_UNLIKELY (ret != GST_FLOW_OK))
4583 gst_buffer_map (buf, &map, GST_MAP_READ);
4584 if (G_LIKELY (map.size >= 8))
4585 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4586 gst_buffer_unmap (buf, &map);
4587 gst_buffer_unref (buf);
4589 /* maybe we already got most we needed, so only consider this eof */
4590 if (G_UNLIKELY (length == 0)) {
4591 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4592 (_("Invalid atom size.")),
4593 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4594 GST_FOURCC_ARGS (fourcc)));
4601 /* record for later parsing when needed */
4602 if (!qtdemux->moof_offset) {
4603 qtdemux->moof_offset = qtdemux->offset;
4605 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4608 qtdemux->offset += length; /* skip moof and keep going */
4610 if (qtdemux->got_moov) {
4611 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4623 GST_LOG_OBJECT (qtdemux,
4624 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4625 GST_FOURCC_ARGS (fourcc), cur_offset);
4626 qtdemux->offset = add_offset (qtdemux->offset, length);
4631 GstBuffer *moov = NULL;
4633 if (qtdemux->got_moov) {
4634 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4635 qtdemux->offset = add_offset (qtdemux->offset, length);
4639 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4640 if (ret != GST_FLOW_OK)
4642 gst_buffer_map (moov, &map, GST_MAP_READ);
4644 if (length != map.size) {
4645 /* Some files have a 'moov' atom at the end of the file which contains
4646 * a terminal 'free' atom where the body of the atom is missing.
4647 * Check for, and permit, this special case.
4649 if (map.size >= 8) {
4650 guint8 *final_data = map.data + (map.size - 8);
4651 guint32 final_length = QT_UINT32 (final_data);
4652 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4654 if (final_fourcc == FOURCC_free
4655 && map.size + final_length - 8 == length) {
4656 /* Ok, we've found that special case. Allocate a new buffer with
4657 * that free atom actually present. */
4658 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4659 gst_buffer_fill (newmoov, 0, map.data, map.size);
4660 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4661 gst_buffer_unmap (moov, &map);
4662 gst_buffer_unref (moov);
4664 gst_buffer_map (moov, &map, GST_MAP_READ);
4669 if (length != map.size) {
4670 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4671 (_("This file is incomplete and cannot be played.")),
4672 ("We got less than expected (received %" G_GSIZE_FORMAT
4673 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4674 (guint) length, cur_offset));
4675 gst_buffer_unmap (moov, &map);
4676 gst_buffer_unref (moov);
4677 ret = GST_FLOW_ERROR;
4680 qtdemux->offset += length;
4682 qtdemux_parse_moov (qtdemux, map.data, length);
4683 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4685 qtdemux_parse_tree (qtdemux);
4686 if (qtdemux->moov_node_compressed) {
4687 g_node_destroy (qtdemux->moov_node_compressed);
4688 g_free (qtdemux->moov_node->data);
4690 qtdemux->moov_node_compressed = NULL;
4691 g_node_destroy (qtdemux->moov_node);
4692 qtdemux->moov_node = NULL;
4693 gst_buffer_unmap (moov, &map);
4694 gst_buffer_unref (moov);
4695 qtdemux->got_moov = TRUE;
4701 GstBuffer *ftyp = NULL;
4703 /* extract major brand; might come in handy for ISO vs QT issues */
4704 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4705 if (ret != GST_FLOW_OK)
4707 qtdemux->offset += length;
4708 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4709 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4710 gst_buffer_unmap (ftyp, &map);
4711 gst_buffer_unref (ftyp);
4716 GstBuffer *styp = NULL;
4718 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &styp);
4719 if (ret != GST_FLOW_OK)
4721 qtdemux->offset += length;
4722 gst_buffer_map (styp, &map, GST_MAP_READ);
4723 qtdemux_parse_styp (qtdemux, map.data, map.size);
4724 gst_buffer_unmap (styp, &map);
4725 gst_buffer_unref (styp);
4730 GstBuffer *uuid = NULL;
4732 /* uuid are extension atoms */
4733 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4734 if (ret != GST_FLOW_OK)
4736 qtdemux->offset += length;
4737 gst_buffer_map (uuid, &map, GST_MAP_READ);
4738 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4739 gst_buffer_unmap (uuid, &map);
4740 gst_buffer_unref (uuid);
4745 GstBuffer *sidx = NULL;
4746 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4747 if (ret != GST_FLOW_OK)
4749 qtdemux->offset += length;
4750 gst_buffer_map (sidx, &map, GST_MAP_READ);
4751 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4752 gst_buffer_unmap (sidx, &map);
4753 gst_buffer_unref (sidx);
4758 GstBuffer *meta = NULL;
4759 GNode *node, *child;
4760 GstByteReader child_data;
4761 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &meta);
4762 if (ret != GST_FLOW_OK)
4764 qtdemux->offset += length;
4765 gst_buffer_map (meta, &map, GST_MAP_READ);
4767 node = g_node_new (map.data);
4769 qtdemux_parse_node (qtdemux, node, map.data, map.size);
4771 /* Parse ONVIF Export File Format CorrectStartTime box if available */
4773 qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb,
4775 qtdemux_parse_cstb (qtdemux, &child_data);
4778 g_node_destroy (node);
4780 gst_buffer_unmap (meta, &map);
4781 gst_buffer_unref (meta);
4786 GstBuffer *unknown = NULL;
4788 GST_LOG_OBJECT (qtdemux,
4789 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4790 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4792 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4793 if (ret != GST_FLOW_OK)
4795 gst_buffer_map (unknown, &map, GST_MAP_READ);
4796 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4797 gst_buffer_unmap (unknown, &map);
4798 gst_buffer_unref (unknown);
4799 qtdemux->offset += length;
4805 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4806 /* digested all data, show what we have */
4807 qtdemux_prepare_streams (qtdemux);
4808 QTDEMUX_EXPOSE_LOCK (qtdemux);
4809 ret = qtdemux_expose_streams (qtdemux);
4810 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4812 qtdemux->state = QTDEMUX_STATE_MOVIE;
4813 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4820 /* Seeks to the previous keyframe of the indexed stream and
4821 * aligns other streams with respect to the keyframe timestamp
4822 * of indexed stream. Only called in case of Reverse Playback
4824 static GstFlowReturn
4825 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4827 guint32 seg_idx = 0, k_index = 0;
4828 guint32 ref_seg_idx, ref_k_index;
4829 GstClockTime k_pos = 0, last_stop = 0;
4830 QtDemuxSegment *seg = NULL;
4831 QtDemuxStream *ref_str = NULL;
4832 guint64 seg_media_start_mov; /* segment media start time in mov format */
4836 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4837 * and finally align all the other streams on that timestamp with their
4838 * respective keyframes */
4839 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4840 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4842 /* No candidate yet, take the first stream */
4848 /* So that stream has a segment, we prefer video streams */
4849 if (str->subtype == FOURCC_vide) {
4855 if (G_UNLIKELY (!ref_str)) {
4856 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4860 if (G_UNLIKELY (!ref_str->from_sample)) {
4861 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4865 /* So that stream has been playing from from_sample to to_sample. We will
4866 * get the timestamp of the previous sample and search for a keyframe before
4867 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4868 if (ref_str->subtype == FOURCC_vide) {
4869 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4870 ref_str->from_sample - 1, FALSE);
4872 if (ref_str->from_sample >= 10)
4873 k_index = ref_str->from_sample - 10;
4879 ref_str->samples[k_index].timestamp +
4880 ref_str->samples[k_index].pts_offset;
4882 /* get current segment for that stream */
4883 seg = &ref_str->segments[ref_str->segment_index];
4884 /* Use segment start in original timescale for comparisons */
4885 seg_media_start_mov = seg->trak_media_start;
4887 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4888 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4889 k_index, target_ts, seg_media_start_mov,
4890 GST_TIME_ARGS (seg->media_start));
4892 /* Crawl back through segments to find the one containing this I frame */
4893 while (target_ts < seg_media_start_mov) {
4894 GST_DEBUG_OBJECT (qtdemux,
4895 "keyframe position (sample %u) is out of segment %u " " target %"
4896 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4897 ref_str->segment_index, target_ts, seg_media_start_mov);
4899 if (G_UNLIKELY (!ref_str->segment_index)) {
4900 /* Reached first segment, let's consider it's EOS */
4903 ref_str->segment_index--;
4904 seg = &ref_str->segments[ref_str->segment_index];
4905 /* Use segment start in original timescale for comparisons */
4906 seg_media_start_mov = seg->trak_media_start;
4908 /* Calculate time position of the keyframe and where we should stop */
4910 QTSTREAMTIME_TO_GSTTIME (ref_str,
4911 target_ts - seg->trak_media_start) + seg->time;
4913 QTSTREAMTIME_TO_GSTTIME (ref_str,
4914 ref_str->samples[ref_str->from_sample].timestamp -
4915 seg->trak_media_start) + seg->time;
4917 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4918 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4919 k_index, GST_TIME_ARGS (k_pos));
4921 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4922 qtdemux->segment.position = last_stop;
4923 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4924 GST_TIME_ARGS (last_stop));
4926 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4927 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4931 ref_seg_idx = ref_str->segment_index;
4932 ref_k_index = k_index;
4934 /* Align them all on this */
4935 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4937 GstClockTime seg_time = 0;
4938 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4940 /* aligning reference stream again might lead to backing up to yet another
4941 * keyframe (due to timestamp rounding issues),
4942 * potentially putting more load on downstream; so let's try to avoid */
4943 if (str == ref_str) {
4944 seg_idx = ref_seg_idx;
4945 seg = &str->segments[seg_idx];
4946 k_index = ref_k_index;
4947 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4948 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4950 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4951 GST_DEBUG_OBJECT (qtdemux,
4952 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4953 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4955 /* get segment and time in the segment */
4956 seg = &str->segments[seg_idx];
4957 seg_time = k_pos - seg->time;
4959 /* get the media time in the segment.
4960 * No adjustment for empty "filler" segments */
4961 if (seg->media_start != GST_CLOCK_TIME_NONE)
4962 seg_time += seg->media_start;
4964 /* get the index of the sample with media time */
4965 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4966 GST_DEBUG_OBJECT (qtdemux,
4967 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4968 GST_TIME_ARGS (seg_time), index);
4970 /* find previous keyframe */
4971 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4974 /* Remember until where we want to go */
4975 str->to_sample = str->from_sample - 1;
4976 /* Define our time position */
4978 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4979 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4980 if (seg->media_start != GST_CLOCK_TIME_NONE)
4981 str->time_position -= seg->media_start;
4983 /* Now seek back in time */
4984 gst_qtdemux_move_stream (qtdemux, str, k_index);
4985 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4986 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4987 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4993 return GST_FLOW_EOS;
4997 * Gets the current qt segment start, stop and position for the
4998 * given time offset. This is used in update_segment()
5001 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
5002 QtDemuxStream * stream, GstClockTime offset,
5003 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
5005 GstClockTime seg_time;
5006 GstClockTime start, stop, time;
5007 QtDemuxSegment *segment;
5009 segment = &stream->segments[stream->segment_index];
5011 /* get time in this segment */
5012 seg_time = (offset - segment->time) * segment->rate;
5014 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
5015 GST_TIME_ARGS (seg_time));
5017 if (G_UNLIKELY (seg_time > segment->duration)) {
5018 GST_LOG_OBJECT (stream->pad,
5019 "seg_time > segment->duration %" GST_TIME_FORMAT,
5020 GST_TIME_ARGS (segment->duration));
5021 seg_time = segment->duration;
5024 /* qtdemux->segment.stop is in outside-time-realm, whereas
5025 * segment->media_stop is in track-time-realm.
5027 * In order to compare the two, we need to bring segment.stop
5028 * into the track-time-realm
5030 * FIXME - does this comment still hold? Don't see any conversion here */
5032 stop = qtdemux->segment.stop;
5033 if (stop == GST_CLOCK_TIME_NONE)
5034 stop = qtdemux->segment.duration;
5035 if (stop == GST_CLOCK_TIME_NONE)
5036 stop = segment->media_stop;
5039 MIN (segment->media_stop, stop - segment->time + segment->media_start);
5041 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5042 start = segment->time + seg_time;
5044 stop = start - seg_time + segment->duration;
5045 } else if (qtdemux->segment.rate >= 0) {
5046 start = MIN (segment->media_start + seg_time, stop);
5049 if (segment->media_start >= qtdemux->segment.start) {
5050 time = segment->time;
5052 time = segment->time + (qtdemux->segment.start - segment->media_start);
5055 start = MAX (segment->media_start, qtdemux->segment.start);
5056 stop = MIN (segment->media_start + seg_time, stop);
5065 * Updates the qt segment used for the stream and pushes a new segment event
5066 * downstream on this stream's pad.
5069 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5070 gint seg_idx, GstClockTime offset, GstClockTime * _start,
5071 GstClockTime * _stop)
5073 QtDemuxSegment *segment;
5074 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
5078 /* update the current segment */
5079 stream->segment_index = seg_idx;
5081 /* get the segment */
5082 segment = &stream->segments[seg_idx];
5084 if (G_UNLIKELY (offset < segment->time)) {
5085 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
5086 GST_TIME_ARGS (segment->time));
5090 /* segment lies beyond total indicated duration */
5091 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5092 segment->time > qtdemux->segment.duration)) {
5093 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5094 " < segment->time %" GST_TIME_FORMAT,
5095 GST_TIME_ARGS (qtdemux->segment.duration),
5096 GST_TIME_ARGS (segment->time));
5100 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5101 &start, &stop, &time);
5103 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5104 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5105 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5107 /* combine global rate with that of the segment */
5108 rate = segment->rate * qtdemux->segment.rate;
5110 /* Copy flags from main segment */
5111 stream->segment.flags = qtdemux->segment.flags;
5113 /* update the segment values used for clipping */
5114 stream->segment.offset = qtdemux->segment.offset;
5115 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5116 stream->segment.applied_rate = qtdemux->segment.applied_rate;
5117 stream->segment.rate = rate;
5118 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5119 stream->cslg_shift);
5121 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5122 stream->cslg_shift);
5124 stream->segment.stop = stop;
5125 stream->segment.time = time;
5126 stream->segment.position = stream->segment.start;
5128 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5131 /* now prepare and send the segment */
5133 event = gst_event_new_segment (&stream->segment);
5134 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5135 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5137 gst_pad_push_event (stream->pad, event);
5138 /* assume we can send more data now */
5139 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5140 /* clear to send tags on this pad now */
5141 gst_qtdemux_push_tags (qtdemux, stream);
5152 /* activate the given segment number @seg_idx of @stream at time @offset.
5153 * @offset is an absolute global position over all the segments.
5155 * This will push out a NEWSEGMENT event with the right values and
5156 * position the stream index to the first decodable sample before
5160 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5161 guint32 seg_idx, GstClockTime offset)
5163 QtDemuxSegment *segment;
5164 guint32 index, kf_index;
5165 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5167 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5168 seg_idx, GST_TIME_ARGS (offset));
5170 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5174 segment = &stream->segments[stream->segment_index];
5176 /* in the fragmented case, we pick a fragment that starts before our
5177 * desired position and rely on downstream to wait for a keyframe
5178 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5179 * tfra entries tells us which trun/sample the key unit is in, but we don't
5180 * make use of this additional information at the moment) */
5181 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5182 stream->to_sample = G_MAXUINT32;
5185 /* well, it will be taken care of below */
5186 qtdemux->fragmented_seek_pending = FALSE;
5187 /* FIXME ideally the do_fragmented_seek can be done right here,
5188 * rather than at loop level
5189 * (which might even allow handling edit lists in a fragmented file) */
5192 /* We don't need to look for a sample in push-based */
5193 if (!qtdemux->pullbased)
5196 /* and move to the keyframe before the indicated media time of the
5198 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5199 if (qtdemux->segment.rate >= 0) {
5200 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5201 stream->to_sample = G_MAXUINT32;
5202 GST_DEBUG_OBJECT (stream->pad,
5203 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5204 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5205 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5207 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5208 stream->to_sample = index;
5209 GST_DEBUG_OBJECT (stream->pad,
5210 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5211 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5212 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5215 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5216 "this is an empty segment");
5220 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5221 * encountered an error and printed a message so we return appropriately */
5225 /* we're at the right spot */
5226 if (index == stream->sample_index) {
5227 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5231 /* find keyframe of the target index */
5232 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5234 /* go back two frames to provide lead-in for non-raw audio decoders */
5235 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5236 guint32 lead_in = 2;
5237 guint32 old_index = kf_index;
5238 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5240 if (gst_structure_has_name (s, "audio/mpeg")) {
5242 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5243 && mpegversion == 1) {
5244 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5249 kf_index = MAX (kf_index, lead_in) - lead_in;
5250 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5251 GST_DEBUG_OBJECT (stream->pad,
5252 "Moving backwards %u frames to ensure sufficient sound lead-in",
5253 old_index - kf_index);
5255 kf_index = old_index;
5259 /* if we move forwards, we don't have to go back to the previous
5260 * keyframe since we already sent that. We can also just jump to
5261 * the keyframe right before the target index if there is one. */
5262 if (index > stream->sample_index) {
5263 /* moving forwards check if we move past a keyframe */
5264 if (kf_index > stream->sample_index) {
5265 GST_DEBUG_OBJECT (stream->pad,
5266 "moving forwards to keyframe at %u "
5267 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5269 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5270 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5271 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5273 GST_DEBUG_OBJECT (stream->pad,
5274 "moving forwards, keyframe at %u "
5275 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5277 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5278 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5281 GST_DEBUG_OBJECT (stream->pad,
5282 "moving backwards to %sframe at %u "
5283 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5284 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5285 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5286 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5287 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5293 /* prepare to get the current sample of @stream, getting essential values.
5295 * This function will also prepare and send the segment when needed.
5297 * Return FALSE if the stream is EOS.
5302 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5303 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5304 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5305 gboolean * keyframe)
5307 QtDemuxSample *sample;
5308 GstClockTime time_position;
5311 g_return_val_if_fail (stream != NULL, FALSE);
5313 time_position = stream->time_position;
5314 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5317 seg_idx = stream->segment_index;
5318 if (G_UNLIKELY (seg_idx == -1)) {
5319 /* find segment corresponding to time_position if we are looking
5321 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5324 /* different segment, activate it, sample_index will be set. */
5325 if (G_UNLIKELY (stream->segment_index != seg_idx))
5326 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5328 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5329 segments[stream->segment_index]))) {
5330 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5332 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5333 " prepare empty sample");
5336 *pts = *dts = time_position;
5337 *duration = seg->duration - (time_position - seg->time);
5344 if (stream->sample_index == -1)
5345 stream->sample_index = 0;
5347 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5348 stream->sample_index, stream->n_samples);
5350 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5351 if (!qtdemux->fragmented)
5354 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5358 GST_OBJECT_LOCK (qtdemux);
5359 flow = qtdemux_add_fragmented_samples (qtdemux);
5360 GST_OBJECT_UNLOCK (qtdemux);
5362 if (flow != GST_FLOW_OK)
5365 while (stream->sample_index >= stream->n_samples);
5368 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5369 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5370 stream->sample_index);
5374 /* now get the info for the sample we're at */
5375 sample = &stream->samples[stream->sample_index];
5377 *dts = QTSAMPLE_DTS (stream, sample);
5378 *pts = QTSAMPLE_PTS (stream, sample);
5379 *offset = sample->offset;
5380 *size = sample->size;
5381 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5382 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5389 stream->time_position = GST_CLOCK_TIME_NONE;
5394 /* move to the next sample in @stream.
5396 * Moves to the next segment when needed.
5399 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5401 QtDemuxSample *sample;
5402 QtDemuxSegment *segment;
5404 /* get current segment */
5405 segment = &stream->segments[stream->segment_index];
5407 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5408 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5412 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5413 /* Mark the stream as EOS */
5414 GST_DEBUG_OBJECT (qtdemux,
5415 "reached max allowed sample %u, mark EOS", stream->to_sample);
5416 stream->time_position = GST_CLOCK_TIME_NONE;
5420 /* move to next sample */
5421 stream->sample_index++;
5422 stream->offset_in_sample = 0;
5424 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5427 /* reached the last sample, we need the next segment */
5428 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5431 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5432 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5433 stream->sample_index);
5437 /* get next sample */
5438 sample = &stream->samples[stream->sample_index];
5440 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5441 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5442 GST_TIME_ARGS (segment->media_stop));
5444 /* see if we are past the segment */
5445 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5448 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5449 /* inside the segment, update time_position, looks very familiar to
5450 * GStreamer segments, doesn't it? */
5451 stream->time_position =
5452 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5454 /* not yet in segment, time does not yet increment. This means
5455 * that we are still prerolling keyframes to the decoder so it can
5456 * decode the first sample of the segment. */
5457 stream->time_position = segment->time;
5461 /* move to the next segment */
5464 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5466 if (stream->segment_index == stream->n_segments - 1) {
5467 /* are we at the end of the last segment, we're EOS */
5468 stream->time_position = GST_CLOCK_TIME_NONE;
5470 /* else we're only at the end of the current segment */
5471 stream->time_position = segment->stop_time;
5473 /* make sure we select a new segment */
5475 /* accumulate previous segments */
5476 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5477 stream->accumulated_base +=
5478 (stream->segment.stop -
5479 stream->segment.start) / ABS (stream->segment.rate);
5481 stream->segment_index = -1;
5486 gst_qtdemux_sync_streams (GstQTDemux * demux)
5490 if (QTDEMUX_N_STREAMS (demux) <= 1)
5493 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5494 QtDemuxStream *stream;
5495 GstClockTime end_time;
5497 stream = QTDEMUX_NTH_STREAM (demux, i);
5502 /* TODO advance time on subtitle streams here, if any some day */
5504 /* some clips/trailers may have unbalanced streams at the end,
5505 * so send EOS on shorter stream to prevent stalling others */
5507 /* do not mess with EOS if SEGMENT seeking */
5508 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5511 if (demux->pullbased) {
5512 /* loop mode is sample time based */
5513 if (!STREAM_IS_EOS (stream))
5516 /* push mode is byte position based */
5517 if (stream->n_samples &&
5518 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5522 if (stream->sent_eos)
5525 /* only act if some gap */
5526 end_time = stream->segments[stream->n_segments - 1].stop_time;
5527 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5528 ", stream end: %" GST_TIME_FORMAT,
5529 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5530 if (GST_CLOCK_TIME_IS_VALID (end_time)
5531 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5534 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5535 GST_PAD_NAME (stream->pad));
5536 stream->sent_eos = TRUE;
5537 event = gst_event_new_eos ();
5538 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5539 gst_event_set_seqnum (event, demux->segment_seqnum);
5540 gst_pad_push_event (stream->pad, event);
5545 /* EOS and NOT_LINKED need to be combined. This means that we return:
5547 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5548 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5550 static GstFlowReturn
5551 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5554 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5557 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5560 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5562 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5566 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5567 * completely clipped
5569 * Should be used only with raw buffers */
5571 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5574 guint64 start, stop, cstart, cstop, diff;
5575 GstClockTime pts, duration;
5577 gint num_rate, denom_rate;
5582 osize = size = gst_buffer_get_size (buf);
5585 /* depending on the type, setup the clip parameters */
5586 if (stream->subtype == FOURCC_soun) {
5587 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5588 num_rate = GST_SECOND;
5589 denom_rate = (gint) CUR_STREAM (stream)->rate;
5591 } else if (stream->subtype == FOURCC_vide) {
5593 num_rate = CUR_STREAM (stream)->fps_n;
5594 denom_rate = CUR_STREAM (stream)->fps_d;
5599 if (frame_size <= 0)
5600 goto bad_frame_size;
5602 /* we can only clip if we have a valid pts */
5603 pts = GST_BUFFER_PTS (buf);
5604 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5607 duration = GST_BUFFER_DURATION (buf);
5609 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5611 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5615 stop = start + duration;
5617 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5618 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5621 /* see if some clipping happened */
5622 diff = cstart - start;
5628 /* bring clipped time to samples and to bytes */
5629 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5632 GST_DEBUG_OBJECT (qtdemux,
5633 "clipping start to %" GST_TIME_FORMAT " %"
5634 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5640 diff = stop - cstop;
5645 /* bring clipped time to samples and then to bytes */
5646 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5648 GST_DEBUG_OBJECT (qtdemux,
5649 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5650 " bytes", GST_TIME_ARGS (cstop), diff);
5655 if (offset != 0 || size != osize)
5656 gst_buffer_resize (buf, offset, size);
5658 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5659 GST_BUFFER_PTS (buf) = pts;
5660 GST_BUFFER_DURATION (buf) = duration;
5664 /* dropped buffer */
5667 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5672 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5677 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5682 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5683 gst_buffer_unref (buf);
5689 gst_qtdemux_align_buffer (GstQTDemux * demux,
5690 GstBuffer * buffer, gsize alignment)
5694 gst_buffer_map (buffer, &map, GST_MAP_READ);
5696 if (map.size < sizeof (guintptr)) {
5697 gst_buffer_unmap (buffer, &map);
5701 if (((guintptr) map.data) & (alignment - 1)) {
5702 GstBuffer *new_buffer;
5703 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5705 new_buffer = gst_buffer_new_allocate (NULL,
5706 gst_buffer_get_size (buffer), ¶ms);
5708 /* Copy data "by hand", so ensure alignment is kept: */
5709 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5711 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5712 GST_DEBUG_OBJECT (demux,
5713 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5716 gst_buffer_unmap (buffer, &map);
5717 gst_buffer_unref (buffer);
5722 gst_buffer_unmap (buffer, &map);
5727 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5733 /* We are converting from pairs to triplets */
5734 *res = ccpair_size / 2 * 3;
5735 storage = g_malloc (*res);
5736 for (i = 0; i * 2 < ccpair_size; i += 1) {
5737 /* FIXME: Use line offset 0 as we simply can't know here */
5739 storage[i * 3] = 0x80 | 0x00;
5741 storage[i * 3] = 0x00 | 0x00;
5742 storage[i * 3 + 1] = ccpair[i * 2];
5743 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5750 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5754 guint32 atom_length, fourcc;
5755 QtDemuxStreamStsdEntry *stsd_entry;
5757 GST_MEMDUMP ("caption atom", data, size);
5759 /* There might be multiple atoms */
5764 atom_length = QT_UINT32 (data);
5765 fourcc = QT_FOURCC (data + 4);
5766 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5769 GST_DEBUG_OBJECT (stream->pad, "here");
5771 /* Check if we have something compatible */
5772 stsd_entry = CUR_STREAM (stream);
5773 switch (stsd_entry->fourcc) {
5775 guint8 *cdat = NULL, *cdt2 = NULL;
5776 gsize cdat_size = 0, cdt2_size = 0;
5777 /* Should be cdat or cdt2 */
5778 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5779 GST_WARNING_OBJECT (stream->pad,
5780 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5781 GST_FOURCC_ARGS (fourcc));
5785 /* Convert to S334-1 Annex A byte triplet */
5786 if (fourcc == FOURCC_cdat)
5787 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5789 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5790 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5793 /* Check for another atom ? */
5794 if (size > atom_length + 8) {
5795 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5796 if (size >= atom_length + new_atom_length) {
5797 fourcc = QT_FOURCC (data + atom_length + 4);
5798 if (fourcc == FOURCC_cdat) {
5801 convert_to_s334_1a (data + atom_length + 8,
5802 new_atom_length - 8, 1, &cdat_size);
5804 GST_WARNING_OBJECT (stream->pad,
5805 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5809 convert_to_s334_1a (data + atom_length + 8,
5810 new_atom_length - 8, 2, &cdt2_size);
5812 GST_WARNING_OBJECT (stream->pad,
5813 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5818 *cclen = cdat_size + cdt2_size;
5819 res = g_malloc (*cclen);
5821 memcpy (res, cdat, cdat_size);
5823 memcpy (res + cdat_size, cdt2, cdt2_size);
5829 if (fourcc != FOURCC_ccdp) {
5830 GST_WARNING_OBJECT (stream->pad,
5831 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5832 GST_FOURCC_ARGS (fourcc));
5835 *cclen = atom_length - 8;
5836 res = g_memdup2 (data + 8, *cclen);
5839 /* Keep this here in case other closed caption formats are added */
5840 g_assert_not_reached ();
5844 GST_MEMDUMP ("Output", res, *cclen);
5849 GST_WARNING ("[cdat] atom is too small or invalid");
5853 /* Handle Closed Caption sample buffers.
5854 * The input buffer metadata must be writable,
5855 * but time/duration etc not yet set and need not be preserved */
5857 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5860 GstBuffer *outbuf = NULL;
5865 gst_buffer_map (buf, &map, GST_MAP_READ);
5867 /* empty buffer is sent to terminate previous subtitle */
5868 if (map.size <= 2) {
5869 gst_buffer_unmap (buf, &map);
5870 gst_buffer_unref (buf);
5874 /* For closed caption, we need to extract the information from the
5875 * [cdat],[cdt2] or [ccdp] atom */
5876 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5877 gst_buffer_unmap (buf, &map);
5879 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5880 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5882 /* Conversion failed or there's nothing */
5884 gst_buffer_unref (buf);
5889 /* DVD subpicture specific sample handling.
5890 * the input buffer metadata must be writable,
5891 * but time/duration etc not yet set and need not be preserved */
5893 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5896 /* send a one time dvd clut event */
5897 if (stream->pending_event && stream->pad)
5898 gst_pad_push_event (stream->pad, stream->pending_event);
5899 stream->pending_event = NULL;
5901 /* empty buffer is sent to terminate previous subtitle */
5902 if (gst_buffer_get_size (buf) <= 2) {
5903 gst_buffer_unref (buf);
5907 /* That's all the processing needed for subpictures */
5911 /* Timed text formats
5912 * the input buffer metadata must be writable,
5913 * but time/duration etc not yet set and need not be preserved */
5915 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5918 GstBuffer *outbuf = NULL;
5923 /* not many cases for now */
5924 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5925 stream->subtype != FOURCC_sbtl)) {
5929 gst_buffer_map (buf, &map, GST_MAP_READ);
5931 /* empty buffer is sent to terminate previous subtitle */
5932 if (map.size <= 2) {
5933 gst_buffer_unmap (buf, &map);
5934 gst_buffer_unref (buf);
5938 nsize = GST_READ_UINT16_BE (map.data);
5939 nsize = MIN (nsize, map.size - 2);
5941 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5944 /* takes care of UTF-8 validation or UTF-16 recognition,
5945 * no other encoding expected */
5946 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5947 gst_buffer_unmap (buf, &map);
5950 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5951 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5953 /* this should not really happen unless the subtitle is corrupted */
5955 gst_buffer_unref (buf);
5957 /* FIXME ? convert optional subsequent style info to markup */
5962 /* WebVTT sample handling according to 14496-30 */
5964 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5967 GstBuffer *outbuf = NULL;
5970 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5971 g_assert_not_reached (); /* The buffer must be mappable */
5974 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5975 GstEvent *gap = NULL;
5976 /* Push a gap event */
5977 stream->segment.position = GST_BUFFER_PTS (buf);
5979 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5980 gst_pad_push_event (stream->pad, gap);
5982 if (GST_BUFFER_DURATION_IS_VALID (buf))
5983 stream->segment.position += GST_BUFFER_DURATION (buf);
5986 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5987 GST_BUFFER_DURATION (buf), map.data, map.size);
5988 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5991 gst_buffer_unmap (buf, &map);
5992 gst_buffer_unref (buf);
5997 static GstFlowReturn
5998 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6001 GstFlowReturn ret = GST_FLOW_OK;
6002 GstClockTime pts, duration;
6004 if (stream->need_clip)
6005 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
6007 if (G_UNLIKELY (buf == NULL))
6010 if (G_UNLIKELY (stream->discont)) {
6011 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6012 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
6013 stream->discont = FALSE;
6015 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6018 GST_LOG_OBJECT (qtdemux,
6019 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
6020 ", duration %" GST_TIME_FORMAT " on pad %s",
6021 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
6022 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
6023 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
6025 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
6026 GstStructure *crypto_info;
6027 QtDemuxAavdEncryptionInfo *info =
6028 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
6030 crypto_info = gst_structure_copy (info->default_properties);
6031 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6032 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
6035 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
6036 || stream->protection_scheme_type == FOURCC_cbcs)) {
6037 GstStructure *crypto_info;
6038 QtDemuxCencSampleSetInfo *info =
6039 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6043 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
6044 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
6045 GST_PTR_FORMAT, event);
6046 gst_pad_push_event (stream->pad, event);
6049 if (info->crypto_info == NULL) {
6050 if (stream->protection_scheme_type == FOURCC_cbcs) {
6051 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
6052 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
6053 GST_ERROR_OBJECT (qtdemux,
6054 "failed to attach cbcs metadata to buffer");
6055 qtdemux_gst_structure_free (crypto_info);
6057 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
6060 GST_DEBUG_OBJECT (qtdemux,
6061 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
6064 /* The end of the crypto_info array matches our n_samples position,
6065 * so count backward from there */
6066 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
6067 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
6068 /* steal structure from array */
6069 crypto_info = g_ptr_array_index (info->crypto_info, index);
6070 g_ptr_array_index (info->crypto_info, index) = NULL;
6071 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
6072 info->crypto_info->len);
6073 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6074 GST_ERROR_OBJECT (qtdemux,
6075 "failed to attach cenc metadata to buffer");
6077 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
6078 index, stream->sample_index);
6083 if (stream->alignment > 1)
6084 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6086 pts = GST_BUFFER_PTS (buf);
6087 duration = GST_BUFFER_DURATION (buf);
6089 ret = gst_pad_push (stream->pad, buf);
6091 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6092 /* mark position in stream, we'll need this to know when to send GAP event */
6093 stream->segment.position = pts + duration;
6101 static GstFlowReturn
6102 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6105 GstFlowReturn ret = GST_FLOW_OK;
6107 if (stream->subtype == FOURCC_clcp
6108 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6110 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6111 guint n_triplets, i;
6112 guint field1_off = 0, field2_off = 0;
6114 /* We have to split CEA608 buffers so that each outgoing buffer contains
6115 * one byte pair per field according to the framerate of the video track.
6117 * If there is only a single byte pair per field we don't have to do
6121 gst_buffer_map (buf, &map, GST_MAP_READ);
6123 n_triplets = map.size / 3;
6124 for (i = 0; i < n_triplets; i++) {
6125 if (map.data[3 * i] & 0x80)
6131 g_assert (n_field1 || n_field2);
6133 /* If there's more than 1 frame we have to split, otherwise we can just
6135 if (n_field1 > 1 || n_field2 > 1) {
6137 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6138 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6140 for (i = 0; i < n_output_buffers; i++) {
6142 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6146 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6147 outptr = outmap.data;
6150 gboolean found = FALSE;
6152 while (map.data + field1_off < map.data + map.size) {
6153 if (map.data[field1_off] & 0x80) {
6154 memcpy (outptr, &map.data[field1_off], 3);
6163 const guint8 empty[] = { 0x80, 0x80, 0x80 };
6165 memcpy (outptr, empty, 3);
6172 gboolean found = FALSE;
6174 while (map.data + field2_off < map.data + map.size) {
6175 if ((map.data[field2_off] & 0x80) == 0) {
6176 memcpy (outptr, &map.data[field2_off], 3);
6185 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6187 memcpy (outptr, empty, 3);
6193 gst_buffer_unmap (outbuf, &outmap);
6195 GST_BUFFER_PTS (outbuf) =
6196 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6197 GST_SECOND * CUR_STREAM (stream)->fps_d,
6198 CUR_STREAM (stream)->fps_n);
6199 GST_BUFFER_DURATION (outbuf) =
6200 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6201 CUR_STREAM (stream)->fps_n);
6202 GST_BUFFER_OFFSET (outbuf) = -1;
6203 GST_BUFFER_OFFSET_END (outbuf) = -1;
6205 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6207 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6210 gst_buffer_unmap (buf, &map);
6211 gst_buffer_unref (buf);
6213 gst_buffer_unmap (buf, &map);
6214 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6217 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6223 /* Sets a buffer's attributes properly and pushes it downstream.
6224 * Also checks for additional actions and custom processing that may
6225 * need to be done first.
6227 static GstFlowReturn
6228 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6229 QtDemuxStream * stream, GstBuffer * buf,
6230 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6231 gboolean keyframe, GstClockTime position, guint64 byte_position)
6233 GstFlowReturn ret = GST_FLOW_OK;
6235 /* offset the timestamps according to the edit list */
6237 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6241 gst_buffer_map (buf, &map, GST_MAP_READ);
6242 url = g_strndup ((gchar *) map.data, map.size);
6243 gst_buffer_unmap (buf, &map);
6244 if (url != NULL && strlen (url) != 0) {
6245 /* we have RTSP redirect now */
6246 g_free (qtdemux->redirect_location);
6247 qtdemux->redirect_location = g_strdup (url);
6248 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6249 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6250 gst_structure_new ("redirect",
6251 "new-location", G_TYPE_STRING, url, NULL)));
6253 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6259 /* position reporting */
6260 if (qtdemux->segment.rate >= 0) {
6261 qtdemux->segment.position = position;
6262 gst_qtdemux_sync_streams (qtdemux);
6265 if (G_UNLIKELY (!stream->pad)) {
6266 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6267 gst_buffer_unref (buf);
6271 /* send out pending buffers */
6272 while (stream->buffers) {
6273 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6275 if (G_UNLIKELY (stream->discont)) {
6276 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6277 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6278 stream->discont = FALSE;
6280 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6283 if (stream->alignment > 1)
6284 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6285 gst_pad_push (stream->pad, buffer);
6287 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6290 /* we're going to modify the metadata */
6291 buf = gst_buffer_make_writable (buf);
6293 if (qtdemux->start_utc_time != GST_CLOCK_TIME_NONE) {
6294 static GstStaticCaps unix_caps = GST_STATIC_CAPS ("timestamp/x-unix");
6295 GstCaps *caps = gst_static_caps_get (&unix_caps);
6296 gst_buffer_add_reference_timestamp_meta (buf, caps,
6297 pts + qtdemux->start_utc_time - stream->cslg_shift,
6298 GST_CLOCK_TIME_NONE);
6299 gst_caps_unref (caps);
6302 GST_BUFFER_DTS (buf) = dts;
6303 GST_BUFFER_PTS (buf) = pts;
6304 GST_BUFFER_DURATION (buf) = duration;
6305 GST_BUFFER_OFFSET (buf) = -1;
6306 GST_BUFFER_OFFSET_END (buf) = -1;
6308 if (G_UNLIKELY (stream->process_func))
6309 buf = stream->process_func (qtdemux, stream, buf);
6316 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6317 stream->on_keyframe = FALSE;
6319 stream->on_keyframe = TRUE;
6322 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6323 gst_buffer_append_memory (buf,
6324 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6326 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6327 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6330 if (G_UNLIKELY (qtdemux->element_index)) {
6331 GstClockTime stream_time;
6334 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6336 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6337 GST_LOG_OBJECT (qtdemux,
6338 "adding association %" GST_TIME_FORMAT "-> %"
6339 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6340 gst_index_add_association (qtdemux->element_index,
6342 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6343 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6344 GST_FORMAT_BYTES, byte_position, NULL);
6349 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6355 static const QtDemuxRandomAccessEntry *
6356 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6357 GstClockTime pos, gboolean after)
6359 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6360 guint n_entries = stream->n_ra_entries;
6363 /* we assume the table is sorted */
6364 for (i = 0; i < n_entries; ++i) {
6365 if (entries[i].ts > pos)
6369 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6370 * probably okay to assume that the index lists the very first fragment */
6377 return &entries[i - 1];
6381 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6383 const QtDemuxRandomAccessEntry *best_entry = NULL;
6386 GST_OBJECT_LOCK (qtdemux);
6388 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6390 /* first see if we can determine where to go to using mfra,
6391 * before we start clearing things */
6392 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6393 const QtDemuxRandomAccessEntry *entry;
6394 QtDemuxStream *stream;
6395 gboolean is_audio_or_video;
6397 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6399 if (stream->ra_entries == NULL)
6402 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6403 is_audio_or_video = TRUE;
6405 is_audio_or_video = FALSE;
6408 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6409 stream->time_position, !is_audio_or_video);
6411 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6412 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6414 stream->pending_seek = entry;
6416 /* decide position to jump to just based on audio/video tracks, not subs */
6417 if (!is_audio_or_video)
6420 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6424 /* no luck, will handle seek otherwise */
6425 if (best_entry == NULL) {
6426 GST_OBJECT_UNLOCK (qtdemux);
6430 /* ok, now we can prepare for processing as of located moof */
6431 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6432 QtDemuxStream *stream;
6434 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6436 g_free (stream->samples);
6437 stream->samples = NULL;
6438 stream->n_samples = 0;
6439 stream->stbl_index = -1; /* no samples have yet been parsed */
6440 stream->sample_index = -1;
6442 if (stream->protection_scheme_info) {
6443 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6444 if (stream->protection_scheme_type == FOURCC_cenc
6445 || stream->protection_scheme_type == FOURCC_cbcs) {
6446 QtDemuxCencSampleSetInfo *info =
6447 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6448 if (info->crypto_info) {
6449 g_ptr_array_free (info->crypto_info, TRUE);
6450 info->crypto_info = NULL;
6456 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6457 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6458 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6459 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6461 qtdemux->moof_offset = best_entry->moof_offset;
6463 qtdemux_add_fragmented_samples (qtdemux);
6465 GST_OBJECT_UNLOCK (qtdemux);
6469 static GstFlowReturn
6470 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6472 GstFlowReturn ret = GST_FLOW_OK;
6473 GstBuffer *buf = NULL;
6474 QtDemuxStream *stream, *target_stream = NULL;
6475 GstClockTime min_time;
6477 GstClockTime dts = GST_CLOCK_TIME_NONE;
6478 GstClockTime pts = GST_CLOCK_TIME_NONE;
6479 GstClockTime duration = 0;
6480 gboolean keyframe = FALSE;
6481 guint sample_size = 0;
6482 guint num_samples = 1;
6487 if (qtdemux->fragmented_seek_pending) {
6488 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6489 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6490 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6491 qtdemux->fragmented_seek_pending = FALSE;
6493 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6497 /* Figure out the next stream sample to output, min_time is expressed in
6498 * global time and runs over the edit list segments. */
6499 min_time = G_MAXUINT64;
6500 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6501 GstClockTime position;
6503 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6504 position = stream->time_position;
6506 if (!GST_CLOCK_TIME_IS_VALID (position))
6509 if (stream->segment_index != -1) {
6510 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6511 position += segment->media_start;
6514 /* position of -1 is EOS */
6515 if (position < min_time) {
6516 min_time = position;
6517 target_stream = stream;
6521 if (G_UNLIKELY (target_stream == NULL)) {
6522 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6526 /* check for segment end */
6527 if (G_UNLIKELY (qtdemux->segment.stop != -1
6528 && qtdemux->segment.rate >= 0
6529 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6530 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6531 target_stream->time_position = GST_CLOCK_TIME_NONE;
6535 /* fetch info for the current sample of this stream */
6536 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, target_stream,
6537 &empty, &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6540 /* Send catche-up GAP event for each other stream if required.
6541 * This logic will be applied only for positive rate */
6542 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux) &&
6543 qtdemux->segment.rate >= 0; i++) {
6544 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6546 if (stream == target_stream ||
6547 !GST_CLOCK_TIME_IS_VALID (stream->segment.stop) ||
6548 !GST_CLOCK_TIME_IS_VALID (stream->segment.position))
6552 GstClockTime gap_threshold;
6553 /* kind of running time with offset segment.base and segment.start */
6554 GstClockTime pseudo_target_time = target_stream->segment.base;
6555 GstClockTime pseudo_cur_time = stream->segment.base;
6557 /* make sure positive offset, segment.position can be smallr than
6558 * segment.start for some reasons */
6559 if (target_stream->segment.position >= target_stream->segment.start) {
6560 pseudo_target_time +=
6561 (target_stream->segment.position - target_stream->segment.start);
6564 if (stream->segment.position >= stream->segment.start)
6565 pseudo_cur_time += (stream->segment.position - stream->segment.start);
6567 /* Only send gap events on non-subtitle streams if lagging way behind. */
6568 if (stream->subtype == FOURCC_subp
6569 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6570 stream->subtype == FOURCC_wvtt)
6571 gap_threshold = 1 * GST_SECOND;
6573 gap_threshold = 3 * GST_SECOND;
6575 /* send gap events until the stream catches up */
6576 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6577 while (GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6578 pseudo_cur_time < (G_MAXUINT64 - gap_threshold) &&
6579 pseudo_cur_time + gap_threshold < pseudo_target_time) {
6581 gst_event_new_gap (stream->segment.position, gap_threshold);
6582 GST_LOG_OBJECT (stream->pad, "Sending %" GST_PTR_FORMAT, gap);
6584 gst_pad_push_event (stream->pad, gap);
6585 stream->segment.position += gap_threshold;
6586 pseudo_cur_time += gap_threshold;
6591 stream = target_stream;
6593 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6594 if (stream->new_caps) {
6595 gst_qtdemux_configure_stream (qtdemux, stream);
6596 qtdemux_do_allocation (stream, qtdemux);
6599 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6600 if (G_UNLIKELY (qtdemux->segment.
6601 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6602 if (stream->subtype == FOURCC_vide) {
6604 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6607 } else if (qtdemux->trickmode_interval > 0) {
6608 GstClockTimeDiff interval;
6610 if (qtdemux->segment.rate > 0)
6611 interval = stream->time_position - stream->last_keyframe_dts;
6613 interval = stream->last_keyframe_dts - stream->time_position;
6615 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6616 && interval < qtdemux->trickmode_interval) {
6617 GST_LOG_OBJECT (qtdemux,
6618 "Skipping keyframe within interval on track-id %u",
6622 stream->last_keyframe_dts = stream->time_position;
6628 GST_DEBUG_OBJECT (qtdemux,
6629 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6630 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6631 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6632 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6633 GST_TIME_ARGS (duration));
6635 if (G_UNLIKELY (empty)) {
6636 /* empty segment, push a gap if there's a second or more
6637 * difference and move to the next one */
6638 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6639 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6640 stream->segment.position = pts + duration;
6644 /* hmm, empty sample, skip and move to next sample */
6645 if (G_UNLIKELY (sample_size <= 0))
6648 /* last pushed sample was out of boundary, goto next sample */
6649 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6652 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6653 GST_DEBUG_OBJECT (qtdemux,
6654 "size %d larger than stream max_buffer_size %d, trimming",
6655 sample_size, stream->max_buffer_size);
6657 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6658 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6659 && sample_size < stream->min_buffer_size) {
6660 guint start_sample_index = stream->sample_index;
6661 guint accumulated_size = sample_size;
6662 guint64 expected_next_offset = offset + sample_size;
6664 GST_DEBUG_OBJECT (qtdemux,
6665 "size %d smaller than stream min_buffer_size %d, combining with the next",
6666 sample_size, stream->min_buffer_size);
6668 while (stream->sample_index < stream->to_sample
6669 && stream->sample_index + 1 < stream->n_samples) {
6670 const QtDemuxSample *next_sample;
6672 /* Increment temporarily */
6673 stream->sample_index++;
6675 /* Failed to parse sample so let's go back to the previous one that was
6676 * still successful */
6677 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6678 stream->sample_index--;
6682 next_sample = &stream->samples[stream->sample_index];
6684 /* Not contiguous with the previous sample so let's go back to the
6685 * previous one that was still successful */
6686 if (next_sample->offset != expected_next_offset) {
6687 stream->sample_index--;
6691 accumulated_size += next_sample->size;
6692 expected_next_offset += next_sample->size;
6693 if (accumulated_size >= stream->min_buffer_size)
6697 num_samples = stream->sample_index + 1 - start_sample_index;
6698 stream->sample_index = start_sample_index;
6699 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6700 num_samples, accumulated_size);
6701 size = accumulated_size;
6706 if (qtdemux->cenc_aux_info_offset > 0) {
6709 GstBuffer *aux_info = NULL;
6711 /* pull the data stored before the sample */
6713 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6714 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6715 if (G_UNLIKELY (ret != GST_FLOW_OK))
6717 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6718 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6719 gst_byte_reader_init (&br, map.data + 8, map.size);
6720 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6721 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6722 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6723 gst_buffer_unmap (aux_info, &map);
6724 gst_buffer_unref (aux_info);
6725 ret = GST_FLOW_ERROR;
6728 gst_buffer_unmap (aux_info, &map);
6729 gst_buffer_unref (aux_info);
6732 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6735 if (stream->use_allocator) {
6736 /* if we have a per-stream allocator, use it */
6737 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6740 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6742 if (G_UNLIKELY (ret != GST_FLOW_OK))
6745 /* Update for both splitting and combining of samples */
6746 if (size != sample_size) {
6747 pts += gst_util_uint64_scale_int (GST_SECOND,
6748 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6751 gst_util_uint64_scale_int (GST_SECOND,
6752 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6755 gst_util_uint64_scale_int (GST_SECOND,
6756 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6759 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6760 dts, pts, duration, keyframe, min_time, offset);
6762 if (size < sample_size) {
6763 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6764 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6766 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6768 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6769 if (time_position >= segment->media_start) {
6770 /* inside the segment, update time_position, looks very familiar to
6771 * GStreamer segments, doesn't it? */
6772 stream->time_position = (time_position - segment->media_start) +
6775 /* not yet in segment, time does not yet increment. This means
6776 * that we are still prerolling keyframes to the decoder so it can
6777 * decode the first sample of the segment. */
6778 stream->time_position = segment->time;
6780 } else if (size > sample_size) {
6781 /* Increase to the last sample we already pulled so that advancing
6782 * below brings us to the next sample we need to pull */
6783 stream->sample_index += num_samples - 1;
6787 GST_OBJECT_LOCK (qtdemux);
6788 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6789 GST_OBJECT_UNLOCK (qtdemux);
6790 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6791 * we have no more data for the pad to push */
6792 if (ret == GST_FLOW_EOS)
6795 stream->offset_in_sample += size;
6796 if (stream->offset_in_sample >= sample_size) {
6797 gst_qtdemux_advance_sample (qtdemux, stream);
6802 gst_qtdemux_advance_sample (qtdemux, stream);
6810 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6816 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6817 /* EOS will be raised if all are EOS */
6824 gst_qtdemux_loop (GstPad * pad)
6826 GstQTDemux *qtdemux;
6830 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6832 cur_offset = qtdemux->offset;
6833 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6834 cur_offset, qt_demux_state_string (qtdemux->state));
6836 switch (qtdemux->state) {
6837 case QTDEMUX_STATE_INITIAL:
6838 case QTDEMUX_STATE_HEADER:
6839 ret = gst_qtdemux_loop_state_header (qtdemux);
6841 case QTDEMUX_STATE_MOVIE:
6842 ret = gst_qtdemux_loop_state_movie (qtdemux);
6843 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6844 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6852 /* if something went wrong, pause */
6853 if (ret != GST_FLOW_OK)
6857 gst_object_unref (qtdemux);
6863 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6864 (NULL), ("streaming stopped, invalid state"));
6865 gst_pad_pause_task (pad);
6866 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6871 const gchar *reason = gst_flow_get_name (ret);
6873 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6875 gst_pad_pause_task (pad);
6877 /* fatal errors need special actions */
6879 if (ret == GST_FLOW_EOS) {
6880 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6881 /* we have no streams, post an error */
6882 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6884 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6887 if ((stop = qtdemux->segment.stop) == -1)
6888 stop = qtdemux->segment.duration;
6890 if (qtdemux->segment.rate >= 0) {
6891 GstMessage *message;
6894 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6895 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6896 GST_FORMAT_TIME, stop);
6897 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6898 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6899 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6900 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6902 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6903 gst_qtdemux_push_event (qtdemux, event);
6905 GstMessage *message;
6908 /* For Reverse Playback */
6909 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6910 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6911 GST_FORMAT_TIME, qtdemux->segment.start);
6912 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6913 qtdemux->segment.start);
6914 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6915 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6916 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6918 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6919 gst_qtdemux_push_event (qtdemux, event);
6924 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6925 event = gst_event_new_eos ();
6926 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6927 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6928 gst_qtdemux_push_event (qtdemux, event);
6930 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6931 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6932 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6941 * Returns if there are samples to be played.
6944 has_next_entry (GstQTDemux * demux)
6946 QtDemuxStream *stream;
6949 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6951 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6952 stream = QTDEMUX_NTH_STREAM (demux, i);
6954 if (stream->sample_index == -1) {
6955 stream->sample_index = 0;
6956 stream->offset_in_sample = 0;
6959 if (stream->sample_index >= stream->n_samples) {
6960 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6963 GST_DEBUG_OBJECT (demux, "Found a sample");
6967 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6974 * Returns the size of the first entry at the current offset.
6975 * If -1, there are none (which means EOS or empty file).
6978 next_entry_size (GstQTDemux * demux)
6980 QtDemuxStream *stream, *target_stream = NULL;
6981 guint64 smalloffs = (guint64) - 1;
6982 QtDemuxSample *sample;
6985 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6988 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6989 stream = QTDEMUX_NTH_STREAM (demux, i);
6991 if (stream->sample_index == -1) {
6992 stream->sample_index = 0;
6993 stream->offset_in_sample = 0;
6996 if (stream->sample_index >= stream->n_samples) {
6997 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
7001 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
7002 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
7003 stream->sample_index);
7007 sample = &stream->samples[stream->sample_index];
7009 GST_LOG_OBJECT (demux,
7010 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
7011 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
7012 stream->sample_index, sample->offset, sample->size);
7014 if (((smalloffs == -1)
7015 || (sample->offset < smalloffs)) && (sample->size)) {
7016 smalloffs = sample->offset;
7017 target_stream = stream;
7024 GST_LOG_OBJECT (demux,
7025 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
7026 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
7028 stream = target_stream;
7029 sample = &stream->samples[stream->sample_index];
7031 if (sample->offset >= demux->offset) {
7032 demux->todrop = sample->offset - demux->offset;
7033 return sample->size + demux->todrop;
7036 GST_DEBUG_OBJECT (demux,
7037 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
7042 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
7044 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
7046 gst_element_post_message (GST_ELEMENT_CAST (demux),
7047 gst_message_new_element (GST_OBJECT_CAST (demux),
7048 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
7052 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
7057 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
7060 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
7061 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
7062 GST_SEEK_TYPE_NONE, -1);
7064 /* store seqnum to drop flush events, they don't need to reach downstream */
7065 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
7066 res = gst_pad_push_event (demux->sinkpad, event);
7067 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
7072 /* check for seekable upstream, above and beyond a mere query */
7074 gst_qtdemux_check_seekability (GstQTDemux * demux)
7077 gboolean seekable = FALSE;
7078 gint64 start = -1, stop = -1;
7080 if (demux->upstream_size)
7083 if (demux->upstream_format_is_time)
7086 query = gst_query_new_seeking (GST_FORMAT_BYTES);
7087 if (!gst_pad_peer_query (demux->sinkpad, query)) {
7088 GST_DEBUG_OBJECT (demux, "seeking query failed");
7092 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
7094 /* try harder to query upstream size if we didn't get it the first time */
7095 if (seekable && stop == -1) {
7096 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
7097 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
7100 /* if upstream doesn't know the size, it's likely that it's not seekable in
7101 * practice even if it technically may be seekable */
7102 if (seekable && (start != 0 || stop <= start)) {
7103 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
7108 gst_query_unref (query);
7110 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
7111 G_GUINT64_FORMAT ")", seekable, start, stop);
7112 demux->upstream_seekable = seekable;
7113 demux->upstream_size = seekable ? stop : -1;
7117 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
7119 g_return_if_fail (bytes <= demux->todrop);
7121 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
7122 gst_adapter_flush (demux->adapter, bytes);
7123 demux->neededbytes -= bytes;
7124 demux->offset += bytes;
7125 demux->todrop -= bytes;
7128 /* PUSH-MODE only: Send a segment, if not done already. */
7130 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
7132 if (G_UNLIKELY (demux->need_segment)) {
7135 if (!demux->upstream_format_is_time) {
7136 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
7138 GstEvent *segment_event;
7139 segment_event = gst_event_new_segment (&demux->segment);
7140 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
7141 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
7142 gst_qtdemux_push_event (demux, segment_event);
7145 demux->need_segment = FALSE;
7147 /* clear to send tags on all streams */
7148 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7149 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7150 gst_qtdemux_push_tags (demux, stream);
7151 if (CUR_STREAM (stream)->sparse) {
7152 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
7153 gst_pad_push_event (stream->pad,
7154 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7160 /* Used for push mode only. */
7162 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7163 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7165 GstClockTime ts, dur;
7169 stream->segments[segment_index].duration - (pos -
7170 stream->segments[segment_index].time);
7171 stream->time_position += dur;
7173 /* Only gaps with a duration of at least one second are propagated.
7174 * Same workaround as in pull mode.
7175 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7176 if (dur >= GST_SECOND) {
7178 gap = gst_event_new_gap (ts, dur);
7180 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7181 "segment: %" GST_PTR_FORMAT, gap);
7182 gst_pad_push_event (stream->pad, gap);
7186 static GstFlowReturn
7187 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7191 demux = GST_QTDEMUX (parent);
7193 GST_DEBUG_OBJECT (demux,
7194 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7195 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7196 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7197 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7198 gst_buffer_get_size (inbuf), demux->offset);
7200 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7201 gboolean is_gap_input = FALSE;
7204 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7206 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7207 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7210 /* Check if we can land back on our feet in the case where upstream is
7211 * handling the seeking/pushing of samples with gaps in between (like
7212 * in the case of trick-mode DASH for example) */
7213 if (demux->upstream_format_is_time
7214 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7215 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7217 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7218 GST_LOG_OBJECT (demux,
7219 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7220 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7222 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7223 stream, GST_BUFFER_OFFSET (inbuf));
7225 QtDemuxSample *sample = &stream->samples[res];
7226 GST_LOG_OBJECT (demux,
7227 "Checking if sample %d from track-id %u is valid (offset:%"
7228 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7229 stream->track_id, sample->offset, sample->size);
7230 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7231 GST_LOG_OBJECT (demux,
7232 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7234 is_gap_input = TRUE;
7235 /* We can go back to standard playback mode */
7236 demux->state = QTDEMUX_STATE_MOVIE;
7237 /* Remember which sample this stream is at */
7238 stream->sample_index = res;
7239 /* Finally update all push-based values to the expected values */
7240 demux->neededbytes = stream->samples[res].size;
7241 demux->offset = GST_BUFFER_OFFSET (inbuf);
7243 demux->mdatsize - demux->offset + demux->mdatoffset;
7248 if (!is_gap_input) {
7249 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7250 /* Reset state if it's a real discont */
7251 demux->neededbytes = 16;
7252 demux->state = QTDEMUX_STATE_INITIAL;
7253 demux->offset = GST_BUFFER_OFFSET (inbuf);
7254 gst_adapter_clear (demux->adapter);
7257 /* Reverse fragmented playback, need to flush all we have before
7258 * consuming a new fragment.
7259 * The samples array have the timestamps calculated by accumulating the
7260 * durations but this won't work for reverse playback of fragments as
7261 * the timestamps of a subsequent fragment should be smaller than the
7262 * previously received one. */
7263 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7264 gst_qtdemux_process_adapter (demux, TRUE);
7265 g_ptr_array_foreach (demux->active_streams,
7266 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7270 gst_adapter_push (demux->adapter, inbuf);
7272 GST_DEBUG_OBJECT (demux,
7273 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7274 demux->neededbytes, gst_adapter_available (demux->adapter));
7276 return gst_qtdemux_process_adapter (demux, FALSE);
7279 static GstFlowReturn
7280 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7282 GstFlowReturn ret = GST_FLOW_OK;
7284 /* we never really mean to buffer that much */
7285 if (demux->neededbytes == -1) {
7289 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7290 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7292 #ifndef GST_DISABLE_GST_DEBUG
7294 guint64 discont_offset, distance_from_discont;
7296 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7297 distance_from_discont =
7298 gst_adapter_distance_from_discont (demux->adapter);
7300 GST_DEBUG_OBJECT (demux,
7301 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7302 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7303 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7304 demux->offset, discont_offset, distance_from_discont);
7308 switch (demux->state) {
7309 case QTDEMUX_STATE_INITIAL:{
7314 gst_qtdemux_check_seekability (demux);
7316 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7318 /* get fourcc/length, set neededbytes */
7319 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7321 gst_adapter_unmap (demux->adapter);
7323 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7324 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7326 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7327 (_("This file is invalid and cannot be played.")),
7328 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7329 GST_FOURCC_ARGS (fourcc)));
7330 ret = GST_FLOW_ERROR;
7333 if (fourcc == FOURCC_mdat) {
7334 gint next_entry = next_entry_size (demux);
7335 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7336 || !demux->fragmented)) {
7337 /* we have the headers, start playback */
7338 demux->state = QTDEMUX_STATE_MOVIE;
7339 demux->neededbytes = next_entry;
7340 demux->mdatleft = size;
7341 demux->mdatsize = demux->mdatleft;
7343 /* no headers yet, try to get them */
7346 guint64 old, target;
7349 old = demux->offset;
7350 target = old + size;
7352 /* try to jump over the atom with a seek */
7353 /* only bother if it seems worth doing so,
7354 * and avoids possible upstream/server problems */
7355 if (demux->upstream_seekable &&
7356 demux->upstream_size > 4 * (1 << 20)) {
7357 res = qtdemux_seek_offset (demux, target);
7359 GST_DEBUG_OBJECT (demux, "skipping seek");
7364 GST_DEBUG_OBJECT (demux, "seek success");
7365 /* remember the offset fo the first mdat so we can seek back to it
7366 * after we have the headers */
7367 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7368 demux->first_mdat = old;
7369 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7372 /* seek worked, continue reading */
7373 demux->offset = target;
7374 demux->neededbytes = 16;
7375 demux->state = QTDEMUX_STATE_INITIAL;
7377 /* seek failed, need to buffer */
7378 demux->offset = old;
7379 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7380 /* there may be multiple mdat (or alike) buffers */
7382 if (demux->mdatbuffer)
7383 bs = gst_buffer_get_size (demux->mdatbuffer);
7386 if (size + bs > 10 * (1 << 20))
7388 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7389 demux->neededbytes = size;
7390 if (!demux->mdatbuffer)
7391 demux->mdatoffset = demux->offset;
7394 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7395 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7396 (_("This file is invalid and cannot be played.")),
7397 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7398 GST_FOURCC_ARGS (fourcc), size));
7399 ret = GST_FLOW_ERROR;
7402 /* this means we already started buffering and still no moov header,
7403 * let's continue buffering everything till we get moov */
7404 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7405 || fourcc == FOURCC_moof))
7407 demux->neededbytes = size;
7408 demux->state = QTDEMUX_STATE_HEADER;
7412 case QTDEMUX_STATE_HEADER:{
7416 GST_DEBUG_OBJECT (demux, "In header");
7418 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7420 /* parse the header */
7421 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7423 if (fourcc == FOURCC_moov) {
7424 /* in usual fragmented setup we could try to scan for more
7425 * and end up at the the moov (after mdat) again */
7426 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7428 || demux->last_moov_offset == demux->offset)) {
7429 GST_DEBUG_OBJECT (demux,
7430 "Skipping moov atom as we have (this) one already");
7432 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7434 if (demux->got_moov && demux->fragmented) {
7435 GST_DEBUG_OBJECT (demux,
7436 "Got a second moov, clean up data from old one");
7437 if (demux->moov_node_compressed) {
7438 g_node_destroy (demux->moov_node_compressed);
7439 if (demux->moov_node)
7440 g_free (demux->moov_node->data);
7442 demux->moov_node_compressed = NULL;
7443 if (demux->moov_node)
7444 g_node_destroy (demux->moov_node);
7445 demux->moov_node = NULL;
7446 demux->start_utc_time = GST_CLOCK_TIME_NONE;
7449 demux->last_moov_offset = demux->offset;
7451 /* Update streams with new moov */
7452 gst_qtdemux_stream_concat (demux,
7453 demux->old_streams, demux->active_streams);
7455 qtdemux_parse_moov (demux, data, demux->neededbytes);
7456 qtdemux_node_dump (demux, demux->moov_node);
7457 qtdemux_parse_tree (demux);
7458 qtdemux_prepare_streams (demux);
7459 QTDEMUX_EXPOSE_LOCK (demux);
7460 qtdemux_expose_streams (demux);
7461 QTDEMUX_EXPOSE_UNLOCK (demux);
7463 demux->got_moov = TRUE;
7465 gst_qtdemux_check_send_pending_segment (demux);
7467 if (demux->moov_node_compressed) {
7468 g_node_destroy (demux->moov_node_compressed);
7469 g_free (demux->moov_node->data);
7471 demux->moov_node_compressed = NULL;
7472 g_node_destroy (demux->moov_node);
7473 demux->moov_node = NULL;
7474 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7476 } else if (fourcc == FOURCC_moof) {
7477 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7479 GstClockTime prev_pts;
7480 guint64 prev_offset;
7481 guint64 adapter_discont_offset, adapter_discont_dist;
7483 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7486 * The timestamp of the moof buffer is relevant as some scenarios
7487 * won't have the initial timestamp in the atoms. Whenever a new
7488 * buffer has started, we get that buffer's PTS and use it as a base
7489 * timestamp for the trun entries.
7491 * To keep track of the current buffer timestamp and starting point
7492 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7493 * from the beginning of the buffer, with the distance and demux->offset
7494 * we know if it is still the same buffer or not.
7496 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7497 prev_offset = demux->offset - dist;
7498 if (demux->fragment_start_offset == -1
7499 || prev_offset > demux->fragment_start_offset) {
7500 demux->fragment_start_offset = prev_offset;
7501 demux->fragment_start = prev_pts;
7502 GST_DEBUG_OBJECT (demux,
7503 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7504 GST_TIME_FORMAT, demux->fragment_start_offset,
7505 GST_TIME_ARGS (demux->fragment_start));
7508 /* We can't use prev_offset() here because this would require
7509 * upstream to set consistent and correct offsets on all buffers
7510 * since the discont. Nothing ever did that in the past and we
7511 * would break backwards compatibility here then.
7512 * Instead take the offset we had at the last discont and count
7513 * the bytes from there. This works with old code as there would
7514 * be no discont between moov and moof, and also works with
7515 * adaptivedemux which correctly sets offset and will set the
7516 * DISCONT flag accordingly when needed.
7518 * We also only do this for upstream TIME segments as otherwise
7519 * there are potential backwards compatibility problems with
7520 * seeking in PUSH mode and upstream providing inconsistent
7522 adapter_discont_offset =
7523 gst_adapter_offset_at_discont (demux->adapter);
7524 adapter_discont_dist =
7525 gst_adapter_distance_from_discont (demux->adapter);
7527 GST_DEBUG_OBJECT (demux,
7528 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7529 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7530 demux->offset, adapter_discont_offset, adapter_discont_dist);
7532 if (demux->upstream_format_is_time) {
7533 demux->moof_offset = adapter_discont_offset;
7534 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7535 demux->moof_offset += adapter_discont_dist;
7536 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7537 demux->moof_offset = demux->offset;
7539 demux->moof_offset = demux->offset;
7542 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7543 demux->moof_offset, NULL)) {
7544 gst_adapter_unmap (demux->adapter);
7545 ret = GST_FLOW_ERROR;
7549 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7550 if (demux->mss_mode && !demux->exposed) {
7551 QTDEMUX_EXPOSE_LOCK (demux);
7552 qtdemux_expose_streams (demux);
7553 QTDEMUX_EXPOSE_UNLOCK (demux);
7556 gst_qtdemux_check_send_pending_segment (demux);
7558 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7560 } else if (fourcc == FOURCC_ftyp) {
7561 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7562 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7563 } else if (fourcc == FOURCC_uuid) {
7564 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7565 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7566 } else if (fourcc == FOURCC_sidx) {
7567 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7568 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7569 } else if (fourcc == FOURCC_meta) {
7570 GNode *node, *child;
7571 GstByteReader child_data;
7573 node = g_node_new ((gpointer) data);
7574 qtdemux_parse_node (demux, node, data, demux->neededbytes);
7576 /* Parse ONVIF Export File Format CorrectStartTime box if available */
7578 qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb,
7580 qtdemux_parse_cstb (demux, &child_data);
7583 g_node_destroy (node);
7587 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7591 /* [free] and [skip] are padding atoms */
7592 GST_DEBUG_OBJECT (demux,
7593 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7594 GST_FOURCC_ARGS (fourcc));
7597 GST_WARNING_OBJECT (demux,
7598 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7599 GST_FOURCC_ARGS (fourcc));
7600 /* Let's jump that one and go back to initial state */
7604 gst_adapter_unmap (demux->adapter);
7607 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7608 gsize remaining_data_size = 0;
7610 /* the mdat was before the header */
7611 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7612 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7613 /* restore our adapter/offset view of things with upstream;
7614 * put preceding buffered data ahead of current moov data.
7615 * This should also handle evil mdat, moov, mdat cases and alike */
7616 gst_adapter_flush (demux->adapter, demux->neededbytes);
7618 /* Store any remaining data after the mdat for later usage */
7619 remaining_data_size = gst_adapter_available (demux->adapter);
7620 if (remaining_data_size > 0) {
7621 g_assert (demux->restoredata_buffer == NULL);
7622 demux->restoredata_buffer =
7623 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7624 demux->restoredata_offset = demux->offset + demux->neededbytes;
7625 GST_DEBUG_OBJECT (demux,
7626 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7627 G_GUINT64_FORMAT, remaining_data_size,
7628 demux->restoredata_offset);
7631 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7632 demux->mdatbuffer = NULL;
7633 demux->offset = demux->mdatoffset;
7634 demux->neededbytes = next_entry_size (demux);
7635 demux->state = QTDEMUX_STATE_MOVIE;
7636 demux->mdatleft = gst_adapter_available (demux->adapter);
7637 demux->mdatsize = demux->mdatleft;
7639 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7640 gst_adapter_flush (demux->adapter, demux->neededbytes);
7642 /* only go back to the mdat if there are samples to play */
7643 if (demux->got_moov && demux->first_mdat != -1
7644 && has_next_entry (demux)) {
7647 /* we need to seek back */
7648 res = qtdemux_seek_offset (demux, demux->first_mdat);
7650 demux->offset = demux->first_mdat;
7652 GST_DEBUG_OBJECT (demux, "Seek back failed");
7655 demux->offset += demux->neededbytes;
7657 demux->neededbytes = 16;
7658 demux->state = QTDEMUX_STATE_INITIAL;
7663 case QTDEMUX_STATE_BUFFER_MDAT:{
7667 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7669 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7670 gst_buffer_extract (buf, 0, fourcc, 4);
7671 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7672 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7673 if (demux->mdatbuffer)
7674 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7676 demux->mdatbuffer = buf;
7677 demux->offset += demux->neededbytes;
7678 demux->neededbytes = 16;
7679 demux->state = QTDEMUX_STATE_INITIAL;
7680 gst_qtdemux_post_progress (demux, 1, 1);
7684 case QTDEMUX_STATE_MOVIE:{
7685 QtDemuxStream *stream = NULL;
7686 QtDemuxSample *sample;
7687 GstClockTime dts, pts, duration;
7691 GST_DEBUG_OBJECT (demux,
7692 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7694 if (demux->fragmented) {
7695 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7697 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7698 /* if needed data starts within this atom,
7699 * then it should not exceed this atom */
7700 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7701 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7702 (_("This file is invalid and cannot be played.")),
7703 ("sample data crosses atom boundary"));
7704 ret = GST_FLOW_ERROR;
7707 demux->mdatleft -= demux->neededbytes;
7709 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7710 /* so we are dropping more than left in this atom */
7711 gst_qtdemux_drop_data (demux, demux->mdatleft);
7712 demux->mdatleft = 0;
7714 /* need to resume atom parsing so we do not miss any other pieces */
7715 demux->state = QTDEMUX_STATE_INITIAL;
7716 demux->neededbytes = 16;
7718 /* check if there was any stored post mdat data from previous buffers */
7719 if (demux->restoredata_buffer) {
7720 g_assert (gst_adapter_available (demux->adapter) == 0);
7722 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7723 demux->restoredata_buffer = NULL;
7724 demux->offset = demux->restoredata_offset;
7731 if (demux->todrop) {
7732 if (demux->cenc_aux_info_offset > 0) {
7736 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7737 data = gst_adapter_map (demux->adapter, demux->todrop);
7738 gst_byte_reader_init (&br, data + 8, demux->todrop);
7739 if (!qtdemux_parse_cenc_aux_info (demux,
7740 QTDEMUX_NTH_STREAM (demux, 0), &br,
7741 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7742 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7743 ret = GST_FLOW_ERROR;
7744 gst_adapter_unmap (demux->adapter);
7745 g_free (demux->cenc_aux_info_sizes);
7746 demux->cenc_aux_info_sizes = NULL;
7749 demux->cenc_aux_info_offset = 0;
7750 g_free (demux->cenc_aux_info_sizes);
7751 demux->cenc_aux_info_sizes = NULL;
7752 gst_adapter_unmap (demux->adapter);
7754 gst_qtdemux_drop_data (demux, demux->todrop);
7758 /* initial newsegment sent here after having added pads,
7759 * possible others in sink_event */
7760 gst_qtdemux_check_send_pending_segment (demux);
7762 /* Figure out which stream this packet belongs to */
7763 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7764 stream = QTDEMUX_NTH_STREAM (demux, i);
7765 if (stream->sample_index >= stream->n_samples) {
7766 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7770 GST_LOG_OBJECT (demux,
7771 "Checking track-id %u (sample_index:%d / offset:%"
7772 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7773 stream->sample_index,
7774 stream->samples[stream->sample_index].offset,
7775 stream->samples[stream->sample_index].size);
7777 if (stream->samples[stream->sample_index].offset == demux->offset)
7781 if (G_UNLIKELY (stream == NULL))
7782 goto unknown_stream;
7784 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7786 if (stream->new_caps) {
7787 gst_qtdemux_configure_stream (demux, stream);
7790 /* Put data in a buffer, set timestamps, caps, ... */
7791 sample = &stream->samples[stream->sample_index];
7793 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7794 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7795 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7797 dts = QTSAMPLE_DTS (stream, sample);
7798 pts = QTSAMPLE_PTS (stream, sample);
7799 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7800 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7802 /* check for segment end */
7803 if (G_UNLIKELY (demux->segment.stop != -1
7804 && demux->segment.stop <= pts && stream->on_keyframe)
7805 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7806 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7807 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7809 /* skip this data, stream is EOS */
7810 gst_adapter_flush (demux->adapter, demux->neededbytes);
7811 demux->offset += demux->neededbytes;
7813 /* check if all streams are eos */
7815 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7816 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7825 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7827 /* FIXME: should either be an assert or a plain check */
7828 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7830 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7831 dts, pts, duration, keyframe, dts, demux->offset);
7835 GST_OBJECT_LOCK (demux);
7836 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7837 GST_OBJECT_UNLOCK (demux);
7839 /* skip this data, stream is EOS */
7840 gst_adapter_flush (demux->adapter, demux->neededbytes);
7843 stream->sample_index++;
7844 stream->offset_in_sample = 0;
7846 /* update current offset and figure out size of next buffer */
7847 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7848 demux->offset, demux->neededbytes);
7849 demux->offset += demux->neededbytes;
7850 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7854 if (ret == GST_FLOW_EOS) {
7855 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7856 demux->neededbytes = -1;
7860 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7861 if (demux->fragmented) {
7862 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7863 /* there may be more to follow, only finish this atom */
7864 demux->todrop = demux->mdatleft;
7865 demux->neededbytes = demux->todrop;
7870 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7871 goto non_ok_unlinked_flow;
7880 /* when buffering movie data, at least show user something is happening */
7881 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7882 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7883 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7884 demux->neededbytes);
7891 non_ok_unlinked_flow:
7893 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7894 gst_flow_get_name (ret));
7899 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7900 ret = GST_FLOW_ERROR;
7905 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7911 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7912 (NULL), ("qtdemuxer invalid state %d", demux->state));
7913 ret = GST_FLOW_ERROR;
7918 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7919 (NULL), ("no 'moov' atom within the first 10 MB"));
7920 ret = GST_FLOW_ERROR;
7926 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7931 query = gst_query_new_scheduling ();
7933 if (!gst_pad_peer_query (sinkpad, query)) {
7934 gst_query_unref (query);
7938 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7939 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7940 gst_query_unref (query);
7945 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7946 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7950 GST_DEBUG_OBJECT (sinkpad, "activating push");
7951 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7956 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7957 GstPadMode mode, gboolean active)
7960 GstQTDemux *demux = GST_QTDEMUX (parent);
7963 case GST_PAD_MODE_PUSH:
7964 demux->pullbased = FALSE;
7967 case GST_PAD_MODE_PULL:
7969 demux->pullbased = TRUE;
7970 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7973 res = gst_pad_stop_task (sinkpad);
7985 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7991 memset (&z, 0, sizeof (z));
7996 if ((ret = inflateInit (&z)) != Z_OK) {
7997 GST_ERROR ("inflateInit() returned %d", ret);
8001 z.next_in = z_buffer;
8002 z.avail_in = z_length;
8004 buffer = (guint8 *) g_malloc (*length);
8005 z.avail_out = *length;
8006 z.next_out = (Bytef *) buffer;
8008 ret = inflate (&z, Z_NO_FLUSH);
8009 if (ret == Z_STREAM_END) {
8011 } else if (ret != Z_OK) {
8012 GST_WARNING ("inflate() returned %d", ret);
8016 if (*length > G_MAXUINT - 4096 || *length > QTDEMUX_MAX_SAMPLE_INDEX_SIZE) {
8017 GST_WARNING ("too big decompressed data");
8023 buffer = (guint8 *) g_realloc (buffer, *length);
8024 z.next_out = (Bytef *) (buffer + z.total_out);
8025 z.avail_out += *length - z.total_out;
8026 } while (z.avail_in > 0);
8028 if (ret != Z_STREAM_END) {
8033 *length = z.total_out;
8040 #endif /* HAVE_ZLIB */
8043 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
8047 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
8049 /* counts as header data */
8050 qtdemux->header_size += length;
8052 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
8053 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
8055 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
8062 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
8063 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
8064 if (dcom == NULL || cmvd == NULL)
8065 goto invalid_compression;
8067 dcom_len = QT_UINT32 (dcom->data);
8069 goto invalid_compression;
8071 method = QT_FOURCC ((guint8 *) dcom->data + 8);
8075 guint uncompressed_length;
8076 guint compressed_length;
8080 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
8082 goto invalid_compression;
8084 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
8085 compressed_length = cmvd_len - 12;
8086 GST_LOG ("length = %u", uncompressed_length);
8089 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
8090 compressed_length, &uncompressed_length);
8093 qtdemux->moov_node_compressed = qtdemux->moov_node;
8094 qtdemux->moov_node = g_node_new (buf);
8096 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
8097 uncompressed_length);
8101 #endif /* HAVE_ZLIB */
8103 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
8104 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
8111 invalid_compression:
8113 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
8119 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
8122 while (G_UNLIKELY (buf < end)) {
8126 if (G_UNLIKELY (buf + 4 > end)) {
8127 GST_LOG_OBJECT (qtdemux, "buffer overrun");
8130 len = QT_UINT32 (buf);
8131 if (G_UNLIKELY (len == 0)) {
8132 GST_LOG_OBJECT (qtdemux, "empty container");
8135 if (G_UNLIKELY (len < 8)) {
8136 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
8139 if (G_UNLIKELY (len > (end - buf))) {
8140 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
8141 (gint) (end - buf));
8145 child = g_node_new ((guint8 *) buf);
8146 g_node_append (node, child);
8147 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
8148 qtdemux_parse_node (qtdemux, child, buf, len);
8156 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
8159 int len = QT_UINT32 (xdxt->data);
8160 guint8 *buf = xdxt->data;
8161 guint8 *end = buf + len;
8164 /* skip size and type */
8172 size = QT_UINT32 (buf);
8173 type = QT_FOURCC (buf + 4);
8175 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
8177 if (buf + size > end || size <= 0)
8183 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8184 GST_FOURCC_ARGS (type));
8188 buffer = gst_buffer_new_and_alloc (size);
8189 gst_buffer_fill (buffer, 0, buf, size);
8190 stream->buffers = g_slist_append (stream->buffers, buffer);
8191 GST_LOG_OBJECT (qtdemux, "parsing theora header");
8194 buffer = gst_buffer_new_and_alloc (size);
8195 gst_buffer_fill (buffer, 0, buf, size);
8196 stream->buffers = g_slist_append (stream->buffers, buffer);
8197 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
8200 buffer = gst_buffer_new_and_alloc (size);
8201 gst_buffer_fill (buffer, 0, buf, size);
8202 stream->buffers = g_slist_append (stream->buffers, buffer);
8203 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
8206 GST_WARNING_OBJECT (qtdemux,
8207 "unknown theora cookie %" GST_FOURCC_FORMAT,
8208 GST_FOURCC_ARGS (type));
8217 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8221 guint32 node_length = 0;
8222 const QtNodeType *type;
8225 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8227 if (G_UNLIKELY (length < 8))
8228 goto not_enough_data;
8230 node_length = QT_UINT32 (buffer);
8231 fourcc = QT_FOURCC (buffer + 4);
8233 /* ignore empty nodes */
8234 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8237 type = qtdemux_type_get (fourcc);
8239 end = buffer + length;
8241 GST_LOG_OBJECT (qtdemux,
8242 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8243 GST_FOURCC_ARGS (fourcc), node_length, type->name);
8245 if (node_length > length)
8246 goto broken_atom_size;
8248 if (type->flags & QT_FLAG_CONTAINER) {
8249 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8254 if (node_length < 20) {
8255 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8258 GST_DEBUG_OBJECT (qtdemux,
8259 "parsing stsd (sample table, sample description) atom");
8260 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8261 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8273 /* also read alac (or whatever) in stead of mp4a in the following,
8274 * since a similar layout is used in other cases as well */
8275 if (fourcc == FOURCC_mp4a)
8277 else if (fourcc == FOURCC_fLaC)
8282 /* There are two things we might encounter here: a true mp4a atom, and
8283 an mp4a entry in an stsd atom. The latter is what we're interested
8284 in, and it looks like an atom, but isn't really one. The true mp4a
8285 atom is short, so we detect it based on length here. */
8286 if (length < min_size) {
8287 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8288 GST_FOURCC_ARGS (fourcc));
8292 /* 'version' here is the sound sample description version. Types 0 and
8293 1 are documented in the QTFF reference, but type 2 is not: it's
8294 described in Apple header files instead (struct SoundDescriptionV2
8296 version = QT_UINT16 (buffer + 16);
8298 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8299 GST_FOURCC_ARGS (fourcc), version);
8301 /* parse any esds descriptors */
8313 GST_WARNING_OBJECT (qtdemux,
8314 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8315 GST_FOURCC_ARGS (fourcc), version);
8320 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8348 /* codec_data is contained inside these atoms, which all have
8349 * the same format. */
8350 /* video sample description size is 86 bytes without extension.
8351 * node_length have to be bigger than 86 bytes because video sample
8352 * description can include extensions such as esds, fiel, glbl, etc. */
8353 if (node_length < 86) {
8354 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8355 " sample description length too short (%u < 86)",
8356 GST_FOURCC_ARGS (fourcc), node_length);
8360 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8361 GST_FOURCC_ARGS (fourcc));
8363 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8365 * revision level (2 bytes) : must be set to 0. */
8366 version = QT_UINT32 (buffer + 16);
8367 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8369 /* compressor name : PASCAL string and informative purposes
8370 * first byte : the number of bytes to be displayed.
8371 * it has to be less than 32 because it is reserved
8372 * space of 32 bytes total including itself. */
8373 str_len = QT_UINT8 (buffer + 50);
8375 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8376 (char *) buffer + 51);
8378 GST_WARNING_OBJECT (qtdemux,
8379 "compressorname length too big (%u > 31)", str_len);
8381 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8383 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8388 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8390 /* You are reading this correctly. QTFF specifies that the
8391 * metadata atom is a short atom, whereas ISO BMFF specifies
8392 * it's a full atom. But since so many people are doing things
8393 * differently, we actually peek into the atom to see which
8396 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8397 GST_FOURCC_ARGS (fourcc));
8400 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8401 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8402 * starts with a 'hdlr' atom */
8403 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8404 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8405 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8406 * with version/flags both set to zero */
8407 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8409 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8414 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8415 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8416 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8425 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8426 GST_FOURCC_ARGS (fourcc));
8430 version = QT_UINT32 (buffer + 12);
8431 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8438 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8443 if (length < offset) {
8444 GST_WARNING_OBJECT (qtdemux,
8445 "skipping too small %" GST_FOURCC_FORMAT " box",
8446 GST_FOURCC_ARGS (fourcc));
8449 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8455 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8460 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8465 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8469 if (!strcmp (type->name, "unknown"))
8470 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8474 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8475 GST_FOURCC_ARGS (fourcc));
8481 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8482 (_("This file is corrupt and cannot be played.")),
8483 ("Not enough data for an atom header, got only %u bytes", length));
8488 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8489 (_("This file is corrupt and cannot be played.")),
8490 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8491 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8498 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8500 /* FIXME: This can only reliably work if demuxers have a
8501 * separate streaming thread per srcpad. This should be
8502 * done in a demuxer base class, which integrates parts
8505 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8510 query = gst_query_new_allocation (stream->caps, FALSE);
8512 if (!gst_pad_peer_query (stream->pad, query)) {
8513 /* not a problem, just debug a little */
8514 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8517 if (stream->allocator)
8518 gst_object_unref (stream->allocator);
8520 if (gst_query_get_n_allocation_params (query) > 0) {
8521 /* try the allocator */
8522 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8524 stream->use_allocator = TRUE;
8526 stream->allocator = NULL;
8527 gst_allocation_params_init (&stream->params);
8528 stream->use_allocator = FALSE;
8530 gst_query_unref (query);
8535 pad_query (const GValue * item, GValue * value, gpointer user_data)
8537 GstPad *pad = g_value_get_object (item);
8538 GstQuery *query = user_data;
8541 res = gst_pad_peer_query (pad, query);
8544 g_value_set_boolean (value, TRUE);
8548 GST_INFO_OBJECT (pad, "pad peer query failed");
8553 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8554 GstPadDirection direction)
8557 GstIteratorFoldFunction func = pad_query;
8558 GValue res = { 0, };
8560 g_value_init (&res, G_TYPE_BOOLEAN);
8561 g_value_set_boolean (&res, FALSE);
8564 if (direction == GST_PAD_SRC)
8565 it = gst_element_iterate_src_pads (element);
8567 it = gst_element_iterate_sink_pads (element);
8569 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8570 gst_iterator_resync (it);
8572 gst_iterator_free (it);
8574 return g_value_get_boolean (&res);
8578 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8579 QtDemuxStream * stream)
8583 GstElement *element = GST_ELEMENT (qtdemux);
8585 gchar **filtered_sys_ids;
8586 GValue event_list = G_VALUE_INIT;
8589 /* 1. Check if we already have the context. */
8590 if (qtdemux->preferred_protection_system_id != NULL) {
8591 GST_LOG_OBJECT (element,
8592 "already have the protection context, no need to request it again");
8596 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8597 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8598 (const gchar **) qtdemux->protection_system_ids->pdata);
8600 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8601 qtdemux->protection_system_ids->len - 1);
8602 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8603 "decryptors for %u of them, running context request",
8604 qtdemux->protection_system_ids->len,
8605 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8608 if (stream->protection_scheme_event_queue.length) {
8609 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8610 stream->protection_scheme_event_queue.length);
8611 walk = stream->protection_scheme_event_queue.tail;
8613 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8614 qtdemux->protection_event_queue.length);
8615 walk = qtdemux->protection_event_queue.tail;
8618 g_value_init (&event_list, GST_TYPE_LIST);
8619 for (; walk; walk = g_list_previous (walk)) {
8620 GValue event_value = G_VALUE_INIT;
8621 g_value_init (&event_value, GST_TYPE_EVENT);
8622 g_value_set_boxed (&event_value, walk->data);
8623 gst_value_list_append_and_take_value (&event_list, &event_value);
8626 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8627 * check if downstream already has a context of the specific type
8628 * 2b) Query upstream as above.
8630 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8631 st = gst_query_writable_structure (query);
8632 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8633 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8635 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8636 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8637 gst_query_parse_context (query, &ctxt);
8638 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8639 gst_element_set_context (element, ctxt);
8640 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8641 gst_query_parse_context (query, &ctxt);
8642 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8643 gst_element_set_context (element, ctxt);
8645 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8646 * the required context type and afterwards check if a
8647 * usable context was set now as in 1). The message could
8648 * be handled by the parent bins of the element and the
8653 GST_INFO_OBJECT (element, "posting need context message");
8654 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8655 "drm-preferred-decryption-system-id");
8656 st = (GstStructure *) gst_message_get_structure (msg);
8657 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8658 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8661 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8662 gst_element_post_message (element, msg);
8665 g_strfreev (filtered_sys_ids);
8666 g_value_unset (&event_list);
8667 gst_query_unref (query);
8671 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8672 QtDemuxStream * stream)
8675 const gchar *selected_system = NULL;
8677 g_return_val_if_fail (qtdemux != NULL, FALSE);
8678 g_return_val_if_fail (stream != NULL, FALSE);
8679 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8682 if (stream->protection_scheme_type == FOURCC_aavd) {
8683 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8684 if (!gst_structure_has_name (s, "application/x-aavd")) {
8685 gst_structure_set (s,
8686 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8688 gst_structure_set_name (s, "application/x-aavd");
8693 if (stream->protection_scheme_type != FOURCC_cenc
8694 && stream->protection_scheme_type != FOURCC_cbcs) {
8695 GST_ERROR_OBJECT (qtdemux,
8696 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8697 GST_FOURCC_ARGS (stream->protection_scheme_type));
8701 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8702 if (!gst_structure_has_name (s, "application/x-cenc")) {
8703 gst_structure_set (s,
8704 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8705 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8706 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8708 gst_structure_set_name (s, "application/x-cenc");
8711 if (qtdemux->protection_system_ids == NULL) {
8712 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8713 "cenc protection system information has been found, not setting a "
8714 "protection system UUID");
8718 gst_qtdemux_request_protection_context (qtdemux, stream);
8719 if (qtdemux->preferred_protection_system_id != NULL) {
8720 const gchar *preferred_system_array[] =
8721 { qtdemux->preferred_protection_system_id, NULL };
8723 selected_system = gst_protection_select_system (preferred_system_array);
8725 if (selected_system) {
8726 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8727 qtdemux->preferred_protection_system_id);
8729 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8730 "because there is no available decryptor",
8731 qtdemux->preferred_protection_system_id);
8735 if (!selected_system) {
8736 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8737 selected_system = gst_protection_select_system ((const gchar **)
8738 qtdemux->protection_system_ids->pdata);
8739 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8740 qtdemux->protection_system_ids->len - 1);
8743 if (!selected_system) {
8744 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8745 "suitable decryptor element has been found");
8749 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8752 gst_structure_set (s,
8753 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8760 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8762 /* fps is calculated base on the duration of the average framerate since
8763 * qt does not have a fixed framerate. */
8764 gboolean fps_available = TRUE;
8765 guint32 first_duration = 0;
8767 if (stream->n_samples > 0)
8768 first_duration = stream->samples[0].duration;
8770 if ((stream->n_samples == 1 && first_duration == 0)
8771 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8773 CUR_STREAM (stream)->fps_n = 0;
8774 CUR_STREAM (stream)->fps_d = 1;
8776 if (stream->duration == 0 || stream->n_samples < 2) {
8777 CUR_STREAM (stream)->fps_n = stream->timescale;
8778 CUR_STREAM (stream)->fps_d = 1;
8779 fps_available = FALSE;
8781 GstClockTime avg_duration;
8785 /* duration and n_samples can be updated for fragmented format
8786 * so, framerate of fragmented format is calculated using data in a moof */
8787 if (qtdemux->fragmented && stream->n_samples_moof > 0
8788 && stream->duration_moof > 0) {
8789 n_samples = stream->n_samples_moof;
8790 duration = stream->duration_moof;
8792 n_samples = stream->n_samples;
8793 duration = stream->duration;
8796 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8797 /* stream->duration is guint64, timescale, n_samples are guint32 */
8799 gst_util_uint64_scale_round (duration -
8800 first_duration, GST_SECOND,
8801 (guint64) (stream->timescale) * (n_samples - 1));
8803 GST_LOG_OBJECT (qtdemux,
8804 "Calculating avg sample duration based on stream (or moof) duration %"
8806 " minus first sample %u, leaving %d samples gives %"
8807 GST_TIME_FORMAT, duration, first_duration,
8808 n_samples - 1, GST_TIME_ARGS (avg_duration));
8811 gst_video_guess_framerate (avg_duration,
8812 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8814 GST_DEBUG_OBJECT (qtdemux,
8815 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8816 stream->timescale, CUR_STREAM (stream)->fps_n,
8817 CUR_STREAM (stream)->fps_d);
8821 return fps_available;
8825 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8827 if (stream->subtype == FOURCC_vide) {
8828 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8830 if (CUR_STREAM (stream)->caps) {
8831 CUR_STREAM (stream)->caps =
8832 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8834 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8835 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8836 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8837 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8839 /* set framerate if calculated framerate is reliable */
8840 if (fps_available) {
8841 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8842 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8843 CUR_STREAM (stream)->fps_d, NULL);
8846 /* calculate pixel-aspect-ratio using display width and height */
8847 GST_DEBUG_OBJECT (qtdemux,
8848 "video size %dx%d, target display size %dx%d",
8849 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8850 stream->display_width, stream->display_height);
8851 /* qt file might have pasp atom */
8852 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8853 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8854 CUR_STREAM (stream)->par_h);
8855 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8856 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8857 CUR_STREAM (stream)->par_h, NULL);
8858 } else if (stream->display_width > 0 && stream->display_height > 0
8859 && CUR_STREAM (stream)->width > 0
8860 && CUR_STREAM (stream)->height > 0) {
8863 /* calculate the pixel aspect ratio using the display and pixel w/h */
8864 n = stream->display_width * CUR_STREAM (stream)->height;
8865 d = stream->display_height * CUR_STREAM (stream)->width;
8868 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8869 CUR_STREAM (stream)->par_w = n;
8870 CUR_STREAM (stream)->par_h = d;
8871 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8872 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8873 CUR_STREAM (stream)->par_h, NULL);
8876 if (CUR_STREAM (stream)->interlace_mode > 0) {
8877 if (CUR_STREAM (stream)->interlace_mode == 1) {
8878 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8879 G_TYPE_STRING, "progressive", NULL);
8880 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8881 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8882 G_TYPE_STRING, "interleaved", NULL);
8883 if (CUR_STREAM (stream)->field_order == 9) {
8884 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8885 G_TYPE_STRING, "top-field-first", NULL);
8886 } else if (CUR_STREAM (stream)->field_order == 14) {
8887 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8888 G_TYPE_STRING, "bottom-field-first", NULL);
8893 /* Create incomplete colorimetry here if needed */
8894 if (CUR_STREAM (stream)->colorimetry.range ||
8895 CUR_STREAM (stream)->colorimetry.matrix ||
8896 CUR_STREAM (stream)->colorimetry.transfer
8897 || CUR_STREAM (stream)->colorimetry.primaries) {
8898 gchar *colorimetry =
8899 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8900 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8901 G_TYPE_STRING, colorimetry, NULL);
8902 g_free (colorimetry);
8905 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8906 guint par_w = 1, par_h = 1;
8908 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8909 par_w = CUR_STREAM (stream)->par_w;
8910 par_h = CUR_STREAM (stream)->par_h;
8913 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8914 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8916 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8919 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8920 "multiview-mode", G_TYPE_STRING,
8921 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8922 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8923 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8928 else if (stream->subtype == FOURCC_soun) {
8929 if (CUR_STREAM (stream)->caps) {
8930 CUR_STREAM (stream)->caps =
8931 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8932 if (CUR_STREAM (stream)->rate > 0)
8933 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8934 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8935 if (CUR_STREAM (stream)->n_channels > 0)
8936 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8937 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8938 if (CUR_STREAM (stream)->n_channels > 2) {
8939 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8940 * correctly; this is just the minimum we can do - assume
8941 * we don't actually have any channel positions. */
8942 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8943 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8948 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8949 const GstStructure *s;
8950 QtDemuxStream *fps_stream = NULL;
8951 gboolean fps_available = FALSE;
8953 /* CEA608 closed caption tracks are a bit special in that each sample
8954 * can contain CCs for multiple frames, and CCs can be omitted and have to
8955 * be inferred from the duration of the sample then.
8957 * As such we take the framerate from the (first) video track here for
8958 * CEA608 as there must be one CC byte pair for every video frame
8959 * according to the spec.
8961 * For CEA708 all is fine and there is one sample per frame.
8964 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8965 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8968 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8969 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8971 if (tmp->subtype == FOURCC_vide) {
8978 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8979 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8980 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8983 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8984 fps_stream = stream;
8987 CUR_STREAM (stream)->caps =
8988 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8990 /* set framerate if calculated framerate is reliable */
8991 if (fps_available) {
8992 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8993 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8994 CUR_STREAM (stream)->fps_d, NULL);
8999 gboolean forward_collection = FALSE;
9000 GstCaps *prev_caps = NULL;
9002 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
9003 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
9004 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
9005 gst_pad_set_active (stream->pad, TRUE);
9007 gst_pad_use_fixed_caps (stream->pad);
9009 if (stream->protected) {
9010 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
9011 GST_ERROR_OBJECT (qtdemux,
9012 "Failed to configure protected stream caps.");
9017 if (stream->new_stream) {
9019 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
9022 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
9025 gst_event_parse_stream_flags (event, &stream_flags);
9026 if (gst_event_parse_group_id (event, &qtdemux->group_id))
9027 qtdemux->have_group_id = TRUE;
9029 qtdemux->have_group_id = FALSE;
9030 gst_event_unref (event);
9031 } else if (!qtdemux->have_group_id) {
9032 qtdemux->have_group_id = TRUE;
9033 qtdemux->group_id = gst_util_group_id_next ();
9036 stream->new_stream = FALSE;
9037 event = gst_event_new_stream_start (stream->stream_id);
9038 if (qtdemux->have_group_id)
9039 gst_event_set_group_id (event, qtdemux->group_id);
9040 if (stream->disabled)
9041 stream_flags |= GST_STREAM_FLAG_UNSELECT;
9042 if (CUR_STREAM (stream)->sparse) {
9043 stream_flags |= GST_STREAM_FLAG_SPARSE;
9045 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
9047 gst_event_set_stream_flags (event, stream_flags);
9048 gst_pad_push_event (stream->pad, event);
9050 forward_collection = TRUE;
9053 prev_caps = gst_pad_get_current_caps (stream->pad);
9055 if (CUR_STREAM (stream)->caps) {
9057 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
9058 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
9059 CUR_STREAM (stream)->caps);
9060 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
9062 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
9065 GST_WARNING_OBJECT (qtdemux, "stream without caps");
9069 gst_caps_unref (prev_caps);
9070 stream->new_caps = FALSE;
9072 if (forward_collection) {
9073 /* Forward upstream collection and selection if any */
9074 GstEvent *upstream_event = gst_pad_get_sticky_event (qtdemux->sinkpad,
9075 GST_EVENT_STREAM_COLLECTION, 0);
9077 gst_pad_push_event (stream->pad, upstream_event);
9084 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
9085 QtDemuxStream * stream)
9087 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
9090 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
9091 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
9092 if (G_UNLIKELY (stream->stsd_sample_description_id >=
9093 stream->stsd_entries_length)) {
9094 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
9095 (_("This file is invalid and cannot be played.")),
9096 ("New sample description id is out of bounds (%d >= %d)",
9097 stream->stsd_sample_description_id, stream->stsd_entries_length));
9099 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
9100 stream->new_caps = TRUE;
9105 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
9106 QtDemuxStream * stream, GstTagList * list)
9108 gboolean ret = TRUE;
9110 if (stream->subtype == FOURCC_vide) {
9111 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9114 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9117 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9118 gst_object_unref (stream->pad);
9124 qtdemux->n_video_streams++;
9125 } else if (stream->subtype == FOURCC_soun) {
9126 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
9129 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9131 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9132 gst_object_unref (stream->pad);
9137 qtdemux->n_audio_streams++;
9138 } else if (stream->subtype == FOURCC_strm) {
9139 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9140 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9141 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9142 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
9143 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9146 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9148 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9149 gst_object_unref (stream->pad);
9154 qtdemux->n_sub_streams++;
9155 } else if (stream->subtype == FOURCC_meta) {
9156 gchar *name = g_strdup_printf ("meta_%u", qtdemux->n_meta_streams);
9159 gst_pad_new_from_static_template (&gst_qtdemux_metasrc_template, name);
9161 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9162 gst_object_unref (stream->pad);
9167 qtdemux->n_meta_streams++;
9168 } else if (CUR_STREAM (stream)->caps) {
9169 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9172 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9174 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9175 gst_object_unref (stream->pad);
9180 qtdemux->n_video_streams++;
9182 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9189 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9190 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9191 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9192 GST_OBJECT_LOCK (qtdemux);
9193 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9194 GST_OBJECT_UNLOCK (qtdemux);
9196 if (stream->stream_tags)
9197 gst_tag_list_unref (stream->stream_tags);
9198 stream->stream_tags = list;
9200 /* global tags go on each pad anyway */
9201 stream->send_global_tags = TRUE;
9202 /* send upstream GST_EVENT_PROTECTION events that were received before
9203 this source pad was created */
9204 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9205 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9209 gst_tag_list_unref (list);
9213 /* find next atom with @fourcc starting at @offset */
9214 static GstFlowReturn
9215 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9216 guint64 * length, guint32 fourcc)
9222 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9223 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9229 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9230 if (G_UNLIKELY (ret != GST_FLOW_OK))
9232 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9235 gst_buffer_unref (buf);
9238 gst_buffer_map (buf, &map, GST_MAP_READ);
9239 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9240 gst_buffer_unmap (buf, &map);
9241 gst_buffer_unref (buf);
9243 if (G_UNLIKELY (*length == 0)) {
9244 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9245 ret = GST_FLOW_ERROR;
9249 if (lfourcc == fourcc) {
9250 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9251 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9254 GST_LOG_OBJECT (qtdemux,
9255 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9256 GST_FOURCC_ARGS (lfourcc), *offset);
9257 if (*offset == G_MAXUINT64)
9267 /* might simply have had last one */
9268 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9273 /* should only do something in pull mode */
9274 /* call with OBJECT lock */
9275 static GstFlowReturn
9276 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9278 guint64 length, offset;
9279 GstBuffer *buf = NULL;
9280 GstFlowReturn ret = GST_FLOW_OK;
9281 GstFlowReturn res = GST_FLOW_OK;
9284 offset = qtdemux->moof_offset;
9285 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9288 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9289 return GST_FLOW_EOS;
9292 /* best not do pull etc with lock held */
9293 GST_OBJECT_UNLOCK (qtdemux);
9295 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9296 if (ret != GST_FLOW_OK)
9299 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9300 if (G_UNLIKELY (ret != GST_FLOW_OK))
9302 gst_buffer_map (buf, &map, GST_MAP_READ);
9303 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9304 gst_buffer_unmap (buf, &map);
9305 gst_buffer_unref (buf);
9310 gst_buffer_unmap (buf, &map);
9311 gst_buffer_unref (buf);
9315 /* look for next moof */
9316 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9317 if (G_UNLIKELY (ret != GST_FLOW_OK))
9321 GST_OBJECT_LOCK (qtdemux);
9323 qtdemux->moof_offset = offset;
9329 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9331 res = GST_FLOW_ERROR;
9336 /* maybe upstream temporarily flushing */
9337 if (ret != GST_FLOW_FLUSHING) {
9338 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9341 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9342 /* resume at current position next time */
9350 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9354 gint32 stts_duration;
9355 GstByteWriter stsc, stts, stsz;
9357 /* Each sample has a different size, which we don't support for merging */
9358 if (stream->sample_size == 0) {
9359 GST_DEBUG_OBJECT (qtdemux,
9360 "Not all samples have the same size, not merging");
9364 /* The stream has a ctts table, we don't support that */
9365 if (stream->ctts_present) {
9366 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9370 /* If there's a sync sample table also ignore this stream */
9371 if (stream->stps_present || stream->stss_present) {
9372 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9376 /* If chunks are considered samples already ignore this stream */
9377 if (stream->chunks_are_samples) {
9378 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9382 /* Require that all samples have the same duration */
9383 if (stream->n_sample_times > 1) {
9384 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9388 /* Parse the stts to get the sample duration and number of samples */
9389 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9390 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9392 /* Parse the number of chunks from the stco manually because the
9393 * reader is already behind that */
9394 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9396 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9399 /* Now parse stsc, convert chunks into single samples and generate a
9400 * new stsc, stts and stsz from this information */
9401 gst_byte_writer_init (&stsc);
9402 gst_byte_writer_init (&stts);
9403 gst_byte_writer_init (&stsz);
9405 /* Note: we skip fourccs, size, version, flags and other fields of the new
9406 * atoms as the byte readers with them are already behind that position
9407 * anyway and only update the values of those inside the stream directly.
9409 stream->n_sample_times = 0;
9410 stream->n_samples = 0;
9411 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9413 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9415 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9416 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9417 sample_description_id =
9418 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9420 if (i == stream->n_samples_per_chunk - 1) {
9421 /* +1 because first_chunk is 1-based */
9422 last_chunk = num_chunks + 1;
9424 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9427 GST_DEBUG_OBJECT (qtdemux,
9428 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9429 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9431 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9432 /* One sample in this chunk */
9433 gst_byte_writer_put_uint32_be (&stsc, 1);
9434 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9436 /* For each chunk write a stts and stsz entry now */
9437 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9438 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9439 for (j = first_chunk; j < last_chunk; j++) {
9440 gst_byte_writer_put_uint32_be (&stsz,
9441 stream->sample_size * samples_per_chunk);
9444 stream->n_sample_times += 1;
9445 stream->n_samples += last_chunk - first_chunk;
9448 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9450 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9451 stream->n_samples, stream->n_sample_times);
9453 /* We don't have a fixed sample size anymore */
9454 stream->sample_size = 0;
9456 /* Free old data for the atoms */
9457 g_free ((gpointer) stream->stsz.data);
9458 stream->stsz.data = NULL;
9459 g_free ((gpointer) stream->stsc.data);
9460 stream->stsc.data = NULL;
9461 g_free ((gpointer) stream->stts.data);
9462 stream->stts.data = NULL;
9464 /* Store new data and replace byte readers */
9465 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9466 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9467 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9468 stream->stts.size = gst_byte_writer_get_size (&stts);
9469 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9470 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9471 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9472 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9473 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9476 /* initialise bytereaders for stbl sub-atoms */
9478 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9480 stream->stbl_index = -1; /* no samples have yet been parsed */
9481 stream->sample_index = -1;
9483 /* time-to-sample atom */
9484 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9487 /* copy atom data into a new buffer for later use */
9488 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9490 /* skip version + flags */
9491 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9492 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9494 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9496 /* make sure there's enough data */
9497 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9498 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9499 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9500 stream->n_sample_times);
9501 if (!stream->n_sample_times)
9505 /* sync sample atom */
9506 stream->stps_present = FALSE;
9507 if ((stream->stss_present =
9508 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9509 &stream->stss) ? TRUE : FALSE) == TRUE) {
9510 /* copy atom data into a new buffer for later use */
9511 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9513 /* skip version + flags */
9514 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9515 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9518 if (stream->n_sample_syncs) {
9519 /* make sure there's enough data */
9520 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9524 /* partial sync sample atom */
9525 if ((stream->stps_present =
9526 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9527 &stream->stps) ? TRUE : FALSE) == TRUE) {
9528 /* copy atom data into a new buffer for later use */
9529 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9531 /* skip version + flags */
9532 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9533 !gst_byte_reader_get_uint32_be (&stream->stps,
9534 &stream->n_sample_partial_syncs))
9537 /* if there are no entries, the stss table contains the real
9539 if (stream->n_sample_partial_syncs) {
9540 /* make sure there's enough data */
9541 if (!qt_atom_parser_has_chunks (&stream->stps,
9542 stream->n_sample_partial_syncs, 4))
9549 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9552 /* copy atom data into a new buffer for later use */
9553 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9555 /* skip version + flags */
9556 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9557 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9560 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9563 if (!stream->n_samples)
9566 /* sample-to-chunk atom */
9567 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9570 /* copy atom data into a new buffer for later use */
9571 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9573 /* skip version + flags */
9574 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9575 !gst_byte_reader_get_uint32_be (&stream->stsc,
9576 &stream->n_samples_per_chunk))
9579 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9580 stream->n_samples_per_chunk);
9582 /* make sure there's enough data */
9583 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9589 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9590 stream->co_size = sizeof (guint32);
9591 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9593 stream->co_size = sizeof (guint64);
9597 /* copy atom data into a new buffer for later use */
9598 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9600 /* skip version + flags */
9601 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9604 /* chunks_are_samples == TRUE means treat chunks as samples */
9605 stream->chunks_are_samples = stream->sample_size
9606 && !CUR_STREAM (stream)->sampled;
9607 if (stream->chunks_are_samples) {
9608 /* treat chunks as samples */
9609 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9612 /* skip number of entries */
9613 if (!gst_byte_reader_skip (&stream->stco, 4))
9616 /* make sure there are enough data in the stsz atom */
9617 if (!stream->sample_size) {
9618 /* different sizes for each sample */
9619 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9624 /* composition time-to-sample */
9625 if ((stream->ctts_present =
9626 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9627 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9628 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9629 guint8 ctts_version;
9630 gboolean checked_ctts = FALSE;
9632 /* copy atom data into a new buffer for later use */
9633 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9635 /* version 1 has signed offsets */
9636 if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9640 if (!gst_byte_reader_skip (&stream->ctts, 3)
9641 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9642 &stream->n_composition_times))
9645 /* make sure there's enough data */
9646 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9650 /* This is optional, if missing we iterate the ctts */
9651 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9652 guint8 cslg_version;
9654 /* cslg version 1 has 64 bit fields */
9655 if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9659 if (!gst_byte_reader_skip (&cslg, 3))
9662 if (cslg_version == 0) {
9663 gint32 composition_to_dts_shift;
9665 if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9668 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9670 gint64 composition_to_dts_shift;
9672 if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9675 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9678 gint32 cslg_least = 0;
9679 guint num_entries, pos;
9682 pos = gst_byte_reader_get_pos (&stream->ctts);
9683 num_entries = stream->n_composition_times;
9685 checked_ctts = TRUE;
9687 stream->cslg_shift = 0;
9689 for (i = 0; i < num_entries; i++) {
9692 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9693 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9694 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9695 * slightly inaccurate PTS could be more usable than corrupted one */
9696 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9697 && ABS (offset) / 2 > stream->duration)) {
9698 GST_WARNING_OBJECT (qtdemux,
9699 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9700 " larger than duration %" G_GUINT64_FORMAT, offset,
9703 stream->cslg_shift = 0;
9704 stream->ctts_present = FALSE;
9708 /* Don't consider "no decode samples" with offset G_MININT32
9709 * for the DTS/PTS shift */
9710 if (offset != G_MININT32 && offset < cslg_least)
9711 cslg_least = offset;
9715 stream->cslg_shift = -cslg_least;
9717 stream->cslg_shift = 0;
9719 /* reset the reader so we can generate sample table */
9720 gst_byte_reader_set_pos (&stream->ctts, pos);
9723 /* Check if ctts values are looking reasonable if that didn't happen above */
9724 if (!checked_ctts) {
9725 guint num_entries, pos;
9728 pos = gst_byte_reader_get_pos (&stream->ctts);
9729 num_entries = stream->n_composition_times;
9731 for (i = 0; i < num_entries; i++) {
9734 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9735 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9736 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9737 * slightly inaccurate PTS could be more usable than corrupted one */
9738 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9739 && ABS (offset) / 2 > stream->duration)) {
9740 GST_WARNING_OBJECT (qtdemux,
9741 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9742 " larger than duration %" G_GUINT64_FORMAT, offset,
9745 stream->cslg_shift = 0;
9746 stream->ctts_present = FALSE;
9751 /* reset the reader so we can generate sample table */
9752 gst_byte_reader_set_pos (&stream->ctts, pos);
9755 /* Ensure the cslg_shift value is consistent so we can use it
9756 * unconditionally to produce TS and Segment */
9757 stream->cslg_shift = 0;
9760 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
9761 stream->cslg_shift);
9763 /* For raw audio streams especially we might want to merge the samples
9764 * to not output one audio sample per buffer. We're doing this here
9765 * before allocating the sample tables so that from this point onwards
9766 * the number of container samples are static */
9767 if (stream->min_buffer_size > 0) {
9768 qtdemux_merge_sample_table (qtdemux, stream);
9772 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9773 stream->n_samples, (guint) sizeof (QtDemuxSample),
9774 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9776 if (stream->n_samples >=
9777 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9778 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9779 "be larger than %uMB (broken file?)", stream->n_samples,
9780 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9784 g_assert (stream->samples == NULL);
9785 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9786 if (!stream->samples) {
9787 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9796 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9797 (_("This file is corrupt and cannot be played.")), (NULL));
9802 gst_qtdemux_stbl_free (stream);
9803 if (!qtdemux->fragmented) {
9804 /* not quite good */
9805 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9808 /* may pick up samples elsewhere */
9814 /* collect samples from the next sample to be parsed up to sample @n for @stream
9815 * by reading the info from @stbl
9817 * This code can be executed from both the streaming thread and the seeking
9818 * thread so it takes the object lock to protect itself
9821 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9824 QtDemuxSample *samples, *first, *cur, *last;
9825 guint32 n_samples_per_chunk;
9828 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9829 GST_FOURCC_FORMAT ", pad %s",
9830 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9831 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9833 n_samples = stream->n_samples;
9836 goto out_of_samples;
9838 GST_OBJECT_LOCK (qtdemux);
9839 if (n <= stream->stbl_index)
9840 goto already_parsed;
9842 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9844 if (!stream->stsz.data) {
9845 /* so we already parsed and passed all the moov samples;
9846 * onto fragmented ones */
9847 g_assert (qtdemux->fragmented);
9851 /* pointer to the sample table */
9852 samples = stream->samples;
9854 /* starts from -1, moves to the next sample index to parse */
9855 stream->stbl_index++;
9857 /* keep track of the first and last sample to fill */
9858 first = &samples[stream->stbl_index];
9861 if (!stream->chunks_are_samples) {
9862 /* set the sample sizes */
9863 if (stream->sample_size == 0) {
9864 /* different sizes for each sample */
9865 for (cur = first; cur <= last; cur++) {
9866 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9867 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9868 (guint) (cur - samples), cur->size);
9871 /* samples have the same size */
9872 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9873 for (cur = first; cur <= last; cur++)
9874 cur->size = stream->sample_size;
9878 n_samples_per_chunk = stream->n_samples_per_chunk;
9881 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9884 if (stream->stsc_chunk_index >= stream->last_chunk
9885 || stream->stsc_chunk_index < stream->first_chunk) {
9886 stream->first_chunk =
9887 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9888 stream->samples_per_chunk =
9889 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9891 stream->stsd_sample_description_id =
9892 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9894 /* chunk numbers are counted from 1 it seems */
9895 if (G_UNLIKELY (stream->first_chunk == 0))
9898 --stream->first_chunk;
9900 /* the last chunk of each entry is calculated by taking the first chunk
9901 * of the next entry; except if there is no next, where we fake it with
9903 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9904 stream->last_chunk = G_MAXUINT32;
9906 stream->last_chunk =
9907 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9908 if (G_UNLIKELY (stream->last_chunk == 0))
9911 --stream->last_chunk;
9914 GST_LOG_OBJECT (qtdemux,
9915 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9916 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9917 stream->samples_per_chunk, stream->stsd_sample_description_id);
9919 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9922 if (stream->last_chunk != G_MAXUINT32) {
9923 if (!qt_atom_parser_peek_sub (&stream->stco,
9924 stream->first_chunk * stream->co_size,
9925 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9930 stream->co_chunk = stream->stco;
9931 if (!gst_byte_reader_skip (&stream->co_chunk,
9932 stream->first_chunk * stream->co_size))
9936 stream->stsc_chunk_index = stream->first_chunk;
9939 last_chunk = stream->last_chunk;
9941 if (stream->chunks_are_samples) {
9942 cur = &samples[stream->stsc_chunk_index];
9944 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9947 stream->stsc_chunk_index = j;
9952 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9955 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9956 "%" G_GUINT64_FORMAT, j, cur->offset);
9958 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9959 CUR_STREAM (stream)->bytes_per_frame > 0) {
9961 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9962 CUR_STREAM (stream)->samples_per_frame *
9963 CUR_STREAM (stream)->bytes_per_frame;
9965 cur->size = stream->samples_per_chunk;
9968 GST_DEBUG_OBJECT (qtdemux,
9969 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9970 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9971 stream->stco_sample_index)), cur->size);
9973 cur->timestamp = stream->stco_sample_index;
9974 cur->duration = stream->samples_per_chunk;
9975 cur->keyframe = TRUE;
9978 stream->stco_sample_index += stream->samples_per_chunk;
9980 stream->stsc_chunk_index = j;
9982 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9983 guint32 samples_per_chunk;
9984 guint64 chunk_offset;
9986 if (!stream->stsc_sample_index
9987 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9988 &stream->chunk_offset))
9991 samples_per_chunk = stream->samples_per_chunk;
9992 chunk_offset = stream->chunk_offset;
9994 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9995 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9996 G_GUINT64_FORMAT " and size %d",
9997 (guint) (cur - samples), chunk_offset, cur->size);
9999 cur->offset = chunk_offset;
10000 chunk_offset += cur->size;
10003 if (G_UNLIKELY (cur > last)) {
10005 stream->stsc_sample_index = k + 1;
10006 stream->chunk_offset = chunk_offset;
10007 stream->stsc_chunk_index = j;
10011 stream->stsc_sample_index = 0;
10013 stream->stsc_chunk_index = j;
10015 stream->stsc_index++;
10018 if (stream->chunks_are_samples)
10022 guint32 n_sample_times;
10024 n_sample_times = stream->n_sample_times;
10027 for (i = stream->stts_index; i < n_sample_times; i++) {
10028 guint32 stts_samples;
10029 gint32 stts_duration;
10032 if (stream->stts_sample_index >= stream->stts_samples
10033 || !stream->stts_sample_index) {
10035 stream->stts_samples =
10036 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10037 stream->stts_duration =
10038 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10040 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
10041 i, stream->stts_samples, stream->stts_duration);
10043 stream->stts_sample_index = 0;
10046 stts_samples = stream->stts_samples;
10047 stts_duration = stream->stts_duration;
10048 stts_time = stream->stts_time;
10050 for (j = stream->stts_sample_index; j < stts_samples; j++) {
10051 GST_DEBUG_OBJECT (qtdemux,
10052 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
10053 (guint) (cur - samples), j,
10054 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
10056 cur->timestamp = stts_time;
10057 cur->duration = stts_duration;
10059 /* avoid 32-bit wrap-around,
10060 * but still mind possible 'negative' duration */
10061 stts_time += (gint64) stts_duration;
10064 if (G_UNLIKELY (cur > last)) {
10066 stream->stts_time = stts_time;
10067 stream->stts_sample_index = j + 1;
10068 if (stream->stts_sample_index >= stream->stts_samples)
10069 stream->stts_index++;
10073 stream->stts_sample_index = 0;
10074 stream->stts_time = stts_time;
10075 stream->stts_index++;
10077 /* fill up empty timestamps with the last timestamp, this can happen when
10078 * the last samples do not decode and so we don't have timestamps for them.
10079 * We however look at the last timestamp to estimate the track length so we
10080 * need something in here. */
10081 for (; cur < last; cur++) {
10082 GST_DEBUG_OBJECT (qtdemux,
10083 "fill sample %d: timestamp %" GST_TIME_FORMAT,
10084 (guint) (cur - samples),
10085 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
10086 cur->timestamp = stream->stts_time;
10087 cur->duration = -1;
10092 /* sample sync, can be NULL */
10093 if (stream->stss_present == TRUE) {
10094 guint32 n_sample_syncs;
10096 n_sample_syncs = stream->n_sample_syncs;
10098 if (!n_sample_syncs) {
10099 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
10100 stream->all_keyframe = TRUE;
10102 for (i = stream->stss_index; i < n_sample_syncs; i++) {
10103 /* note that the first sample is index 1, not 0 */
10106 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
10108 if (G_LIKELY (index > 0 && index <= n_samples)) {
10110 samples[index].keyframe = TRUE;
10111 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10112 /* and exit if we have enough samples */
10113 if (G_UNLIKELY (index >= n)) {
10120 stream->stss_index = i;
10123 /* stps marks partial sync frames like open GOP I-Frames */
10124 if (stream->stps_present == TRUE) {
10125 guint32 n_sample_partial_syncs;
10127 n_sample_partial_syncs = stream->n_sample_partial_syncs;
10129 /* if there are no entries, the stss table contains the real
10131 if (n_sample_partial_syncs) {
10132 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
10133 /* note that the first sample is index 1, not 0 */
10136 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
10138 if (G_LIKELY (index > 0 && index <= n_samples)) {
10140 samples[index].keyframe = TRUE;
10141 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10142 /* and exit if we have enough samples */
10143 if (G_UNLIKELY (index >= n)) {
10150 stream->stps_index = i;
10154 /* no stss, all samples are keyframes */
10155 stream->all_keyframe = TRUE;
10156 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10161 /* composition time to sample */
10162 if (stream->ctts_present == TRUE) {
10163 guint32 n_composition_times;
10164 guint32 ctts_count;
10165 gint32 ctts_soffset;
10167 /* Fill in the pts_offsets */
10169 n_composition_times = stream->n_composition_times;
10171 for (i = stream->ctts_index; i < n_composition_times; i++) {
10172 if (stream->ctts_sample_index >= stream->ctts_count
10173 || !stream->ctts_sample_index) {
10174 stream->ctts_count =
10175 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10176 stream->ctts_soffset =
10177 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10178 stream->ctts_sample_index = 0;
10181 ctts_count = stream->ctts_count;
10182 ctts_soffset = stream->ctts_soffset;
10184 /* FIXME: Set offset to 0 for "no decode samples". This needs
10185 * to be handled in a codec specific manner ideally. */
10186 if (ctts_soffset == G_MININT32)
10189 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10190 cur->pts_offset = ctts_soffset;
10193 if (G_UNLIKELY (cur > last)) {
10195 stream->ctts_sample_index = j + 1;
10199 stream->ctts_sample_index = 0;
10200 stream->ctts_index++;
10204 stream->stbl_index = n;
10205 /* if index has been completely parsed, free data that is no-longer needed */
10206 if (n + 1 == stream->n_samples) {
10207 gst_qtdemux_stbl_free (stream);
10208 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10209 if (qtdemux->pullbased) {
10210 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10211 while (n + 1 == stream->n_samples)
10212 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10216 GST_OBJECT_UNLOCK (qtdemux);
10223 GST_LOG_OBJECT (qtdemux,
10224 "Tried to parse up to sample %u but this sample has already been parsed",
10226 /* if fragmented, there may be more */
10227 if (qtdemux->fragmented && n == stream->stbl_index)
10229 GST_OBJECT_UNLOCK (qtdemux);
10235 GST_LOG_OBJECT (qtdemux,
10236 "Tried to parse up to sample %u but there are only %u samples", n + 1,
10237 stream->n_samples);
10238 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10239 (_("This file is corrupt and cannot be played.")), (NULL));
10244 GST_OBJECT_UNLOCK (qtdemux);
10245 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10246 (_("This file is corrupt and cannot be played.")), (NULL));
10251 /* collect all segment info for @stream.
10254 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10258 /* accept edts if they contain gaps at start and there is only
10259 * one media segment */
10260 gboolean allow_pushbased_edts = TRUE;
10261 gint media_segments_count = 0;
10263 /* parse and prepare segment info from the edit list */
10264 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10265 stream->n_segments = 0;
10266 stream->segments = NULL;
10267 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10270 gint segment_number, entry_size;
10272 GstClockTime stime;
10273 const guint8 *buffer;
10277 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10278 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10281 buffer = elst->data;
10283 size = QT_UINT32 (buffer);
10284 /* version, flags, n_segments */
10286 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10289 version = QT_UINT8 (buffer + 8);
10290 entry_size = (version == 1) ? 20 : 12;
10292 n_segments = QT_UINT32 (buffer + 12);
10294 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10295 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10299 /* we might allocate a bit too much, at least allocate 1 segment */
10300 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10302 /* segments always start from 0 */
10306 for (segment_number = 0; segment_number < n_segments; segment_number++) {
10308 guint64 media_time;
10309 gboolean empty_edit = FALSE;
10310 QtDemuxSegment *segment;
10312 GstClockTime media_start = GST_CLOCK_TIME_NONE;
10314 if (version == 1) {
10315 media_time = QT_UINT64 (buffer + 8);
10316 duration = QT_UINT64 (buffer);
10317 if (media_time == G_MAXUINT64)
10320 media_time = QT_UINT32 (buffer + 4);
10321 duration = QT_UINT32 (buffer);
10322 if (media_time == G_MAXUINT32)
10327 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10329 segment = &stream->segments[segment_number];
10331 /* time and duration expressed in global timescale */
10332 segment->time = stime;
10333 if (duration != 0 || empty_edit) {
10334 /* edge case: empty edits with duration=zero are treated here.
10335 * (files should not have these anyway). */
10337 /* add non scaled values so we don't cause roundoff errors */
10339 stime = QTTIME_TO_GSTTIME (qtdemux, time);
10340 segment->duration = stime - segment->time;
10342 /* zero duration does not imply media_start == media_stop
10343 * but, only specify media_start. The edit ends with the track. */
10344 stime = segment->duration = GST_CLOCK_TIME_NONE;
10345 /* Don't allow more edits after this one. */
10346 n_segments = segment_number + 1;
10348 segment->stop_time = stime;
10350 segment->trak_media_start = media_time;
10351 /* media_time expressed in stream timescale */
10353 segment->media_start = media_start;
10354 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10355 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10356 media_segments_count++;
10358 segment->media_start = GST_CLOCK_TIME_NONE;
10359 segment->media_stop = GST_CLOCK_TIME_NONE;
10361 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10363 if (rate_int <= 1) {
10364 /* 0 is not allowed, some programs write 1 instead of the floating point
10366 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10370 segment->rate = rate_int / 65536.0;
10373 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10374 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10375 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10376 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10377 segment_number, GST_TIME_ARGS (segment->time),
10378 GST_TIME_ARGS (segment->duration),
10379 GST_TIME_ARGS (segment->media_start), media_time,
10380 GST_TIME_ARGS (segment->media_stop),
10381 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10382 stream->timescale);
10383 if (segment->stop_time > qtdemux->segment.stop &&
10384 !qtdemux->upstream_format_is_time) {
10385 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10386 " extends to %" GST_TIME_FORMAT
10387 " past the end of the declared movie duration %" GST_TIME_FORMAT
10388 " movie segment will be extended", segment_number,
10389 GST_TIME_ARGS (segment->stop_time),
10390 GST_TIME_ARGS (qtdemux->segment.stop));
10391 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10394 buffer += entry_size;
10396 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10397 stream->n_segments = n_segments;
10398 if (media_segments_count != 1)
10399 allow_pushbased_edts = FALSE;
10403 /* push based does not handle segments, so act accordingly here,
10404 * and warn if applicable */
10405 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10406 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10407 /* remove and use default one below, we stream like it anyway */
10408 g_free (stream->segments);
10409 stream->segments = NULL;
10410 stream->n_segments = 0;
10413 /* no segments, create one to play the complete trak */
10414 if (stream->n_segments == 0) {
10415 GstClockTime stream_duration =
10416 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10418 if (stream->segments == NULL)
10419 stream->segments = g_new (QtDemuxSegment, 1);
10421 /* represent unknown our way */
10422 if (stream_duration == 0)
10423 stream_duration = GST_CLOCK_TIME_NONE;
10425 stream->segments[0].time = 0;
10426 stream->segments[0].stop_time = stream_duration;
10427 stream->segments[0].duration = stream_duration;
10428 stream->segments[0].media_start = 0;
10429 stream->segments[0].media_stop = stream_duration;
10430 stream->segments[0].rate = 1.0;
10431 stream->segments[0].trak_media_start = 0;
10433 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10434 GST_TIME_ARGS (stream_duration));
10435 stream->n_segments = 1;
10436 stream->dummy_segment = TRUE;
10438 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10444 * Parses the stsd atom of a svq3 trak looking for
10445 * the SMI and gama atoms.
10448 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10449 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10451 const guint8 *_gamma = NULL;
10452 GstBuffer *_seqh = NULL;
10453 const guint8 *stsd_data = stsd_entry_data;
10454 guint32 length = QT_UINT32 (stsd_data);
10458 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10464 version = QT_UINT16 (stsd_data);
10465 if (version == 3) {
10466 if (length >= 70) {
10469 while (length > 8) {
10470 guint32 fourcc, size;
10471 const guint8 *data;
10472 size = QT_UINT32 (stsd_data);
10473 fourcc = QT_FOURCC (stsd_data + 4);
10474 data = stsd_data + 8;
10477 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10478 "svq3 atom parsing");
10487 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10488 " for gama atom, expected 12", size);
10493 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10495 if (_seqh != NULL) {
10496 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10497 " found, ignoring");
10499 seqh_size = QT_UINT32 (data + 4);
10500 if (seqh_size > 0) {
10501 _seqh = gst_buffer_new_and_alloc (seqh_size);
10502 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10509 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10510 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10514 if (size <= length) {
10520 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10523 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10524 G_GUINT16_FORMAT, version);
10534 } else if (_seqh) {
10535 gst_buffer_unref (_seqh);
10540 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10543 GstByteReader dref;
10547 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10548 * atom that might contain a 'data' atom with the rtsp uri.
10549 * This case was reported in bug #597497, some info about
10550 * the hndl atom can be found in TN1195
10552 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10553 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10556 guint32 dref_num_entries = 0;
10557 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10558 gst_byte_reader_skip (&dref, 4) &&
10559 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10562 /* search dref entries for hndl atom */
10563 for (i = 0; i < dref_num_entries; i++) {
10564 guint32 size = 0, type;
10565 guint8 string_len = 0;
10566 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10567 qt_atom_parser_get_fourcc (&dref, &type)) {
10568 if (type == FOURCC_hndl) {
10569 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10571 /* skip data reference handle bytes and the
10572 * following pascal string and some extra 4
10573 * bytes I have no idea what are */
10574 if (!gst_byte_reader_skip (&dref, 4) ||
10575 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10576 !gst_byte_reader_skip (&dref, string_len + 4)) {
10577 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10581 /* iterate over the atoms to find the data atom */
10582 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10586 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10587 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10588 if (atom_type == FOURCC_data) {
10589 const guint8 *uri_aux = NULL;
10591 /* found the data atom that might contain the rtsp uri */
10592 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10593 "hndl atom, interpreting it as an URI");
10594 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10596 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10597 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10599 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10600 "didn't contain a rtsp address");
10602 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10607 /* skipping to the next entry */
10608 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10611 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10618 /* skip to the next entry */
10619 if (!gst_byte_reader_skip (&dref, size - 8))
10622 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10625 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10631 #define AMR_NB_ALL_MODES 0x81ff
10632 #define AMR_WB_ALL_MODES 0x83ff
10634 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10636 /* The 'damr' atom is of the form:
10638 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10639 * 32 b 8 b 16 b 8 b 8 b
10641 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10642 * represents the highest mode used in the stream (and thus the maximum
10643 * bitrate), with a couple of special cases as seen below.
10646 /* Map of frame type ID -> bitrate */
10647 static const guint nb_bitrates[] = {
10648 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10650 static const guint wb_bitrates[] = {
10651 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10657 gst_buffer_map (buf, &map, GST_MAP_READ);
10659 if (map.size != 0x11) {
10660 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10664 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10665 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10666 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10670 mode_set = QT_UINT16 (map.data + 13);
10672 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10673 max_mode = 7 + (wb ? 1 : 0);
10675 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10676 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10678 if (max_mode == -1) {
10679 GST_DEBUG ("No mode indication was found (mode set) = %x",
10684 gst_buffer_unmap (buf, &map);
10685 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10688 gst_buffer_unmap (buf, &map);
10693 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10694 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10697 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10703 if (gst_byte_reader_get_remaining (reader) < 36)
10706 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10707 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10708 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10709 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10710 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10711 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10712 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10713 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10714 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10716 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10717 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10718 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10720 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10721 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10723 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10724 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10731 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10732 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10739 * This macro will only compare value abdegh, it expects cfi to have already
10742 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10743 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10745 /* only handle the cases where the last column has standard values */
10746 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10747 const gchar *rotation_tag = NULL;
10749 /* no rotation needed */
10750 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10752 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10753 rotation_tag = "rotate-90";
10754 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10755 rotation_tag = "rotate-180";
10756 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10757 rotation_tag = "rotate-270";
10759 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10762 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10763 GST_STR_NULL (rotation_tag));
10764 if (rotation_tag != NULL) {
10765 if (*taglist == NULL)
10766 *taglist = gst_tag_list_new_empty ();
10767 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10768 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10771 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10776 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10777 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10781 GstBuffer *adrm_buf = NULL;
10782 QtDemuxAavdEncryptionInfo *info;
10784 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10785 if (G_UNLIKELY (!adrm)) {
10786 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10789 adrm_size = QT_UINT32 (adrm->data);
10790 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10792 stream->protection_scheme_type = FOURCC_aavd;
10794 if (!stream->protection_scheme_info)
10795 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10797 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10799 if (info->default_properties)
10800 gst_structure_free (info->default_properties);
10801 info->default_properties = gst_structure_new ("application/x-aavd",
10802 "encrypted", G_TYPE_BOOLEAN, TRUE,
10803 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10804 gst_buffer_unref (adrm_buf);
10806 *original_fmt = FOURCC_mp4a;
10810 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10811 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10812 * Common Encryption (cenc), the function will also parse the tenc box (defined
10813 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10814 * (typically an enc[v|a|t|s] sample entry); the function will set
10815 * @original_fmt to the fourcc of the original unencrypted stream format.
10816 * Returns TRUE if successful; FALSE otherwise. */
10818 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10819 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10825 QtDemuxCencSampleSetInfo *info;
10827 const guint8 *tenc_data;
10829 g_return_val_if_fail (qtdemux != NULL, FALSE);
10830 g_return_val_if_fail (stream != NULL, FALSE);
10831 g_return_val_if_fail (container != NULL, FALSE);
10832 g_return_val_if_fail (original_fmt != NULL, FALSE);
10834 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10835 if (G_UNLIKELY (!sinf)) {
10836 if (stream->protection_scheme_type == FOURCC_cenc
10837 || stream->protection_scheme_type == FOURCC_cbcs) {
10838 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10839 "mandatory for Common Encryption");
10845 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10846 if (G_UNLIKELY (!frma)) {
10847 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10851 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10852 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10853 GST_FOURCC_ARGS (*original_fmt));
10855 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10857 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10860 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10861 stream->protection_scheme_version =
10862 QT_UINT32 ((const guint8 *) schm->data + 16);
10864 GST_DEBUG_OBJECT (qtdemux,
10865 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10866 "protection_scheme_version: %#010x",
10867 GST_FOURCC_ARGS (stream->protection_scheme_type),
10868 stream->protection_scheme_version);
10870 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10872 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10875 if (stream->protection_scheme_type != FOURCC_cenc &&
10876 stream->protection_scheme_type != FOURCC_piff &&
10877 stream->protection_scheme_type != FOURCC_cbcs) {
10878 GST_ERROR_OBJECT (qtdemux,
10879 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10880 GST_FOURCC_ARGS (stream->protection_scheme_type));
10884 if (G_UNLIKELY (!stream->protection_scheme_info))
10885 stream->protection_scheme_info =
10886 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10888 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10890 if (stream->protection_scheme_type == FOURCC_cenc
10891 || stream->protection_scheme_type == FOURCC_cbcs) {
10892 guint8 is_encrypted;
10894 guint8 constant_iv_size = 0;
10895 const guint8 *default_kid;
10896 guint8 crypt_byte_block = 0;
10897 guint8 skip_byte_block = 0;
10898 const guint8 *constant_iv = NULL;
10900 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10902 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10903 "which is mandatory for Common Encryption");
10906 tenc_data = (const guint8 *) tenc->data + 12;
10907 is_encrypted = QT_UINT8 (tenc_data + 2);
10908 iv_size = QT_UINT8 (tenc_data + 3);
10909 default_kid = (tenc_data + 4);
10910 if (stream->protection_scheme_type == FOURCC_cbcs) {
10911 guint8 possible_pattern_info;
10912 if (iv_size == 0) {
10913 constant_iv_size = QT_UINT8 (tenc_data + 20);
10914 if (constant_iv_size != 8 && constant_iv_size != 16) {
10915 GST_ERROR_OBJECT (qtdemux,
10916 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10919 constant_iv = (tenc_data + 21);
10921 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10922 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10923 skip_byte_block = possible_pattern_info & 0x0f;
10925 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10926 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10927 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10928 } else if (stream->protection_scheme_type == FOURCC_piff) {
10930 static const guint8 piff_track_encryption_uuid[] = {
10931 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10932 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10935 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10937 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10938 "which is mandatory for Common Encryption");
10942 tenc_data = (const guint8 *) tenc->data + 8;
10943 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10944 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10945 GST_ERROR_OBJECT (qtdemux,
10946 "Unsupported track encryption box with uuid: %s", box_uuid);
10950 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10951 gst_byte_reader_init (&br, tenc_data, 20);
10952 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10953 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10956 stream->protection_scheme_type = FOURCC_cenc;
10963 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10964 QtDemuxStream ** stream2)
10966 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10970 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10975 /*parse svmi header if existing */
10976 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10978 guint len = QT_UINT32 ((guint8 *) svmi->data);
10979 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10981 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10982 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10983 guint8 frame_type, frame_layout;
10984 guint32 stereo_mono_change_count;
10989 /* MPEG-A stereo video */
10990 if (qtdemux->major_brand == FOURCC_ss02)
10991 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10993 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10994 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10995 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10997 switch (frame_type) {
10999 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
11002 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
11005 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
11008 /* mode 3 is primary/secondary view sequence, ie
11009 * left/right views in separate tracks. See section 7.2
11010 * of ISO/IEC 23000-11:2009 */
11011 /* In the future this might be supported using related
11012 * streams, like an enhancement track - if files like this
11014 GST_FIXME_OBJECT (qtdemux,
11015 "Implement stereo video in separate streams");
11018 if ((frame_layout & 0x1) == 0)
11019 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
11021 GST_LOG_OBJECT (qtdemux,
11022 "StereoVideo: composition type: %u, is_left_first: %u",
11023 frame_type, frame_layout);
11025 if (stereo_mono_change_count > 1) {
11026 GST_FIXME_OBJECT (qtdemux,
11027 "Mixed-mono flags are not yet supported in qtdemux.");
11030 stream->multiview_mode = mode;
11031 stream->multiview_flags = flags;
11038 /* parse the traks.
11039 * With each track we associate a new QtDemuxStream that contains all the info
11041 * traks that do not decode to something (like strm traks) will not have a pad.
11044 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
11046 GstByteReader tkhd;
11060 QtDemuxStream *stream = NULL;
11061 const guint8 *stsd_data;
11062 const guint8 *stsd_entry_data;
11063 guint remaining_stsd_len;
11064 guint stsd_entry_count;
11066 guint16 lang_code; /* quicktime lang code or packed iso code */
11068 guint32 tkhd_flags = 0;
11069 guint8 tkhd_version = 0;
11070 guint32 w = 0, h = 0;
11071 guint value_size, stsd_len, len;
11075 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
11077 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
11078 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
11079 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
11082 /* pick between 64 or 32 bits */
11083 value_size = tkhd_version == 1 ? 8 : 4;
11084 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
11085 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
11088 /* Check if current moov has duplicated track_id */
11089 if (qtdemux_find_stream (qtdemux, track_id))
11090 goto existing_stream;
11092 stream = _create_stream (qtdemux, track_id);
11093 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11095 /* need defaults for fragments */
11096 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
11098 if ((tkhd_flags & 1) == 0)
11099 stream->disabled = TRUE;
11101 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
11102 tkhd_version, tkhd_flags, stream->track_id);
11104 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
11107 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
11108 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
11109 if (qtdemux->major_brand != FOURCC_mjp2 ||
11110 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
11114 len = QT_UINT32 ((guint8 *) mdhd->data);
11115 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
11116 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
11117 if (version == 0x01000000) {
11120 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
11121 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
11122 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
11126 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
11127 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
11128 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
11131 if (lang_code < 0x400) {
11132 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
11133 } else if (lang_code == 0x7fff) {
11134 stream->lang_id[0] = 0; /* unspecified */
11136 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11137 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11138 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11139 stream->lang_id[3] = 0;
11142 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11143 stream->timescale);
11144 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11146 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11147 lang_code, stream->lang_id);
11149 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11152 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11153 /* chapters track reference */
11154 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11156 gsize length = GST_READ_UINT32_BE (chap->data);
11157 if (qtdemux->chapters_track_id)
11158 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11160 if (length >= 12) {
11161 qtdemux->chapters_track_id =
11162 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11167 /* fragmented files may have bogus duration in moov */
11168 if (!qtdemux->fragmented &&
11169 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11170 guint64 tdur1, tdur2;
11172 /* don't overflow */
11173 tdur1 = stream->timescale * (guint64) qtdemux->duration;
11174 tdur2 = qtdemux->timescale * (guint64) stream->duration;
11177 * some of those trailers, nowadays, have prologue images that are
11178 * themselves video tracks as well. I haven't really found a way to
11179 * identify those yet, except for just looking at their duration. */
11180 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11181 GST_WARNING_OBJECT (qtdemux,
11182 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11183 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11184 "found, assuming preview image or something; skipping track",
11185 stream->duration, stream->timescale, qtdemux->duration,
11186 qtdemux->timescale);
11187 gst_qtdemux_stream_unref (stream);
11192 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11195 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11196 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11198 len = QT_UINT32 ((guint8 *) hdlr->data);
11200 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11201 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11202 GST_FOURCC_ARGS (stream->subtype));
11204 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11207 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11210 /* Parse out svmi (and later st3d/sv3d) atoms */
11211 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
11214 /* parse rest of tkhd */
11215 if (stream->subtype == FOURCC_vide) {
11218 /* version 1 uses some 64-bit ints */
11219 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11222 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11225 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11226 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11229 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11230 &stream->stream_tags);
11234 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11236 stsd_data = (const guint8 *) stsd->data;
11238 /* stsd should at least have one entry */
11239 stsd_len = QT_UINT32 (stsd_data);
11240 if (stsd_len < 24) {
11241 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11242 if (stream->subtype == FOURCC_vivo) {
11243 gst_qtdemux_stream_unref (stream);
11250 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11251 /* each stsd entry must contain at least 8 bytes */
11252 if (stream->stsd_entries_length == 0
11253 || stream->stsd_entries_length > stsd_len / 8) {
11254 stream->stsd_entries_length = 0;
11257 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11258 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
11259 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
11261 stsd_entry_data = stsd_data + 16;
11262 remaining_stsd_len = stsd_len - 16;
11263 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11265 gchar *codec = NULL;
11266 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11268 /* and that entry should fit within stsd */
11269 len = QT_UINT32 (stsd_entry_data);
11270 if (len > remaining_stsd_len)
11273 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11274 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
11275 GST_FOURCC_ARGS (entry->fourcc));
11276 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
11278 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11279 goto error_encrypted;
11281 if (fourcc == FOURCC_aavd) {
11282 if (stream->subtype != FOURCC_soun) {
11283 GST_ERROR_OBJECT (qtdemux,
11284 "Unexpeced stsd type 'aavd' outside 'soun' track");
11286 /* encrypted audio with sound sample description v0 */
11287 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11288 stream->protected = TRUE;
11289 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11290 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11294 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11295 /* FIXME this looks wrong, there might be multiple children
11296 * with the same type */
11297 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11298 stream->protected = TRUE;
11299 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11300 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11303 if (stream->subtype == FOURCC_vide) {
11308 gint depth, palette_size, palette_count;
11309 guint32 *palette_data = NULL;
11311 entry->sampled = TRUE;
11313 stream->display_width = w >> 16;
11314 stream->display_height = h >> 16;
11317 if (len < 86) /* TODO verify */
11320 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11321 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11322 entry->fps_n = 0; /* this is filled in later */
11323 entry->fps_d = 0; /* this is filled in later */
11324 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11325 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11327 /* if color_table_id is 0, ctab atom must follow; however some files
11328 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11329 * if color table is not present we'll correct the value */
11330 if (entry->color_table_id == 0 &&
11332 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11333 entry->color_table_id = -1;
11336 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11337 entry->width, entry->height, entry->bits_per_sample,
11338 entry->color_table_id);
11340 depth = entry->bits_per_sample;
11342 /* more than 32 bits means grayscale */
11343 gray = (depth > 32);
11344 /* low 32 bits specify the depth */
11347 /* different number of palette entries is determined by depth. */
11349 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11350 palette_count = (1 << depth);
11351 palette_size = palette_count * 4;
11353 if (entry->color_table_id) {
11354 switch (palette_count) {
11358 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11361 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11366 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11368 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11373 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11376 g_memdup2 (ff_qt_default_palette_256, palette_size);
11379 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11380 (_("The video in this file might not play correctly.")),
11381 ("unsupported palette depth %d", depth));
11385 gint i, j, start, end;
11391 start = QT_UINT32 (stsd_entry_data + offset + 70);
11392 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11393 end = QT_UINT16 (stsd_entry_data + offset + 76);
11395 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11396 start, end, palette_count);
11403 if (len < 94 + (end - start) * 8)
11406 /* palette is always the same size */
11407 palette_data = g_malloc0 (256 * 4);
11408 palette_size = 256 * 4;
11410 for (j = 0, i = start; i <= end; j++, i++) {
11411 guint32 a, r, g, b;
11413 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11414 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11415 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11416 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11418 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11419 (g & 0xff00) | (b >> 8);
11424 gst_caps_unref (entry->caps);
11427 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11429 if (G_UNLIKELY (!entry->caps)) {
11430 g_free (palette_data);
11431 goto unknown_stream;
11435 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11436 GST_TAG_VIDEO_CODEC, codec, NULL);
11441 if (palette_data) {
11444 if (entry->rgb8_palette)
11445 gst_memory_unref (entry->rgb8_palette);
11446 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11447 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11449 s = gst_caps_get_structure (entry->caps, 0);
11451 /* non-raw video has a palette_data property. raw video has the palette as
11452 * an extra plane that we append to the output buffers before we push
11454 if (!gst_structure_has_name (s, "video/x-raw")) {
11455 GstBuffer *palette;
11457 palette = gst_buffer_new ();
11458 gst_buffer_append_memory (palette, entry->rgb8_palette);
11459 entry->rgb8_palette = NULL;
11461 gst_caps_set_simple (entry->caps, "palette_data",
11462 GST_TYPE_BUFFER, palette, NULL);
11463 gst_buffer_unref (palette);
11465 } else if (palette_count != 0) {
11466 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11467 (NULL), ("Unsupported palette depth %d", depth));
11470 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11471 QT_UINT16 (stsd_entry_data + offset + 32));
11477 /* pick 'the' stsd child */
11478 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11479 // We should skip parsing the stsd for non-protected streams if
11480 // the entry doesn't match the fourcc, since they don't change
11481 // format. However, for protected streams we can have partial
11482 // encryption, where parts of the stream are encrypted and parts
11483 // not. For both parts of such streams, we should ensure the
11484 // esds overrides are parsed for both from the stsd.
11485 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11486 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11488 else if (!stream->protected)
11493 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11494 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11495 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11496 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11500 const guint8 *pasp_data = (const guint8 *) pasp->data;
11501 gint len = QT_UINT32 (pasp_data);
11504 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11505 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11507 CUR_STREAM (stream)->par_w = 0;
11508 CUR_STREAM (stream)->par_h = 0;
11511 CUR_STREAM (stream)->par_w = 0;
11512 CUR_STREAM (stream)->par_h = 0;
11516 const guint8 *fiel_data = (const guint8 *) fiel->data;
11517 gint len = QT_UINT32 (fiel_data);
11520 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11521 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11526 const guint8 *colr_data = (const guint8 *) colr->data;
11527 gint len = QT_UINT32 (colr_data);
11529 if (len == 19 || len == 18) {
11530 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11532 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11533 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11534 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11535 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11536 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11538 CUR_STREAM (stream)->colorimetry.primaries =
11539 gst_video_color_primaries_from_iso (primaries);
11540 CUR_STREAM (stream)->colorimetry.transfer =
11541 gst_video_transfer_function_from_iso (transfer_function);
11542 CUR_STREAM (stream)->colorimetry.matrix =
11543 gst_video_color_matrix_from_iso (matrix);
11544 CUR_STREAM (stream)->colorimetry.range =
11545 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11546 GST_VIDEO_COLOR_RANGE_16_235;
11548 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11551 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11556 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11557 stream->stream_tags);
11564 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11565 const guint8 *avc_data = stsd_entry_data + 0x56;
11568 while (len >= 0x8) {
11571 if (QT_UINT32 (avc_data) <= len)
11572 size = QT_UINT32 (avc_data) - 0x8;
11577 /* No real data, so break out */
11580 switch (QT_FOURCC (avc_data + 0x4)) {
11583 /* parse, if found */
11586 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11588 /* First 4 bytes are the length of the atom, the next 4 bytes
11589 * are the fourcc, the next 1 byte is the version, and the
11590 * subsequent bytes are profile_tier_level structure like data. */
11591 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11592 avc_data + 8 + 1, size - 1);
11593 buf = gst_buffer_new_and_alloc (size);
11594 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11595 gst_caps_set_simple (entry->caps,
11596 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11597 gst_buffer_unref (buf);
11605 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11607 /* First 4 bytes are the length of the atom, the next 4 bytes
11608 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11609 * next 1 byte is the version, and the
11610 * subsequent bytes are sequence parameter set like data. */
11612 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11614 gst_codec_utils_h264_caps_set_level_and_profile
11615 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11617 buf = gst_buffer_new_and_alloc (size);
11618 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11619 gst_caps_set_simple (entry->caps,
11620 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11621 gst_buffer_unref (buf);
11627 guint avg_bitrate, max_bitrate;
11629 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11633 max_bitrate = QT_UINT32 (avc_data + 0xc);
11634 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11636 if (!max_bitrate && !avg_bitrate)
11639 /* Some muxers seem to swap the average and maximum bitrates
11640 * (I'm looking at you, YouTube), so we swap for sanity. */
11641 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11642 guint temp = avg_bitrate;
11644 avg_bitrate = max_bitrate;
11645 max_bitrate = temp;
11648 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11649 gst_tag_list_add (stream->stream_tags,
11650 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11651 max_bitrate, NULL);
11653 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11654 gst_tag_list_add (stream->stream_tags,
11655 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11667 avc_data += size + 8;
11678 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11679 const guint8 *hevc_data = stsd_entry_data + 0x56;
11682 while (len >= 0x8) {
11685 if (QT_UINT32 (hevc_data) <= len)
11686 size = QT_UINT32 (hevc_data) - 0x8;
11691 /* No real data, so break out */
11694 switch (QT_FOURCC (hevc_data + 0x4)) {
11697 /* parse, if found */
11700 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11702 /* First 4 bytes are the length of the atom, the next 4 bytes
11703 * are the fourcc, the next 1 byte is the version, and the
11704 * subsequent bytes are sequence parameter set like data. */
11705 gst_codec_utils_h265_caps_set_level_tier_and_profile
11706 (entry->caps, hevc_data + 8 + 1, size - 1);
11708 buf = gst_buffer_new_and_alloc (size);
11709 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11710 gst_caps_set_simple (entry->caps,
11711 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11712 gst_buffer_unref (buf);
11719 hevc_data += size + 8;
11732 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11733 GST_FOURCC_ARGS (fourcc));
11735 /* codec data might be in glbl extension atom */
11737 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11743 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11745 len = QT_UINT32 (data);
11748 buf = gst_buffer_new_and_alloc (len);
11749 gst_buffer_fill (buf, 0, data + 8, len);
11750 gst_caps_set_simple (entry->caps,
11751 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11752 gst_buffer_unref (buf);
11759 /* see annex I of the jpeg2000 spec */
11760 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11761 const guint8 *data;
11762 const gchar *colorspace = NULL;
11764 guint32 ncomp_map = 0;
11765 gint32 *comp_map = NULL;
11766 guint32 nchan_def = 0;
11767 gint32 *chan_def = NULL;
11769 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11770 /* some required atoms */
11771 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11774 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11778 /* number of components; redundant with info in codestream, but useful
11780 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11781 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11783 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11785 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11788 GST_DEBUG_OBJECT (qtdemux, "found colr");
11789 /* extract colour space info */
11790 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11791 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11793 colorspace = "sRGB";
11796 colorspace = "GRAY";
11799 colorspace = "sYUV";
11807 /* colr is required, and only values 16, 17, and 18 are specified,
11808 so error if we have no colorspace */
11811 /* extract component mapping */
11812 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11814 guint32 cmap_len = 0;
11816 cmap_len = QT_UINT32 (cmap->data);
11817 if (cmap_len >= 8) {
11818 /* normal box, subtract off header */
11820 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11821 if (cmap_len % 4 == 0) {
11822 ncomp_map = (cmap_len / 4);
11823 comp_map = g_new0 (gint32, ncomp_map);
11824 for (i = 0; i < ncomp_map; i++) {
11827 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11828 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11829 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11830 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11835 /* extract channel definitions */
11836 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11838 guint32 cdef_len = 0;
11840 cdef_len = QT_UINT32 (cdef->data);
11841 if (cdef_len >= 10) {
11842 /* normal box, subtract off header and len */
11844 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11845 if (cdef_len % 6 == 0) {
11846 nchan_def = (cdef_len / 6);
11847 chan_def = g_new0 (gint32, nchan_def);
11848 for (i = 0; i < nchan_def; i++)
11850 for (i = 0; i < nchan_def; i++) {
11851 guint16 cn, typ, asoc;
11852 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11853 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11854 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11855 if (cn < nchan_def) {
11858 chan_def[cn] = asoc;
11861 chan_def[cn] = 0; /* alpha */
11864 chan_def[cn] = -typ;
11872 gst_caps_set_simple (entry->caps,
11873 "num-components", G_TYPE_INT, ncomp, NULL);
11874 gst_caps_set_simple (entry->caps,
11875 "colorspace", G_TYPE_STRING, colorspace, NULL);
11878 GValue arr = { 0, };
11879 GValue elt = { 0, };
11881 g_value_init (&arr, GST_TYPE_ARRAY);
11882 g_value_init (&elt, G_TYPE_INT);
11883 for (i = 0; i < ncomp_map; i++) {
11884 g_value_set_int (&elt, comp_map[i]);
11885 gst_value_array_append_value (&arr, &elt);
11887 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11888 "component-map", &arr);
11889 g_value_unset (&elt);
11890 g_value_unset (&arr);
11895 GValue arr = { 0, };
11896 GValue elt = { 0, };
11898 g_value_init (&arr, GST_TYPE_ARRAY);
11899 g_value_init (&elt, G_TYPE_INT);
11900 for (i = 0; i < nchan_def; i++) {
11901 g_value_set_int (&elt, chan_def[i]);
11902 gst_value_array_append_value (&arr, &elt);
11904 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11905 "channel-definitions", &arr);
11906 g_value_unset (&elt);
11907 g_value_unset (&arr);
11911 /* some optional atoms */
11912 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11913 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11915 /* indicate possible fields in caps */
11917 data = (guint8 *) field->data + 8;
11919 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11920 (gint) * data, NULL);
11922 /* add codec_data if provided */
11927 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11928 data = prefix->data;
11929 len = QT_UINT32 (data);
11932 buf = gst_buffer_new_and_alloc (len);
11933 gst_buffer_fill (buf, 0, data + 8, len);
11934 gst_caps_set_simple (entry->caps,
11935 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11936 gst_buffer_unref (buf);
11945 GstBuffer *seqh = NULL;
11946 const guint8 *gamma_data = NULL;
11947 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11949 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11952 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11953 QT_FP32 (gamma_data), NULL);
11956 /* sorry for the bad name, but we don't know what this is, other
11957 * than its own fourcc */
11958 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11960 gst_buffer_unref (seqh);
11963 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11964 buf = gst_buffer_new_and_alloc (len);
11965 gst_buffer_fill (buf, 0, stsd_data, len);
11966 gst_caps_set_simple (entry->caps,
11967 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11968 gst_buffer_unref (buf);
11973 /* https://developer.apple.com/standards/qtff-2001.pdf,
11974 * page 92, "Video Sample Description", under table 3.1 */
11977 const gint compressor_offset =
11978 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11979 const gint min_size = compressor_offset + 32 + 2 + 2;
11982 guint16 color_table_id = 0;
11985 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11987 /* recover information on interlaced/progressive */
11988 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11992 len = QT_UINT32 (jpeg->data);
11993 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11995 if (len >= min_size) {
11996 gst_byte_reader_init (&br, jpeg->data, len);
11998 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11999 gst_byte_reader_get_uint16_le (&br, &color_table_id);
12000 if (color_table_id != 0) {
12001 /* the spec says there can be concatenated chunks in the data, and we want
12002 * to find one called field. Walk through them. */
12003 gint offset = min_size;
12004 while (offset + 8 < len) {
12005 guint32 size = 0, tag;
12006 ok = gst_byte_reader_get_uint32_le (&br, &size);
12007 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
12008 if (!ok || size < 8) {
12009 GST_WARNING_OBJECT (qtdemux,
12010 "Failed to walk optional chunk list");
12013 GST_DEBUG_OBJECT (qtdemux,
12014 "Found optional %4.4s chunk, size %u",
12015 (const char *) &tag, size);
12016 if (tag == FOURCC_fiel) {
12017 guint8 n_fields = 0, ordering = 0;
12018 gst_byte_reader_get_uint8 (&br, &n_fields);
12019 gst_byte_reader_get_uint8 (&br, &ordering);
12020 if (n_fields == 1 || n_fields == 2) {
12021 GST_DEBUG_OBJECT (qtdemux,
12022 "Found fiel tag with %u fields, ordering %u",
12023 n_fields, ordering);
12025 gst_caps_set_simple (CUR_STREAM (stream)->caps,
12026 "interlace-mode", G_TYPE_STRING, "interleaved",
12029 GST_WARNING_OBJECT (qtdemux,
12030 "Found fiel tag with invalid fields (%u)", n_fields);
12036 GST_DEBUG_OBJECT (qtdemux,
12037 "Color table ID is 0, not trying to get interlacedness");
12040 GST_WARNING_OBJECT (qtdemux,
12041 "Length of jpeg chunk is too small, not trying to get interlacedness");
12049 gst_caps_set_simple (entry->caps,
12050 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
12056 GNode *xith, *xdxt;
12058 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
12059 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12063 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
12067 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
12068 /* collect the headers and store them in a stream list so that we can
12069 * send them out first */
12070 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
12080 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
12081 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12084 ovc1_data = ovc1->data;
12085 ovc1_len = QT_UINT32 (ovc1_data);
12086 if (ovc1_len <= 198) {
12087 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
12090 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
12091 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
12092 gst_caps_set_simple (entry->caps,
12093 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12094 gst_buffer_unref (buf);
12099 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12100 const guint8 *vc1_data = stsd_entry_data + 0x56;
12106 if (QT_UINT32 (vc1_data) <= len)
12107 size = QT_UINT32 (vc1_data) - 8;
12112 /* No real data, so break out */
12115 switch (QT_FOURCC (vc1_data + 0x4)) {
12116 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
12120 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
12121 buf = gst_buffer_new_and_alloc (size);
12122 gst_buffer_fill (buf, 0, vc1_data + 8, size);
12123 gst_caps_set_simple (entry->caps,
12124 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12125 gst_buffer_unref (buf);
12132 vc1_data += size + 8;
12138 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12139 const guint8 *av1_data = stsd_entry_data + 0x56;
12142 while (len >= 0x8) {
12145 if (QT_UINT32 (av1_data) <= len)
12146 size = QT_UINT32 (av1_data) - 0x8;
12151 /* No real data, so break out */
12154 switch (QT_FOURCC (av1_data + 0x4)) {
12157 /* parse, if found */
12159 guint8 pres_delay_field;
12161 GST_DEBUG_OBJECT (qtdemux,
12162 "found av1C codec_data in stsd of size %d", size);
12164 /* not enough data, just ignore and hope for the best */
12169 * 4 bytes: atom length
12174 * 1 bits: initial_presentation_delay_present
12175 * 4 bits: initial_presentation_delay (if present else reserved
12179 if (av1_data[9] != 0) {
12180 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
12184 /* We skip initial_presentation_delay* for now */
12185 pres_delay_field = *(av1_data + 12);
12186 if (pres_delay_field & (1 << 5)) {
12187 gst_caps_set_simple (entry->caps,
12188 "presentation-delay", G_TYPE_INT,
12189 (gint) (pres_delay_field & 0x0F) + 1, NULL);
12192 buf = gst_buffer_new_and_alloc (size - 5);
12193 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12194 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12195 gst_caps_set_simple (entry->caps,
12196 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12197 gst_buffer_unref (buf);
12206 av1_data += size + 8;
12212 /* TODO: Need to parse vpcC for VP8 codec too.
12213 * Note that VPCodecConfigurationBox (vpcC) is defined for
12214 * vp08, vp09, and vp10 fourcc. */
12217 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12218 const guint8 *vpcc_data = stsd_entry_data + 0x56;
12221 while (len >= 0x8) {
12224 if (QT_UINT32 (vpcc_data) <= len)
12225 size = QT_UINT32 (vpcc_data) - 0x8;
12230 /* No real data, so break out */
12233 switch (QT_FOURCC (vpcc_data + 0x4)) {
12236 const gchar *profile_str = NULL;
12237 const gchar *chroma_format_str = NULL;
12240 guint8 chroma_format;
12241 GstVideoColorimetry cinfo;
12243 /* parse, if found */
12244 GST_DEBUG_OBJECT (qtdemux,
12245 "found vp codec_data in stsd of size %d", size);
12247 /* the meaning of "size" is length of the atom body, excluding
12248 * atom length and fourcc fields */
12253 * 4 bytes: atom length
12260 * 3 bits: chromaSubsampling
12261 * 1 bit: videoFullRangeFlag
12262 * 1 byte: colourPrimaries
12263 * 1 byte: transferCharacteristics
12264 * 1 byte: matrixCoefficients
12265 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
12266 * rest: codecIntializationData (not used for vp8 and vp9)
12269 if (vpcc_data[8] != 1) {
12270 GST_WARNING_OBJECT (qtdemux,
12271 "unknown vpcC version %d", vpcc_data[8]);
12275 profile = vpcc_data[12];
12294 gst_caps_set_simple (entry->caps,
12295 "profile", G_TYPE_STRING, profile_str, NULL);
12298 /* skip level, the VP9 spec v0.6 defines only one level atm,
12299 * but webm spec define various ones. Add level to caps
12300 * if we really need it then */
12302 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12303 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12304 gst_caps_set_simple (entry->caps,
12305 "bit-depth-luma", G_TYPE_UINT, bitdepth,
12306 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12309 chroma_format = (vpcc_data[14] & 0xe) >> 1;
12310 switch (chroma_format) {
12313 chroma_format_str = "4:2:0";
12316 chroma_format_str = "4:2:2";
12319 chroma_format_str = "4:4:4";
12325 if (chroma_format_str) {
12326 gst_caps_set_simple (entry->caps,
12327 "chroma-format", G_TYPE_STRING, chroma_format_str,
12331 if ((vpcc_data[14] & 0x1) != 0)
12332 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12334 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12336 gst_video_color_primaries_from_iso (vpcc_data[15]);
12338 gst_video_transfer_function_from_iso (vpcc_data[16]);
12340 gst_video_color_matrix_from_iso (vpcc_data[17]);
12342 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12343 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12344 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12345 /* set this only if all values are known, otherwise this
12346 * might overwrite valid ones parsed from other color box */
12347 CUR_STREAM (stream)->colorimetry = cinfo;
12356 vpcc_data += size + 8;
12366 GST_INFO_OBJECT (qtdemux,
12367 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12368 GST_FOURCC_ARGS (fourcc), entry->caps);
12370 } else if (stream->subtype == FOURCC_soun) {
12372 int version, samplesize;
12373 guint16 compression_id;
12374 gboolean amrwb = FALSE;
12377 /* sample description entry (16) + sound sample description v0 (20) */
12381 version = QT_UINT32 (stsd_entry_data + offset);
12382 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12383 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12384 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12385 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12387 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12388 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12389 QT_UINT32 (stsd_entry_data + offset + 4));
12390 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12391 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12392 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12393 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12394 QT_UINT16 (stsd_entry_data + offset + 14));
12395 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12397 if (compression_id == 0xfffe)
12398 entry->sampled = TRUE;
12400 /* first assume uncompressed audio */
12401 entry->bytes_per_sample = samplesize / 8;
12402 entry->samples_per_frame = entry->n_channels;
12403 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12404 entry->samples_per_packet = entry->samples_per_frame;
12405 entry->bytes_per_packet = entry->bytes_per_sample;
12409 if (version == 0x00010000) {
12410 /* sample description entry (16) + sound sample description v1 (20+16) */
12414 /* take information from here over the normal sample description */
12415 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12416 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12417 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12418 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12420 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12421 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12422 entry->samples_per_packet);
12423 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12424 entry->bytes_per_packet);
12425 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12426 entry->bytes_per_frame);
12427 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12428 entry->bytes_per_sample);
12430 if (!entry->sampled && entry->bytes_per_packet) {
12431 entry->samples_per_frame = (entry->bytes_per_frame /
12432 entry->bytes_per_packet) * entry->samples_per_packet;
12433 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12434 entry->samples_per_frame);
12436 } else if (version == 0x00020000) {
12437 /* sample description entry (16) + sound sample description v2 (56) */
12441 /* take information from here over the normal sample description */
12442 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12443 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12444 entry->samples_per_frame = entry->n_channels;
12445 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12446 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12447 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12448 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12450 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12451 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12452 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12453 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12454 entry->bytes_per_sample * 8);
12455 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12456 QT_UINT32 (stsd_entry_data + offset + 24));
12457 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12458 entry->bytes_per_packet);
12459 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12460 entry->samples_per_packet);
12461 } else if (version != 0x00000) {
12462 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12467 /* Yes, these have to be hard-coded */
12470 entry->samples_per_packet = 6;
12471 entry->bytes_per_packet = 1;
12472 entry->bytes_per_frame = 1 * entry->n_channels;
12473 entry->bytes_per_sample = 1;
12474 entry->samples_per_frame = 6 * entry->n_channels;
12479 entry->samples_per_packet = 3;
12480 entry->bytes_per_packet = 1;
12481 entry->bytes_per_frame = 1 * entry->n_channels;
12482 entry->bytes_per_sample = 1;
12483 entry->samples_per_frame = 3 * entry->n_channels;
12488 entry->samples_per_packet = 64;
12489 entry->bytes_per_packet = 34;
12490 entry->bytes_per_frame = 34 * entry->n_channels;
12491 entry->bytes_per_sample = 2;
12492 entry->samples_per_frame = 64 * entry->n_channels;
12498 entry->samples_per_packet = 1;
12499 entry->bytes_per_packet = 1;
12500 entry->bytes_per_frame = 1 * entry->n_channels;
12501 entry->bytes_per_sample = 1;
12502 entry->samples_per_frame = 1 * entry->n_channels;
12507 entry->samples_per_packet = 160;
12508 entry->bytes_per_packet = 33;
12509 entry->bytes_per_frame = 33 * entry->n_channels;
12510 entry->bytes_per_sample = 2;
12511 entry->samples_per_frame = 160 * entry->n_channels;
12514 /* fix up any invalid header information from above */
12519 /* Sometimes these are set to 0 in the sound sample descriptions so
12520 * let's try to infer useful values from the other information we
12521 * have available */
12522 if (entry->bytes_per_sample == 0)
12523 entry->bytes_per_sample =
12524 entry->bytes_per_frame / entry->n_channels;
12525 if (entry->bytes_per_sample == 0)
12526 entry->bytes_per_sample = samplesize / 8;
12528 if (entry->bytes_per_frame == 0)
12529 entry->bytes_per_frame =
12530 entry->bytes_per_sample * entry->n_channels;
12532 if (entry->bytes_per_packet == 0)
12533 entry->bytes_per_packet = entry->bytes_per_sample;
12535 if (entry->samples_per_frame == 0)
12536 entry->samples_per_frame = entry->n_channels;
12538 if (entry->samples_per_packet == 0)
12539 entry->samples_per_packet = entry->samples_per_frame;
12549 entry->bytes_per_sample = 3;
12553 entry->bytes_per_sample = 4;
12556 entry->bytes_per_sample = 8;
12559 entry->bytes_per_sample = 2;
12562 g_assert_not_reached ();
12565 entry->samples_per_frame = entry->n_channels;
12566 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12567 entry->samples_per_packet = entry->samples_per_frame;
12568 entry->bytes_per_packet = entry->bytes_per_sample;
12576 gst_caps_unref (entry->caps);
12578 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12579 stsd_entry_data + 32, len - 16, &codec);
12590 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12592 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12594 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12596 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12599 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12600 const gchar *format_str;
12604 format_str = (enda_value) ? "S24LE" : "S24BE";
12607 format_str = (enda_value) ? "S32LE" : "S32BE";
12610 format_str = (enda_value) ? "F32LE" : "F32BE";
12613 format_str = (enda_value) ? "F64LE" : "F64BE";
12616 g_assert_not_reached ();
12619 gst_caps_set_simple (entry->caps,
12620 "format", G_TYPE_STRING, format_str, NULL);
12626 const guint8 *owma_data;
12627 const gchar *codec_name = NULL;
12631 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12632 /* FIXME this should also be gst_riff_strf_auds,
12633 * but the latter one is actually missing bits-per-sample :( */
12638 gint32 nSamplesPerSec;
12639 gint32 nAvgBytesPerSec;
12640 gint16 nBlockAlign;
12641 gint16 wBitsPerSample;
12644 WAVEFORMATEX *wfex;
12646 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12647 owma_data = stsd_entry_data;
12648 owma_len = QT_UINT32 (owma_data);
12649 if (owma_len <= 54) {
12650 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12653 wfex = (WAVEFORMATEX *) (owma_data + 36);
12654 buf = gst_buffer_new_and_alloc (owma_len - 54);
12655 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12656 if (wfex->wFormatTag == 0x0161) {
12657 codec_name = "Windows Media Audio";
12659 } else if (wfex->wFormatTag == 0x0162) {
12660 codec_name = "Windows Media Audio 9 Pro";
12662 } else if (wfex->wFormatTag == 0x0163) {
12663 codec_name = "Windows Media Audio 9 Lossless";
12664 /* is that correct? gstffmpegcodecmap.c is missing it, but
12665 * fluendo codec seems to support it */
12669 gst_caps_set_simple (entry->caps,
12670 "codec_data", GST_TYPE_BUFFER, buf,
12671 "wmaversion", G_TYPE_INT, version,
12672 "block_align", G_TYPE_INT,
12673 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12674 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12675 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12676 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12677 gst_buffer_unref (buf);
12681 codec = g_strdup (codec_name);
12687 gint len = QT_UINT32 (stsd_entry_data) - offset;
12688 const guint8 *wfex_data = stsd_entry_data + offset;
12689 const gchar *codec_name = NULL;
12691 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12692 /* FIXME this should also be gst_riff_strf_auds,
12693 * but the latter one is actually missing bits-per-sample :( */
12698 gint32 nSamplesPerSec;
12699 gint32 nAvgBytesPerSec;
12700 gint16 nBlockAlign;
12701 gint16 wBitsPerSample;
12706 /* FIXME: unify with similar wavformatex parsing code above */
12707 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12713 if (QT_UINT32 (wfex_data) <= len)
12714 size = QT_UINT32 (wfex_data) - 8;
12719 /* No real data, so break out */
12722 switch (QT_FOURCC (wfex_data + 4)) {
12723 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12725 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12730 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12731 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12732 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12733 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12734 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12735 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12736 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12738 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12739 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12740 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12741 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12742 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12743 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12745 if (wfex.wFormatTag == 0x0161) {
12746 codec_name = "Windows Media Audio";
12748 } else if (wfex.wFormatTag == 0x0162) {
12749 codec_name = "Windows Media Audio 9 Pro";
12751 } else if (wfex.wFormatTag == 0x0163) {
12752 codec_name = "Windows Media Audio 9 Lossless";
12753 /* is that correct? gstffmpegcodecmap.c is missing it, but
12754 * fluendo codec seems to support it */
12758 gst_caps_set_simple (entry->caps,
12759 "wmaversion", G_TYPE_INT, version,
12760 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12761 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12762 "width", G_TYPE_INT, wfex.wBitsPerSample,
12763 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12765 if (size > wfex.cbSize) {
12768 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12769 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12770 size - wfex.cbSize);
12771 gst_caps_set_simple (entry->caps,
12772 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12773 gst_buffer_unref (buf);
12775 GST_WARNING_OBJECT (qtdemux, "no codec data");
12780 codec = g_strdup (codec_name);
12788 wfex_data += size + 8;
12794 const guint8 *dops_data;
12795 guint8 *channel_mapping = NULL;
12798 guint8 channel_mapping_family;
12799 guint8 stream_count;
12800 guint8 coupled_count;
12803 version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12805 dops_data = stsd_entry_data + 51;
12807 dops_data = stsd_entry_data + 35;
12809 channels = GST_READ_UINT8 (dops_data + 10);
12810 rate = GST_READ_UINT32_LE (dops_data + 13);
12811 channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12812 stream_count = GST_READ_UINT8 (dops_data + 20);
12813 coupled_count = GST_READ_UINT8 (dops_data + 21);
12815 if (channels > 0) {
12816 channel_mapping = g_malloc (channels * sizeof (guint8));
12817 for (i = 0; i < channels; i++)
12818 channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12821 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12822 channel_mapping_family, stream_count, coupled_count,
12824 g_free (channel_mapping);
12835 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12836 GST_TAG_AUDIO_CODEC, codec, NULL);
12840 /* some bitrate info may have ended up in caps */
12841 s = gst_caps_get_structure (entry->caps, 0);
12842 gst_structure_get_int (s, "bitrate", &bitrate);
12844 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12845 GST_TAG_BITRATE, bitrate, NULL);
12849 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12850 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12851 if (stream->protected) {
12852 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12853 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12855 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12865 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12867 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12869 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12873 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12874 16 bits is a byte-swapped wave-style codec identifier,
12875 and we can find a WAVE header internally to a 'wave' atom here.
12876 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12877 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12880 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12881 if (len < offset + 20) {
12882 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12884 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12885 const guint8 *data = stsd_entry_data + offset + 16;
12887 GNode *waveheadernode;
12889 wavenode = g_node_new ((guint8 *) data);
12890 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12891 const guint8 *waveheader;
12894 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12895 if (waveheadernode) {
12896 waveheader = (const guint8 *) waveheadernode->data;
12897 headerlen = QT_UINT32 (waveheader);
12899 if (headerlen > 8) {
12900 gst_riff_strf_auds *header = NULL;
12901 GstBuffer *headerbuf;
12907 headerbuf = gst_buffer_new_and_alloc (headerlen);
12908 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12910 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12911 headerbuf, &header, &extra)) {
12912 gst_caps_unref (entry->caps);
12913 /* FIXME: Need to do something with the channel reorder map */
12915 gst_riff_create_audio_caps (header->format, NULL, header,
12916 extra, NULL, NULL, NULL);
12919 gst_buffer_unref (extra);
12924 GST_DEBUG ("Didn't find waveheadernode for this codec");
12926 g_node_destroy (wavenode);
12929 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12930 stream->stream_tags);
12934 /* FIXME: what is in the chunk? */
12937 gint len = QT_UINT32 (stsd_data);
12939 /* seems to be always = 116 = 0x74 */
12945 gint len = QT_UINT32 (stsd_entry_data);
12948 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12950 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12951 gst_caps_set_simple (entry->caps,
12952 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12953 gst_buffer_unref (buf);
12955 gst_caps_set_simple (entry->caps,
12956 "samplesize", G_TYPE_INT, samplesize, NULL);
12961 GNode *alac, *wave = NULL;
12963 /* apparently, m4a has this atom appended directly in the stsd entry,
12964 * while mov has it in a wave atom */
12965 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12967 /* alac now refers to stsd entry atom */
12968 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12970 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12972 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12975 const guint8 *alac_data = alac->data;
12976 gint len = QT_UINT32 (alac->data);
12980 GST_DEBUG_OBJECT (qtdemux,
12981 "discarding alac atom with unexpected len %d", len);
12983 /* codec-data contains alac atom size and prefix,
12984 * ffmpeg likes it that way, not quite gst-ish though ...*/
12985 buf = gst_buffer_new_and_alloc (len);
12986 gst_buffer_fill (buf, 0, alac->data, len);
12987 gst_caps_set_simple (entry->caps,
12988 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12989 gst_buffer_unref (buf);
12991 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12992 entry->n_channels = QT_UINT8 (alac_data + 21);
12993 entry->rate = QT_UINT32 (alac_data + 32);
12994 samplesize = QT_UINT8 (alac_data + 16 + 1);
12997 gst_caps_set_simple (entry->caps,
12998 "samplesize", G_TYPE_INT, samplesize, NULL);
13003 /* The codingname of the sample entry is 'fLaC' */
13004 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
13007 /* The 'dfLa' box is added to the sample entry to convey
13008 initializing information for the decoder. */
13009 const GNode *dfla =
13010 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
13013 const guint32 len = QT_UINT32 (dfla->data);
13015 /* Must contain at least dfLa box header (12),
13016 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
13018 GST_DEBUG_OBJECT (qtdemux,
13019 "discarding dfla atom with unexpected len %d", len);
13021 /* skip dfLa header to get the METADATA_BLOCKs */
13022 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
13023 const guint32 metadata_blocks_len = len - 12;
13025 gchar *stream_marker = g_strdup ("fLaC");
13026 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
13027 strlen (stream_marker));
13030 guint32 remainder = 0;
13031 guint32 block_size = 0;
13032 gboolean is_last = FALSE;
13034 GValue array = G_VALUE_INIT;
13035 GValue value = G_VALUE_INIT;
13037 g_value_init (&array, GST_TYPE_ARRAY);
13038 g_value_init (&value, GST_TYPE_BUFFER);
13040 gst_value_set_buffer (&value, block);
13041 gst_value_array_append_value (&array, &value);
13042 g_value_reset (&value);
13044 gst_buffer_unref (block);
13046 /* check there's at least one METADATA_BLOCK_HEADER's worth
13047 * of data, and we haven't already finished parsing */
13048 while (!is_last && ((index + 3) < metadata_blocks_len)) {
13049 remainder = metadata_blocks_len - index;
13051 /* add the METADATA_BLOCK_HEADER size to the signalled size */
13053 (metadata_blocks[index + 1] << 16) +
13054 (metadata_blocks[index + 2] << 8) +
13055 metadata_blocks[index + 3];
13057 /* be careful not to read off end of box */
13058 if (block_size > remainder) {
13062 is_last = metadata_blocks[index] >> 7;
13064 block = gst_buffer_new_and_alloc (block_size);
13066 gst_buffer_fill (block, 0, &metadata_blocks[index],
13069 gst_value_set_buffer (&value, block);
13070 gst_value_array_append_value (&array, &value);
13071 g_value_reset (&value);
13073 gst_buffer_unref (block);
13075 index += block_size;
13078 /* only append the metadata if we successfully read all of it */
13080 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
13081 (stream)->caps, 0), "streamheader", &array);
13083 GST_WARNING_OBJECT (qtdemux,
13084 "discarding all METADATA_BLOCKs due to invalid "
13085 "block_size %d at idx %d, rem %d", block_size, index,
13089 g_value_unset (&value);
13090 g_value_unset (&array);
13092 /* The sample rate obtained from the stsd may not be accurate
13093 * since it cannot represent rates greater than 65535Hz, so
13094 * override that value with the sample rate from the
13095 * METADATA_BLOCK_STREAMINFO block */
13096 CUR_STREAM (stream)->rate =
13097 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
13108 gint len = QT_UINT32 (stsd_entry_data);
13111 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
13114 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
13116 /* If we have enough data, let's try to get the 'damr' atom. See
13117 * the 3GPP container spec (26.244) for more details. */
13118 if ((len - 0x34) > 8 &&
13119 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
13120 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13121 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
13124 gst_caps_set_simple (entry->caps,
13125 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13126 gst_buffer_unref (buf);
13132 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
13133 gint len = QT_UINT32 (stsd_entry_data);
13134 guint16 sound_version = 0;
13135 /* FIXME: Can this be determined somehow? There doesn't seem to be
13136 * anything in mp4a atom that specifis compression */
13138 guint16 channels = entry->n_channels;
13139 guint32 time_scale = (guint32) entry->rate;
13140 gint sample_rate_index = -1;
13143 sound_version = QT_UINT16 (stsd_entry_data + 16);
13145 if (sound_version == 1) {
13146 channels = QT_UINT16 (stsd_entry_data + 24);
13147 time_scale = QT_UINT32 (stsd_entry_data + 30);
13149 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
13153 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
13157 sample_rate_index =
13158 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
13159 if (sample_rate_index >= 0 && channels > 0) {
13160 guint8 codec_data[2];
13163 /* build AAC codec data */
13164 codec_data[0] = profile << 3;
13165 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
13166 codec_data[1] = (sample_rate_index & 0x01) << 7;
13167 codec_data[1] |= (channels & 0xF) << 3;
13169 buf = gst_buffer_new_and_alloc (2);
13170 gst_buffer_fill (buf, 0, codec_data, 2);
13171 gst_caps_set_simple (entry->caps,
13172 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13173 gst_buffer_unref (buf);
13183 /* Fully handled elsewhere */
13186 GST_INFO_OBJECT (qtdemux,
13187 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13191 GST_INFO_OBJECT (qtdemux,
13192 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13193 GST_FOURCC_ARGS (fourcc), entry->caps);
13195 } else if (stream->subtype == FOURCC_strm) {
13196 if (fourcc == FOURCC_rtsp) {
13197 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
13199 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
13200 GST_FOURCC_ARGS (fourcc));
13201 goto unknown_stream;
13203 entry->sampled = TRUE;
13204 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
13205 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
13206 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
13208 entry->sampled = TRUE;
13209 entry->sparse = TRUE;
13212 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13215 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13216 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13221 /* hunt for sort-of codec data */
13225 GNode *mp4s = NULL;
13226 GNode *esds = NULL;
13228 /* look for palette in a stsd->mp4s->esds sub-atom */
13229 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
13231 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
13232 if (esds == NULL) {
13234 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13238 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13239 stream->stream_tags);
13243 GST_INFO_OBJECT (qtdemux,
13244 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13247 GST_INFO_OBJECT (qtdemux,
13248 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13249 GST_FOURCC_ARGS (fourcc), entry->caps);
13250 } else if (stream->subtype == FOURCC_meta) {
13251 entry->sampled = TRUE;
13252 entry->sparse = TRUE;
13255 qtdemux_meta_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13258 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13259 GST_TAG_CODEC, codec, NULL);
13264 GST_INFO_OBJECT (qtdemux,
13265 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13266 GST_FOURCC_ARGS (fourcc), entry->caps);
13268 /* everything in 1 sample */
13269 entry->sampled = TRUE;
13272 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13275 if (entry->caps == NULL)
13276 goto unknown_stream;
13279 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13280 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13286 /* promote to sampled format */
13287 if (entry->fourcc == FOURCC_samr) {
13288 /* force mono 8000 Hz for AMR */
13289 entry->sampled = TRUE;
13290 entry->n_channels = 1;
13291 entry->rate = 8000;
13292 } else if (entry->fourcc == FOURCC_sawb) {
13293 /* force mono 16000 Hz for AMR-WB */
13294 entry->sampled = TRUE;
13295 entry->n_channels = 1;
13296 entry->rate = 16000;
13297 } else if (entry->fourcc == FOURCC_mp4a) {
13298 entry->sampled = TRUE;
13302 stsd_entry_data += len;
13303 remaining_stsd_len -= len;
13307 /* collect sample information */
13308 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13309 goto samples_failed;
13311 if (qtdemux->fragmented) {
13314 /* need all moov samples as basis; probably not many if any at all */
13315 /* prevent moof parsing taking of at this time */
13316 offset = qtdemux->moof_offset;
13317 qtdemux->moof_offset = 0;
13318 if (stream->n_samples &&
13319 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13320 qtdemux->moof_offset = offset;
13321 goto samples_failed;
13323 qtdemux->moof_offset = offset;
13324 /* movie duration more reliable in this case (e.g. mehd) */
13325 if (qtdemux->segment.duration &&
13326 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13328 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13331 /* configure segments */
13332 if (!qtdemux_parse_segments (qtdemux, stream, trak))
13333 goto segments_failed;
13335 /* add some language tag, if useful */
13336 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13337 strcmp (stream->lang_id, "und")) {
13338 const gchar *lang_code;
13340 /* convert ISO 639-2 code to ISO 639-1 */
13341 lang_code = gst_tag_get_language_code (stream->lang_id);
13342 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13343 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13346 /* Check for UDTA tags */
13347 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13348 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13351 /* Insert and sort new stream in track-id order.
13352 * This will help in comparing old/new streams during stream update check */
13353 g_ptr_array_add (qtdemux->active_streams, stream);
13354 g_ptr_array_sort (qtdemux->active_streams,
13355 (GCompareFunc) qtdemux_track_id_compare_func);
13356 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13357 QTDEMUX_N_STREAMS (qtdemux));
13364 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13365 (_("This file is corrupt and cannot be played.")), (NULL));
13367 gst_qtdemux_stream_unref (stream);
13372 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13373 gst_qtdemux_stream_unref (stream);
13379 /* we posted an error already */
13380 /* free stbl sub-atoms */
13381 gst_qtdemux_stbl_free (stream);
13382 gst_qtdemux_stream_unref (stream);
13387 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13393 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13394 GST_FOURCC_ARGS (stream->subtype));
13395 gst_qtdemux_stream_unref (stream);
13400 /* If we can estimate the overall bitrate, and don't have information about the
13401 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13402 * the overall bitrate minus the sum of the bitrates of all other streams. This
13403 * should be useful for the common case where we have one audio and one video
13404 * stream and can estimate the bitrate of one, but not the other. */
13406 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13408 QtDemuxStream *stream = NULL;
13409 gint64 size, sys_bitrate, sum_bitrate = 0;
13410 GstClockTime duration;
13414 if (qtdemux->fragmented)
13417 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13419 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13421 GST_DEBUG_OBJECT (qtdemux,
13422 "Size in bytes of the stream not known - bailing");
13426 /* Subtract the header size */
13427 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13428 size, qtdemux->header_size);
13430 if (size < qtdemux->header_size)
13433 size = size - qtdemux->header_size;
13435 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13436 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13440 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13441 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13442 switch (str->subtype) {
13445 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13446 CUR_STREAM (str)->caps);
13447 /* retrieve bitrate, prefer avg then max */
13449 if (str->stream_tags) {
13450 if (gst_tag_list_get_uint (str->stream_tags,
13451 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13452 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13453 if (gst_tag_list_get_uint (str->stream_tags,
13454 GST_TAG_NOMINAL_BITRATE, &bitrate))
13455 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13456 if (gst_tag_list_get_uint (str->stream_tags,
13457 GST_TAG_BITRATE, &bitrate))
13458 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13461 sum_bitrate += bitrate;
13464 GST_DEBUG_OBJECT (qtdemux,
13465 ">1 stream with unknown bitrate - bailing");
13472 /* For other subtypes, we assume no significant impact on bitrate */
13478 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13482 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13484 if (sys_bitrate < sum_bitrate) {
13485 /* This can happen, since sum_bitrate might be derived from maximum
13486 * bitrates and not average bitrates */
13487 GST_DEBUG_OBJECT (qtdemux,
13488 "System bitrate less than sum bitrate - bailing");
13492 bitrate = sys_bitrate - sum_bitrate;
13493 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13494 ", Stream bitrate = %u", sys_bitrate, bitrate);
13496 if (!stream->stream_tags)
13497 stream->stream_tags = gst_tag_list_new_empty ();
13499 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13501 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13502 GST_TAG_BITRATE, bitrate, NULL);
13505 static GstFlowReturn
13506 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13508 GstFlowReturn ret = GST_FLOW_OK;
13511 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13513 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13514 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13515 guint32 sample_num = 0;
13517 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13518 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13520 if (qtdemux->fragmented && qtdemux->pullbased) {
13521 /* need all moov samples first */
13522 GST_OBJECT_LOCK (qtdemux);
13523 while (stream->n_samples == 0)
13524 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13526 GST_OBJECT_UNLOCK (qtdemux);
13528 /* discard any stray moof */
13529 qtdemux->moof_offset = 0;
13532 /* prepare braking */
13533 if (ret != GST_FLOW_ERROR)
13536 /* in pull mode, we should have parsed some sample info by now;
13537 * and quite some code will not handle no samples.
13538 * in push mode, we'll just have to deal with it */
13539 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13540 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13541 g_ptr_array_remove_index (qtdemux->active_streams, i);
13544 } else if (stream->track_id == qtdemux->chapters_track_id &&
13545 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13546 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13547 so that it doesn't look like a subtitle track */
13548 g_ptr_array_remove_index (qtdemux->active_streams, i);
13553 /* parse the initial sample for use in setting the frame rate cap */
13554 while (sample_num == 0 && sample_num < stream->n_samples) {
13555 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13565 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13567 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13571 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13575 /* Different length, updated */
13576 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13579 /* streams in list are sorted in track-id order */
13580 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13581 /* Different stream-id, updated */
13582 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13583 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13591 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13592 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13594 /* Connect old stream's srcpad to new stream */
13595 newstream->pad = oldstream->pad;
13596 oldstream->pad = NULL;
13598 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13599 * case we need to force one through */
13600 newstream->new_stream = newstream->pad != NULL
13601 && GST_PAD_IS_EOS (newstream->pad);
13603 return gst_qtdemux_configure_stream (qtdemux, newstream);
13607 qtdemux_update_streams (GstQTDemux * qtdemux)
13610 g_assert (qtdemux->streams_aware);
13612 /* At below, figure out which stream in active_streams has identical stream-id
13613 * with that of in old_streams. If there is matching stream-id,
13614 * corresponding newstream will not be exposed again,
13615 * but demux will reuse srcpad of matched old stream
13617 * active_streams : newly created streams from the latest moov
13618 * old_streams : existing streams (belong to previous moov)
13621 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13622 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13623 QtDemuxStream *oldstream = NULL;
13626 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13627 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13629 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13630 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13631 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13633 /* null pad stream cannot be reused */
13634 if (oldstream->pad == NULL)
13639 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13641 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13644 /* we don't need to preserve order of old streams */
13645 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13649 /* now we have all info and can expose */
13650 list = stream->stream_tags;
13651 stream->stream_tags = NULL;
13652 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13660 /* Must be called with expose lock */
13661 static GstFlowReturn
13662 qtdemux_expose_streams (GstQTDemux * qtdemux)
13666 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13668 if (!qtdemux_is_streams_update (qtdemux)) {
13669 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13670 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13671 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13672 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13673 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13674 return GST_FLOW_ERROR;
13677 g_ptr_array_set_size (qtdemux->old_streams, 0);
13678 qtdemux->need_segment = TRUE;
13680 return GST_FLOW_OK;
13683 if (qtdemux->streams_aware) {
13684 if (!qtdemux_update_streams (qtdemux))
13685 return GST_FLOW_ERROR;
13687 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13688 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13691 /* now we have all info and can expose */
13692 list = stream->stream_tags;
13693 stream->stream_tags = NULL;
13694 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13695 return GST_FLOW_ERROR;
13700 gst_qtdemux_guess_bitrate (qtdemux);
13702 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13704 /* If we have still old_streams, it's no more used stream */
13705 for (i = 0; i < qtdemux->old_streams->len; i++) {
13706 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13711 event = gst_event_new_eos ();
13712 if (qtdemux->segment_seqnum)
13713 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13715 gst_pad_push_event (stream->pad, event);
13719 g_ptr_array_set_size (qtdemux->old_streams, 0);
13721 /* check if we should post a redirect in case there is a single trak
13722 * and it is a redirecting trak */
13723 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13724 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13727 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13728 "an external content");
13729 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13730 gst_structure_new ("redirect",
13731 "new-location", G_TYPE_STRING,
13732 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13733 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13734 g_free (qtdemux->redirect_location);
13735 qtdemux->redirect_location =
13736 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13739 g_ptr_array_foreach (qtdemux->active_streams,
13740 (GFunc) qtdemux_do_allocation, qtdemux);
13742 qtdemux->need_segment = TRUE;
13744 qtdemux->exposed = TRUE;
13745 return GST_FLOW_OK;
13750 GstStructure *structure; /* helper for sort function */
13752 guint min_req_bitrate;
13753 guint min_req_qt_version;
13757 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13759 GstQtReference *ref_a = (GstQtReference *) a;
13760 GstQtReference *ref_b = (GstQtReference *) b;
13762 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13763 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13765 /* known bitrates go before unknown; higher bitrates go first */
13766 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13769 /* sort the redirects and post a message for the application.
13772 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13774 GstQtReference *best;
13777 GValue list_val = { 0, };
13780 g_assert (references != NULL);
13782 references = g_list_sort (references, qtdemux_redirects_sort_func);
13784 best = (GstQtReference *) references->data;
13786 g_value_init (&list_val, GST_TYPE_LIST);
13788 for (l = references; l != NULL; l = l->next) {
13789 GstQtReference *ref = (GstQtReference *) l->data;
13790 GValue struct_val = { 0, };
13792 ref->structure = gst_structure_new ("redirect",
13793 "new-location", G_TYPE_STRING, ref->location, NULL);
13795 if (ref->min_req_bitrate > 0) {
13796 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13797 ref->min_req_bitrate, NULL);
13800 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13801 g_value_set_boxed (&struct_val, ref->structure);
13802 gst_value_list_append_value (&list_val, &struct_val);
13803 g_value_unset (&struct_val);
13804 /* don't free anything here yet, since we need best->structure below */
13807 g_assert (best != NULL);
13808 s = gst_structure_copy (best->structure);
13810 if (g_list_length (references) > 1) {
13811 gst_structure_set_value (s, "locations", &list_val);
13814 g_value_unset (&list_val);
13816 for (l = references; l != NULL; l = l->next) {
13817 GstQtReference *ref = (GstQtReference *) l->data;
13819 gst_structure_free (ref->structure);
13820 g_free (ref->location);
13823 g_list_free (references);
13825 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13826 g_free (qtdemux->redirect_location);
13827 qtdemux->redirect_location =
13828 g_strdup (gst_structure_get_string (s, "new-location"));
13829 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13830 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13833 /* look for redirect nodes, collect all redirect information and
13837 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13839 GNode *rmra, *rmda, *rdrf;
13841 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13843 GList *redirects = NULL;
13845 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13847 GstQtReference ref = { NULL, NULL, 0, 0 };
13848 GNode *rmdr, *rmvc;
13850 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13851 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13852 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13853 ref.min_req_bitrate);
13856 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13857 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13858 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13860 #ifndef GST_DISABLE_GST_DEBUG
13861 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13863 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13865 GST_LOG_OBJECT (qtdemux,
13866 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13867 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13868 bitmask, check_type);
13869 if (package == FOURCC_qtim && check_type == 0) {
13870 ref.min_req_qt_version = version;
13874 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13880 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13881 if (ref_len > 20) {
13882 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13883 ref_data = (guint8 *) rdrf->data + 20;
13884 if (ref_type == FOURCC_alis) {
13885 guint record_len, record_version, fn_len;
13887 if (ref_len > 70) {
13888 /* MacOSX alias record, google for alias-layout.txt */
13889 record_len = QT_UINT16 (ref_data + 4);
13890 record_version = QT_UINT16 (ref_data + 4 + 2);
13891 fn_len = QT_UINT8 (ref_data + 50);
13892 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13893 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13896 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13899 } else if (ref_type == FOURCC_url_) {
13900 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13902 GST_DEBUG_OBJECT (qtdemux,
13903 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13904 GST_FOURCC_ARGS (ref_type));
13906 if (ref.location != NULL) {
13907 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13909 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13911 GST_WARNING_OBJECT (qtdemux,
13912 "Failed to extract redirect location from rdrf atom");
13915 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13919 /* look for others */
13920 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13923 if (redirects != NULL) {
13924 qtdemux_process_redirects (qtdemux, redirects);
13930 static GstTagList *
13931 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13935 if (tags == NULL) {
13936 tags = gst_tag_list_new_empty ();
13937 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13940 if (qtdemux->major_brand == FOURCC_mjp2)
13941 fmt = "Motion JPEG 2000";
13942 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13944 else if (qtdemux->major_brand == FOURCC_qt__)
13946 else if (qtdemux->fragmented)
13949 fmt = "ISO MP4/M4A";
13951 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13952 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13954 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13960 /* we have read the complete moov node now.
13961 * This function parses all of the relevant info, creates the traks and
13962 * prepares all data structures for playback
13965 qtdemux_parse_tree (GstQTDemux * qtdemux)
13972 guint64 creation_time;
13973 GstDateTime *datetime = NULL;
13976 /* make sure we have a usable taglist */
13977 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13979 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13980 if (mvhd == NULL) {
13981 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13982 return qtdemux_parse_redirects (qtdemux);
13985 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13986 if (version == 1) {
13987 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13988 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13989 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13990 } else if (version == 0) {
13991 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13992 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13993 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13995 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13999 /* Moving qt creation time (secs since 1904) to unix time */
14000 if (creation_time != 0) {
14001 /* Try to use epoch first as it should be faster and more commonly found */
14002 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
14005 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
14006 /* some data cleansing sanity */
14007 now_s = g_get_real_time () / G_USEC_PER_SEC;
14008 if (now_s + 24 * 3600 < creation_time) {
14009 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
14011 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
14014 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
14015 GDateTime *dt, *dt_local;
14017 dt = g_date_time_add_seconds (base_dt, creation_time);
14018 dt_local = g_date_time_to_local (dt);
14019 datetime = gst_date_time_new_from_g_date_time (dt_local);
14021 g_date_time_unref (base_dt);
14022 g_date_time_unref (dt);
14026 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
14027 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
14029 gst_date_time_unref (datetime);
14032 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
14033 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
14035 /* check for fragmented file and get some (default) data */
14036 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
14039 GstByteReader mehd_data;
14041 /* let track parsing or anyone know weird stuff might happen ... */
14042 qtdemux->fragmented = TRUE;
14044 /* compensate for total duration */
14045 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
14047 qtdemux_parse_mehd (qtdemux, &mehd_data);
14050 /* Update the movie segment duration, unless it was directly given to us
14051 * by upstream. Otherwise let it as is, as we don't want to mangle the
14052 * duration provided by upstream that may come e.g. from a MPD file. */
14053 if (!qtdemux->upstream_format_is_time) {
14054 GstClockTime duration;
14055 /* set duration in the segment info */
14056 gst_qtdemux_get_duration (qtdemux, &duration);
14057 qtdemux->segment.duration = duration;
14058 /* also do not exceed duration; stop is set that way post seek anyway,
14059 * and segment activation falls back to duration,
14060 * whereas loop only checks stop, so let's align this here as well */
14061 qtdemux->segment.stop = duration;
14064 /* parse all traks */
14065 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
14067 qtdemux_parse_trak (qtdemux, trak);
14068 /* iterate all siblings */
14069 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
14072 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14075 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
14077 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14079 GST_LOG_OBJECT (qtdemux, "No udta node found.");
14082 /* maybe also some tags in meta box */
14083 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
14085 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
14086 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14088 GST_LOG_OBJECT (qtdemux, "No meta node found.");
14091 /* parse any protection system info */
14092 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
14094 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
14095 qtdemux_parse_pssh (qtdemux, pssh);
14096 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
14099 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
14104 /* taken from ffmpeg */
14106 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14118 len = (len << 7) | (c & 0x7f);
14127 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14128 gsize codec_data_size)
14130 GList *list = NULL;
14131 guint8 *p = codec_data;
14132 gint i, offset, num_packets;
14133 guint *length, last;
14135 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14137 if (codec_data == NULL || codec_data_size == 0)
14140 /* start of the stream and vorbis audio or theora video, need to
14141 * send the codec_priv data as first three packets */
14142 num_packets = p[0] + 1;
14143 GST_DEBUG_OBJECT (qtdemux,
14144 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14145 (guint) num_packets, codec_data_size);
14147 /* Let's put some limits, Don't think there even is a xiph codec
14148 * with more than 3-4 headers */
14149 if (G_UNLIKELY (num_packets > 16)) {
14150 GST_WARNING_OBJECT (qtdemux,
14151 "Unlikely number of xiph headers, most likely not valid");
14155 length = g_alloca (num_packets * sizeof (guint));
14159 /* first packets, read length values */
14160 for (i = 0; i < num_packets - 1; i++) {
14162 while (offset < codec_data_size) {
14163 length[i] += p[offset];
14164 if (p[offset++] != 0xff)
14169 if (offset + last > codec_data_size)
14172 /* last packet is the remaining size */
14173 length[i] = codec_data_size - offset - last;
14175 for (i = 0; i < num_packets; i++) {
14178 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14180 if (offset + length[i] > codec_data_size)
14183 hdr = gst_buffer_new_memdup (p + offset, length[i]);
14184 list = g_list_append (list, hdr);
14186 offset += length[i];
14195 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14201 /* this can change the codec originally present in @list */
14203 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14204 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14206 int len = QT_UINT32 (esds->data);
14207 guint8 *ptr = esds->data;
14208 guint8 *end = ptr + len;
14210 guint8 *data_ptr = NULL;
14212 guint8 object_type_id = 0;
14213 guint8 stream_type = 0;
14214 const char *codec_name = NULL;
14215 GstCaps *caps = NULL;
14217 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14219 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14221 while (ptr + 1 < end) {
14222 tag = QT_UINT8 (ptr);
14223 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14225 len = read_descr_size (ptr, end, &ptr);
14226 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14228 /* Check the stated amount of data is available for reading */
14229 if (len < 0 || ptr + len > end)
14233 case ES_DESCRIPTOR_TAG:
14234 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14235 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14238 case DECODER_CONFIG_DESC_TAG:{
14239 guint max_bitrate, avg_bitrate;
14241 object_type_id = QT_UINT8 (ptr);
14242 stream_type = QT_UINT8 (ptr + 1) >> 2;
14243 max_bitrate = QT_UINT32 (ptr + 5);
14244 avg_bitrate = QT_UINT32 (ptr + 9);
14245 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14246 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14247 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14248 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14249 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14250 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14251 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14252 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14254 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14255 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14256 avg_bitrate, NULL);
14261 case DECODER_SPECIFIC_INFO_TAG:
14262 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14263 if (object_type_id == 0xe0 && len == 0x40) {
14269 GST_DEBUG_OBJECT (qtdemux,
14270 "Have VOBSUB palette. Creating palette event");
14271 /* move to decConfigDescr data and read palette */
14273 for (i = 0; i < 16; i++) {
14274 clut[i] = QT_UINT32 (data);
14278 s = gst_structure_new ("application/x-gst-dvd", "event",
14279 G_TYPE_STRING, "dvd-spu-clut-change",
14280 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14281 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14282 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14283 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14284 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14285 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14286 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14287 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14290 /* store event and trigger custom processing */
14291 stream->pending_event =
14292 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14294 /* Generic codec_data handler puts it on the caps */
14301 case SL_CONFIG_DESC_TAG:
14302 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14306 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14308 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14314 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14315 * in use, and should also be used to override some other parameters for some
14317 switch (object_type_id) {
14318 case 0x20: /* MPEG-4 */
14319 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14320 * profile_and_level_indication */
14321 if (data_ptr != NULL && data_len >= 5 &&
14322 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14323 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14324 data_ptr + 4, data_len - 4);
14326 break; /* Nothing special needed here */
14327 case 0x21: /* H.264 */
14328 codec_name = "H.264 / AVC";
14329 caps = gst_caps_new_simple ("video/x-h264",
14330 "stream-format", G_TYPE_STRING, "avc",
14331 "alignment", G_TYPE_STRING, "au", NULL);
14333 case 0x40: /* AAC (any) */
14334 case 0x66: /* AAC Main */
14335 case 0x67: /* AAC LC */
14336 case 0x68: /* AAC SSR */
14337 /* Override channels and rate based on the codec_data, as it's often
14339 /* Only do so for basic setup without HE-AAC extension */
14340 if (data_ptr && data_len == 2) {
14341 guint channels, rate;
14343 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14345 entry->n_channels = channels;
14347 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14349 entry->rate = rate;
14352 /* Set level and profile if possible */
14353 if (data_ptr != NULL && data_len >= 2) {
14354 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14355 data_ptr, data_len);
14357 const gchar *profile_str = NULL;
14360 guint8 *codec_data;
14361 gint rate_idx, profile;
14363 /* No codec_data, let's invent something.
14364 * FIXME: This is wrong for SBR! */
14366 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14368 buffer = gst_buffer_new_and_alloc (2);
14369 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14370 codec_data = map.data;
14373 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14376 switch (object_type_id) {
14378 profile_str = "main";
14382 profile_str = "lc";
14386 profile_str = "ssr";
14394 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14396 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14398 gst_buffer_unmap (buffer, &map);
14399 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14400 GST_TYPE_BUFFER, buffer, NULL);
14401 gst_buffer_unref (buffer);
14404 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14405 G_TYPE_STRING, profile_str, NULL);
14409 case 0x60: /* MPEG-2, various profiles */
14415 codec_name = "MPEG-2 video";
14416 caps = gst_caps_new_simple ("video/mpeg",
14417 "mpegversion", G_TYPE_INT, 2,
14418 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14420 case 0x69: /* MPEG-2 BC audio */
14421 case 0x6B: /* MPEG-1 audio */
14422 caps = gst_caps_new_simple ("audio/mpeg",
14423 "mpegversion", G_TYPE_INT, 1, NULL);
14424 codec_name = "MPEG-1 audio";
14426 case 0x6A: /* MPEG-1 */
14427 codec_name = "MPEG-1 video";
14428 caps = gst_caps_new_simple ("video/mpeg",
14429 "mpegversion", G_TYPE_INT, 1,
14430 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14432 case 0x6C: /* MJPEG */
14434 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14436 codec_name = "Motion-JPEG";
14438 case 0x6D: /* PNG */
14440 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14442 codec_name = "PNG still images";
14444 case 0x6E: /* JPEG2000 */
14445 codec_name = "JPEG-2000";
14446 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14448 case 0xA4: /* Dirac */
14449 codec_name = "Dirac";
14450 caps = gst_caps_new_empty_simple ("video/x-dirac");
14452 case 0xA5: /* AC3 */
14453 codec_name = "AC-3 audio";
14454 caps = gst_caps_new_simple ("audio/x-ac3",
14455 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14457 case 0xA9: /* AC3 */
14458 codec_name = "DTS audio";
14459 caps = gst_caps_new_simple ("audio/x-dts",
14460 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14463 if (stream_type == 0x05 && data_ptr) {
14465 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14468 GValue arr_val = G_VALUE_INIT;
14469 GValue buf_val = G_VALUE_INIT;
14472 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14473 codec_name = "Vorbis";
14474 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14475 g_value_init (&arr_val, GST_TYPE_ARRAY);
14476 g_value_init (&buf_val, GST_TYPE_BUFFER);
14477 for (tmp = headers; tmp; tmp = tmp->next) {
14478 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14479 gst_value_array_append_value (&arr_val, &buf_val);
14481 s = gst_caps_get_structure (caps, 0);
14482 gst_structure_take_value (s, "streamheader", &arr_val);
14483 g_value_unset (&buf_val);
14484 g_list_free (headers);
14491 case 0xE1: /* QCELP */
14492 /* QCELP, the codec_data is a riff tag (little endian) with
14493 * 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). */
14494 caps = gst_caps_new_empty_simple ("audio/qcelp");
14495 codec_name = "QCELP";
14501 /* If we have a replacement caps, then change our caps for this stream */
14503 gst_caps_unref (entry->caps);
14504 entry->caps = caps;
14507 if (codec_name && list)
14508 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14509 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14511 /* Add the codec_data attribute to caps, if we have it */
14515 buffer = gst_buffer_new_and_alloc (data_len);
14516 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14518 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14519 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14521 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14523 gst_buffer_unref (buffer);
14528 static inline GstCaps *
14529 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14533 char *s, fourstr[5];
14535 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14536 for (i = 0; i < 4; i++) {
14537 if (!g_ascii_isalnum (fourstr[i]))
14540 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14541 caps = gst_caps_new_empty_simple (s);
14546 #define _codec(name) \
14548 if (codec_name) { \
14549 *codec_name = g_strdup (name); \
14554 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14555 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14556 const guint8 * stsd_entry_data, gchar ** codec_name)
14558 GstCaps *caps = NULL;
14559 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14563 _codec ("PNG still images");
14564 caps = gst_caps_new_empty_simple ("image/png");
14567 _codec ("JPEG still images");
14569 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14572 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14573 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14574 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14575 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14576 _codec ("Motion-JPEG");
14578 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14581 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14582 _codec ("Motion-JPEG format B");
14583 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14586 _codec ("JPEG-2000");
14587 /* override to what it should be according to spec, avoid palette_data */
14588 entry->bits_per_sample = 24;
14589 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14592 _codec ("Sorensen video v.3");
14593 caps = gst_caps_new_simple ("video/x-svq",
14594 "svqversion", G_TYPE_INT, 3, NULL);
14596 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14597 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14598 _codec ("Sorensen video v.1");
14599 caps = gst_caps_new_simple ("video/x-svq",
14600 "svqversion", G_TYPE_INT, 1, NULL);
14602 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14603 caps = gst_caps_new_empty_simple ("video/x-raw");
14604 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14605 _codec ("Windows Raw RGB");
14606 stream->alignment = 32;
14612 bps = QT_UINT16 (stsd_entry_data + 82);
14615 format = GST_VIDEO_FORMAT_RGB15;
14618 format = GST_VIDEO_FORMAT_RGB16;
14621 format = GST_VIDEO_FORMAT_RGB;
14624 format = GST_VIDEO_FORMAT_ARGB;
14632 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14633 format = GST_VIDEO_FORMAT_I420;
14635 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14636 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14637 format = GST_VIDEO_FORMAT_I420;
14640 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14641 format = GST_VIDEO_FORMAT_UYVY;
14643 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14644 format = GST_VIDEO_FORMAT_v308;
14646 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14647 format = GST_VIDEO_FORMAT_v216;
14650 format = GST_VIDEO_FORMAT_v210;
14652 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14653 format = GST_VIDEO_FORMAT_r210;
14655 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14656 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14657 format = GST_VIDEO_FORMAT_v410;
14660 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14661 * but different order than AYUV
14662 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14663 format = GST_VIDEO_FORMAT_v408;
14666 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14667 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14668 _codec ("MPEG-1 video");
14669 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14670 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14672 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14673 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14674 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14675 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14676 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14677 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14678 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14679 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14680 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14681 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14682 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14683 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14684 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14685 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14686 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14687 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14688 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14689 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14690 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14691 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14692 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14693 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14694 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14695 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14696 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14697 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14698 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14699 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14700 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14701 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14702 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14703 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14704 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14705 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14706 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14707 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14708 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14709 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14710 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14711 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14712 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14713 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14714 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14715 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14716 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14717 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14718 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14719 _codec ("MPEG-2 video");
14720 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14721 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14723 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14724 _codec ("GIF still images");
14725 caps = gst_caps_new_empty_simple ("image/gif");
14728 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14730 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14732 /* ffmpeg uses the height/width props, don't know why */
14733 caps = gst_caps_new_simple ("video/x-h263",
14734 "variant", G_TYPE_STRING, "itu", NULL);
14738 _codec ("MPEG-4 video");
14739 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14740 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14742 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14743 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14744 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14745 caps = gst_caps_new_simple ("video/x-msmpeg",
14746 "msmpegversion", G_TYPE_INT, 43, NULL);
14748 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14750 caps = gst_caps_new_simple ("video/x-divx",
14751 "divxversion", G_TYPE_INT, 3, NULL);
14753 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14754 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14756 caps = gst_caps_new_simple ("video/x-divx",
14757 "divxversion", G_TYPE_INT, 4, NULL);
14759 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14761 caps = gst_caps_new_simple ("video/x-divx",
14762 "divxversion", G_TYPE_INT, 5, NULL);
14765 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14767 caps = gst_caps_new_simple ("video/x-ffv",
14768 "ffvversion", G_TYPE_INT, 1, NULL);
14771 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14772 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14777 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14778 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14779 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14783 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14784 _codec ("Cinepak");
14785 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14787 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14788 _codec ("Apple QuickDraw");
14789 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14791 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14792 _codec ("Apple video");
14793 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14798 _codec ("H.264 / AVC");
14799 caps = gst_caps_new_simple ("video/x-h264",
14800 "stream-format", G_TYPE_STRING, "avc",
14801 "alignment", G_TYPE_STRING, "au", NULL);
14805 _codec ("H.264 / AVC");
14806 caps = gst_caps_new_simple ("video/x-h264",
14807 "stream-format", G_TYPE_STRING, "avc3",
14808 "alignment", G_TYPE_STRING, "au", NULL);
14813 _codec ("H.265 / HEVC");
14814 caps = gst_caps_new_simple ("video/x-h265",
14815 "stream-format", G_TYPE_STRING, "hvc1",
14816 "alignment", G_TYPE_STRING, "au", NULL);
14820 _codec ("H.265 / HEVC");
14821 caps = gst_caps_new_simple ("video/x-h265",
14822 "stream-format", G_TYPE_STRING, "hev1",
14823 "alignment", G_TYPE_STRING, "au", NULL);
14826 _codec ("Run-length encoding");
14827 caps = gst_caps_new_simple ("video/x-rle",
14828 "layout", G_TYPE_STRING, "quicktime", NULL);
14831 _codec ("Run-length encoding");
14832 caps = gst_caps_new_simple ("video/x-rle",
14833 "layout", G_TYPE_STRING, "microsoft", NULL);
14835 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14836 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14837 _codec ("Indeo Video 3");
14838 caps = gst_caps_new_simple ("video/x-indeo",
14839 "indeoversion", G_TYPE_INT, 3, NULL);
14841 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14842 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14843 _codec ("Intel Video 4");
14844 caps = gst_caps_new_simple ("video/x-indeo",
14845 "indeoversion", G_TYPE_INT, 4, NULL);
14849 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14850 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14851 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14852 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14853 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14854 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14855 _codec ("DV Video");
14856 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14857 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14859 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14860 case FOURCC_dv5p: /* DVCPRO50 PAL */
14861 _codec ("DVCPro50 Video");
14862 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14863 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14865 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14866 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14867 _codec ("DVCProHD Video");
14868 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14869 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14871 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14872 _codec ("Apple Graphics (SMC)");
14873 caps = gst_caps_new_empty_simple ("video/x-smc");
14875 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14877 caps = gst_caps_new_empty_simple ("video/x-vp3");
14879 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14880 _codec ("VP6 Flash");
14881 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14885 caps = gst_caps_new_empty_simple ("video/x-theora");
14886 /* theora uses one byte of padding in the data stream because it does not
14887 * allow 0 sized packets while theora does */
14888 entry->padding = 1;
14892 caps = gst_caps_new_empty_simple ("video/x-dirac");
14894 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14895 _codec ("TIFF still images");
14896 caps = gst_caps_new_empty_simple ("image/tiff");
14898 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14899 _codec ("Apple Intermediate Codec");
14900 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14902 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14903 _codec ("AVID DNxHD");
14904 caps = gst_caps_from_string ("video/x-dnxhd");
14908 _codec ("On2 VP8");
14909 caps = gst_caps_from_string ("video/x-vp8");
14912 _codec ("Google VP9");
14913 caps = gst_caps_from_string ("video/x-vp9");
14916 _codec ("Apple ProRes LT");
14918 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14922 _codec ("Apple ProRes HQ");
14924 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14928 _codec ("Apple ProRes");
14930 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14934 _codec ("Apple ProRes Proxy");
14936 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14940 _codec ("Apple ProRes 4444");
14942 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14945 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14946 if (entry->bits_per_sample > 0) {
14947 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14952 _codec ("Apple ProRes 4444 XQ");
14954 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14957 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14958 if (entry->bits_per_sample > 0) {
14959 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14964 _codec ("GoPro CineForm");
14965 caps = gst_caps_from_string ("video/x-cineform");
14970 caps = gst_caps_new_simple ("video/x-wmv",
14971 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14975 caps = gst_caps_new_simple ("video/x-av1",
14976 "alignment", G_TYPE_STRING, "tu", NULL);
14978 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14981 caps = _get_unknown_codec_name ("video", fourcc);
14986 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14989 gst_video_info_init (&info);
14990 gst_video_info_set_format (&info, format, entry->width, entry->height);
14992 caps = gst_video_info_to_caps (&info);
14993 *codec_name = gst_pb_utils_get_codec_description (caps);
14995 /* enable clipping for raw video streams */
14996 stream->need_clip = TRUE;
14997 stream->alignment = 32;
15004 round_up_pow2 (guint n)
15016 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15017 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
15018 int len, gchar ** codec_name)
15021 const GstStructure *s;
15024 GstAudioFormat format = 0;
15027 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15029 depth = entry->bytes_per_packet * 8;
15032 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
15034 /* 8-bit audio is unsigned */
15036 format = GST_AUDIO_FORMAT_U8;
15037 /* otherwise it's signed and big-endian just like 'twos' */
15039 endian = G_BIG_ENDIAN;
15046 endian = G_LITTLE_ENDIAN;
15049 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
15051 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
15055 caps = gst_caps_new_simple ("audio/x-raw",
15056 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15057 "layout", G_TYPE_STRING, "interleaved", NULL);
15058 stream->alignment = GST_ROUND_UP_8 (depth);
15059 stream->alignment = round_up_pow2 (stream->alignment);
15063 _codec ("Raw 64-bit floating-point audio");
15064 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15066 caps = gst_caps_new_simple ("audio/x-raw",
15067 "format", G_TYPE_STRING, "F64BE",
15068 "layout", G_TYPE_STRING, "interleaved", NULL);
15069 stream->alignment = 8;
15072 _codec ("Raw 32-bit floating-point audio");
15073 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15075 caps = gst_caps_new_simple ("audio/x-raw",
15076 "format", G_TYPE_STRING, "F32BE",
15077 "layout", G_TYPE_STRING, "interleaved", NULL);
15078 stream->alignment = 4;
15081 _codec ("Raw 24-bit PCM audio");
15082 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15084 caps = gst_caps_new_simple ("audio/x-raw",
15085 "format", G_TYPE_STRING, "S24BE",
15086 "layout", G_TYPE_STRING, "interleaved", NULL);
15087 stream->alignment = 4;
15090 _codec ("Raw 32-bit PCM audio");
15091 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15093 caps = gst_caps_new_simple ("audio/x-raw",
15094 "format", G_TYPE_STRING, "S32BE",
15095 "layout", G_TYPE_STRING, "interleaved", NULL);
15096 stream->alignment = 4;
15099 _codec ("Raw 16-bit PCM audio");
15100 caps = gst_caps_new_simple ("audio/x-raw",
15101 "format", G_TYPE_STRING, "S16LE",
15102 "layout", G_TYPE_STRING, "interleaved", NULL);
15103 stream->alignment = 2;
15106 _codec ("Mu-law audio");
15107 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
15110 _codec ("A-law audio");
15111 caps = gst_caps_new_empty_simple ("audio/x-alaw");
15115 _codec ("Microsoft ADPCM");
15116 /* Microsoft ADPCM-ACM code 2 */
15117 caps = gst_caps_new_simple ("audio/x-adpcm",
15118 "layout", G_TYPE_STRING, "microsoft", NULL);
15122 _codec ("DVI/IMA ADPCM");
15123 caps = gst_caps_new_simple ("audio/x-adpcm",
15124 "layout", G_TYPE_STRING, "dvi", NULL);
15128 _codec ("DVI/Intel IMA ADPCM");
15129 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15130 caps = gst_caps_new_simple ("audio/x-adpcm",
15131 "layout", G_TYPE_STRING, "quicktime", NULL);
15135 /* MPEG layer 3, CBR only (pre QT4.1) */
15138 _codec ("MPEG-1 layer 3");
15139 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15140 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15141 "mpegversion", G_TYPE_INT, 1, NULL);
15143 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15144 _codec ("MPEG-1 layer 2");
15146 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15147 "mpegversion", G_TYPE_INT, 1, NULL);
15150 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15151 _codec ("EAC-3 audio");
15152 caps = gst_caps_new_simple ("audio/x-eac3",
15153 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15154 entry->sampled = TRUE;
15156 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15158 _codec ("AC-3 audio");
15159 caps = gst_caps_new_simple ("audio/x-ac3",
15160 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15161 entry->sampled = TRUE;
15163 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15164 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15165 _codec ("DTS audio");
15166 caps = gst_caps_new_simple ("audio/x-dts",
15167 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15168 entry->sampled = TRUE;
15170 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15171 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15172 _codec ("DTS-HD audio");
15173 caps = gst_caps_new_simple ("audio/x-dts",
15174 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15175 entry->sampled = TRUE;
15179 caps = gst_caps_new_simple ("audio/x-mace",
15180 "maceversion", G_TYPE_INT, 3, NULL);
15184 caps = gst_caps_new_simple ("audio/x-mace",
15185 "maceversion", G_TYPE_INT, 6, NULL);
15187 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15189 caps = gst_caps_new_empty_simple ("application/ogg");
15191 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15192 _codec ("DV audio");
15193 caps = gst_caps_new_empty_simple ("audio/x-dv");
15196 _codec ("MPEG-4 AAC audio");
15197 caps = gst_caps_new_simple ("audio/mpeg",
15198 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15199 "stream-format", G_TYPE_STRING, "raw", NULL);
15201 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15202 _codec ("QDesign Music");
15203 caps = gst_caps_new_empty_simple ("audio/x-qdm");
15206 _codec ("QDesign Music v.2");
15207 /* FIXME: QDesign music version 2 (no constant) */
15208 if (FALSE && data) {
15209 caps = gst_caps_new_simple ("audio/x-qdm2",
15210 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15211 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15212 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15214 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15218 _codec ("GSM audio");
15219 caps = gst_caps_new_empty_simple ("audio/x-gsm");
15222 _codec ("AMR audio");
15223 caps = gst_caps_new_empty_simple ("audio/AMR");
15226 _codec ("AMR-WB audio");
15227 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15230 _codec ("Quicktime IMA ADPCM");
15231 caps = gst_caps_new_simple ("audio/x-adpcm",
15232 "layout", G_TYPE_STRING, "quicktime", NULL);
15235 _codec ("Apple lossless audio");
15236 caps = gst_caps_new_empty_simple ("audio/x-alac");
15239 _codec ("Free Lossless Audio Codec");
15240 caps = gst_caps_new_simple ("audio/x-flac",
15241 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15243 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15244 _codec ("QualComm PureVoice");
15245 caps = gst_caps_from_string ("audio/qcelp");
15250 caps = gst_caps_new_empty_simple ("audio/x-wma");
15254 caps = gst_caps_new_empty_simple ("audio/x-opus");
15261 GstAudioFormat format;
15264 FLAG_IS_FLOAT = 0x1,
15265 FLAG_IS_BIG_ENDIAN = 0x2,
15266 FLAG_IS_SIGNED = 0x4,
15267 FLAG_IS_PACKED = 0x8,
15268 FLAG_IS_ALIGNED_HIGH = 0x10,
15269 FLAG_IS_NON_INTERLEAVED = 0x20
15271 _codec ("Raw LPCM audio");
15273 if (data && len >= 36) {
15274 depth = QT_UINT32 (data + 24);
15275 flags = QT_UINT32 (data + 28);
15276 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15278 if ((flags & FLAG_IS_FLOAT) == 0) {
15283 if ((flags & FLAG_IS_ALIGNED_HIGH))
15286 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15287 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15288 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15289 caps = gst_caps_new_simple ("audio/x-raw",
15290 "format", G_TYPE_STRING,
15292 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15293 "UNKNOWN", "layout", G_TYPE_STRING,
15294 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15295 "interleaved", NULL);
15296 stream->alignment = GST_ROUND_UP_8 (depth);
15297 stream->alignment = round_up_pow2 (stream->alignment);
15302 if (flags & FLAG_IS_BIG_ENDIAN)
15303 format = GST_AUDIO_FORMAT_F64BE;
15305 format = GST_AUDIO_FORMAT_F64LE;
15307 if (flags & FLAG_IS_BIG_ENDIAN)
15308 format = GST_AUDIO_FORMAT_F32BE;
15310 format = GST_AUDIO_FORMAT_F32LE;
15312 caps = gst_caps_new_simple ("audio/x-raw",
15313 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15314 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15315 "non-interleaved" : "interleaved", NULL);
15316 stream->alignment = width / 8;
15320 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15323 caps = gst_caps_new_empty_simple ("audio/x-ac4");
15326 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15330 caps = _get_unknown_codec_name ("audio", fourcc);
15336 GstCaps *templ_caps =
15337 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15338 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15339 gst_caps_unref (caps);
15340 gst_caps_unref (templ_caps);
15341 caps = intersection;
15344 /* enable clipping for raw audio streams */
15345 s = gst_caps_get_structure (caps, 0);
15346 name = gst_structure_get_name (s);
15347 if (g_str_has_prefix (name, "audio/x-raw")) {
15348 stream->need_clip = TRUE;
15349 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15350 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15351 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15352 stream->max_buffer_size);
15358 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15359 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15360 const guint8 * stsd_entry_data, gchar ** codec_name)
15364 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15368 _codec ("DVD subtitle");
15369 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15370 stream->process_func = gst_qtdemux_process_buffer_dvd;
15373 _codec ("Quicktime timed text");
15376 _codec ("3GPP timed text");
15378 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15380 /* actual text piece needs to be extracted */
15381 stream->process_func = gst_qtdemux_process_buffer_text;
15384 _codec ("XML subtitles");
15385 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15390 const gchar *buf = "WEBVTT\n\n";
15392 _codec ("WebVTT subtitles");
15393 caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15394 stream->process_func = gst_qtdemux_process_buffer_wvtt;
15396 /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15397 buffer = gst_buffer_new_and_alloc (8);
15398 gst_buffer_fill (buffer, 0, buf, 8);
15399 stream->buffers = g_slist_append (stream->buffers, buffer);
15404 _codec ("CEA 608 Closed Caption");
15406 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15407 G_TYPE_STRING, "s334-1a", NULL);
15408 stream->process_func = gst_qtdemux_process_buffer_clcp;
15409 stream->need_split = TRUE;
15412 _codec ("CEA 708 Closed Caption");
15414 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15415 G_TYPE_STRING, "cdp", NULL);
15416 stream->process_func = gst_qtdemux_process_buffer_clcp;
15421 caps = _get_unknown_codec_name ("text", fourcc);
15429 qtdemux_meta_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15430 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15431 const guint8 * stsd_entry_data, gchar ** codec_name)
15433 GstCaps *caps = NULL;
15435 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15439 gsize size = QT_UINT32 (stsd_entry_data);
15440 GstByteReader reader = GST_BYTE_READER_INIT (stsd_entry_data, size);
15441 const gchar *content_encoding;
15442 const gchar *namespaces;
15443 const gchar *schema_locations;
15445 if (!gst_byte_reader_skip (&reader, 8 + 6 + 2)) {
15446 GST_WARNING_OBJECT (qtdemux, "Too short metx sample entry");
15450 if (!gst_byte_reader_get_string (&reader, &content_encoding) ||
15451 !gst_byte_reader_get_string (&reader, &namespaces) ||
15452 !gst_byte_reader_get_string (&reader, &schema_locations)) {
15453 GST_WARNING_OBJECT (qtdemux, "Too short metx sample entry");
15457 if (strstr (namespaces, "http://www.onvif.org/ver10/schema") != 0) {
15458 if (content_encoding == NULL || *content_encoding == '\0'
15459 || g_ascii_strcasecmp (content_encoding, "xml") == 0) {
15460 _codec ("ONVIF Timed XML MetaData");
15462 gst_caps_new_simple ("application/x-onvif-metadata", "parsed",
15463 G_TYPE_BOOLEAN, TRUE, NULL);
15465 GST_DEBUG_OBJECT (qtdemux, "Unknown content encoding: %s",
15469 GST_DEBUG_OBJECT (qtdemux, "Unknown metadata namespaces: %s",
15480 caps = _get_unknown_codec_name ("meta", fourcc);
15486 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15487 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15488 const guint8 * stsd_entry_data, gchar ** codec_name)
15494 _codec ("MPEG 1 video");
15495 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15496 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15506 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15507 const gchar * system_id)
15511 if (!qtdemux->protection_system_ids)
15512 qtdemux->protection_system_ids =
15513 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15514 /* Check whether we already have an entry for this system ID. */
15515 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15516 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15517 if (g_ascii_strcasecmp (system_id, id) == 0) {
15521 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15522 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,